From 5b3c0d6fd02d85ffafaea81ef58f8f4197d1e202 Mon Sep 17 00:00:00 2001 From: mayanje Date: Thu, 21 Oct 2021 16:08:53 +0200 Subject: [PATCH 1/9] WI #2039 Compute cyclic call using transitive closure. --- .../BasicCfgInstrs/CyclicPerformRecursive.cbl | 17 ++ .../CyclicPerformRecursive.diag | 11 + .../BasicCfgInstrs/CyclicPerformRecursive.dot | 51 +++++ .../ExtendedPerformProc3Recursive0.diag | 12 + .../ExtendedPerformProc4Recursive0.diag | 28 +++ .../PerformProc1Recursive0.diag | 1 + .../PerformProc2Recursive0.diag | 4 + .../PerformProc3Recursive0.diag | 12 + .../PerformProc4Recursive0.diag | 28 +++ .../PerformProcIterativeAfterRecursive0.diag | 1 + .../PerformProcIterativeAfterRecursive1.diag | 1 + .../PerformProcIterativeAfterRecursive2.diag | 1 + .../PerformProcIterativeRecursive0.diag | 1 + .../BasicControlFlowInstructionTest.cs | 7 + .../Cfg/ControlFlowGraphBuilder.Paragraph.cs | 2 +- .../Cfg/ControlFlowGraphBuilder.cs | 216 +++++++++++++++++- TypeCobol.Analysis/Graph/ControlFlowGraph.cs | 6 +- 17 files changed, 387 insertions(+), 12 deletions(-) create mode 100644 TypeCobol.Analysis.Test/BasicCfgInstrs/CyclicPerformRecursive.cbl create mode 100644 TypeCobol.Analysis.Test/BasicCfgInstrs/CyclicPerformRecursive.diag create mode 100644 TypeCobol.Analysis.Test/BasicCfgInstrs/CyclicPerformRecursive.dot diff --git a/TypeCobol.Analysis.Test/BasicCfgInstrs/CyclicPerformRecursive.cbl b/TypeCobol.Analysis.Test/BasicCfgInstrs/CyclicPerformRecursive.cbl new file mode 100644 index 000000000..96e7ed9e6 --- /dev/null +++ b/TypeCobol.Analysis.Test/BasicCfgInstrs/CyclicPerformRecursive.cbl @@ -0,0 +1,17 @@ + IDENTIFICATION DIVISION. + PROGRAM-ID. TCOMFL06. + PROCEDURE DIVISION. + main. + perform a + goback + . + a. + perform b + . + b. + perform c + . + c. + perform a + . + END PROGRAM TCOMFL06. \ No newline at end of file diff --git a/TypeCobol.Analysis.Test/BasicCfgInstrs/CyclicPerformRecursive.diag b/TypeCobol.Analysis.Test/BasicCfgInstrs/CyclicPerformRecursive.diag new file mode 100644 index 000000000..db9e05132 --- /dev/null +++ b/TypeCobol.Analysis.Test/BasicCfgInstrs/CyclicPerformRecursive.diag @@ -0,0 +1,11 @@ +--- Diagnostics --- +Line 5[12,20] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM a', recursive instruction is ' perform b'. +Line 5[12,20] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM a', recursive instruction is ' perform c'. +Line 5[12,20] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM a', recursive instruction is ' perform a'. +Line 6[12,17] <37, Warning, General> - Warning: Unreachable code detected +Line 9[12,20] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM b', recursive instruction is ' perform c'. +Line 9[12,20] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM b', recursive instruction is ' perform a'. +Line 9[12,20] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM b', recursive instruction is ' perform b'. +Line 12[12,20] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM c', recursive instruction is ' perform a'. +Line 12[12,20] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM c', recursive instruction is ' perform b'. +Line 12[12,20] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM c', recursive instruction is ' perform c'. diff --git a/TypeCobol.Analysis.Test/BasicCfgInstrs/CyclicPerformRecursive.dot b/TypeCobol.Analysis.Test/BasicCfgInstrs/CyclicPerformRecursive.dot new file mode 100644 index 000000000..fdbe69782 --- /dev/null +++ b/TypeCobol.Analysis.Test/BasicCfgInstrs/CyclicPerformRecursive.dot @@ -0,0 +1,51 @@ +digraph Cfg { +compound=true; +node [ +shape = "record" +] + +edge [ +arrowtail = "empty" +] +Block0 [ +label = "{START|}" +] +Block1 [ +label = "{MAIN. Block1|}" +] +Block2 [ +label = "{Block2| perform a\l}" +] +Block14 [ +label = "{A. Block14|}" +] +Block15 [ +label = "{Block15| perform b\l}" +] +Block25 [ +label = "{B. Block25|}" +] +Block18 [ +label = "{Block18| perform c\l}" +] +Block27 [ +label = "{C. Block27|}" +] +Block21 [ +label = "{Block21| perform a\l}" +] +Block29 [ +label = "{A. Block29|}" +] +Block0 -> Block1 +Block1 -> Block2 +Block2 -> Block14 +Block14 -> Block15 +Block15 -> Block25 +Block25 -> Block18 +Block18 -> Block27 +Block27 -> Block21 +Block21 -> Block29 +Block29 -> Block15 + +} diff --git a/TypeCobol.Analysis.Test/BasicCfgInstrs/ExtendedPerformProc3Recursive0.diag b/TypeCobol.Analysis.Test/BasicCfgInstrs/ExtendedPerformProc3Recursive0.diag index 37f27f57b..45dd3fc2f 100644 --- a/TypeCobol.Analysis.Test/BasicCfgInstrs/ExtendedPerformProc3Recursive0.diag +++ b/TypeCobol.Analysis.Test/BasicCfgInstrs/ExtendedPerformProc3Recursive0.diag @@ -1,3 +1,15 @@ --- Diagnostics --- +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2'. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec3'. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec'. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2'. +Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec'. +Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec2'. +Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec3'. +Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec2'. +Line 20[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec2'. +Line 20[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec'. +Line 20[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec2'. +Line 20[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec3'. Line 28[15,29] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2'. Line 29[15,57] <37, Warning, General> - Warning: Unreachable code detected diff --git a/TypeCobol.Analysis.Test/BasicCfgInstrs/ExtendedPerformProc4Recursive0.diag b/TypeCobol.Analysis.Test/BasicCfgInstrs/ExtendedPerformProc4Recursive0.diag index 16afa8351..e21d775ec 100644 --- a/TypeCobol.Analysis.Test/BasicCfgInstrs/ExtendedPerformProc4Recursive0.diag +++ b/TypeCobol.Analysis.Test/BasicCfgInstrs/ExtendedPerformProc4Recursive0.diag @@ -1,4 +1,32 @@ --- Diagnostics --- +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2'. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec3'. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec4'. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec'. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2'. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec3 test after varying n from 1 by 1 until n'. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec4 varying n from 1 by 1 until n > 5'. +Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec3 test after varying n from 1 by 1 until n'. +Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec4 varying n from 1 by 1 until n > 5'. +Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec2'. +Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec'. +Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec2'. +Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec3'. +Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec4'. +Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec'. +Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec2'. +Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec3'. +Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec4'. +Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec2'. +Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec3 test after varying n from 1 by 1 until n'. +Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec4 varying n from 1 by 1 until n > 5'. +Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec2'. +Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec'. +Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec2'. +Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec3'. +Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec4'. +Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec3 test after varying n from 1 by 1 until n'. +Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec4 varying n from 1 by 1 until n > 5'. Line 31[15,29] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2'. Line 32[15,57] <37, Warning, General> - Warning: Unreachable code detected Line 57[15,64] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec4 varying n from 1 by 1 until n > 5'. diff --git a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc1Recursive0.diag b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc1Recursive0.diag index 7a1c41c0c..e97bc375a 100644 --- a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc1Recursive0.diag +++ b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc1Recursive0.diag @@ -1,2 +1,3 @@ --- Diagnostics --- +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec'. Line 16[15,29] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec'. diff --git a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc2Recursive0.diag b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc2Recursive0.diag index c5163b4b7..aab59fb9d 100644 --- a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc2Recursive0.diag +++ b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc2Recursive0.diag @@ -1,2 +1,6 @@ --- Diagnostics --- +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2'. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec'. +Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec'. +Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec2'. Line 27[15,29] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2'. diff --git a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc3Recursive0.diag b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc3Recursive0.diag index 18ede9f54..86cf84618 100644 --- a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc3Recursive0.diag +++ b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc3Recursive0.diag @@ -1,2 +1,14 @@ --- Diagnostics --- +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2'. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec3'. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec'. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2'. +Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec'. +Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec2'. +Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec3'. +Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec2'. +Line 20[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec2'. +Line 20[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec'. +Line 20[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec2'. +Line 20[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec3'. Line 28[15,29] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2'. diff --git a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc4Recursive0.diag b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc4Recursive0.diag index 6953076dc..a4ec6eaa6 100644 --- a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc4Recursive0.diag +++ b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc4Recursive0.diag @@ -1,4 +1,32 @@ --- Diagnostics --- +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2'. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec3'. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec4'. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec'. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2'. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec3 test after varying n from 1 by 1 until n'. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec4 varying n from 1 by 1 until n > 5'. +Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec3 test after varying n from 1 by 1 until n'. +Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec4 varying n from 1 by 1 until n > 5'. +Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec2'. +Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec'. +Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec2'. +Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec3'. +Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec4'. +Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec'. +Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec2'. +Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec3'. +Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec4'. +Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec2'. +Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec3 test after varying n from 1 by 1 until n'. +Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec4 varying n from 1 by 1 until n > 5'. +Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec2'. +Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec'. +Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec2'. +Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec3'. +Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec4'. +Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec3 test after varying n from 1 by 1 until n'. +Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec4 varying n from 1 by 1 until n > 5'. Line 31[15,29] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2'. Line 57[15,64] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec4 varying n from 1 by 1 until n > 5'. Line 57[15,64] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec3 test after varying n from 1 by 1 until n'. diff --git a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeAfterRecursive0.diag b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeAfterRecursive0.diag index 0189177ad..57dd3b18d 100644 --- a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeAfterRecursive0.diag +++ b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeAfterRecursive0.diag @@ -1,2 +1,3 @@ --- Diagnostics --- +Line 8[12,71] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec varying n from 1 by 1 until n > 5'. Line 16[15,64] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec varying n from 1 by 1 until n > 5'. diff --git a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeAfterRecursive1.diag b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeAfterRecursive1.diag index c0376cafa..610bd32bf 100644 --- a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeAfterRecursive1.diag +++ b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeAfterRecursive1.diag @@ -1,2 +1,3 @@ --- Diagnostics --- +Line 8[12,60] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec test after varying n from 1 by 1 until n>5'. Line 16[15,72] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec test after varying n from 1 by 1 until n>5'. diff --git a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeAfterRecursive2.diag b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeAfterRecursive2.diag index c0376cafa..eef2859f5 100644 --- a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeAfterRecursive2.diag +++ b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeAfterRecursive2.diag @@ -1,2 +1,3 @@ --- Diagnostics --- +Line 8[12,71] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec test after varying n from 1 by 1 until n>5'. Line 16[15,72] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec test after varying n from 1 by 1 until n>5'. diff --git a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeRecursive0.diag b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeRecursive0.diag index 0189177ad..5be6ff278 100644 --- a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeRecursive0.diag +++ b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeRecursive0.diag @@ -1,2 +1,3 @@ --- Diagnostics --- +Line 8[12,60] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec varying n from 1 by 1 until n > 5'. Line 16[15,64] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec varying n from 1 by 1 until n > 5'. diff --git a/TypeCobol.Analysis.Test/BasicControlFlowInstructionTest.cs b/TypeCobol.Analysis.Test/BasicControlFlowInstructionTest.cs index 948b64199..b83f08f7c 100644 --- a/TypeCobol.Analysis.Test/BasicControlFlowInstructionTest.cs +++ b/TypeCobol.Analysis.Test/BasicControlFlowInstructionTest.cs @@ -723,5 +723,12 @@ public void ExtendedPerformProcIterativeAfterRecursive2() const string baseName = "PerformProcIterativeAfterRecursive2"; TestTemplate(inputFileName: baseName, expectedDiagnosticsFileName: baseName, mode: CfgBuildingMode.Extended); } + + [TestMethod] + public void CyclicPerformRecursive() + { + const string baseName = "CyclicPerformRecursive"; + TestTemplate(inputFileName: baseName, expectedDiagnosticsFileName: baseName, mode: CfgBuildingMode.Extended); + } } } diff --git a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.Paragraph.cs b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.Paragraph.cs index a1b89ae5c..c0a56cd9a 100644 --- a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.Paragraph.cs +++ b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.Paragraph.cs @@ -60,7 +60,7 @@ public override IEnumerator GetEnumerator() public override void AccumulateSentencesThrough(List sentences, Procedure end, out Procedure last) { - if (_sentences != null) + if (_sentences != null && sentences != null) sentences.AddRange(_sentences); last = this; } diff --git a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.cs b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.cs index fa7929feb..791ab14e6 100644 --- a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.cs +++ b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.cs @@ -986,13 +986,196 @@ T GetUnique(IList list) where T : Node #endregion + /// + /// Add a Direct Call to the Call Relation. + /// For a PERFORM THRU all intermediate procedure are added to the relation. + /// + /// The caller of the PERFOM procedure + /// The PERFOM procedure called + /// CALL Relation + /// The domain of the call relation + private void AddDirectCallRelation(PerformProcedure performCaller, Procedure caller, PerformProcedure callee, + Dictionary, HashSet>> callRelation, + HashSet callRelationDomain) + { + var item = PendingPERFORMProcedures.FirstOrDefault(i => i.Item1 == callee); + if (item == null) + return; + SymbolReference calleeReference = callee.CodeElement.Procedure; + SymbolReference throughProcedureReference = callee.CodeElement.ThroughProcedure; + + Node calleeNode = ResolveProcedure(callee, item.Item2, calleeReference); + if (calleeNode == null) + return; + Procedure calleeProcedure = _nodeToProcedure[calleeNode]; + if (throughProcedureReference != null) + { + Node throughProcedureNode = ResolveProcedure(callee, item.Item2, throughProcedureReference); + if (throughProcedureNode == null) + return; + + Procedure throughProcedure = _nodeToProcedure[throughProcedureNode]; + if (calleeProcedure.Number > throughProcedure.Number) + { + // the second procedure name is declared before the first one. + return; + } + + int currentProcedureNumber = calleeProcedure.Number; + while (currentProcedureNumber <= throughProcedure.Number) + { + Procedure currentProcedure = this.CurrentProgramCfgBuilder.AllProcedures[currentProcedureNumber]; + currentProcedure.AccumulateSentencesThrough(null, throughProcedure, out var lastProcedure); + currentProcedureNumber = lastProcedure.Number + 1; + + addToRelation(currentProcedure, callee); + } + } + else + { + addToRelation(calleeProcedure, callee); + } + callRelationDomain.Add(caller); + + void addToRelation(Procedure _calleeProcedure, PerformProcedure _callee) + { + if (!callRelation.TryGetValue(caller, out var callees)) + { + callees = new Tuple, HashSet>(performCaller, new List(), new HashSet()); + callRelation[caller] = callees; + } + if (!callees.Item3.Contains(_calleeProcedure)) + { + callees.Item3.Add(_calleeProcedure); + } + if (!callees.Item2.Contains(_callee)) + { + callees.Item2.Add(_callee); + } + callRelationDomain.Add(_calleeProcedure); + } + } + + /// + /// Compute the transitive closure of the CALL relation. + /// We browse the the graph represented using the Call Relation, then we found during the visit cycles. + /// In the same time we compute the call chain. + /// + /// CALL Relation + /// The domain of the call relation + /// Already reported recursif procedures + private void TransitiveClosureCallRelation(Dictionary, HashSet>> callRelation, HashSet callRelationDomain, + HashSet reportedProcedures) + { + Stack S = new Stack(); + Dictionary N = new Dictionary(); + + foreach(var a in callRelationDomain) + { + var na = Visited(a); + if (na == 0) + dfs(a); + } + // Report all cyclic procedure. + foreach (var item in callRelation) + { + if (!reportedProcedures.Contains(item.Value.Item1)) + { + if (item.Value.Item3.Contains(item.Key)) + { + this.Cfg.AddRecursivePerform(item.Value.Item1, item.Value.Item2); + } + } + } + + void dfs(Procedure a) + { + S.Push(a); + int d = S.Count; + N[a] = d; + var fa = f(a); + if (fa.Item3 != null) + { //For all procedure b called by a + foreach (var b in fa.Item3.ToArray()) + { + int nb = Visited(b); + if (nb == 0) + dfs(b);//Procedure not visited yet + int _na = Visited(a); + int _nb = Visited(b); + N[a] = Math.Min(_na, _nb); // N[b] < N[a] : we find a cycle + var fb = f(b); + // f(a) = f(a) U f(b) + // We update the call chain + foreach (var p in fb.Item2) + { + if (!fa.Item2.Contains(p)) + { + fa.Item2.Add(p); + } + } + foreach (var pb in fb.Item3) + { + fa.Item3.Add(pb); + } + } + } + var na = Visited(a); + if (na == d) + { // a is an entry point of a calculated component + do + { + N[S.Peek()] = Int32.MaxValue; // The Node(The procedure) is terminated + if (callRelation.TryGetValue(S.Peek(), out var top)) + { + foreach (var pp in fa.Item2) + { + if (!top.Item2.Contains(pp)) + { + top.Item2.Add(pp); + } + } + foreach (var pb in fa.Item3) + { + top.Item3.Add(pb); + } + } + else + { + callRelation[S.Peek()] = new Tuple, HashSet>( + fa.Item1, new List(fa.Item2), new HashSet(fa.Item3)); + } + } while (S.Count > 0 && S.Pop() != a); + } + } + + int Visited(Procedure a) + { + if (N.TryGetValue(a, out var na)) + return na; + return 0; + } + Tuple, HashSet> f(Procedure a) + { + if (callRelation.TryGetValue(a, out var v)) + return v; + else + return new Tuple, HashSet>(null, new List(), new HashSet()); + } + } + /// /// Resolve a pending PERFORM procedure /// /// A Tuple made of the PerformProcedure node, the section in which the PERFORM appears /// and the Basic Block Group associated to the Perform Procedure. /// List of new PERFORMs cloned during the resolve process. - private void ResolvePendingPERFORMProcedure(Tuple perform, List> clonedPerforms) + /// The Call relation. + /// The Call relation domain. + /// Already reported recursif procedures + private void ResolvePendingPERFORMProcedure(Tuple perform, List> clonedPerforms, + Dictionary, HashSet>> callRelation, HashSet callRelationDomain, + HashSet reportedProcedures) { PerformProcedure p = perform.Item1; SectionNode sectionNode = perform.Item2; @@ -1023,30 +1206,39 @@ private void ResolvePendingPERFORMProcedure(Tuple sentences = new List(); + List procedures = new List(); + int n = 0; int currentProcedureNumber = procedure.Number; while (currentProcedureNumber <= throughProcedure.Number) { var currentProcedure = this.CurrentProgramCfgBuilder.AllProcedures[currentProcedureNumber]; currentProcedure.AccumulateSentencesThrough(sentences, throughProcedure, out var lastProcedure); currentProcedureNumber = lastProcedure.Number + 1; + while (n < sentences.Count) + { + procedures.Add(currentProcedure); + n++; + } } //Store sentences into the group - StoreSentences(sentences); + StoreSentences(sentences, procedures); } else { //Store all sentences from the procedure into the group - StoreSentences(procedure); + StoreSentences(procedure, new List() { procedure }); } //And finally relocate the Graph. RelocateBasicBlockForNodeGroupGraph(p, group, clonedBlocksIndexMap); - void StoreSentences(IEnumerable sentences) + void StoreSentences(IEnumerable sentences, List procedures) { + int n = 0; foreach (var sentence in sentences) { + var currentProcedure = n >= procedures.Count ? procedures[procedures.Count - 1] : procedures[n++]; foreach (var block in sentence.Blocks) { System.Diagnostics.Debug.Assert(!clonedBlocksIndexMap.ContainsKey(block.Index)); @@ -1056,6 +1248,7 @@ void StoreSentences(IEnumerable sentences) if (block is BasicBlockForNodeGroup group0) { isPerform = true; //To avoid a second dynamic cast + AddDirectCallRelation(p, currentProcedure, (PerformProcedure)group0.Instructions.Last.Value, callRelation, callRelationDomain); //Is there a recursion in the graph ? if (group.RecursivityGroupSet.Get(group0.GroupIndex) && !group0.HasFlag(BasicBlock.Flags.Recursive)) @@ -1064,7 +1257,8 @@ void StoreSentences(IEnumerable sentences) group0.SetFlag(BasicBlock.Flags.Recursive, true); Node offendingInstruction = group0.Instructions.Last.Value; System.Diagnostics.Debug.Assert(offendingInstruction != null); - this.Cfg.AddRecursivePerform(p, offendingInstruction); + this.Cfg.AddRecursivePerform(p, new List() { offendingInstruction }); + reportedProcedures.Add(p); } var clonedGroup0 = clonedPerforms @@ -1174,14 +1368,17 @@ private void ResolvePendingPERFORMProcedures() { if (this.CurrentProgramCfgBuilder.PendingPERFORMProcedures != null) { + Dictionary, HashSet>> callRelation = + new Dictionary, HashSet>>(); + HashSet callRelationDomain = new HashSet(); + HashSet reportedProcedures = new HashSet(); var clonedPerforms = new List>(); - //First pass: resolve targets of PERFORMs, some new groups may be created during this foreach (var item in this.CurrentProgramCfgBuilder.PendingPERFORMProcedures) { item.Item3.RecursivityGroupSet = new BitArray(GroupCounter + 1); item.Item3.RecursivityGroupSet.Set(item.Item3.GroupIndex, true); - ResolvePendingPERFORMProcedure(item, clonedPerforms); + ResolvePendingPERFORMProcedure(item, clonedPerforms, callRelation, callRelationDomain, reportedProcedures); } //Second pass: resolve cloned groups created during first pass @@ -1189,9 +1386,12 @@ private void ResolvePendingPERFORMProcedures() { //We are using a regular for instead of foreach because new groups may also be created during this second pass. //New groups/performs to resolve are added at tail and all are processed during this second pass - ResolvePendingPERFORMProcedure(clonedPerforms[i], clonedPerforms); + ResolvePendingPERFORMProcedure(clonedPerforms[i], clonedPerforms, callRelation, callRelationDomain, reportedProcedures); } + // Report Cyclic PERFORM call + TransitiveClosureCallRelation(callRelation, callRelationDomain, reportedProcedures); + //Index groups by their GroupIndex, keep only the final instance of each group after all resolve have been done var groupOrder = new Dictionary(); foreach (var item in this.CurrentProgramCfgBuilder.PendingPERFORMProcedures) diff --git a/TypeCobol.Analysis/Graph/ControlFlowGraph.cs b/TypeCobol.Analysis/Graph/ControlFlowGraph.cs index e38b7f3c7..91ef75b4c 100644 --- a/TypeCobol.Analysis/Graph/ControlFlowGraph.cs +++ b/TypeCobol.Analysis/Graph/ControlFlowGraph.cs @@ -226,7 +226,7 @@ internal void AddWrongOrderPerformThru(PerformProcedure performThru, N procedure /// /// Perform node /// Recursive jump node - internal void AddRecursivePerform(PerformProcedure perform, N recursiveJump) + internal void AddRecursivePerform(PerformProcedure perform, List recursiveJump) { if (RecursivePerforms == null) { @@ -235,11 +235,11 @@ internal void AddRecursivePerform(PerformProcedure perform, N recursiveJump) if (RecursivePerforms.TryGetValue(perform, out var nodes)) { - nodes.Add(recursiveJump); + nodes.AddRange(recursiveJump); } else { - RecursivePerforms.Add(perform, new List() { recursiveJump }); + RecursivePerforms.Add(perform, recursiveJump); } } From 9bf7eb1746a516e366933a2677128b7a4ace8fd7 Mon Sep 17 00:00:00 2001 From: mayanje Date: Fri, 29 Oct 2021 17:33:06 +0200 Subject: [PATCH 2/9] WI #2039 Use PerformTarget class. --- .../Cfg/ControlFlowGraphBuilder.Paragraph.cs | 2 +- .../ControlFlowGraphBuilder.PerformTarget.cs | 95 ++++++++++++ .../Cfg/ControlFlowGraphBuilder.Sentence.cs | 5 + .../Cfg/ControlFlowGraphBuilder.cs | 144 +++++------------- TypeCobol.Analysis/TypeCobol.Analysis.csproj | 1 + 5 files changed, 140 insertions(+), 107 deletions(-) create mode 100644 TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.PerformTarget.cs diff --git a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.Paragraph.cs b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.Paragraph.cs index c0a56cd9a..a1b89ae5c 100644 --- a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.Paragraph.cs +++ b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.Paragraph.cs @@ -60,7 +60,7 @@ public override IEnumerator GetEnumerator() public override void AccumulateSentencesThrough(List sentences, Procedure end, out Procedure last) { - if (_sentences != null && sentences != null) + if (_sentences != null) sentences.AddRange(_sentences); last = this; } diff --git a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.PerformTarget.cs b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.PerformTarget.cs new file mode 100644 index 000000000..31bc8ada8 --- /dev/null +++ b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.PerformTarget.cs @@ -0,0 +1,95 @@ +using System.Collections.Generic; +using TypeCobol.Compiler.CodeElements; +using TypeCobol.Compiler.Nodes; +using SectionNode = TypeCobol.Compiler.Nodes.Section; + +namespace TypeCobol.Analysis.Cfg +{ + public partial class ControlFlowGraphBuilder + { + /// + /// PerfomrTarget class to capture target sentences and procedures from a PERFORM instruction. + /// + private class PerformTarget + { + /// + /// All target sentences + /// + internal List Sentences { get; private set; } + /// + /// All target procedures. + /// + internal List Procedures { get; private set; } + + public PerformTarget(List sentences, List procedures) + { + this.Sentences = sentences; + this.Procedures = procedures; + } + } + + /// + /// Cache of PerformTarget instances already calculated for a Perform procedure + /// + private Dictionary _performTargetCache; + private PerformTarget ComputePerformTarget(PerformProcedure p, SectionNode sectionNode) + { + if (_performTargetCache == null) + _performTargetCache = new Dictionary(); + if (_performTargetCache.TryGetValue(p, out var target)) { + return target; + } + + SymbolReference procedureReference = p.CodeElement.Procedure; + SymbolReference throughProcedureReference = p.CodeElement.ThroughProcedure; + + Node procedureNode = ResolveProcedure(p, sectionNode, procedureReference); + if (procedureNode == null) + return null; + + Procedure procedure = _nodeToProcedure[procedureNode]; + List sentences = new List(); + List procedures = new List(); + if (throughProcedureReference != null) + { + Node throughProcedureNode = ResolveProcedure(p, sectionNode, throughProcedureReference); + if (throughProcedureNode == null) + return null; + + Procedure throughProcedure = _nodeToProcedure[throughProcedureNode]; + if (procedure.Number > throughProcedure.Number) + { + // the second procedure name is declared before the first one. + this.Cfg.AddWrongOrderPerformThru(p, procedureNode, throughProcedureNode); + return null; + } + + //Accumulate sentences located between the two procedures + int n = 0; + int currentProcedureNumber = procedure.Number; + while (currentProcedureNumber <= throughProcedure.Number) + { + var currentProcedure = this.CurrentProgramCfgBuilder.AllProcedures[currentProcedureNumber]; + currentProcedure.AccumulateSentencesThrough(sentences, throughProcedure, out var lastProcedure); + currentProcedureNumber = lastProcedure.Number + 1; + procedures.Add(currentProcedure); + while (n < sentences.Count) + { + sentences[n++].Procedure = currentProcedure; + } + } + } else + { + procedures.Add(procedure); + foreach (var sentence in procedure) + { + sentences.Add(sentence); + sentence.Procedure = procedure; + } + } + target = new PerformTarget(sentences, procedures); + _performTargetCache[p] = target; + return target; + } + } +} diff --git a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.Sentence.cs b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.Sentence.cs index ede69526f..24c8bb1fe 100644 --- a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.Sentence.cs +++ b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.Sentence.cs @@ -17,6 +17,11 @@ private class Sentence : ProcedureDivisionRegion /// public int? FirstBlockIndex { get; } + /// + /// The associated procedure + /// + internal Procedure Procedure { get; set; } + /// /// Constructor. /// diff --git a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.cs b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.cs index 791ab14e6..2d5d1ae80 100644 --- a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.cs +++ b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.cs @@ -987,72 +987,45 @@ T GetUnique(IList list) where T : Node #endregion /// - /// Add a Direct Call to the Call Relation. + /// Add a Direct Call Peform to the Call Perform Relation. /// For a PERFORM THRU all intermediate procedure are added to the relation. /// /// The caller of the PERFOM procedure /// The PERFOM procedure called - /// CALL Relation - /// The domain of the call relation - private void AddDirectCallRelation(PerformProcedure performCaller, Procedure caller, PerformProcedure callee, - Dictionary, HashSet>> callRelation, - HashSet callRelationDomain) + /// CALL Relation + /// The domain of the call relation + private void AddDirectCallPerformRelation(PerformProcedure performCaller, Procedure caller, PerformProcedure callee, + Dictionary, HashSet>> callPerformRelation, + HashSet callPerformRelationDomain) { var item = PendingPERFORMProcedures.FirstOrDefault(i => i.Item1 == callee); if (item == null) return; - SymbolReference calleeReference = callee.CodeElement.Procedure; - SymbolReference throughProcedureReference = callee.CodeElement.ThroughProcedure; - - Node calleeNode = ResolveProcedure(callee, item.Item2, calleeReference); - if (calleeNode == null) + PerformTarget performTarget = ComputePerformTarget(callee, item.Item2); + if (performTarget == null) return; - Procedure calleeProcedure = _nodeToProcedure[calleeNode]; - if (throughProcedureReference != null) + foreach (Procedure calleeProcedure in performTarget.Procedures) { - Node throughProcedureNode = ResolveProcedure(callee, item.Item2, throughProcedureReference); - if (throughProcedureNode == null) - return; - - Procedure throughProcedure = _nodeToProcedure[throughProcedureNode]; - if (calleeProcedure.Number > throughProcedure.Number) - { - // the second procedure name is declared before the first one. - return; - } - - int currentProcedureNumber = calleeProcedure.Number; - while (currentProcedureNumber <= throughProcedure.Number) - { - Procedure currentProcedure = this.CurrentProgramCfgBuilder.AllProcedures[currentProcedureNumber]; - currentProcedure.AccumulateSentencesThrough(null, throughProcedure, out var lastProcedure); - currentProcedureNumber = lastProcedure.Number + 1; - - addToRelation(currentProcedure, callee); - } - } - else - { - addToRelation(calleeProcedure, callee); + addToRelation(calleeProcedure); } - callRelationDomain.Add(caller); + callPerformRelationDomain.Add(caller); - void addToRelation(Procedure _calleeProcedure, PerformProcedure _callee) + void addToRelation(Procedure _calleeProcedure) { - if (!callRelation.TryGetValue(caller, out var callees)) + if (!callPerformRelation.TryGetValue(caller, out var callees)) { callees = new Tuple, HashSet>(performCaller, new List(), new HashSet()); - callRelation[caller] = callees; + callPerformRelation[caller] = callees; } if (!callees.Item3.Contains(_calleeProcedure)) { callees.Item3.Add(_calleeProcedure); } - if (!callees.Item2.Contains(_callee)) + if (!callees.Item2.Contains(callee)) { - callees.Item2.Add(_callee); + callees.Item2.Add(callee); } - callRelationDomain.Add(_calleeProcedure); + callPerformRelationDomain.Add(_calleeProcedure); } } @@ -1062,15 +1035,19 @@ void addToRelation(Procedure _calleeProcedure, PerformProcedure _callee) /// In the same time we compute the call chain. /// /// CALL Relation - /// The domain of the call relation + /// The domain of the call relation /// Already reported recursif procedures - private void TransitiveClosureCallRelation(Dictionary, HashSet>> callRelation, HashSet callRelationDomain, + private void TransitiveClosureCallRelation(Dictionary, HashSet>> callRelation, HashSet callPerformRelationDomain, HashSet reportedProcedures) { Stack S = new Stack(); + // The dictionary is used for three purposes + // 1) To record unmarked procedures (N[p] == 0). + // 2) To associate a positive number value with procedures that are active consideration (0 < N[p] < Infnity). + // 3) To mark Infinity Procedures whose cycles have already been found Dictionary N = new Dictionary(); - foreach(var a in callRelationDomain) + foreach(var a in callPerformRelationDomain) { var na = Visited(a); if (na == 0) @@ -1170,75 +1147,30 @@ Tuple, HashSet> f(Procedure a) /// A Tuple made of the PerformProcedure node, the section in which the PERFORM appears /// and the Basic Block Group associated to the Perform Procedure. /// List of new PERFORMs cloned during the resolve process. - /// The Call relation. - /// The Call relation domain. + /// The Call relation. + /// The Call relation domain. /// Already reported recursif procedures private void ResolvePendingPERFORMProcedure(Tuple perform, List> clonedPerforms, - Dictionary, HashSet>> callRelation, HashSet callRelationDomain, + Dictionary, HashSet>> callPerformRelation, HashSet callPerformRelationDomain, HashSet reportedProcedures) { PerformProcedure p = perform.Item1; SectionNode sectionNode = perform.Item2; BasicBlockForNodeGroup group = perform.Item3; - SymbolReference procedureReference = p.CodeElement.Procedure; - SymbolReference throughProcedureReference = p.CodeElement.ThroughProcedure; - - Node procedureNode = ResolveProcedure(p, sectionNode, procedureReference); - if (procedureNode == null) + PerformTarget performTarget = ComputePerformTarget(p, sectionNode); + if (performTarget == null) return; - - Procedure procedure = _nodeToProcedure[procedureNode]; var clonedBlocksIndexMap = new Dictionary(); - if (throughProcedureReference != null) - { - Node throughProcedureNode = ResolveProcedure(p, sectionNode, throughProcedureReference); - if (throughProcedureNode == null) - return; - - Procedure throughProcedure = _nodeToProcedure[throughProcedureNode]; - if (procedure.Number > throughProcedure.Number) - { - // the second procedure name is declared before the first one. - this.Cfg.AddWrongOrderPerformThru(p, procedureNode, throughProcedureNode); - return; - } - - //Accumulate sentences located between the two procedures - List sentences = new List(); - List procedures = new List(); - int n = 0; - int currentProcedureNumber = procedure.Number; - while (currentProcedureNumber <= throughProcedure.Number) - { - var currentProcedure = this.CurrentProgramCfgBuilder.AllProcedures[currentProcedureNumber]; - currentProcedure.AccumulateSentencesThrough(sentences, throughProcedure, out var lastProcedure); - currentProcedureNumber = lastProcedure.Number + 1; - while (n < sentences.Count) - { - procedures.Add(currentProcedure); - n++; - } - } - - //Store sentences into the group - StoreSentences(sentences, procedures); - } - else - { - //Store all sentences from the procedure into the group - StoreSentences(procedure, new List() { procedure }); - } - + StoreSentences(performTarget); //And finally relocate the Graph. RelocateBasicBlockForNodeGroupGraph(p, group, clonedBlocksIndexMap); - void StoreSentences(IEnumerable sentences, List procedures) + void StoreSentences(PerformTarget target) { - int n = 0; - foreach (var sentence in sentences) + foreach (var sentence in performTarget.Sentences) { - var currentProcedure = n >= procedures.Count ? procedures[procedures.Count - 1] : procedures[n++]; + var currentProcedure = sentence.Procedure; foreach (var block in sentence.Blocks) { System.Diagnostics.Debug.Assert(!clonedBlocksIndexMap.ContainsKey(block.Index)); @@ -1248,7 +1180,7 @@ void StoreSentences(IEnumerable sentences, List procedures) if (block is BasicBlockForNodeGroup group0) { isPerform = true; //To avoid a second dynamic cast - AddDirectCallRelation(p, currentProcedure, (PerformProcedure)group0.Instructions.Last.Value, callRelation, callRelationDomain); + AddDirectCallPerformRelation(p, currentProcedure, (PerformProcedure)group0.Instructions.Last.Value, callPerformRelation, callPerformRelationDomain); //Is there a recursion in the graph ? if (group.RecursivityGroupSet.Get(group0.GroupIndex) && !group0.HasFlag(BasicBlock.Flags.Recursive)) @@ -1370,7 +1302,7 @@ private void ResolvePendingPERFORMProcedures() { Dictionary, HashSet>> callRelation = new Dictionary, HashSet>>(); - HashSet callRelationDomain = new HashSet(); + HashSet callPerformRelationDomain = new HashSet(); HashSet reportedProcedures = new HashSet(); var clonedPerforms = new List>(); //First pass: resolve targets of PERFORMs, some new groups may be created during this @@ -1378,7 +1310,7 @@ private void ResolvePendingPERFORMProcedures() { item.Item3.RecursivityGroupSet = new BitArray(GroupCounter + 1); item.Item3.RecursivityGroupSet.Set(item.Item3.GroupIndex, true); - ResolvePendingPERFORMProcedure(item, clonedPerforms, callRelation, callRelationDomain, reportedProcedures); + ResolvePendingPERFORMProcedure(item, clonedPerforms, callRelation, callPerformRelationDomain, reportedProcedures); } //Second pass: resolve cloned groups created during first pass @@ -1386,11 +1318,11 @@ private void ResolvePendingPERFORMProcedures() { //We are using a regular for instead of foreach because new groups may also be created during this second pass. //New groups/performs to resolve are added at tail and all are processed during this second pass - ResolvePendingPERFORMProcedure(clonedPerforms[i], clonedPerforms, callRelation, callRelationDomain, reportedProcedures); + ResolvePendingPERFORMProcedure(clonedPerforms[i], clonedPerforms, callRelation, callPerformRelationDomain, reportedProcedures); } // Report Cyclic PERFORM call - TransitiveClosureCallRelation(callRelation, callRelationDomain, reportedProcedures); + TransitiveClosureCallRelation(callRelation, callPerformRelationDomain, reportedProcedures); //Index groups by their GroupIndex, keep only the final instance of each group after all resolve have been done var groupOrder = new Dictionary(); diff --git a/TypeCobol.Analysis/TypeCobol.Analysis.csproj b/TypeCobol.Analysis/TypeCobol.Analysis.csproj index fd58633f1..b1bf66ac4 100644 --- a/TypeCobol.Analysis/TypeCobol.Analysis.csproj +++ b/TypeCobol.Analysis/TypeCobol.Analysis.csproj @@ -68,6 +68,7 @@ + From d80af72842c12ec5ca7d6ffbf3533a747e80ccf2 Mon Sep 17 00:00:00 2001 From: mayanje Date: Tue, 2 Nov 2021 17:34:41 +0100 Subject: [PATCH 3/9] WI #2039 Remove old diagnostics --- .../CyclicPerformRecursive.diag | 18 +++--- .../ExtendedPerformProc3Recursive0.diag | 25 ++++---- .../ExtendedPerformProc4Recursive0.diag | 59 +++++++++---------- .../BasicCfgInstrs/PerformIdentity.diag | 2 +- .../PerformProc1Recursive0.diag | 3 +- .../PerformProc2Recursive0.diag | 9 ++- .../PerformProc3Recursive0.diag | 25 ++++---- .../PerformProc4Recursive0.diag | 59 +++++++++---------- .../PerformProcIterativeAfterRecursive0.diag | 3 +- .../PerformProcIterativeAfterRecursive1.diag | 3 +- .../PerformProcIterativeAfterRecursive2.diag | 3 +- .../PerformProcIterativeRecursive0.diag | 3 +- .../BasicCfgInstrs/SG102A.diag | 4 -- .../Cfg/ControlFlowGraphBuilder.cs | 39 ++++-------- TypeCobol.Analysis/Resource.Designer.cs | 34 +++++------ TypeCobol.Analysis/Resource.resx | 2 +- 16 files changed, 127 insertions(+), 164 deletions(-) diff --git a/TypeCobol.Analysis.Test/BasicCfgInstrs/CyclicPerformRecursive.diag b/TypeCobol.Analysis.Test/BasicCfgInstrs/CyclicPerformRecursive.diag index db9e05132..f77827768 100644 --- a/TypeCobol.Analysis.Test/BasicCfgInstrs/CyclicPerformRecursive.diag +++ b/TypeCobol.Analysis.Test/BasicCfgInstrs/CyclicPerformRecursive.diag @@ -1,11 +1,11 @@ --- Diagnostics --- -Line 5[12,20] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM a', recursive instruction is ' perform b'. -Line 5[12,20] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM a', recursive instruction is ' perform c'. -Line 5[12,20] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM a', recursive instruction is ' perform a'. +Line 5[12,20] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM a', recursive instruction is ' perform b' at line 9. +Line 5[12,20] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM a', recursive instruction is ' perform c' at line 12. +Line 5[12,20] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM a', recursive instruction is ' perform a' at line 15. Line 6[12,17] <37, Warning, General> - Warning: Unreachable code detected -Line 9[12,20] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM b', recursive instruction is ' perform c'. -Line 9[12,20] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM b', recursive instruction is ' perform a'. -Line 9[12,20] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM b', recursive instruction is ' perform b'. -Line 12[12,20] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM c', recursive instruction is ' perform a'. -Line 12[12,20] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM c', recursive instruction is ' perform b'. -Line 12[12,20] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM c', recursive instruction is ' perform c'. +Line 9[12,20] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM b', recursive instruction is ' perform c' at line 12. +Line 9[12,20] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM b', recursive instruction is ' perform a' at line 15. +Line 9[12,20] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM b', recursive instruction is ' perform b' at line 9. +Line 12[12,20] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM c', recursive instruction is ' perform a' at line 15. +Line 12[12,20] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM c', recursive instruction is ' perform b' at line 9. +Line 12[12,20] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM c', recursive instruction is ' perform c' at line 12. diff --git a/TypeCobol.Analysis.Test/BasicCfgInstrs/ExtendedPerformProc3Recursive0.diag b/TypeCobol.Analysis.Test/BasicCfgInstrs/ExtendedPerformProc3Recursive0.diag index 45dd3fc2f..ddf8d787a 100644 --- a/TypeCobol.Analysis.Test/BasicCfgInstrs/ExtendedPerformProc3Recursive0.diag +++ b/TypeCobol.Analysis.Test/BasicCfgInstrs/ExtendedPerformProc3Recursive0.diag @@ -1,15 +1,14 @@ --- Diagnostics --- -Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2'. -Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec3'. -Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec'. -Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2'. -Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec'. -Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec2'. -Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec3'. -Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec2'. -Line 20[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec2'. -Line 20[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec'. -Line 20[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec2'. -Line 20[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec3'. -Line 28[15,29] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2'. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2' at line 16. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec3' at line 20. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec' at line 28. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2' at line 39. +Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec' at line 28. +Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec2' at line 16. +Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec3' at line 20. +Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec2' at line 39. +Line 20[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec2' at line 39. +Line 20[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec' at line 28. +Line 20[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec2' at line 16. +Line 20[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec3' at line 20. Line 29[15,57] <37, Warning, General> - Warning: Unreachable code detected diff --git a/TypeCobol.Analysis.Test/BasicCfgInstrs/ExtendedPerformProc4Recursive0.diag b/TypeCobol.Analysis.Test/BasicCfgInstrs/ExtendedPerformProc4Recursive0.diag index e21d775ec..dcbfbbdc3 100644 --- a/TypeCobol.Analysis.Test/BasicCfgInstrs/ExtendedPerformProc4Recursive0.diag +++ b/TypeCobol.Analysis.Test/BasicCfgInstrs/ExtendedPerformProc4Recursive0.diag @@ -1,33 +1,30 @@ --- Diagnostics --- -Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2'. -Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec3'. -Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec4'. -Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec'. -Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2'. -Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec3 test after varying n from 1 by 1 until n'. -Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec4 varying n from 1 by 1 until n > 5'. -Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec3 test after varying n from 1 by 1 until n'. -Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec4 varying n from 1 by 1 until n > 5'. -Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec2'. -Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec'. -Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec2'. -Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec3'. -Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec4'. -Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec'. -Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec2'. -Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec3'. -Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec4'. -Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec2'. -Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec3 test after varying n from 1 by 1 until n'. -Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec4 varying n from 1 by 1 until n > 5'. -Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec2'. -Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec'. -Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec2'. -Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec3'. -Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec4'. -Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec3 test after varying n from 1 by 1 until n'. -Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec4 varying n from 1 by 1 until n > 5'. -Line 31[15,29] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2'. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2' at line 17. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec3' at line 21. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec4' at line 23. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec' at line 31. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2' at line 42. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec3 test after varying n from 1 by 1 until n' at line 53. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec4 varying n from 1 by 1 until n > 5' at line 57. +Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec3 test after varying n from 1 by 1 until n' at line 53. +Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec4 varying n from 1 by 1 until n > 5' at line 57. +Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec2' at line 42. +Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec' at line 31. +Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec2' at line 17. +Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec3' at line 21. +Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec4' at line 23. +Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec' at line 31. +Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec2' at line 17. +Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec3' at line 21. +Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec4' at line 23. +Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec2' at line 42. +Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec3 test after varying n from 1 by 1 until n' at line 53. +Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec4 varying n from 1 by 1 until n > 5' at line 57. +Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec2' at line 42. +Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec' at line 31. +Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec2' at line 17. +Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec3' at line 21. +Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec4' at line 23. +Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec3 test after varying n from 1 by 1 until n' at line 53. +Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec4 varying n from 1 by 1 until n > 5' at line 57. Line 32[15,57] <37, Warning, General> - Warning: Unreachable code detected -Line 57[15,64] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec4 varying n from 1 by 1 until n > 5'. -Line 57[15,64] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec3 test after varying n from 1 by 1 until n'. diff --git a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformIdentity.diag b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformIdentity.diag index 0449f56a9..e1480353d 100644 --- a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformIdentity.diag +++ b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformIdentity.diag @@ -1,2 +1,2 @@ --- Diagnostics --- -Line 6[12,23] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM main', recursive instruction is ' PERFORM main'. +Line 6[12,23] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM main', recursive instruction is ' PERFORM main' at line 6. diff --git a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc1Recursive0.diag b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc1Recursive0.diag index e97bc375a..a38256d6f 100644 --- a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc1Recursive0.diag +++ b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc1Recursive0.diag @@ -1,3 +1,2 @@ --- Diagnostics --- -Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec'. -Line 16[15,29] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec'. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec' at line 16. diff --git a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc2Recursive0.diag b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc2Recursive0.diag index aab59fb9d..1fd8269b0 100644 --- a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc2Recursive0.diag +++ b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc2Recursive0.diag @@ -1,6 +1,5 @@ --- Diagnostics --- -Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2'. -Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec'. -Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec'. -Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec2'. -Line 27[15,29] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2'. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2' at line 16. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec' at line 27. +Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec' at line 27. +Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec2' at line 16. diff --git a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc3Recursive0.diag b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc3Recursive0.diag index 86cf84618..ac7b2673f 100644 --- a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc3Recursive0.diag +++ b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc3Recursive0.diag @@ -1,14 +1,13 @@ --- Diagnostics --- -Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2'. -Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec3'. -Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec'. -Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2'. -Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec'. -Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec2'. -Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec3'. -Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec2'. -Line 20[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec2'. -Line 20[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec'. -Line 20[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec2'. -Line 20[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec3'. -Line 28[15,29] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2'. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2' at line 16. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec3' at line 20. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec' at line 28. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2' at line 39. +Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec' at line 28. +Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec2' at line 16. +Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec3' at line 20. +Line 16[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec2' at line 39. +Line 20[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec2' at line 39. +Line 20[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec' at line 28. +Line 20[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec2' at line 16. +Line 20[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec3' at line 20. diff --git a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc4Recursive0.diag b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc4Recursive0.diag index a4ec6eaa6..6c6dbd69f 100644 --- a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc4Recursive0.diag +++ b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProc4Recursive0.diag @@ -1,32 +1,29 @@ --- Diagnostics --- -Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2'. -Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec3'. -Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec4'. -Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec'. -Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2'. -Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec3 test after varying n from 1 by 1 until n'. -Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec4 varying n from 1 by 1 until n > 5'. -Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec3 test after varying n from 1 by 1 until n'. -Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec4 varying n from 1 by 1 until n > 5'. -Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec2'. -Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec'. -Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec2'. -Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec3'. -Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec4'. -Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec'. -Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec2'. -Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec3'. -Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec4'. -Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec2'. -Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec3 test after varying n from 1 by 1 until n'. -Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec4 varying n from 1 by 1 until n > 5'. -Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec2'. -Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec'. -Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec2'. -Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec3'. -Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec4'. -Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec3 test after varying n from 1 by 1 until n'. -Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec4 varying n from 1 by 1 until n > 5'. -Line 31[15,29] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2'. -Line 57[15,64] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec4 varying n from 1 by 1 until n > 5'. -Line 57[15,64] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec3 test after varying n from 1 by 1 until n'. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2' at line 17. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec3' at line 21. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec4' at line 23. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec' at line 31. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec2' at line 42. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec3 test after varying n from 1 by 1 until n' at line 53. +Line 8[12,26] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec4 varying n from 1 by 1 until n > 5' at line 57. +Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec3 test after varying n from 1 by 1 until n' at line 53. +Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec4 varying n from 1 by 1 until n > 5' at line 57. +Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec2' at line 42. +Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec' at line 31. +Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec2' at line 17. +Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec3' at line 21. +Line 9[12,27] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec4', recursive instruction is ' perform pararec4' at line 23. +Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec' at line 31. +Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec2' at line 17. +Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec3' at line 21. +Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec4' at line 23. +Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec2' at line 42. +Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec3 test after varying n from 1 by 1 until n' at line 53. +Line 17[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec2', recursive instruction is ' perform pararec4 varying n from 1 by 1 until n > 5' at line 57. +Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec2' at line 42. +Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec' at line 31. +Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec2' at line 17. +Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec3' at line 21. +Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec4' at line 23. +Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec3 test after varying n from 1 by 1 until n' at line 53. +Line 21[15,30] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec3', recursive instruction is ' perform pararec4 varying n from 1 by 1 until n > 5' at line 57. diff --git a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeAfterRecursive0.diag b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeAfterRecursive0.diag index 57dd3b18d..45bf3057b 100644 --- a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeAfterRecursive0.diag +++ b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeAfterRecursive0.diag @@ -1,3 +1,2 @@ --- Diagnostics --- -Line 8[12,71] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec varying n from 1 by 1 until n > 5'. -Line 16[15,64] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec varying n from 1 by 1 until n > 5'. +Line 8[12,71] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec varying n from 1 by 1 until n > 5' at line 16. diff --git a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeAfterRecursive1.diag b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeAfterRecursive1.diag index 610bd32bf..ba456c070 100644 --- a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeAfterRecursive1.diag +++ b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeAfterRecursive1.diag @@ -1,3 +1,2 @@ --- Diagnostics --- -Line 8[12,60] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec test after varying n from 1 by 1 until n>5'. -Line 16[15,72] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec test after varying n from 1 by 1 until n>5'. +Line 8[12,60] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec test after varying n from 1 by 1 until n>5' at line 16. diff --git a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeAfterRecursive2.diag b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeAfterRecursive2.diag index eef2859f5..75a9713ea 100644 --- a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeAfterRecursive2.diag +++ b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeAfterRecursive2.diag @@ -1,3 +1,2 @@ --- Diagnostics --- -Line 8[12,71] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec test after varying n from 1 by 1 until n>5'. -Line 16[15,72] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec test after varying n from 1 by 1 until n>5'. +Line 8[12,71] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec test after varying n from 1 by 1 until n>5' at line 16. diff --git a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeRecursive0.diag b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeRecursive0.diag index 5be6ff278..0b0c0aa4f 100644 --- a/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeRecursive0.diag +++ b/TypeCobol.Analysis.Test/BasicCfgInstrs/PerformProcIterativeRecursive0.diag @@ -1,3 +1,2 @@ --- Diagnostics --- -Line 8[12,60] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec varying n from 1 by 1 until n > 5'. -Line 16[15,64] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec varying n from 1 by 1 until n > 5'. +Line 8[12,60] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM pararec', recursive instruction is ' perform pararec varying n from 1 by 1 until n > 5' at line 16. diff --git a/TypeCobol.Analysis.Test/BasicCfgInstrs/SG102A.diag b/TypeCobol.Analysis.Test/BasicCfgInstrs/SG102A.diag index aa0cf7dc4..06af16610 100644 --- a/TypeCobol.Analysis.Test/BasicCfgInstrs/SG102A.diag +++ b/TypeCobol.Analysis.Test/BasicCfgInstrs/SG102A.diag @@ -15,10 +15,6 @@ Line 242[13,46] <37, Warning, General> - Warning: "end-if" is missing Line 250[12,37] <37, Warning, General> - Warning: "end-if" is missing Line 266[12,43] <37, Warning, General> - Warning: "end-if" is missing Line 267[12,42] <37, Warning, General> - Warning: "end-if" is missing -Line 269[41,66] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM WRITE-LINE', recursive instruction is ' PERFORM WRT-LN'. -Line 269[41,66] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM WRITE-LINE', recursive instruction is ' PERFORM WRT-LN 2 TIMES'. -Line 269[41,66] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM WRITE-LINE', recursive instruction is ' PERFORM WRT-LN'. -Line 269[41,66] <37, Warning, General> - Warning: A recursive loop has been encountered while analyzing 'PERFORM WRITE-LINE', recursive instruction is ' PERFORM WRT-LN'. Line 276[12,43] <37, Warning, General> - Warning: "end-if" is missing Line 277[12,38] <37, Warning, General> - Warning: "end-if" is missing Line 293[12,16] <37, Warning, General> - Warning: ALTER should not be used diff --git a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.cs b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.cs index 2d5d1ae80..ffe3b0d83 100644 --- a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.cs +++ b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.cs @@ -1036,12 +1036,10 @@ void addToRelation(Procedure _calleeProcedure) /// /// CALL Relation /// The domain of the call relation - /// Already reported recursif procedures - private void TransitiveClosureCallRelation(Dictionary, HashSet>> callRelation, HashSet callPerformRelationDomain, - HashSet reportedProcedures) + private void TransitiveClosureCallRelation(Dictionary, HashSet>> callRelation, HashSet callPerformRelationDomain) { Stack S = new Stack(); - // The dictionary is used for three purposes + // The dictionary N is used for three purposes // 1) To record unmarked procedures (N[p] == 0). // 2) To associate a positive number value with procedures that are active consideration (0 < N[p] < Infnity). // 3) To mark Infinity Procedures whose cycles have already been found @@ -1056,12 +1054,9 @@ private void TransitiveClosureCallRelation(Dictionary, HashSet> f(Procedure a) /// List of new PERFORMs cloned during the resolve process. /// The Call relation. /// The Call relation domain. - /// Already reported recursif procedures private void ResolvePendingPERFORMProcedure(Tuple perform, List> clonedPerforms, - Dictionary, HashSet>> callPerformRelation, HashSet callPerformRelationDomain, - HashSet reportedProcedures) + Dictionary, HashSet>> callPerformRelation, HashSet callPerformRelationDomain) { PerformProcedure p = perform.Item1; SectionNode sectionNode = perform.Item2; @@ -1182,17 +1175,6 @@ void StoreSentences(PerformTarget target) isPerform = true; //To avoid a second dynamic cast AddDirectCallPerformRelation(p, currentProcedure, (PerformProcedure)group0.Instructions.Last.Value, callPerformRelation, callPerformRelationDomain); - //Is there a recursion in the graph ? - if (group.RecursivityGroupSet.Get(group0.GroupIndex) && !group0.HasFlag(BasicBlock.Flags.Recursive)) - { - //Flag group and store recursive perform - group0.SetFlag(BasicBlock.Flags.Recursive, true); - Node offendingInstruction = group0.Instructions.Last.Value; - System.Diagnostics.Debug.Assert(offendingInstruction != null); - this.Cfg.AddRecursivePerform(p, new List() { offendingInstruction }); - reportedProcedures.Add(p); - } - var clonedGroup0 = clonedPerforms .Select(t => t.Item3) .SingleOrDefault(g => g.GroupIndex == group0.GroupIndex); @@ -1303,14 +1285,13 @@ private void ResolvePendingPERFORMProcedures() Dictionary, HashSet>> callRelation = new Dictionary, HashSet>>(); HashSet callPerformRelationDomain = new HashSet(); - HashSet reportedProcedures = new HashSet(); var clonedPerforms = new List>(); //First pass: resolve targets of PERFORMs, some new groups may be created during this foreach (var item in this.CurrentProgramCfgBuilder.PendingPERFORMProcedures) { item.Item3.RecursivityGroupSet = new BitArray(GroupCounter + 1); item.Item3.RecursivityGroupSet.Set(item.Item3.GroupIndex, true); - ResolvePendingPERFORMProcedure(item, clonedPerforms, callRelation, callPerformRelationDomain, reportedProcedures); + ResolvePendingPERFORMProcedure(item, clonedPerforms, callRelation, callPerformRelationDomain); } //Second pass: resolve cloned groups created during first pass @@ -1318,11 +1299,11 @@ private void ResolvePendingPERFORMProcedures() { //We are using a regular for instead of foreach because new groups may also be created during this second pass. //New groups/performs to resolve are added at tail and all are processed during this second pass - ResolvePendingPERFORMProcedure(clonedPerforms[i], clonedPerforms, callRelation, callPerformRelationDomain, reportedProcedures); + ResolvePendingPERFORMProcedure(clonedPerforms[i], clonedPerforms, callRelation, callPerformRelationDomain); } // Report Cyclic PERFORM call - TransitiveClosureCallRelation(callRelation, callPerformRelationDomain, reportedProcedures); + TransitiveClosureCallRelation(callRelation, callPerformRelationDomain); //Index groups by their GroupIndex, keep only the final instance of each group after all resolve have been done var groupOrder = new Dictionary(); @@ -1575,7 +1556,7 @@ private void CreateOptionalDiagnostics() System.Diagnostics.Debug.Assert(offendingInstruction.CodeElement != null); string offendingStatement = offendingInstruction.CodeElement.SourceText; Diagnostic d = new Diagnostic(_compilerOptions.CheckRecursivePerforms.GetMessageCode(), perform.CodeElement.Position(), - string.Format(Resource.RecursiveBlockOnPerformProcedure, performTarget, offendingStatement)); + string.Format(Resource.RecursiveBlockOnPerformProcedure, performTarget, offendingStatement, offendingInstruction.CodeElement.Line)); AddDiagnostic(d); } } diff --git a/TypeCobol.Analysis/Resource.Designer.cs b/TypeCobol.Analysis/Resource.Designer.cs index 885a89a33..8b89e992b 100644 --- a/TypeCobol.Analysis/Resource.Designer.cs +++ b/TypeCobol.Analysis/Resource.Designer.cs @@ -1,10 +1,10 @@ //------------------------------------------------------------------------------ // -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 +// Ce code a été généré par un outil. +// Version du runtime :4.0.30319.42000 // -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. +// Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si +// le code est régénéré. // //------------------------------------------------------------------------------ @@ -13,13 +13,13 @@ namespace TypeCobol.Analysis { /// - /// A strongly-typed resource class, for looking up localized strings, etc. + /// Une classe de ressource fortement typée destinée, entre autres, à la consultation des chaînes localisées. /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + // Cette classe a été générée automatiquement par la classe StronglyTypedResourceBuilder + // à l'aide d'un outil, tel que ResGen ou Visual Studio. + // Pour ajouter ou supprimer un membre, modifiez votre fichier .ResX, puis réexécutez ResGen + // avec l'option /str ou régénérez votre projet VS. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resource { @@ -33,7 +33,7 @@ internal Resource() { } /// - /// Returns the cached ResourceManager instance used by this class. + /// Retourne l'instance ResourceManager mise en cache utilisée par cette classe. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Resources.ResourceManager ResourceManager { @@ -47,8 +47,8 @@ internal Resource() { } /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. + /// Remplace la propriété CurrentUICulture du thread actuel pour toutes + /// les recherches de ressources à l'aide de cette classe de ressource fortement typée. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Globalization.CultureInfo Culture { @@ -61,7 +61,7 @@ internal Resource() { } /// - /// Looks up a localized string similar to Bad ALTER instruction: could not locate corresponding altered GO TO.. + /// Recherche une chaîne localisée semblable à Bad ALTER instruction: could not locate corresponding altered GO TO.. /// internal static string BadAlterIntrWithNoSiblingGotoInstr { get { @@ -70,7 +70,7 @@ internal static string BadAlterIntrWithNoSiblingGotoInstr { } /// - /// Looks up a localized string similar to PERFORM '{0}' THRU '{1}': '{1}' is declared before '{0}'.. + /// Recherche une chaîne localisée semblable à PERFORM '{0}' THRU '{1}': '{1}' is declared before '{0}'.. /// internal static string BadPerformProcedureThru { get { @@ -79,7 +79,7 @@ internal static string BadPerformProcedureThru { } /// - /// Looks up a localized string similar to Statement '{0}' located at line {1}, column {2} prevents this PERFORM statement to reach its exit.. + /// Recherche une chaîne localisée semblable à Statement '{0}' located at line {1}, column {2} prevents this PERFORM statement to reach its exit.. /// internal static string BasicBlockGroupGoesBeyondTheLimit { get { @@ -88,7 +88,7 @@ internal static string BasicBlockGroupGoesBeyondTheLimit { } /// - /// Looks up a localized string similar to A recursive loop has been encountered while analyzing 'PERFORM {0}', recursive instruction is '{1}'.. + /// Recherche une chaîne localisée semblable à A recursive loop has been encountered while analyzing 'PERFORM {0}', recursive instruction is '{1}' at line {2}.. /// internal static string RecursiveBlockOnPerformProcedure { get { diff --git a/TypeCobol.Analysis/Resource.resx b/TypeCobol.Analysis/Resource.resx index 1cdc2c18a..b06686800 100644 --- a/TypeCobol.Analysis/Resource.resx +++ b/TypeCobol.Analysis/Resource.resx @@ -127,6 +127,6 @@ Statement '{0}' located at line {1}, column {2} prevents this PERFORM statement to reach its exit. - A recursive loop has been encountered while analyzing 'PERFORM {0}', recursive instruction is '{1}'. + A recursive loop has been encountered while analyzing 'PERFORM {0}', recursive instruction is '{1}' at line {2}. \ No newline at end of file From c5f891a0e072c72caec2093ff33c27449e19913d Mon Sep 17 00:00:00 2001 From: mayanje Date: Wed, 3 Nov 2021 11:28:37 +0100 Subject: [PATCH 4/9] WI #2039 Change review --- .../Cfg/ControlFlowGraphBuilder.cs | 80 +++++++++---------- 1 file changed, 37 insertions(+), 43 deletions(-) diff --git a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.cs b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.cs index ffe3b0d83..900cd9ecb 100644 --- a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.cs +++ b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.cs @@ -987,13 +987,13 @@ T GetUnique(IList list) where T : Node #endregion /// - /// Add a Direct Call Peform to the Call Perform Relation. - /// For a PERFORM THRU all intermediate procedure are added to the relation. + /// Add a Direct Call Perform to the Call Perform Relation. + /// For a PERFORM THRU all intermediate procedures are added to the relation. /// /// The caller of the PERFOM procedure - /// The PERFOM procedure called - /// CALL Relation - /// The domain of the call relation + /// The PERFORM procedure called + /// Call Perform Relation + /// The domain of the call perform relation private void AddDirectCallPerformRelation(PerformProcedure performCaller, Procedure caller, PerformProcedure callee, Dictionary, HashSet>> callPerformRelation, HashSet callPerformRelationDomain) @@ -1010,22 +1010,19 @@ private void AddDirectCallPerformRelation(PerformProcedure performCaller, Proced } callPerformRelationDomain.Add(caller); - void addToRelation(Procedure _calleeProcedure) + void addToRelation(Procedure procedure) { if (!callPerformRelation.TryGetValue(caller, out var callees)) { callees = new Tuple, HashSet>(performCaller, new List(), new HashSet()); - callPerformRelation[caller] = callees; - } - if (!callees.Item3.Contains(_calleeProcedure)) - { - callees.Item3.Add(_calleeProcedure); + callPerformRelation.Add(caller, callees); } + callees.Item3.Add(procedure); if (!callees.Item2.Contains(callee)) { callees.Item2.Add(callee); } - callPerformRelationDomain.Add(_calleeProcedure); + callPerformRelationDomain.Add(procedure); } } @@ -1034,10 +1031,11 @@ void addToRelation(Procedure _calleeProcedure) /// We browse the the graph represented using the Call Relation, then we found during the visit cycles. /// In the same time we compute the call chain. /// - /// CALL Relation - /// The domain of the call relation - private void TransitiveClosureCallRelation(Dictionary, HashSet>> callRelation, HashSet callPerformRelationDomain) + /// Call Perform Relation + /// The domain of the call perform relation + private void TransitiveClosureCallRelation(Dictionary, HashSet>> callPerformRelation, HashSet callPerformRelationDomain) { + // The dfs stack of all procedures in active consideration. Stack S = new Stack(); // The dictionary N is used for three purposes // 1) To record unmarked procedures (N[p] == 0). @@ -1052,7 +1050,7 @@ private void TransitiveClosureCallRelation(Dictionary, HashSet>( - fa.Item1, new List(fa.Item2), new HashSet(fa.Item3)); + callPerformRelation.Add(S.Peek(), new Tuple, HashSet>( + fa.Item1, new List(fa.Item2), new HashSet(fa.Item3))); } } while (S.Count > 0 && S.Pop() != a); } @@ -1129,11 +1108,26 @@ int Visited(Procedure a) } Tuple, HashSet> f(Procedure a) { - if (callRelation.TryGetValue(a, out var v)) + if (callPerformRelation.TryGetValue(a, out var v)) return v; else return new Tuple, HashSet>(null, new List(), new HashSet()); } + void UpdatePerformCallChain(Tuple, HashSet> from, + Tuple, HashSet> to) + { + foreach (var p in from.Item2) + { + if (!to.Item2.Contains(p)) + { + to.Item2.Add(p); + } + } + foreach (var p in from.Item3) + { + to.Item3.Add(p); + } + } } /// From 4b969b9ee01d682e52294b7667aafdc2015455a1 Mon Sep 17 00:00:00 2001 From: mayanje Date: Fri, 12 Nov 2021 11:02:21 +0100 Subject: [PATCH 5/9] WI #2039 Change review --- .../ControlFlowGraphBuilder.PerformTarget.cs | 20 +++++++----------- .../Cfg/ControlFlowGraphBuilder.Sentence.cs | 6 ++++-- .../Cfg/ControlFlowGraphBuilder.cs | 21 ++++++++++--------- 3 files changed, 23 insertions(+), 24 deletions(-) diff --git a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.PerformTarget.cs b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.PerformTarget.cs index 31bc8ada8..30efc8c3c 100644 --- a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.PerformTarget.cs +++ b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.PerformTarget.cs @@ -8,18 +8,18 @@ namespace TypeCobol.Analysis.Cfg public partial class ControlFlowGraphBuilder { /// - /// PerfomrTarget class to capture target sentences and procedures from a PERFORM instruction. + /// PerformTarget class to capture target sentences and procedures from a PERFORM instruction. /// private class PerformTarget { /// /// All target sentences /// - internal List Sentences { get; private set; } + internal List Sentences { get; set; } /// /// All target procedures. /// - internal List Procedures { get; private set; } + internal List Procedures { get; set; } public PerformTarget(List sentences, List procedures) { @@ -32,11 +32,12 @@ public PerformTarget(List sentences, List procedures) /// Cache of PerformTarget instances already calculated for a Perform procedure /// private Dictionary _performTargetCache; - private PerformTarget ComputePerformTarget(PerformProcedure p, SectionNode sectionNode) + private PerformTarget GetPerformTarget(PerformProcedure p, SectionNode sectionNode) { if (_performTargetCache == null) _performTargetCache = new Dictionary(); - if (_performTargetCache.TryGetValue(p, out var target)) { + if (_performTargetCache.TryGetValue(p, out var target)) + { return target; } @@ -65,7 +66,6 @@ private PerformTarget ComputePerformTarget(PerformProcedure p, SectionNode secti } //Accumulate sentences located between the two procedures - int n = 0; int currentProcedureNumber = procedure.Number; while (currentProcedureNumber <= throughProcedure.Number) { @@ -73,18 +73,14 @@ private PerformTarget ComputePerformTarget(PerformProcedure p, SectionNode secti currentProcedure.AccumulateSentencesThrough(sentences, throughProcedure, out var lastProcedure); currentProcedureNumber = lastProcedure.Number + 1; procedures.Add(currentProcedure); - while (n < sentences.Count) - { - sentences[n++].Procedure = currentProcedure; - } } - } else + } + else { procedures.Add(procedure); foreach (var sentence in procedure) { sentences.Add(sentence); - sentence.Procedure = procedure; } } target = new PerformTarget(sentences, procedures); diff --git a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.Sentence.cs b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.Sentence.cs index 24c8bb1fe..7b703c33c 100644 --- a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.Sentence.cs +++ b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.Sentence.cs @@ -20,7 +20,7 @@ private class Sentence : ProcedureDivisionRegion /// /// The associated procedure /// - internal Procedure Procedure { get; set; } + internal readonly Procedure Procedure; /// /// Constructor. @@ -28,13 +28,15 @@ private class Sentence : ProcedureDivisionRegion /// Order number of appearance of the sentence. /// First block of the sentence. /// Index of the first block the global SuccessorEdges list. + /// the procedure to which the sentence belongs. /// Pass null if the first block is a root block and consequently has no index in successors list. - public Sentence(int number, BasicBlockForNode firstBlock, int? firstBlockIndex) + public Sentence(int number, BasicBlockForNode firstBlock, int? firstBlockIndex, Procedure procedure) : base(number) { _blocks = new LinkedList(); _blocks.AddLast(firstBlock); FirstBlockIndex = firstBlockIndex; + this.Procedure = procedure; } /// diff --git a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.cs b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.cs index 900cd9ecb..98cd9bd87 100644 --- a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.cs +++ b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.cs @@ -634,18 +634,15 @@ public override void Exit(Node node) /// /// Link this sentence to the current section or paragraph if any. /// - /// The sentence to link. + /// The sentence to link. private void LinkBlockSentenceToCurrentSectionParagraph(Sentence sentence) { - var currentProcedure = (Procedure) this.CurrentProgramCfgBuilder.CurrentParagraph ?? - this.CurrentProgramCfgBuilder.CurrentSection; - - if (currentProcedure != null) + if (sentence.Procedure != null) { - currentProcedure.AddSentence(sentence); + sentence.Procedure.AddSentence(sentence); //Give to this block the name of its paragraph/section as tag. - sentence.FirstBlock.Tag = currentProcedure.Name; + sentence.FirstBlock.Tag = sentence.Procedure.Name; } } @@ -666,7 +663,11 @@ private void StartBlockSentence() this.CurrentProgramCfgBuilder.CurrentBasicBlock.SuccessorEdges.Add(firstBlockIndex.Value); this.CurrentProgramCfgBuilder.Cfg.SuccessorEdges.Add(firstBlock); } - Sentence sentence = new Sentence(number, firstBlock, firstBlockIndex); + + Procedure currentProcedure = (Procedure)this.CurrentProgramCfgBuilder.CurrentParagraph ?? + this.CurrentProgramCfgBuilder.CurrentSection; + + Sentence sentence = new Sentence(number, firstBlock, firstBlockIndex, currentProcedure); this.CurrentProgramCfgBuilder.AllSentences.Add(sentence); this.CurrentProgramCfgBuilder.CurrentSentence = sentence; @@ -1001,7 +1002,7 @@ private void AddDirectCallPerformRelation(PerformProcedure performCaller, Proced var item = PendingPERFORMProcedures.FirstOrDefault(i => i.Item1 == callee); if (item == null) return; - PerformTarget performTarget = ComputePerformTarget(callee, item.Item2); + PerformTarget performTarget = GetPerformTarget(callee, item.Item2); if (performTarget == null) return; foreach (Procedure calleeProcedure in performTarget.Procedures) @@ -1145,7 +1146,7 @@ private void ResolvePendingPERFORMProcedure(Tuple(); From 5ce94ee602d8d536ede62588345edf6179e3778b Mon Sep 17 00:00:00 2001 From: mayanje Date: Wed, 17 Nov 2021 11:49:02 +0100 Subject: [PATCH 6/9] WI #2039 Refactor the Perform Call relation. --- ...rolFlowGraphBuilder.PerformCallRelation.cs | 202 ++++++++++++++++++ .../Cfg/ControlFlowGraphBuilder.cs | 175 ++++----------- TypeCobol.Analysis/TypeCobol.Analysis.csproj | 1 + 3 files changed, 241 insertions(+), 137 deletions(-) create mode 100644 TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.PerformCallRelation.cs diff --git a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.PerformCallRelation.cs b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.PerformCallRelation.cs new file mode 100644 index 000000000..ec6b5d03e --- /dev/null +++ b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.PerformCallRelation.cs @@ -0,0 +1,202 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TypeCobol.Compiler.Nodes; + +namespace TypeCobol.Analysis.Cfg +{ + public partial class ControlFlowGraphBuilder + { + /// + /// Represent the perform call chain of a PerformProcedure caller + /// + private class PerformCallChain + { + /// + /// Source Perform Procedure instruction + /// + internal PerformProcedure PerformCaller; + /// + /// List of PerformProcedure (Nodes) that form the call chain from the 'PerformCaller' + /// + internal List PerformCallees; + /// + /// All target procedures + /// + internal HashSet Procedures; + + /// + /// Constructor + /// + /// + internal PerformCallChain(PerformProcedure performCaller) + { + this.PerformCaller = performCaller; + this.PerformCallees = new List(); + this.Procedures = new HashSet(); + } + /// + /// Constructor + /// + /// + /// + /// + internal PerformCallChain(PerformProcedure performCaller, List performCallees, HashSet procedures) + { + this.PerformCaller = performCaller; + this.PerformCallees = performCallees; + this.Procedures = procedures; + } + } + + /// + /// Representation of Perform Call Relation. + /// It is a dictionary which gives for each Procedure its Perform Call chain. + /// + private class PerformCallRelation : Dictionary + { + /// + /// The Relation's domain + /// + internal HashSet Domain; + + internal PerformCallRelation() + { + Domain = new HashSet(); + } + /// + /// Add a PERFORM CALL relation : Caller => Callee (Procedure) + /// Example of code: + /// main. + /// perform a + /// goback + /// . + /// a. + /// perform b + /// . + /// The relation is: a => b + /// + /// PERFORM procedure caller, source instruction: in the example (perform a) + /// Caller procedure: in the example 'a'/// + /// The PERFORM procedure called, target instruction: in the example (perform b) + /// The called procedure: in the example 'b' + internal void AddToRelation(PerformProcedure performCaller, Procedure caller, PerformProcedure performCallee, Procedure callee) + { + if (!TryGetValue(caller, out var performCallChain)) + { + performCallChain = new PerformCallChain(performCaller); + Add(caller, performCallChain); + } + performCallChain.Procedures.Add(callee); + if (!performCallChain.PerformCallees.Contains(performCallee)) + { + performCallChain.PerformCallees.Add(performCallee); + } + Domain.Add(caller); + Domain.Add(callee); + } + + /// + /// Compute the transitive closure of the PERFORM CALL relation. + /// We browse the the graph represented using the Call Relation, then we found during the visit cycles. + /// In the same time we compute the call chain. + /// + internal void TransitiveClosure() + { + // The dfs stack of all procedures in active consideration. + Stack S = new Stack(); + // The dictionary N is used for three purposes + // 1) To record unmarked procedures (N[p] == 0). + // 2) To associate a positive number value with procedures that are active consideration (0 < N[p] < Infnity). + // 3) To mark Infinity Procedures whose cycles have already been found + Dictionary N = new Dictionary(); + + // For each procedure in the relation's domain + foreach (var a in Domain) + { // For each procedure 'a' not yet considered, treat it. + var na = Visited(a); + if (na == 0) + dfs(a); + } + + // Depth First Search Traversal. + void dfs(Procedure a) + { + S.Push(a); + int d = S.Count; + N[a] = d; + var fa = GetPerformCallChain(a); + if (fa.Procedures != null) + { //For all procedure b called by a + foreach (var b in fa.Procedures.ToArray()) + { + int nb = Visited(b); + if (nb == 0) + dfs(b);//Procedure not visited yet + int _na = Visited(a); + int _nb = Visited(b); + N[a] = Math.Min(_na, _nb); // N[b] < N[a] : we find a cycle + var fb = GetPerformCallChain(b); + // f(a) = f(a) U f(b) + // We update the call chain + UpdatePerformCallChain(fb, fa); + } + } + var na = Visited(a); + if (na == d) + { // 'a' is an entry point of a calculated component, that is to say the start procedure of a cycle. + // because if na != d then 'a' has been included in another cycle whose root is not 'a'. + do + { + N[S.Peek()] = Int32.MaxValue; // The Node(The procedure) is terminated + if (TryGetValue(S.Peek(), out var top)) + { + UpdatePerformCallChain(fa, top); + } + else + { + Add(S.Peek(), new PerformCallChain( + fa.PerformCaller, new List(fa.PerformCallees), new HashSet(fa.Procedures))); + } + } while (S.Count > 0 && S.Pop() != a); + } + } + // Get the visited mark of the procedure a + int Visited(Procedure a) + { + if (N.TryGetValue(a, out var na)) + return na; + return 0; + } + // Get the PerformCallChain value of the procedure a + PerformCallChain GetPerformCallChain(Procedure a) + { + if (TryGetValue(a, out var v)) + return v; + else + return new PerformCallChain(null, new List(), new HashSet()); + } + // Update PerformCallChain value of procedure 'to' when prodecure 'from' call + // procedure 'to' this the transitive aspect: all procedures called by 'from' are + // also called by 'to' + void UpdatePerformCallChain(PerformCallChain from, PerformCallChain to) + { + foreach (var p in from.PerformCallees) + { + if (!to.PerformCallees.Contains(p)) + { + to.PerformCallees.Add(p); + } + } + foreach (var p in from.Procedures) + { + to.Procedures.Add(p); + } + } + } + } + } +} + diff --git a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.cs b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.cs index 98cd9bd87..be0a94998 100644 --- a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.cs +++ b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.cs @@ -911,9 +911,8 @@ private void ResolvePendingGOTOs() case StatementType.GotoSimpleStatement: { GotoSimpleStatement simpleGoto = (GotoSimpleStatement)@goto.CodeElement; - HashSet alteredSymbolRefs = null; //Check if we have altered GOTOs to take in account. - if (PendingAlteredGOTOS != null && PendingAlteredGOTOS.TryGetValue(@goto, out alteredSymbolRefs)) + if (PendingAlteredGOTOS != null && PendingAlteredGOTOS.TryGetValue(@goto, out HashSet alteredSymbolRefs)) { int i = 0; target = new SymbolReference[alteredSymbolRefs.Count + 1]; @@ -990,143 +989,49 @@ T GetUnique(IList list) where T : Node /// /// Add a Direct Call Perform to the Call Perform Relation. /// For a PERFORM THRU all intermediate procedures are added to the relation. - /// - /// The caller of the PERFOM procedure - /// The PERFORM procedure called - /// Call Perform Relation - /// The domain of the call perform relation - private void AddDirectCallPerformRelation(PerformProcedure performCaller, Procedure caller, PerformProcedure callee, - Dictionary, HashSet>> callPerformRelation, - HashSet callPerformRelationDomain) - { - var item = PendingPERFORMProcedures.FirstOrDefault(i => i.Item1 == callee); + /// Example of code: + /// main. + /// perform a + /// goback + /// . + /// a. + /// perform b + /// . + /// The relation is: a => b + /// + /// PERFORM procedure caller, source instruction: in the example (perform a) + /// The Procedure of the performCaller: in the example 'a' + /// The PERFORM procedure called, target instruction: in the example (perform b) + /// Call Perform Relation + private void AddDirectCallPerformRelation(PerformProcedure performCaller, Procedure caller, PerformProcedure performCallee, + PerformCallRelation performCallRelation) + { + var item = PendingPERFORMProcedures.FirstOrDefault(i => i.Item1 == performCallee); if (item == null) return; - PerformTarget performTarget = GetPerformTarget(callee, item.Item2); + PerformTarget performTarget = GetPerformTarget(performCallee, item.Item2); if (performTarget == null) return; foreach (Procedure calleeProcedure in performTarget.Procedures) { - addToRelation(calleeProcedure); - } - callPerformRelationDomain.Add(caller); - - void addToRelation(Procedure procedure) - { - if (!callPerformRelation.TryGetValue(caller, out var callees)) - { - callees = new Tuple, HashSet>(performCaller, new List(), new HashSet()); - callPerformRelation.Add(caller, callees); - } - callees.Item3.Add(procedure); - if (!callees.Item2.Contains(callee)) - { - callees.Item2.Add(callee); - } - callPerformRelationDomain.Add(procedure); + performCallRelation.AddToRelation(performCaller, caller, performCallee, calleeProcedure); } } /// - /// Compute the transitive closure of the CALL relation. - /// We browse the the graph represented using the Call Relation, then we found during the visit cycles. - /// In the same time we compute the call chain. + /// Report Recursive Perform Call diagnostics /// - /// Call Perform Relation - /// The domain of the call perform relation - private void TransitiveClosureCallRelation(Dictionary, HashSet>> callPerformRelation, HashSet callPerformRelationDomain) + /// Call Perform Relation + private void ReportRecursivePerformCall(PerformCallRelation performCallRelation) { - // The dfs stack of all procedures in active consideration. - Stack S = new Stack(); - // The dictionary N is used for three purposes - // 1) To record unmarked procedures (N[p] == 0). - // 2) To associate a positive number value with procedures that are active consideration (0 < N[p] < Infnity). - // 3) To mark Infinity Procedures whose cycles have already been found - Dictionary N = new Dictionary(); - - foreach(var a in callPerformRelationDomain) - { - var na = Visited(a); - if (na == 0) - dfs(a); - } + // First Compute the transitive closure of the relation. + performCallRelation.TransitiveClosure(); // Report all cyclic procedure. - foreach (var item in callPerformRelation) - { - if (item.Value.Item3.Contains(item.Key)) - { - this.Cfg.AddRecursivePerform(item.Value.Item1, item.Value.Item2); - } - } - - void dfs(Procedure a) - { - S.Push(a); - int d = S.Count; - N[a] = d; - var fa = f(a); - if (fa.Item3 != null) - { //For all procedure b called by a - foreach (var b in fa.Item3.ToArray()) - { - int nb = Visited(b); - if (nb == 0) - dfs(b);//Procedure not visited yet - int _na = Visited(a); - int _nb = Visited(b); - N[a] = Math.Min(_na, _nb); // N[b] < N[a] : we find a cycle - var fb = f(b); - // f(a) = f(a) U f(b) - // We update the call chain - UpdatePerformCallChain(fb, fa); - } - } - var na = Visited(a); - if (na == d) - { // 'a' is an entry point of a calculated component, that is to say the start procedure of a cycle. - // because if na != d then 'a' has been included in another cycle whose root is not 'a'. - do - { - N[S.Peek()] = Int32.MaxValue; // The Node(The procedure) is terminated - if (callPerformRelation.TryGetValue(S.Peek(), out var top)) - { - UpdatePerformCallChain(fa, top); - } - else - { - callPerformRelation.Add(S.Peek(), new Tuple, HashSet>( - fa.Item1, new List(fa.Item2), new HashSet(fa.Item3))); - } - } while (S.Count > 0 && S.Pop() != a); - } - } - - int Visited(Procedure a) + foreach (var item in performCallRelation) { - if (N.TryGetValue(a, out var na)) - return na; - return 0; - } - Tuple, HashSet> f(Procedure a) - { - if (callPerformRelation.TryGetValue(a, out var v)) - return v; - else - return new Tuple, HashSet>(null, new List(), new HashSet()); - } - void UpdatePerformCallChain(Tuple, HashSet> from, - Tuple, HashSet> to) - { - foreach (var p in from.Item2) - { - if (!to.Item2.Contains(p)) - { - to.Item2.Add(p); - } - } - foreach (var p in from.Item3) + if (item.Value.Procedures.Contains(item.Key)) { - to.Item3.Add(p); + this.Cfg.AddRecursivePerform(item.Value.PerformCaller, item.Value.PerformCallees); } } } @@ -1137,10 +1042,9 @@ void UpdatePerformCallChain(Tuple, HashSetA Tuple made of the PerformProcedure node, the section in which the PERFORM appears /// and the Basic Block Group associated to the Perform Procedure. /// List of new PERFORMs cloned during the resolve process. - /// The Call relation. - /// The Call relation domain. + /// The Perform Call relation. private void ResolvePendingPERFORMProcedure(Tuple perform, List> clonedPerforms, - Dictionary, HashSet>> callPerformRelation, HashSet callPerformRelationDomain) + PerformCallRelation performCallRelation) { PerformProcedure p = perform.Item1; SectionNode sectionNode = perform.Item2; @@ -1168,7 +1072,7 @@ void StoreSentences(PerformTarget target) if (block is BasicBlockForNodeGroup group0) { isPerform = true; //To avoid a second dynamic cast - AddDirectCallPerformRelation(p, currentProcedure, (PerformProcedure)group0.Instructions.Last.Value, callPerformRelation, callPerformRelationDomain); + AddDirectCallPerformRelation(p, currentProcedure, (PerformProcedure)group0.Instructions.Last.Value, performCallRelation); var clonedGroup0 = clonedPerforms .Select(t => t.Item3) @@ -1277,16 +1181,14 @@ private void ResolvePendingPERFORMProcedures() { if (this.CurrentProgramCfgBuilder.PendingPERFORMProcedures != null) { - Dictionary, HashSet>> callRelation = - new Dictionary, HashSet>>(); - HashSet callPerformRelationDomain = new HashSet(); + PerformCallRelation performCallRelation = new PerformCallRelation(); var clonedPerforms = new List>(); //First pass: resolve targets of PERFORMs, some new groups may be created during this foreach (var item in this.CurrentProgramCfgBuilder.PendingPERFORMProcedures) { item.Item3.RecursivityGroupSet = new BitArray(GroupCounter + 1); item.Item3.RecursivityGroupSet.Set(item.Item3.GroupIndex, true); - ResolvePendingPERFORMProcedure(item, clonedPerforms, callRelation, callPerformRelationDomain); + ResolvePendingPERFORMProcedure(item, clonedPerforms, performCallRelation); } //Second pass: resolve cloned groups created during first pass @@ -1294,11 +1196,11 @@ private void ResolvePendingPERFORMProcedures() { //We are using a regular for instead of foreach because new groups may also be created during this second pass. //New groups/performs to resolve are added at tail and all are processed during this second pass - ResolvePendingPERFORMProcedure(clonedPerforms[i], clonedPerforms, callRelation, callPerformRelationDomain); + ResolvePendingPERFORMProcedure(clonedPerforms[i], clonedPerforms, performCallRelation); } - // Report Cyclic PERFORM call - TransitiveClosureCallRelation(callRelation, callPerformRelationDomain); + // Report Recursive PERFORM call + ReportRecursivePerformCall(performCallRelation); //Index groups by their GroupIndex, keep only the final instance of each group after all resolve have been done var groupOrder = new Dictionary(); @@ -1387,7 +1289,6 @@ private void ComputeBasicBlockGroupTerminalBlocks(BasicBlockForNodeGroup group) if (group.Group.Count > 0 && group.TerminalBlocks == null) { LinkedListNode> first = group.Group.First; - MultiBranchContext ctx = new MultiBranchContext(null); List> terminals = new List>(); this.CurrentProgramCfgBuilder.Cfg.GetTerminalSuccessorEdges(first.Value, terminals); group.TerminalBlocks = terminals; @@ -2315,7 +2216,7 @@ public virtual void LeavePerformLoop(Perform perform) this.CurrentProgramCfgBuilder.Cfg.SuccessorEdges.Add(nextBlock); - int transBlockIndex = -1; + int transBlockIndex; if (IsIterative(perform.CodeElement)) { //For an Iterative perform, body transition is the perform instruction //the next block is a transition for the perform. diff --git a/TypeCobol.Analysis/TypeCobol.Analysis.csproj b/TypeCobol.Analysis/TypeCobol.Analysis.csproj index b1bf66ac4..f1826ccef 100644 --- a/TypeCobol.Analysis/TypeCobol.Analysis.csproj +++ b/TypeCobol.Analysis/TypeCobol.Analysis.csproj @@ -34,6 +34,7 @@ + From 35d07340d7b3b9b07e9c14b37b416179dbdebbd2 Mon Sep 17 00:00:00 2001 From: mayanje Date: Thu, 18 Nov 2021 15:44:25 +0100 Subject: [PATCH 7/9] WI #2039 Change Review --- ...FlowGraphBuilder.BasicBlockForNodeGroup.cs | 11 --- ...rolFlowGraphBuilder.PerformCallRelation.cs | 96 ++++++++++--------- .../ControlFlowGraphBuilder.PerformTarget.cs | 3 + .../Cfg/ControlFlowGraphBuilder.cs | 11 +-- TypeCobol.Analysis/Graph/ControlFlowGraph.cs | 14 +-- 5 files changed, 57 insertions(+), 78 deletions(-) diff --git a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.BasicBlockForNodeGroup.cs b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.BasicBlockForNodeGroup.cs index 33d588ffc..f3445407e 100644 --- a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.BasicBlockForNodeGroup.cs +++ b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.BasicBlockForNodeGroup.cs @@ -63,17 +63,6 @@ internal bool IsAfterIterativeGroup set; } - /// - /// To detect recursivity on PERFORM Procedure calls. - /// This is a bit array of GroupIndex encountered during the workflow - /// call of other PERFORM. - /// - internal BitArray RecursivityGroupSet - { - get; - set; - } - /// /// Constructor. /// diff --git a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.PerformCallRelation.cs b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.PerformCallRelation.cs index ec6b5d03e..1a2e4afe2 100644 --- a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.PerformCallRelation.cs +++ b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.PerformCallRelation.cs @@ -100,81 +100,83 @@ internal void AddToRelation(PerformProcedure performCaller, Procedure caller, Pe /// /// Compute the transitive closure of the PERFORM CALL relation. - /// We browse the the graph represented using the Call Relation, then we found during the visit cycles. + /// We browse the graph represented using the Call Relation, then we found during the visit cycles. /// In the same time we compute the call chain. /// internal void TransitiveClosure() { // The dfs stack of all procedures in active consideration. - Stack S = new Stack(); - // The dictionary N is used for three purposes - // 1) To record unmarked procedures (N[p] == 0). - // 2) To associate a positive number value with procedures that are active consideration (0 < N[p] < Infnity). + Stack dfsStack = new Stack(); + // The dictionary dfsMark is used for three purposes + // 1) To record unmarked procedures (dfsMark[p] == 0). + // 2) To associate a positive number value with procedures that are active consideration (0 < dfsMark[p] < Infnity). // 3) To mark Infinity Procedures whose cycles have already been found - Dictionary N = new Dictionary(); + Dictionary dfsMark = new Dictionary(); // For each procedure in the relation's domain - foreach (var a in Domain) - { // For each procedure 'a' not yet considered, treat it. - var na = Visited(a); - if (na == 0) - dfs(a); + foreach (var procedure in Domain) + { // For each procedure not yet visted, treat it. + var proc_visitMark = Visited(procedure); + if (proc_visitMark == 0) + dfs(procedure); } // Depth First Search Traversal. - void dfs(Procedure a) + void dfs(Procedure proc_a) { - S.Push(a); - int d = S.Count; - N[a] = d; - var fa = GetPerformCallChain(a); - if (fa.Procedures != null) + dfsStack.Push(proc_a); + int depth = dfsStack.Count; + dfsMark[proc_a] = depth; + var proca_callChain = GetPerformCallChain(proc_a); + if (proca_callChain.Procedures != null) { //For all procedure b called by a - foreach (var b in fa.Procedures.ToArray()) + foreach (var proc_b in proca_callChain.Procedures.ToArray()) { - int nb = Visited(b); - if (nb == 0) - dfs(b);//Procedure not visited yet - int _na = Visited(a); - int _nb = Visited(b); - N[a] = Math.Min(_na, _nb); // N[b] < N[a] : we find a cycle - var fb = GetPerformCallChain(b); - // f(a) = f(a) U f(b) + int procb_VisitMark = Visited(proc_b); + if (procb_VisitMark == 0) + { + dfs(proc_b);//Procedure not visited yet + procb_VisitMark = Visited(proc_b); ; + } + int proca_VisitMark = Visited(proc_a); + dfsMark[proc_a] = Math.Min(proca_VisitMark, procb_VisitMark); // N[b] < N[a] : we find a cycle + var procb_callChain = GetPerformCallChain(proc_b); + // proca_callChain = proca_callChain U procb_callChain // We update the call chain - UpdatePerformCallChain(fb, fa); + UpdatePerformCallChain(procb_callChain, proca_callChain); } } - var na = Visited(a); - if (na == d) + var proca_visitMark = Visited(proc_a); + if (proca_visitMark == depth) { // 'a' is an entry point of a calculated component, that is to say the start procedure of a cycle. // because if na != d then 'a' has been included in another cycle whose root is not 'a'. do { - N[S.Peek()] = Int32.MaxValue; // The Node(The procedure) is terminated - if (TryGetValue(S.Peek(), out var top)) + dfsMark[dfsStack.Peek()] = Int32.MaxValue; // The Node(The procedure) is terminated + if (TryGetValue(dfsStack.Peek(), out var top)) { - UpdatePerformCallChain(fa, top); + UpdatePerformCallChain(proca_callChain, top); } else { - Add(S.Peek(), new PerformCallChain( - fa.PerformCaller, new List(fa.PerformCallees), new HashSet(fa.Procedures))); + Add(dfsStack.Peek(), new PerformCallChain( + proca_callChain.PerformCaller, new List(proca_callChain.PerformCallees), new HashSet(proca_callChain.Procedures))); } - } while (S.Count > 0 && S.Pop() != a); + } while (dfsStack.Count > 0 && dfsStack.Pop() != proc_a); } } - // Get the visited mark of the procedure a - int Visited(Procedure a) + // Get the visited mark of the procedure + int Visited(Procedure procedure) { - if (N.TryGetValue(a, out var na)) - return na; + if (dfsMark.TryGetValue(procedure, out var visitMark)) + return visitMark; return 0; } // Get the PerformCallChain value of the procedure a - PerformCallChain GetPerformCallChain(Procedure a) + PerformCallChain GetPerformCallChain(Procedure procedure) { - if (TryGetValue(a, out var v)) - return v; + if (TryGetValue(procedure, out var callChain)) + return callChain; else return new PerformCallChain(null, new List(), new HashSet()); } @@ -183,16 +185,16 @@ PerformCallChain GetPerformCallChain(Procedure a) // also called by 'to' void UpdatePerformCallChain(PerformCallChain from, PerformCallChain to) { - foreach (var p in from.PerformCallees) + foreach (var perform in from.PerformCallees) { - if (!to.PerformCallees.Contains(p)) + if (!to.PerformCallees.Contains(perform)) { - to.PerformCallees.Add(p); + to.PerformCallees.Add(perform); } } - foreach (var p in from.Procedures) + foreach (var procedure in from.Procedures) { - to.Procedures.Add(p); + to.Procedures.Add(procedure); } } } diff --git a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.PerformTarget.cs b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.PerformTarget.cs index 30efc8c3c..8fb453ba8 100644 --- a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.PerformTarget.cs +++ b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.PerformTarget.cs @@ -46,7 +46,10 @@ private PerformTarget GetPerformTarget(PerformProcedure p, SectionNode sectionNo Node procedureNode = ResolveProcedure(p, sectionNode, procedureReference); if (procedureNode == null) + { + _performTargetCache[p] = null; return null; + } Procedure procedure = _nodeToProcedure[procedureNode]; List sentences = new List(); diff --git a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.cs b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.cs index be0a94998..750ba5539 100644 --- a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.cs +++ b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.cs @@ -1054,11 +1054,11 @@ private void ResolvePendingPERFORMProcedure(Tuple(); - StoreSentences(performTarget); + StoreSentences(); //And finally relocate the Graph. RelocateBasicBlockForNodeGroupGraph(p, group, clonedBlocksIndexMap); - void StoreSentences(PerformTarget target) + void StoreSentences() { foreach (var sentence in performTarget.Sentences) { @@ -1109,9 +1109,6 @@ void StoreSentences(PerformTarget target) clonedGroup.Group = new LinkedList>(); clonedGroup.TerminalBlocks = null; - group.RecursivityGroupSet.Set(clonedGroup.GroupIndex, true); - clonedGroup.RecursivityGroupSet = new BitArray(group.RecursivityGroupSet); - var originalPerform = this.CurrentProgramCfgBuilder.PendingPERFORMProcedures .Single(t => t.Item3 == block); clonedPerforms.Add(new Tuple(originalPerform.Item1, originalPerform.Item2, clonedGroup)); @@ -1186,8 +1183,6 @@ private void ResolvePendingPERFORMProcedures() //First pass: resolve targets of PERFORMs, some new groups may be created during this foreach (var item in this.CurrentProgramCfgBuilder.PendingPERFORMProcedures) { - item.Item3.RecursivityGroupSet = new BitArray(GroupCounter + 1); - item.Item3.RecursivityGroupSet.Set(item.Item3.GroupIndex, true); ResolvePendingPERFORMProcedure(item, clonedPerforms, performCallRelation); } @@ -1208,13 +1203,11 @@ private void ResolvePendingPERFORMProcedures() { BasicBlockForNodeGroup group = item.Item3; groupOrder[group.GroupIndex] = group; - group.RecursivityGroupSet = null; } foreach (var item in clonedPerforms) { BasicBlockForNodeGroup group = item.Item3; groupOrder[group.GroupIndex] = group; - group.RecursivityGroupSet = null; } //Extend groups according to the current building mode diff --git a/TypeCobol.Analysis/Graph/ControlFlowGraph.cs b/TypeCobol.Analysis/Graph/ControlFlowGraph.cs index 91ef75b4c..47b060755 100644 --- a/TypeCobol.Analysis/Graph/ControlFlowGraph.cs +++ b/TypeCobol.Analysis/Graph/ControlFlowGraph.cs @@ -225,22 +225,14 @@ internal void AddWrongOrderPerformThru(PerformProcedure performThru, N procedure /// Register a recursive jump for a perform statement. /// /// Perform node - /// Recursive jump node - internal void AddRecursivePerform(PerformProcedure perform, List recursiveJump) + /// Recursive jump node + internal void AddRecursivePerform(PerformProcedure perform, List recursiveCallChain) { if (RecursivePerforms == null) { RecursivePerforms = new Dictionary>(); } - - if (RecursivePerforms.TryGetValue(perform, out var nodes)) - { - nodes.AddRange(recursiveJump); - } - else - { - RecursivePerforms.Add(perform, recursiveJump); - } + RecursivePerforms.Add(perform, recursiveCallChain); } /// From 49d4035efd9def3da718baef440584a02250ee18 Mon Sep 17 00:00:00 2001 From: mayanje Date: Mon, 22 Nov 2021 17:38:56 +0100 Subject: [PATCH 8/9] WI #2039 Change review --- .../Cfg/ControlFlowGraphBuilder.PerformTarget.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.PerformTarget.cs b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.PerformTarget.cs index 8fb453ba8..e1e03fe9d 100644 --- a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.PerformTarget.cs +++ b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.PerformTarget.cs @@ -40,14 +40,13 @@ private PerformTarget GetPerformTarget(PerformProcedure p, SectionNode sectionNo { return target; } - + _performTargetCache[p] = null;//By default SymbolReference procedureReference = p.CodeElement.Procedure; SymbolReference throughProcedureReference = p.CodeElement.ThroughProcedure; Node procedureNode = ResolveProcedure(p, sectionNode, procedureReference); if (procedureNode == null) { - _performTargetCache[p] = null; return null; } @@ -58,7 +57,9 @@ private PerformTarget GetPerformTarget(PerformProcedure p, SectionNode sectionNo { Node throughProcedureNode = ResolveProcedure(p, sectionNode, throughProcedureReference); if (throughProcedureNode == null) + { return null; + } Procedure throughProcedure = _nodeToProcedure[throughProcedureNode]; if (procedure.Number > throughProcedure.Number) From 99deb0536c36b7887c06e79f3aa844ee2c19fe8d Mon Sep 17 00:00:00 2001 From: mayanje Date: Tue, 30 Nov 2021 17:05:12 +0100 Subject: [PATCH 9/9] WI #2039 Change review --- .../Cfg/ControlFlowGraphBuilder.PerformTarget.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.PerformTarget.cs b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.PerformTarget.cs index e1e03fe9d..0f366f136 100644 --- a/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.PerformTarget.cs +++ b/TypeCobol.Analysis/Cfg/ControlFlowGraphBuilder.PerformTarget.cs @@ -82,10 +82,7 @@ private PerformTarget GetPerformTarget(PerformProcedure p, SectionNode sectionNo else { procedures.Add(procedure); - foreach (var sentence in procedure) - { - sentences.Add(sentence); - } + sentences.AddRange(procedure); } target = new PerformTarget(sentences, procedures); _performTargetCache[p] = target;