From b9077f6abdc4f1554cd4443212d61b53f043f04b Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Fri, 10 Jan 2020 16:41:08 +0100 Subject: [PATCH 01/27] Move and add tests --- src/main/java/tfm/programs/WhileLoop.java | 2 + src/main/java/tfm/programs/cfg/CFG_Test1.java | 5 ++ src/main/java/tfm/programs/cfg/CFG_Test2.java | 8 ++++ src/main/java/tfm/programs/cfg/CFG_Test3.java | 8 ++++ src/main/java/tfm/programs/cfg/CFG_Test4.java | 11 +++++ src/main/java/tfm/programs/cfg/CFG_Test5.java | 9 ++++ src/test/res/carlos/Test1.java | 8 ++++ src/test/res/ltd-samples/BasicBreak.java | 17 +++++++ src/test/res/ltd-samples/BasicContinue.java | 17 +++++++ src/test/res/ltd-samples/BasicForeach.java | 9 ++++ src/test/res/ltd-samples/BasicIf.java | 11 +++++ src/test/res/ltd-samples/BasicIfElse.java | 19 ++++++++ src/test/res/ltd-samples/BasicSwitch.java | 28 +++++++++++ .../res/ltd-samples/BasicSwitchDefault.java | 23 +++++++++ .../res/ltd-samples/BasicSwitchNoBreak.java | 16 +++++++ src/test/res/ltd-samples/Bucles_1.java | 14 ++++++ src/test/res/ltd-samples/Bucles_2.java | 21 +++++++++ src/test/res/ltd-samples/Bucles_3.java | 35 ++++++++++++++ src/test/res/ltd-samples/Bucles_4.java | 37 +++++++++++++++ src/test/res/ltd-samples/Bucles_5.java | 47 +++++++++++++++++++ src/test/res/ltd-samples/Bucles_6.java | 23 +++++++++ src/test/res/ltd-samples/Bucles_Josep.java | 39 +++++++++++++++ src/test/res/ltd-samples/ReturnTest.java | 12 +++++ src/test/res/ltd-samples/Test_1.java | 12 +++++ src/test/res/ltd-samples/Test_2.java | 13 +++++ src/test/res/ltd-samples/Test_3.java | 13 +++++ src/test/res/ltd-samples/Test_4.java | 18 +++++++ src/test/res/ltd-samples/Test_5.java | 19 ++++++++ src/test/res/ltd-samples/Test_6.java | 17 +++++++ src/test/res/ltd-samples/Test_7.java | 18 +++++++ src/test/res/ltd-samples/Test_8.java | 19 ++++++++ src/test/res/ltd-samples/Test_9.java | 35 ++++++++++++++ .../res/papers/Example1_Horwitz_PPDG.java | 8 ++++ src/test/res/papers/Sergio.java | 16 +++++++ src/test/res/papers/SergioContinue.java | 11 +++++ src/test/res/programs | 1 + 36 files changed, 619 insertions(+) create mode 100644 src/main/java/tfm/programs/cfg/CFG_Test1.java create mode 100644 src/main/java/tfm/programs/cfg/CFG_Test2.java create mode 100644 src/main/java/tfm/programs/cfg/CFG_Test3.java create mode 100644 src/main/java/tfm/programs/cfg/CFG_Test4.java create mode 100644 src/main/java/tfm/programs/cfg/CFG_Test5.java create mode 100644 src/test/res/carlos/Test1.java create mode 100644 src/test/res/ltd-samples/BasicBreak.java create mode 100644 src/test/res/ltd-samples/BasicContinue.java create mode 100644 src/test/res/ltd-samples/BasicForeach.java create mode 100644 src/test/res/ltd-samples/BasicIf.java create mode 100644 src/test/res/ltd-samples/BasicIfElse.java create mode 100644 src/test/res/ltd-samples/BasicSwitch.java create mode 100644 src/test/res/ltd-samples/BasicSwitchDefault.java create mode 100644 src/test/res/ltd-samples/BasicSwitchNoBreak.java create mode 100755 src/test/res/ltd-samples/Bucles_1.java create mode 100755 src/test/res/ltd-samples/Bucles_2.java create mode 100755 src/test/res/ltd-samples/Bucles_3.java create mode 100755 src/test/res/ltd-samples/Bucles_4.java create mode 100755 src/test/res/ltd-samples/Bucles_5.java create mode 100644 src/test/res/ltd-samples/Bucles_6.java create mode 100644 src/test/res/ltd-samples/Bucles_Josep.java create mode 100644 src/test/res/ltd-samples/ReturnTest.java create mode 100644 src/test/res/ltd-samples/Test_1.java create mode 100644 src/test/res/ltd-samples/Test_2.java create mode 100644 src/test/res/ltd-samples/Test_3.java create mode 100644 src/test/res/ltd-samples/Test_4.java create mode 100644 src/test/res/ltd-samples/Test_5.java create mode 100644 src/test/res/ltd-samples/Test_6.java create mode 100644 src/test/res/ltd-samples/Test_7.java create mode 100644 src/test/res/ltd-samples/Test_8.java create mode 100644 src/test/res/ltd-samples/Test_9.java create mode 100644 src/test/res/papers/Example1_Horwitz_PPDG.java create mode 100644 src/test/res/papers/Sergio.java create mode 100644 src/test/res/papers/SergioContinue.java create mode 120000 src/test/res/programs diff --git a/src/main/java/tfm/programs/WhileLoop.java b/src/main/java/tfm/programs/WhileLoop.java index 81b2f48..da61f46 100644 --- a/src/main/java/tfm/programs/WhileLoop.java +++ b/src/main/java/tfm/programs/WhileLoop.java @@ -2,6 +2,8 @@ package tfm.programs; public class WhileLoop { + void main() {} + void while1() { int x = 1; int y = 2; diff --git a/src/main/java/tfm/programs/cfg/CFG_Test1.java b/src/main/java/tfm/programs/cfg/CFG_Test1.java new file mode 100644 index 0000000..01539fd --- /dev/null +++ b/src/main/java/tfm/programs/cfg/CFG_Test1.java @@ -0,0 +1,5 @@ +public class CFG_Test1 { + public static void main(String[] args) { + + } +} \ No newline at end of file diff --git a/src/main/java/tfm/programs/cfg/CFG_Test2.java b/src/main/java/tfm/programs/cfg/CFG_Test2.java new file mode 100644 index 0000000..b885e30 --- /dev/null +++ b/src/main/java/tfm/programs/cfg/CFG_Test2.java @@ -0,0 +1,8 @@ +public class CFG_Test2 { + public static void main(String[] args) { + int a = 1; + int b = 2; + int c = 3; + int d = 4; + } +} \ No newline at end of file diff --git a/src/main/java/tfm/programs/cfg/CFG_Test3.java b/src/main/java/tfm/programs/cfg/CFG_Test3.java new file mode 100644 index 0000000..e1fba8c --- /dev/null +++ b/src/main/java/tfm/programs/cfg/CFG_Test3.java @@ -0,0 +1,8 @@ +public class CFG_Test3 { + public static void main(String[] args) { + int a = 1; + while (a < 10) + a++; + System.out.println(a); + } +} \ No newline at end of file diff --git a/src/main/java/tfm/programs/cfg/CFG_Test4.java b/src/main/java/tfm/programs/cfg/CFG_Test4.java new file mode 100644 index 0000000..1580ba5 --- /dev/null +++ b/src/main/java/tfm/programs/cfg/CFG_Test4.java @@ -0,0 +1,11 @@ +public class CFG_Test4 { + public static void main(String[] args) { + int a = 1; + if (a % 2 == 0) { + a++; + } else { + a--; + } + System.out.println(a); + } +} \ No newline at end of file diff --git a/src/main/java/tfm/programs/cfg/CFG_Test5.java b/src/main/java/tfm/programs/cfg/CFG_Test5.java new file mode 100644 index 0000000..816e456 --- /dev/null +++ b/src/main/java/tfm/programs/cfg/CFG_Test5.java @@ -0,0 +1,9 @@ +public class CFG_Test5 { + public static void main(String[] args) { + int a = 1; + if (a % 2 == 0) { + a++; + } + System.out.println(a); + } +} \ No newline at end of file diff --git a/src/test/res/carlos/Test1.java b/src/test/res/carlos/Test1.java new file mode 100644 index 0000000..da111af --- /dev/null +++ b/src/test/res/carlos/Test1.java @@ -0,0 +1,8 @@ +public class Test1 { + public static void main(String[] args) { + for (int a = 0; a < 10; a++) { + System.out.println(a); + } + System.out.println(true); + } +} diff --git a/src/test/res/ltd-samples/BasicBreak.java b/src/test/res/ltd-samples/BasicBreak.java new file mode 100644 index 0000000..17204ab --- /dev/null +++ b/src/test/res/ltd-samples/BasicBreak.java @@ -0,0 +1,17 @@ +package mytest; + +public class BasicBreak { + public static void main(String[] args) { + int x = 0; + bucle: + while (true) { + x++; + for (int y = 0; y < 10; y++) { + if (y == x) break; + if (y * 2 == x) break bucle; + } + if (x > 10) break; + x++; + } + } +} diff --git a/src/test/res/ltd-samples/BasicContinue.java b/src/test/res/ltd-samples/BasicContinue.java new file mode 100644 index 0000000..a55a66b --- /dev/null +++ b/src/test/res/ltd-samples/BasicContinue.java @@ -0,0 +1,17 @@ +package mytest; + +public class BasicContinue { + public static void main(String[] args) { + int x = 0; + bucle: + while (x < 20) { + x++; + for (int y = 0; y < 10; y++) { + if (y == x) continue; + if (y * 2 == x) continue bucle; + } + if (x > 10) continue; + x++; + } + } +} diff --git a/src/test/res/ltd-samples/BasicForeach.java b/src/test/res/ltd-samples/BasicForeach.java new file mode 100644 index 0000000..08dd728 --- /dev/null +++ b/src/test/res/ltd-samples/BasicForeach.java @@ -0,0 +1,9 @@ +public class BasicForeach { + public static void main(String[] args){ + int[] numbers = + {1,2,3,4,5,6,7,8,9,10}; + for (int item : numbers) { + System.out.println("Count is: " + item); + } + } +} \ No newline at end of file diff --git a/src/test/res/ltd-samples/BasicIf.java b/src/test/res/ltd-samples/BasicIf.java new file mode 100644 index 0000000..5ceb9ec --- /dev/null +++ b/src/test/res/ltd-samples/BasicIf.java @@ -0,0 +1,11 @@ +public class BasicIf { + public static void main(String[] args) { + boolean isMoving = false; + int currentSpeed = 10; + if (isMoving) { + currentSpeed--; + } else { + System.err.println("The bicycle has already stopped!"); + } + } +} \ No newline at end of file diff --git a/src/test/res/ltd-samples/BasicIfElse.java b/src/test/res/ltd-samples/BasicIfElse.java new file mode 100644 index 0000000..c8099fd --- /dev/null +++ b/src/test/res/ltd-samples/BasicIfElse.java @@ -0,0 +1,19 @@ +public class BasicIfElse { + public static void main(String[] args) { + int testscore = 76; + char grade; + + if (testscore >= 90) { + grade = 'A'; + } else if (testscore >= 80) { + grade = 'B'; + } else if (testscore >= 70) { + grade = 'C'; + } else if (testscore >= 60) { + grade = 'D'; + } else { + grade = 'F'; + } + System.out.println("Grade = " + grade); + } +} diff --git a/src/test/res/ltd-samples/BasicSwitch.java b/src/test/res/ltd-samples/BasicSwitch.java new file mode 100644 index 0000000..1ea12d6 --- /dev/null +++ b/src/test/res/ltd-samples/BasicSwitch.java @@ -0,0 +1,28 @@ +package mytest; + +public class BasicSwitch { + public static void main(String[] args) { + int x = Integer.valueOf(args[0]); + int y = -1; + switch (x) { + case 1: + y = 10; + break; + case 2: + y = 20; + break; + case 3: + y = 30; + break; + case 4: + case 5: + y = 100; + break; + case 6: + System.err.println("Error"); + case 10: + y = 0; + } + System.out.println(y); + } +} diff --git a/src/test/res/ltd-samples/BasicSwitchDefault.java b/src/test/res/ltd-samples/BasicSwitchDefault.java new file mode 100644 index 0000000..70262e3 --- /dev/null +++ b/src/test/res/ltd-samples/BasicSwitchDefault.java @@ -0,0 +1,23 @@ +package mytest; + +public class BasicSwitchDefault { + public static void main(String[] args) { + int x = Integer.valueOf(args[0]); + int y; + switch (x % 3) { + case 0: + y = 10; + break; + case 1: + y = 20; + break; + case 2: + y = 30; + break; + default: + y = -1; + break; + } + System.out.println(y); + } +} diff --git a/src/test/res/ltd-samples/BasicSwitchNoBreak.java b/src/test/res/ltd-samples/BasicSwitchNoBreak.java new file mode 100644 index 0000000..ab94ff6 --- /dev/null +++ b/src/test/res/ltd-samples/BasicSwitchNoBreak.java @@ -0,0 +1,16 @@ +package mytest; + +public class BasicSwitchNoBreak { + public static void main(String[] args) { + String res = ""; + switch (args[0]) { + case "a": + res = "abc"; + case "b": + res = "bac"; + case "c": + res = "cab"; + } + System.out.println(res); + } +} diff --git a/src/test/res/ltd-samples/Bucles_1.java b/src/test/res/ltd-samples/Bucles_1.java new file mode 100755 index 0000000..664ab83 --- /dev/null +++ b/src/test/res/ltd-samples/Bucles_1.java @@ -0,0 +1,14 @@ +package ejemplos; + +public class Bucles_1 { + + public static void main(String[] args) { + // BUCLE WHILE (sin anidamiento) + int x = 1; + while (x <= 10) { + System.out.print(x); + x++; + } + System.out.println(); + } +} diff --git a/src/test/res/ltd-samples/Bucles_2.java b/src/test/res/ltd-samples/Bucles_2.java new file mode 100755 index 0000000..3d388e2 --- /dev/null +++ b/src/test/res/ltd-samples/Bucles_2.java @@ -0,0 +1,21 @@ +package ejemplos; + +public class Bucles_2 { + + public static void main(String[] args) { + // BUCLE WHILE anidado a otro WHILE + System.out.println("Empieza bucle WHILE anidado a otro WHILE:"); + int x = 1; + char y = 'a'; + while (x <= 10) { + System.out.print(" " + x); + y = 'a'; + while (y <= 'c') { + System.out.print(" " + y); + y++; + } + x++; + } + System.out.println(); + } +} diff --git a/src/test/res/ltd-samples/Bucles_3.java b/src/test/res/ltd-samples/Bucles_3.java new file mode 100755 index 0000000..96e4d86 --- /dev/null +++ b/src/test/res/ltd-samples/Bucles_3.java @@ -0,0 +1,35 @@ +package ejemplos; + +public class Bucles_3 { + + public static void main(String[] args) { + int x; + + // BUCLE FOR (sin anidamiento) + System.out.println("Empieza bucle FOR:"); + for (x = 1; x <= 10; x++) { + System.out.print(" " + x); + } + System.out.println(); + + // BUCLE WHILE (sin anidamiento) + System.out.println("Empieza bucle WHILE:"); + x = 1; + while (x <= 10) { + System.out.print(" " + x); + x++; + } + System.out.println(); + + // BUCLE DO WHILE (sin anidamiento) + System.out.println("Empieza bucle DO WHILE:"); + x = 1; + do { + System.out.print(" " + x); + x++; + } + while (x <= 10); + System.out.println(); + + } +} diff --git a/src/test/res/ltd-samples/Bucles_4.java b/src/test/res/ltd-samples/Bucles_4.java new file mode 100755 index 0000000..9f3c130 --- /dev/null +++ b/src/test/res/ltd-samples/Bucles_4.java @@ -0,0 +1,37 @@ +package ejemplos; + +public class Bucles_4 { + + public static void main(String[] args) { + int x = 1; + + //Bucle 1: Contador + while (x < 10) { + System.out.println(x); + x++; + } + + //Bucle 2: Sumatorio + int suma = 0; + int y = 1; + while (y < 10) { + suma += y; + y++; + } + System.out.println(suma); + + //Bucle 3: Sumatorio + int sumatorio = 0; + int min = 10; + int max = 100; + for (int num = min; num <= max; num++) { + sumatorio += num; + } + System.out.println(sumatorio); + + int count = 0; + while (count < 10) + count++; + System.out.println(count); + } +} \ No newline at end of file diff --git a/src/test/res/ltd-samples/Bucles_5.java b/src/test/res/ltd-samples/Bucles_5.java new file mode 100755 index 0000000..e54d85e --- /dev/null +++ b/src/test/res/ltd-samples/Bucles_5.java @@ -0,0 +1,47 @@ +package ejemplos; + +public class Bucles_5 { + + public static void main(String[] args) { + int x = 0; + char y = '0'; + + // BUCLE FOR anidado a otro FOR + System.out.println("Empieza bucle FOR anidado a otro FOR:"); + for (x = 1; x <= 10; x++) { + System.out.print(" " + x); + for (y = 'a'; y <= 'c'; y++) { + System.out.print(" " + y); + } + } + System.out.println(); + + // BUCLE WHILE anidado a otro WHILE + System.out.println("Empieza bucle WHILE anidado a otro WHILE:"); + x = 1; + while (x <= 10) { + System.out.print(" " + x); + y = 'a'; + while (y <= 'c') { + System.out.print(" " + y); + y++; + } + x++; + } + System.out.println(); + + // BUCLE FOR anidado a bucle DO WHILE + System.out.println("Empieza bucle FOR anidado a bucle DO WHILE:"); + x = 1; + do { + System.out.print(" " + x); + for (y = 'a'; y <= 'c'; y++) { + System.out.print(" " + y); + } + x++; + } + while (x <= 10); + System.out.println(); + + } +} diff --git a/src/test/res/ltd-samples/Bucles_6.java b/src/test/res/ltd-samples/Bucles_6.java new file mode 100644 index 0000000..9ba83b5 --- /dev/null +++ b/src/test/res/ltd-samples/Bucles_6.java @@ -0,0 +1,23 @@ +package ejemplos; + +public class Bucles_6 { + + public static void main(String[] args) { + // BUCLE WHILE (sin anidamiento) + System.out.println("Empieza bucle WHILE:"); + int x = 1; + while (x <= 10) { + System.out.print(" " + x); + x++; + while (x <= 10) { + System.out.print(" " + x); + x++; + } + } + while (x <= 10) { + System.out.print(" " + x); + x++; + } + System.out.println(); + } +} diff --git a/src/test/res/ltd-samples/Bucles_Josep.java b/src/test/res/ltd-samples/Bucles_Josep.java new file mode 100644 index 0000000..d391cee --- /dev/null +++ b/src/test/res/ltd-samples/Bucles_Josep.java @@ -0,0 +1,39 @@ +package ejemplos; + +public class Bucles_Josep { + + public static void main(String[] args) { + + int x=0; + int y=0, z=0; + + z=x+y; + + if (z>0) + { + for(int a=1;a==1;) + { + a++; + if (a == 2) + break; + a++; + } + } + + while(z==0) + { + if (z==0) + { + z++; + } + else + { + z--; + } + } + + + + + } +} diff --git a/src/test/res/ltd-samples/ReturnTest.java b/src/test/res/ltd-samples/ReturnTest.java new file mode 100644 index 0000000..4b3f7e8 --- /dev/null +++ b/src/test/res/ltd-samples/ReturnTest.java @@ -0,0 +1,12 @@ +public class ReturnTest { + public static void main(String[] args) { + int i = Integer.valueOf(args[0]); + if (i == 0) { + System.out.println("true"); + return; + } else { + System.out.println("false"); + return; + } + } +} \ No newline at end of file diff --git a/src/test/res/ltd-samples/Test_1.java b/src/test/res/ltd-samples/Test_1.java new file mode 100644 index 0000000..7264be0 --- /dev/null +++ b/src/test/res/ltd-samples/Test_1.java @@ -0,0 +1,12 @@ +package ejemplos; + +public class Test_1 { + + public static void main(String[] args) { + System.out.println("HOLA mundo"); + int x = 1; + x = 2; + x = 3; + x = 4; + } +} diff --git a/src/test/res/ltd-samples/Test_2.java b/src/test/res/ltd-samples/Test_2.java new file mode 100644 index 0000000..3ce1e38 --- /dev/null +++ b/src/test/res/ltd-samples/Test_2.java @@ -0,0 +1,13 @@ +package ejemplos; + +public class Test_2 { + + public static void main(String[] args) { + int x = 1; + x++; + ++x; + int y = 0; + x = x + y; + System.out.println(x); + } +} diff --git a/src/test/res/ltd-samples/Test_3.java b/src/test/res/ltd-samples/Test_3.java new file mode 100644 index 0000000..e08b7f7 --- /dev/null +++ b/src/test/res/ltd-samples/Test_3.java @@ -0,0 +1,13 @@ +package ejemplos; + +public class Test_3 { + + public static void main(String[] args) { + int x = 1; + + if (x == 1) + x = 2; + x = 3; + x = 4; + } +} diff --git a/src/test/res/ltd-samples/Test_4.java b/src/test/res/ltd-samples/Test_4.java new file mode 100644 index 0000000..43e923c --- /dev/null +++ b/src/test/res/ltd-samples/Test_4.java @@ -0,0 +1,18 @@ +package ejemplos; + +public class Test_4 { + + public static void main(String[] args) { + int x = 1; + + if (x == 1) { + x = 2; + if (x >= 1) { + x = 3; + x = 4; + } + } + x = 5; + x = 6; + } +} diff --git a/src/test/res/ltd-samples/Test_5.java b/src/test/res/ltd-samples/Test_5.java new file mode 100644 index 0000000..4dc96e4 --- /dev/null +++ b/src/test/res/ltd-samples/Test_5.java @@ -0,0 +1,19 @@ +package ejemplos; + +public class Test_5 { + + public static void main(String[] args) { + int x = 1; + + if (x == 1) { + x = 2; + if (x >= 1) { + x = 3; + x = 4; + } + x = 5; + } + x = 6; + x = 7; + } +} diff --git a/src/test/res/ltd-samples/Test_6.java b/src/test/res/ltd-samples/Test_6.java new file mode 100644 index 0000000..91d0e19 --- /dev/null +++ b/src/test/res/ltd-samples/Test_6.java @@ -0,0 +1,17 @@ +package ejemplos; + +public class Test_6 { + + public static void main(String[] args) { + int x = 1; + + if (x == 1) { + x = 2; + x = 3; + } else { + x = 4; + x = 5; + } + x = 6; + } +} diff --git a/src/test/res/ltd-samples/Test_7.java b/src/test/res/ltd-samples/Test_7.java new file mode 100644 index 0000000..60b7f5f --- /dev/null +++ b/src/test/res/ltd-samples/Test_7.java @@ -0,0 +1,18 @@ +package ejemplos; + + +public class Test_7 { + + public static void main(String[] args) { + int x = 1; + + if (x == 1) { + x = 2; + } else x = 3; + x = 4; + if (x == 2) { + x = 5; + } else if (x == 3) x = 6; + x = 7; + } +} diff --git a/src/test/res/ltd-samples/Test_8.java b/src/test/res/ltd-samples/Test_8.java new file mode 100644 index 0000000..92c240f --- /dev/null +++ b/src/test/res/ltd-samples/Test_8.java @@ -0,0 +1,19 @@ +package ejemplos; + +public class Test_8 { + + public static void main(String[] args) { + int x = 1; + + if (x == 1) { + x = 2; + } + x = 5; + x = 6; + if (x == 2) { + x = 7; + } + if (x == 3) x = 8; + x = 9; + } +} diff --git a/src/test/res/ltd-samples/Test_9.java b/src/test/res/ltd-samples/Test_9.java new file mode 100644 index 0000000..95a3c53 --- /dev/null +++ b/src/test/res/ltd-samples/Test_9.java @@ -0,0 +1,35 @@ +package ejemplos; + +public class Test_9 { + + + public static void main(String[] args) { + // ANIDAMIENTO de IF y WHILE + + // ANIDAMIENTO de IF y WHILE 2 + + int x = 0; + if (x > 1) { + x = 1; + while (x > 2) { + x = 2; + while (x > 3) { + x = 3; + if (x > 4) { + x = 4; + if (x > 5) { + x = 5; + } + x--; + } + x--; + } + x--; + } + x--; + } + + x--; + + } +} diff --git a/src/test/res/papers/Example1_Horwitz_PPDG.java b/src/test/res/papers/Example1_Horwitz_PPDG.java new file mode 100644 index 0000000..da381ff --- /dev/null +++ b/src/test/res/papers/Example1_Horwitz_PPDG.java @@ -0,0 +1,8 @@ +public class Test { + public static void main(String[] args) { + switch (X) { + case e1: + + } + } +} \ No newline at end of file diff --git a/src/test/res/papers/Sergio.java b/src/test/res/papers/Sergio.java new file mode 100644 index 0000000..b9bd607 --- /dev/null +++ b/src/test/res/papers/Sergio.java @@ -0,0 +1,16 @@ +public class Test { + public static void main(String[] args) { + while (X) { + if (Y) { + if (Z) { + A(); + break; + } + B(); + break; + } + C(); + } + D(); + } +} \ No newline at end of file diff --git a/src/test/res/papers/SergioContinue.java b/src/test/res/papers/SergioContinue.java new file mode 100644 index 0000000..cb68a46 --- /dev/null +++ b/src/test/res/papers/SergioContinue.java @@ -0,0 +1,11 @@ +public class Test { + public static void main(String[] args) { + while (X) { + if (Y) { + if (Z) { + + } + } + } + } +} \ No newline at end of file diff --git a/src/test/res/programs b/src/test/res/programs new file mode 120000 index 0000000..2fb351c --- /dev/null +++ b/src/test/res/programs @@ -0,0 +1 @@ +../../main/java/tfm/programs \ No newline at end of file -- GitLab From 5c2a63ac2e50b1e6e472c14a919f5dd32789d02a Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Fri, 10 Jan 2020 17:11:58 +0100 Subject: [PATCH 02/27] Improved CFG generation Covers statements, loops, `if`, `switch`, jumps (`break`, `return`...). Does not include elements from the ACFG. --- src/main/java/tfm/utils/ASTUtils.java | 15 +- .../java/tfm/visitors/cfg/CFGBuilder.java | 361 +++++++++--------- 2 files changed, 187 insertions(+), 189 deletions(-) diff --git a/src/main/java/tfm/utils/ASTUtils.java b/src/main/java/tfm/utils/ASTUtils.java index a8e7031..788e34e 100644 --- a/src/main/java/tfm/utils/ASTUtils.java +++ b/src/main/java/tfm/utils/ASTUtils.java @@ -3,9 +3,7 @@ package tfm.utils; import com.github.javaparser.Position; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.NodeList; -import com.github.javaparser.ast.stmt.BlockStmt; -import com.github.javaparser.ast.stmt.EmptyStmt; -import com.github.javaparser.ast.stmt.Statement; +import com.github.javaparser.ast.stmt.*; import java.util.Objects; import java.util.Optional; @@ -59,4 +57,15 @@ public class ASTUtils { return Objects.equals(parent, upper) || isContained(upper, parent); } + + public static boolean switchHasDefaultCase(SwitchStmt stmt) { + return switchGetDefaultCase(stmt) != null; + } + + public static SwitchEntryStmt switchGetDefaultCase(SwitchStmt stmt) { + for (SwitchEntryStmt entry : stmt.getEntries()) + if (!entry.getLabel().isPresent()) + return entry; + return null; + } } diff --git a/src/main/java/tfm/visitors/cfg/CFGBuilder.java b/src/main/java/tfm/visitors/cfg/CFGBuilder.java index 633aad8..6c9550f 100644 --- a/src/main/java/tfm/visitors/cfg/CFGBuilder.java +++ b/src/main/java/tfm/visitors/cfg/CFGBuilder.java @@ -1,8 +1,10 @@ package tfm.visitors.cfg; +import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.expr.BooleanLiteralExpr; import com.github.javaparser.ast.expr.Expression; +import com.github.javaparser.ast.expr.SimpleName; import com.github.javaparser.ast.stmt.*; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; import tfm.graphs.CFGGraph; @@ -12,259 +14,246 @@ import tfm.utils.ASTUtils; import java.util.*; public class CFGBuilder extends VoidVisitorAdapter { - - private CFGGraph graph; - - private Queue lastParentNodes; - private List bodyBreaks; + /** Stores whether a method visit has started, to avoid mapping multiple methods onto one CFG. */ + private boolean begunMethod = false; + + /** Stores the CFG representing the method analyzed. */ + private final CFGGraph graph; + /** Nodes that haven't yet been connected to another one. + * The next node will be the destination, they are the source. */ + private final List> hangingNodes = new LinkedList<>(); + /** Stack of break statements collected in various (nestable) breakable blocks. */ + private final Stack>> breakStack = new Stack<>(); + /** Stack of continue statements collected in various (nestable) continuable blocks. */ + private final Stack>> continueStack = new Stack<>(); + /** Lists of labelled break statements, mapped according to their label. */ + private final Map>> breakMap = new HashMap<>(); + /** Lists of labelled continue statements, mapped according to their label. */ + private final Map>> continueMap = new HashMap<>(); + /** Return statements that should be connected to the final node, if it is created at the end of the */ + private final List> returnList = new LinkedList<>(); + /** Stack of lists of hanging cases on switch statements */ + private final Stack>> switchEntriesStack = new Stack<>(); public CFGBuilder(CFGGraph graph) { this.graph = graph; - this.lastParentNodes = Collections.asLifoQueue( - new ArrayDeque<>( - Collections.singletonList(graph.getRootNode()) - ) - ); - - this.bodyBreaks = new ArrayList<>(); } - @Override - public void visit(ExpressionStmt expressionStmt, Void arg) { - String expression = expressionStmt.toString().replace("\"", "\\\""); + private GraphNode connectTo(T n) { + return connectTo(n, n.toString()); + } - GraphNode nextNode = addNodeAndArcs(expression, expressionStmt); + private GraphNode connectTo(T n, String text) { + GraphNode dest = graph.addNode(text, n); + connectTo(dest); + return dest; + } - lastParentNodes.add(nextNode); + private void connectTo(GraphNode node) { + for (GraphNode src : hangingNodes) + graph.addControlFlowEdge(src, node); + hangingNodes.clear(); + hangingNodes.add(node); } -// @Override -// public void visit(VariableDeclarationExpr variableDeclarationExpr, Void arg) { -// GraphNode nextNode = addNodeAndArcs(variableDeclarationExpr.toString()); -// -// lastParentNodes.add(nextNode); -// -// Logger.log(variableDeclarationExpr); -// -// super.visit(variableDeclarationExpr, arg); -// } + @Override + public void visit(ExpressionStmt expressionStmt, Void arg) { + connectTo(expressionStmt); + } @Override public void visit(IfStmt ifStmt, Void arg) { - GraphNode ifCondition = addNodeAndArcs( - String.format("if (%s)", ifStmt.getCondition().toString()), - ifStmt - ); - - lastParentNodes.add(ifCondition); + // *if* -> {then else} -> after + GraphNode cond = connectTo(ifStmt, String.format("if (%s)", ifStmt.getCondition())); - // Visit "then" + // if -> {*then* else} -> after ifStmt.getThenStmt().accept(this, arg); + List> hangingThenNodes = new LinkedList<>(hangingNodes); - Queue lastThenNodes = new ArrayDeque<>(lastParentNodes); - - if (ifStmt.hasElseBranch()) { - lastParentNodes.clear(); - lastParentNodes.add(ifCondition); // Set if nodes as root - + if (ifStmt.getElseStmt().isPresent()) { + // if -> {then *else*} -> after + hangingNodes.clear(); + hangingNodes.add(cond); ifStmt.getElseStmt().get().accept(this, arg); - - lastParentNodes.addAll(lastThenNodes); + hangingNodes.addAll(hangingThenNodes); } else { - lastParentNodes.add(ifCondition); + // if -> {then **} -> after + hangingNodes.add(cond); } + // if -> {then else} -> *after* } @Override - public void visit(WhileStmt whileStmt, Void arg) { - GraphNode whileCondition = addNodeAndArcs( - String.format("while (%s)", whileStmt.getCondition().toString()), - whileStmt - ); + public void visit(LabeledStmt n, Void arg) { + breakMap.put(n.getLabel(), new LinkedList<>()); + continueMap.put(n.getLabel(), new LinkedList<>()); + super.visit(n, arg); + hangingNodes.addAll(breakMap.remove(n.getLabel())); + // Remove the label from the continue map; the list should have been emptied + // in the corresponding loop. + assert continueMap.remove(n.getLabel()).isEmpty(); + } + + private void hangLabelledContinueStmts(Node loopParent) { + if (loopParent instanceof LabeledStmt) { + SimpleName label = ((LabeledStmt) loopParent).getLabel(); + if (continueMap.containsKey(label)) { + List> list = continueMap.get(label); + hangingNodes.addAll(list); + list.clear(); + } + } + } - lastParentNodes.add(whileCondition); + @Override + public void visit(WhileStmt whileStmt, Void arg) { + GraphNode cond = connectTo(whileStmt, String.format("while (%s)", whileStmt.getCondition())); + breakStack.push(new LinkedList<>()); + continueStack.push(new LinkedList<>()); whileStmt.getBody().accept(this, arg); - while (!lastParentNodes.isEmpty()) { - graph.addControlFlowEdge(lastParentNodes.poll(), whileCondition); - } - - lastParentNodes.add(whileCondition); - lastParentNodes.addAll(bodyBreaks); - bodyBreaks.clear(); + hangingNodes.addAll(continueStack.pop()); + hangLabelledContinueStmts(whileStmt.getParentNode().orElse(null)); + // Loop contains anything + if (hangingNodes.size() != 1 || hangingNodes.get(0) != cond) + connectTo(cond); + hangingNodes.addAll(breakStack.pop()); } @Override public void visit(DoStmt doStmt, Void arg) { - BlockStmt body = ASTUtils.blockWrapper(doStmt.getBody()); + breakStack.push(new LinkedList<>()); + continueStack.push(new LinkedList<>()); - body.accept(this, arg); + GraphNode cond = connectTo(doStmt, String.format("while (%s)", doStmt.getCondition())); - GraphNode doWhileNode = addNodeAndArcs( - String.format("while (%s)", doStmt.getCondition()), - doStmt - ); + doStmt.getBody().accept(this, arg); - if (!body.isEmpty()) { - Statement firstBodyStatement = body.getStatement(0); - - graph.findNodeByASTNode(firstBodyStatement) - .ifPresent(node -> graph.addControlFlowEdge(doWhileNode, node)); - } - - lastParentNodes.add(doWhileNode); - lastParentNodes.addAll(bodyBreaks); - bodyBreaks.clear(); + hangingNodes.addAll(continueStack.pop()); + hangLabelledContinueStmts(doStmt.getParentNode().orElse(null)); + // Loop contains anything + if (hangingNodes.size() != 1 || hangingNodes.get(0) != cond) + connectTo(cond); + hangingNodes.addAll(breakStack.pop()); } @Override public void visit(ForStmt forStmt, Void arg) { -// String inizialization = forStmt.getInitialization().stream() -// .map(GraphNode::toString) -// .collect(Collectors.joining(",")); -// -// String update = forStmt.getUpdate().stream() -// .map(GraphNode::toString) -// .collect(Collectors.joining(",")); - - Expression comparison = forStmt.getCompare().orElse(new BooleanLiteralExpr(true)); -// - forStmt.getInitialization().forEach(expression -> new ExpressionStmt(expression).accept(this, null)); - - GraphNode forNode = addNodeAndArcs( - String.format("for (;%s;)", comparison), - forStmt - ); - - lastParentNodes.add(forNode); - - BlockStmt body = ASTUtils.blockWrapper(forStmt.getBody()).clone(); - - forStmt.getUpdate().forEach(body::addStatement); - - body.accept(this, arg); - - while (!lastParentNodes.isEmpty()) { - graph.addControlFlowEdge(lastParentNodes.poll(), forNode); - } - - lastParentNodes.add(forNode); - lastParentNodes.addAll(bodyBreaks); - bodyBreaks.clear(); + breakStack.push(new LinkedList<>()); + continueStack.push(new LinkedList<>()); + + // Initialization + forStmt.getInitialization().forEach(expression -> new ExpressionStmt(expression).accept(this, arg)); + + // Condition + Expression condition = forStmt.getCompare().orElse(new BooleanLiteralExpr(true)); + GraphNode cond = connectTo(forStmt, String.format("for (;%s;)", condition)); + + // Body and update expressions + forStmt.getBody().accept(this, arg); + forStmt.getUpdate().forEach(e -> new ExpressionStmt(e).accept(this, arg)); + + // Condition if body contained anything + hangingNodes.addAll(continueStack.pop()); + hangLabelledContinueStmts(forStmt.getParentNode().orElse(null)); + if ((hangingNodes.size()) != 1 || hangingNodes.get(0) != cond) + connectTo(cond); + hangingNodes.addAll(breakStack.pop()); } @Override public void visit(ForEachStmt forEachStmt, Void arg) { - GraphNode foreachNode = addNodeAndArcs( - String.format("for (%s : %s)", forEachStmt.getVariable(), forEachStmt.getIterable()), - forEachStmt - ); + breakStack.push(new LinkedList<>()); + continueStack.push(new LinkedList<>()); - lastParentNodes.add(foreachNode); + GraphNode cond = connectTo(forEachStmt, + String.format("for (%s : %s)", forEachStmt.getVariable(), forEachStmt.getIterable())); forEachStmt.getBody().accept(this, arg); - while (!lastParentNodes.isEmpty()) { - graph.addControlFlowEdge(lastParentNodes.poll(), foreachNode); - } + hangingNodes.addAll(continueStack.pop()); + hangLabelledContinueStmts(forEachStmt.getParentNode().orElse(null)); + if (hangingNodes.size() != 1 || hangingNodes.get(0) != cond) + connectTo(cond); + hangingNodes.addAll(breakStack.pop()); + } - lastParentNodes.add(foreachNode); - lastParentNodes.addAll(bodyBreaks); - bodyBreaks.clear(); + /** Switch entry, considered part of the condition of the switch. */ + @Override + public void visit(SwitchEntryStmt entryStmt, Void arg) { + // Case header (prev -> case EXPR) + GraphNode node; + if (entryStmt.getLabel().isPresent()) { + node = connectTo(entryStmt, "case " + entryStmt.getLabel().get()); + } else { + node = connectTo(entryStmt, "default"); + } + switchEntriesStack.peek().add(node); + // Case body (case EXPR --> body) + entryStmt.getStatements().accept(this, arg); + // body --> next } @Override public void visit(SwitchStmt switchStmt, Void arg) { - GraphNode switchNode = addNodeAndArcs( - String.format("switch (%s)", switchStmt.getSelector()), - switchStmt - ); - - lastParentNodes.add(switchNode); - - List allEntryBreaks = new ArrayList<>(); - - List lastEntryStatementsWithNoBreak = new ArrayList<>(); - - switchStmt.getEntries().forEach(switchEntryStmt -> { - String label = switchEntryStmt.getLabel() - .map(expression -> "case " + expression) - .orElse("default"); - - GraphNode switchEntryNode = addNodeAndArcs(label, switchEntryStmt); - - lastParentNodes.add(switchEntryNode); - lastParentNodes.addAll(lastEntryStatementsWithNoBreak); - lastEntryStatementsWithNoBreak.clear(); - - switchEntryStmt.getStatements().accept(this, null); - - if (!bodyBreaks.isEmpty()) { // means it has break - allEntryBreaks.addAll(bodyBreaks); // save breaks of entry - - lastParentNodes.clear(); - lastParentNodes.add(switchEntryNode); // Set switch as the only parent - - bodyBreaks.clear(); // Clear breaks - } else { - lastEntryStatementsWithNoBreak.addAll(lastParentNodes); - lastParentNodes.clear(); - lastParentNodes.add(switchEntryNode); - } - }); - - lastParentNodes.addAll(allEntryBreaks); + // Link previous statement to the switch's selector + switchEntriesStack.push(new LinkedList<>()); + breakStack.push(new LinkedList<>()); + GraphNode cond = connectTo(switchStmt, String.format("switch (%s)", switchStmt.getSelector())); + // expr --> each case (fallthrough by default, so case --> case too) + for (SwitchEntryStmt entry : switchStmt.getEntries()) { + entry.accept(this, arg); // expr && prev case --> case --> next case + hangingNodes.add(cond); // expr --> next case + } + // The next statement will be linked to: + // 1. All break statements that broke from the switch (done with break section) + // 2. If the switch doesn't have a default statement, the switch's selector (already present) + // 3. If the last entry doesn't break, to the last statement (present already) + // If the last case is a default case, remove the selector node from the list of nodes (see 2) + if (ASTUtils.switchHasDefaultCase(switchStmt)) + hangingNodes.remove(cond); + switchEntriesStack.pop(); + // End block and break section + hangingNodes.addAll(breakStack.pop()); } @Override public void visit(BreakStmt breakStmt, Void arg) { - bodyBreaks.addAll(lastParentNodes); + GraphNode node = connectTo(breakStmt); + if (breakStmt.getLabel().isPresent()) + breakMap.get(breakStmt.getLabel().get()).add(node); + else + breakStack.peek().add(node); + hangingNodes.clear(); } @Override public void visit(ContinueStmt continueStmt, Void arg) { - Statement continuableStatement = ASTUtils.findFirstAncestorStatementFrom(continueStmt, ASTUtils::isLoop); - - GraphNode continuableNode = graph.findNodeByASTNode(continuableStatement).get(); - - lastParentNodes.forEach(parentNode -> graph.addControlFlowEdge(parentNode, continuableNode)); + GraphNode node = connectTo(continueStmt); + if (continueStmt.getLabel().isPresent()) + continueMap.get(continueStmt.getLabel().get()).add(node); + else + continueStack.peek().add(node); + hangingNodes.clear(); } @Override public void visit(ReturnStmt returnStmt, Void arg) { - GraphNode node = addNodeAndArcs( - returnStmt.toString(), - returnStmt - ); - - lastParentNodes.add(node); + GraphNode node = connectTo(returnStmt); + returnList.add(node); + hangingNodes.clear(); } @Override public void visit(MethodDeclaration methodDeclaration, Void arg) { - if (!lastParentNodes.isEmpty() && Objects.equals(lastParentNodes.peek().getData(), "Stop")) { + if (begunMethod) throw new IllegalStateException("CFG is only allowed for one method, not multiple!"); - } + begunMethod = true; + hangingNodes.add(graph.getRootNode()); super.visit(methodDeclaration, arg); - - lastParentNodes.add(addNodeAndArcs("Stop", new EmptyStmt())); + returnList.stream().filter(node -> !hangingNodes.contains(node)).forEach(hangingNodes::add); + connectTo(new EmptyStmt(), "Exit"); } - - private GraphNode addNodeAndArcs(String nodeData, Statement statement) { - GraphNode node = graph.addNode(nodeData, statement); - - GraphNode parent = lastParentNodes.poll(); // ALWAYS exists a parent - graph.addControlFlowEdge(parent, node); - - while (!lastParentNodes.isEmpty()) { - parent = lastParentNodes.poll(); - graph.addControlFlowEdge(parent, node); - } - - return node; - } - - } -- GitLab From 3705ffac232d8d41cb51d93388bb5d3d648a71fc Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Fri, 10 Jan 2020 17:28:32 +0100 Subject: [PATCH 03/27] Add support for ACFG and APDG --- src/main/java/tfm/arcs/Arc.java | 20 ++++-- .../java/tfm/arcs/cfg/ControlFlowArc.java | 45 +++++++++++- .../tfm/arcs/pdg/ControlDependencyArc.java | 17 ++++- .../java/tfm/arcs/pdg/DataDependencyArc.java | 14 +++- src/main/java/tfm/exec/Config.java | 16 +++++ src/main/java/tfm/graphs/CFGGraph.java | 40 ++++++----- .../java/tfm/visitors/cfg/CFGBuilder.java | 70 ++++++++++++++++++- .../java/tfm/visitors/pdg/PDGBuilder.java | 20 +++++- 8 files changed, 208 insertions(+), 34 deletions(-) create mode 100644 src/main/java/tfm/exec/Config.java diff --git a/src/main/java/tfm/arcs/Arc.java b/src/main/java/tfm/arcs/Arc.java index 5c13d31..30932fa 100644 --- a/src/main/java/tfm/arcs/Arc.java +++ b/src/main/java/tfm/arcs/Arc.java @@ -12,10 +12,16 @@ public abstract class Arc extends edg.graphlib.Arrow) from, (edg.graphlib.Vertex) to); } + /** @see tfm.arcs.cfg.ControlFlowArc */ public abstract boolean isControlFlowArrow(); + /** @see tfm.arcs.cfg.ControlFlowArc.NonExecutable */ + public abstract boolean isExecutableControlFlowArrow(); + + /** @see tfm.arcs.pdg.ControlDependencyArc */ public abstract boolean isControlDependencyArrow(); + /** @see tfm.arcs.pdg.DataDependencyArc */ public abstract boolean isDataDependencyArrow(); @Override @@ -28,8 +34,8 @@ public abstract class Arc extends edg.graphlib.Arrow from = (GraphNode) getFrom(); + GraphNode to = (GraphNode) getTo(); return String.format("%s -> %s", from.getId(), @@ -58,12 +64,12 @@ public abstract class Arc extends edg.graphlib.Arrow arc = (Arc) o; - GraphNode from = (GraphNode) arc.getFrom(); - GraphNode from2 = (GraphNode) getFrom(); - GraphNode to = (GraphNode) getTo(); - GraphNode to2 = (GraphNode) arc.getTo(); + GraphNode from = (GraphNode) arc.getFrom(); + GraphNode from2 = (GraphNode) getFrom(); + GraphNode to = (GraphNode) getTo(); + GraphNode to2 = (GraphNode) arc.getTo(); return Objects.equals(arc.getData(), getData()) && Objects.equals(from.getId(), from2.getId()) && diff --git a/src/main/java/tfm/arcs/cfg/ControlFlowArc.java b/src/main/java/tfm/arcs/cfg/ControlFlowArc.java index f51233c..74ca504 100644 --- a/src/main/java/tfm/arcs/cfg/ControlFlowArc.java +++ b/src/main/java/tfm/arcs/cfg/ControlFlowArc.java @@ -4,9 +4,14 @@ import tfm.arcs.Arc; import tfm.arcs.data.VoidArcData; import tfm.nodes.GraphNode; +/** + * An edge of the {@link tfm.graphs.CFGGraph}, representing the direct + * flow of control. It connects two instructions if, when the source + * is executed, one of the possible next instructions is the destination. + */ public class ControlFlowArc extends Arc { - public ControlFlowArc(GraphNode from, GraphNode to) { + public ControlFlowArc(GraphNode from, GraphNode to) { super(from, to); } @@ -15,6 +20,11 @@ public class ControlFlowArc extends Arc { return true; } + @Override + public boolean isExecutableControlFlowArrow() { + return true; + } + @Override public boolean isControlDependencyArrow() { return false; @@ -33,4 +43,37 @@ public class ControlFlowArc extends Arc { ); } + /** + * Represents a non-executable control flow arc, used within the {@link tfm.exec.Config#ACFG}. + * Initially it had the following meaning: connecting a statement with + * the following one as if the source was a {@code nop} command (no operation). + *
+ * It is used to improve control dependence, and it should be skipped when + * computing data dependence and other analyses. + */ + public final static class NonExecutable extends ControlFlowArc { + public NonExecutable(GraphNode from, GraphNode to) { + super(from, to); + } + + @Override + public String toString() { + return "NonExecutable" + super.toString(); + } + + @Override + public boolean isExecutableControlFlowArrow() { + return false; + } + + @Override + public String toGraphvizRepresentation() { + return super.toGraphvizRepresentation() + "[style = dashed]"; + } + + @Override + public boolean equals(Object o) { + return o instanceof NonExecutable && super.equals(o); + } + } } diff --git a/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java b/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java index 6d7c79b..e2b82e5 100644 --- a/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java +++ b/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java @@ -4,9 +4,15 @@ import tfm.arcs.Arc; import tfm.arcs.data.ArcData; import tfm.nodes.GraphNode; +/** + * An arc used in the {@link tfm.graphs.PDGGraph} and {@link tfm.graphs.SDGGraph} + * used to represent control dependence between two nodes. The traditional definition of + * control dependence is: a node {@code a} is control dependent on node + * {@code b} if and only if {@code b} alters the number of times {@code a} is executed. + */ public class ControlDependencyArc extends Arc { - public ControlDependencyArc(GraphNode from, GraphNode to) { + public ControlDependencyArc(GraphNode from, GraphNode to) { super(from, to); } @@ -15,6 +21,11 @@ public class ControlDependencyArc extends Arc { return false; } + @Override + public boolean isExecutableControlFlowArrow() { + return false; + } + @Override public boolean isControlDependencyArrow() { return true; @@ -28,8 +39,8 @@ public class ControlDependencyArc extends Arc { @Override public String toString() { return String.format("ControlDependencyArc{%s -> %s}", - ((GraphNode) getFrom()).getId(), - ((GraphNode) getTo()).getId() + ((GraphNode) getFrom()).getId(), + ((GraphNode) getTo()).getId() ); } } diff --git a/src/main/java/tfm/arcs/pdg/DataDependencyArc.java b/src/main/java/tfm/arcs/pdg/DataDependencyArc.java index 11e8ac0..95a3e2e 100644 --- a/src/main/java/tfm/arcs/pdg/DataDependencyArc.java +++ b/src/main/java/tfm/arcs/pdg/DataDependencyArc.java @@ -8,9 +8,16 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +/** + * An arc used in the {@link tfm.graphs.PDGGraph} and {@link tfm.graphs.SDGGraph}, + * representing the declaration of some data linked to its usage (of that value). + * There is data dependency between two nodes if and only if (1) the source may + * declare a variable, (2) the destination may use it, and (3) there is a + * path between the nodes where the variable is not redefined. + */ public class DataDependencyArc extends Arc { - public DataDependencyArc(GraphNode from, GraphNode to, String variable, String... variables) { + public DataDependencyArc(GraphNode from, GraphNode to, String variable, String... variables) { super(from, to); List variablesList = new ArrayList<>(variables.length + 1); @@ -28,6 +35,11 @@ public class DataDependencyArc extends Arc { return false; } + @Override + public boolean isExecutableControlFlowArrow() { + return false; + } + @Override public boolean isControlDependencyArrow() { return false; diff --git a/src/main/java/tfm/exec/Config.java b/src/main/java/tfm/exec/Config.java new file mode 100644 index 0000000..eed9da3 --- /dev/null +++ b/src/main/java/tfm/exec/Config.java @@ -0,0 +1,16 @@ +package tfm.exec; + +/** + * Configuration for the different graphs created in the process of program slicing. + *
+ * The Control Flow Graph has different variations, each with its own name or code. + *
    + *
  • CFG
  • : the original proposal. It works well with statements, loops and branch instructions. + *
  • ACFG
  • : the augmented CFG; adds non-executable edges to represent unconditional + * jumps such as {@code break}, {@code return}, {@code switch} and much more. + *
+ */ +public class Config { + public static final int CFG = 0, ACFG = 1; + public static int CFG_TYPE = CFG; +} diff --git a/src/main/java/tfm/graphs/CFGGraph.java b/src/main/java/tfm/graphs/CFGGraph.java index 8faf9e3..0af2cda 100644 --- a/src/main/java/tfm/graphs/CFGGraph.java +++ b/src/main/java/tfm/graphs/CFGGraph.java @@ -15,6 +15,13 @@ import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; +/** + * The Control Flow Graph represents the statements of a method in + * a graph, displaying the connections between each statement and the ones that + * may follow it. You can build one manually or use the {@link tfm.visitors.cfg.CFGBuilder CFGBuilder}. + * @see ControlFlowArc + * @see tfm.exec.Config Config (for the available variations of the CFG) + */ public class CFGGraph extends Graph { public CFGGraph() { @@ -35,9 +42,16 @@ public class CFGGraph extends Graph { return "Start"; } + public void addControlFlowEdge(GraphNode from, GraphNode to) { + addControlFlowEdge(from, to, true); + } + @SuppressWarnings("unchecked") - public void addControlFlowEdge(GraphNode from, GraphNode to) { - super.addEdge((Arrow) new ControlFlowArc(from, to)); + public void addControlFlowEdge(GraphNode from, GraphNode to, boolean executable) { + if (executable) + super.addEdge((Arrow) new ControlFlowArc(from, to)); + else + super.addEdge((Arrow) new ControlFlowArc.NonExecutable(from, to)); } @Override @@ -51,8 +65,8 @@ public class CFGGraph extends Graph { String arrows = getArrows().stream() - .sorted(Comparator.comparingInt(arrow -> ((GraphNode) arrow.getFrom()).getId())) - .map(arrow -> ((Arc) arrow).toGraphvizRepresentation()) + .sorted(Comparator.comparingInt(arrow -> ((GraphNode) arrow.getFrom()).getId())) + .map(arrow -> ((Arc) arrow).toGraphvizRepresentation()) .collect(Collectors.joining(lineSep)); return "digraph g{" + lineSep + @@ -67,11 +81,6 @@ public class CFGGraph extends Graph { } public Set> findLastDefinitionsFrom(GraphNode startNode, String variable) { -// Logger.log("======================================================="); -// Logger.log("Starting from " + startNode); -// Logger.log("Looking for variable " + variable); -// Logger.log(cfgGraph.toString()); - if (!this.contains(startNode)) { throw new NodeNotFoundException(startNode, this); } @@ -81,34 +90,27 @@ public class CFGGraph extends Graph { private Set> findLastDefinitionsFrom(Set visited, GraphNode startNode, GraphNode currentNode, String variable) { visited.add(currentNode.getId()); - -// Logger.log("On " + currentNode); - Set> res = new HashSet<>(); for (Arc arc : currentNode.getIncomingArcs()) { ControlFlowArc controlFlowArc = (ControlFlowArc) arc; + // Ignore non-executable edges when computing data dependence. + if (arc instanceof ControlFlowArc.NonExecutable) + continue; GraphNode from = controlFlowArc.getFromNode(); -// Logger.log("Arrow from node: " + from); - if (!Objects.equals(startNode, from) && visited.contains(from.getId())) { -// Logger.log("It's already visited. Continuing..."); continue; } if (from.getDefinedVariables().contains(variable)) { -// Logger.log("Contains defined variable: " + variable); res.add(from); } else { -// Logger.log("Doesn't contain the variable, searching inside it"); res.addAll(findLastDefinitionsFrom(visited, startNode, from, variable)); } } -// Logger.format("Done with node %s", currentNode.getId()); - return res; } } diff --git a/src/main/java/tfm/visitors/cfg/CFGBuilder.java b/src/main/java/tfm/visitors/cfg/CFGBuilder.java index 6c9550f..e95f9a9 100644 --- a/src/main/java/tfm/visitors/cfg/CFGBuilder.java +++ b/src/main/java/tfm/visitors/cfg/CFGBuilder.java @@ -6,13 +6,33 @@ import com.github.javaparser.ast.expr.BooleanLiteralExpr; import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.expr.SimpleName; import com.github.javaparser.ast.stmt.*; +import com.github.javaparser.ast.visitor.VoidVisitor; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; +import tfm.exec.Config; import tfm.graphs.CFGGraph; import tfm.nodes.GraphNode; import tfm.utils.ASTUtils; import java.util.*; +/** + * Populates a {@link CFGGraph}, given one and an AST root node. + * For now it only accepts {@link MethodDeclaration} as roots, as it disallows + * multiple methods. + *
+ * Usage: + *
    + *
  1. Create a new {@link CFGGraph}.
  2. + *
  3. Create a new {@link CFGBuilder}, passing the graph as argument.
  4. + *
  5. Accept the builder as a visitor of the {@link MethodDeclaration} you + * want to analyse using {@link Node#accept(VoidVisitor, Object)}: {@code methodDecl.accept(builder, null)}
  6. + *
  7. Once the previous step is finished, the complete CFG is saved in + * the object created in the first step. The builder should be discarded + * and not reused.
  8. + *
+ * Configuration: this builder can be used to generate both the CFG and ACFG (see {@link Config}). + * Before performing the visit you should set the configuration to the one you prefer. + */ public class CFGBuilder extends VoidVisitorAdapter { /** Stores whether a method visit has started, to avoid mapping multiple methods onto one CFG. */ private boolean begunMethod = false; @@ -22,6 +42,8 @@ public class CFGBuilder extends VoidVisitorAdapter { /** Nodes that haven't yet been connected to another one. * The next node will be the destination, they are the source. */ private final List> hangingNodes = new LinkedList<>(); + /** Same as {@link CFGBuilder#hangingNodes}, but to be connected as non-executable edges. */ + private final List> nonExecHangingNodes = new LinkedList<>(); /** Stack of break statements collected in various (nestable) breakable blocks. */ private final Stack>> breakStack = new Stack<>(); /** Stack of continue statements collected in various (nestable) continuable blocks. */ @@ -52,7 +74,10 @@ public class CFGBuilder extends VoidVisitorAdapter { private void connectTo(GraphNode node) { for (GraphNode src : hangingNodes) graph.addControlFlowEdge(src, node); + for (GraphNode src : nonExecHangingNodes) + graph.addControlFlowEdge(src, node, false); hangingNodes.clear(); + nonExecHangingNodes.clear(); hangingNodes.add(node); } @@ -69,13 +94,16 @@ public class CFGBuilder extends VoidVisitorAdapter { // if -> {*then* else} -> after ifStmt.getThenStmt().accept(this, arg); List> hangingThenNodes = new LinkedList<>(hangingNodes); + List> hangingThenFalseNodes = new LinkedList<>(nonExecHangingNodes); if (ifStmt.getElseStmt().isPresent()) { // if -> {then *else*} -> after hangingNodes.clear(); + nonExecHangingNodes.clear(); hangingNodes.add(cond); ifStmt.getElseStmt().get().accept(this, arg); hangingNodes.addAll(hangingThenNodes); + nonExecHangingNodes.addAll(hangingThenFalseNodes); } else { // if -> {then **} -> after hangingNodes.add(cond); @@ -118,6 +146,8 @@ public class CFGBuilder extends VoidVisitorAdapter { // Loop contains anything if (hangingNodes.size() != 1 || hangingNodes.get(0) != cond) connectTo(cond); + else if (!nonExecHangingNodes.isEmpty()) + connectTo(cond); hangingNodes.addAll(breakStack.pop()); } @@ -135,6 +165,8 @@ public class CFGBuilder extends VoidVisitorAdapter { // Loop contains anything if (hangingNodes.size() != 1 || hangingNodes.get(0) != cond) connectTo(cond); + else if (!nonExecHangingNodes.isEmpty()) + connectTo(cond); hangingNodes.addAll(breakStack.pop()); } @@ -159,6 +191,8 @@ public class CFGBuilder extends VoidVisitorAdapter { hangLabelledContinueStmts(forStmt.getParentNode().orElse(null)); if ((hangingNodes.size()) != 1 || hangingNodes.get(0) != cond) connectTo(cond); + else if (!nonExecHangingNodes.isEmpty()) + connectTo(cond); hangingNodes.addAll(breakStack.pop()); } @@ -176,6 +210,8 @@ public class CFGBuilder extends VoidVisitorAdapter { hangLabelledContinueStmts(forEachStmt.getParentNode().orElse(null)); if (hangingNodes.size() != 1 || hangingNodes.get(0) != cond) connectTo(cond); + else if (!nonExecHangingNodes.isEmpty()) + connectTo(cond); hangingNodes.addAll(breakStack.pop()); } @@ -213,7 +249,31 @@ public class CFGBuilder extends VoidVisitorAdapter { // If the last case is a default case, remove the selector node from the list of nodes (see 2) if (ASTUtils.switchHasDefaultCase(switchStmt)) hangingNodes.remove(cond); - switchEntriesStack.pop(); + List> entries = switchEntriesStack.pop(); + if (Config.CFG_TYPE == Config.ACFG) { + GraphNode def = null; + for (GraphNode entry : entries) { + if (!entry.getAstNode().getLabel().isPresent()) { + def = entry; + break; + } + } + if (def != null) { + List> aux = new LinkedList<>(hangingNodes); + List> aux2 = new LinkedList<>(nonExecHangingNodes); + hangingNodes.clear(); + nonExecHangingNodes.clear(); + entries.remove(def); + nonExecHangingNodes.addAll(entries); + connectTo(def); + hangingNodes.clear(); + hangingNodes.addAll(aux); + nonExecHangingNodes.add(def); + nonExecHangingNodes.addAll(aux2); + } else { + nonExecHangingNodes.addAll(entries); + } + } // End block and break section hangingNodes.addAll(breakStack.pop()); } @@ -226,6 +286,8 @@ public class CFGBuilder extends VoidVisitorAdapter { else breakStack.peek().add(node); hangingNodes.clear(); + if (Config.CFG_TYPE == Config.ACFG) + nonExecHangingNodes.add(node); } @Override @@ -236,6 +298,8 @@ public class CFGBuilder extends VoidVisitorAdapter { else continueStack.peek().add(node); hangingNodes.clear(); + if (Config.CFG_TYPE == Config.ACFG) + nonExecHangingNodes.add(node); } @Override @@ -243,6 +307,8 @@ public class CFGBuilder extends VoidVisitorAdapter { GraphNode node = connectTo(returnStmt); returnList.add(node); hangingNodes.clear(); + if (Config.CFG_TYPE == Config.ACFG) + nonExecHangingNodes.add(node); } @Override @@ -254,6 +320,8 @@ public class CFGBuilder extends VoidVisitorAdapter { hangingNodes.add(graph.getRootNode()); super.visit(methodDeclaration, arg); returnList.stream().filter(node -> !hangingNodes.contains(node)).forEach(hangingNodes::add); + if (Config.CFG_TYPE == Config.ACFG) + nonExecHangingNodes.add(graph.getRootNode()); connectTo(new EmptyStmt(), "Exit"); } } diff --git a/src/main/java/tfm/visitors/pdg/PDGBuilder.java b/src/main/java/tfm/visitors/pdg/PDGBuilder.java index 37aff8c..cd5553f 100644 --- a/src/main/java/tfm/visitors/pdg/PDGBuilder.java +++ b/src/main/java/tfm/visitors/pdg/PDGBuilder.java @@ -1,6 +1,5 @@ package tfm.visitors.pdg; -import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.stmt.BlockStmt; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; @@ -9,6 +8,23 @@ import tfm.graphs.PDGGraph; import tfm.nodes.GraphNode; import tfm.visitors.cfg.CFGBuilder; +/** + * Populates a {@link PDGGraph}, given a complete {@link CFGGraph}, an empty {@link PDGGraph} and an AST root node. + * For now it only accepts {@link MethodDeclaration} as root, as it can only receive a single CFG. + *
+ * Usage: + *
    + *
  1. Create and fill a {@link CFGGraph} for the desired method.
  2. + *
  3. Create an empty {@link PDGGraph} (optionally passing the {@link CFGGraph} as argument).
  4. + *
  5. Create a new {@link PDGBuilder}, passing both graphs as arguments.
  6. + *
  7. Accept the builder as a visitor of the {@link MethodDeclaration} you want to analyse using + * {@link com.github.javaparser.ast.Node#accept(com.github.javaparser.ast.visitor.VoidVisitor, Object) Node#accept(VoidVisitor, Object)}: + * {@code methodDecl.accept(builder, null)}
  8. + *
  9. Once the previous step is finished, the complete PDG is saved in + * the object created in the second step. The builder should be discarded + * and not reused.
  10. + *
+ */ public class PDGBuilder extends VoidVisitorAdapter> { private PDGGraph pdgGraph; @@ -40,7 +56,7 @@ public class PDGBuilder extends VoidVisitorAdapter> { BlockStmt methodBody = methodDeclaration.getBody().get(); // build CFG - methodBody.accept(new CFGBuilder(cfgGraph), null); + methodDeclaration.accept(new CFGBuilder(cfgGraph), null); // Build control dependency ControlDependencyBuilder controlDependencyBuilder = new ControlDependencyBuilder(pdgGraph, cfgGraph); -- GitLab From 65be4201df9042b29f1ef2543825260bdfbb0e4f Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Fri, 10 Jan 2020 18:46:53 +0100 Subject: [PATCH 04/27] Better control dependence generation. Includes documentation for the updated classes. --- src/main/java/tfm/exec/Config.java | 9 + src/main/java/tfm/graphs/PDGGraph.java | 98 ++++------- src/main/java/tfm/nodes/GraphNode.java | 13 +- .../pdg/ControlDependencyBuilder.java | 166 ++++++++++-------- .../java/tfm/visitors/pdg/PDGBuilder.java | 8 +- 5 files changed, 150 insertions(+), 144 deletions(-) diff --git a/src/main/java/tfm/exec/Config.java b/src/main/java/tfm/exec/Config.java index eed9da3..fc54dd7 100644 --- a/src/main/java/tfm/exec/Config.java +++ b/src/main/java/tfm/exec/Config.java @@ -9,8 +9,17 @@ package tfm.exec; *
  • ACFG
  • : the augmented CFG; adds non-executable edges to represent unconditional * jumps such as {@code break}, {@code return}, {@code switch} and much more. * + * The Program Dependence Graph has variations in a similar fashion. + *
      + *
    • PDG
    • : based on the CFG, it computes control and data dependence to connect the nodes. + *
    • APDG
    • : similar to the PDG, but based on the ACFG. The non-executable edges are ignored + * when computing data dependencies. + *
    */ public class Config { public static final int CFG = 0, ACFG = 1; + public static final int PDG = 0, APDG = 1; + public static int CFG_TYPE = CFG; + public static int PDG_TYPE = PDG; } diff --git a/src/main/java/tfm/graphs/PDGGraph.java b/src/main/java/tfm/graphs/PDGGraph.java index 7cd03b4..705f962 100644 --- a/src/main/java/tfm/graphs/PDGGraph.java +++ b/src/main/java/tfm/graphs/PDGGraph.java @@ -2,10 +2,10 @@ package tfm.graphs; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.MethodDeclaration; -import com.github.javaparser.ast.stmt.EmptyStmt; import edg.graphlib.Arrow; import org.jetbrains.annotations.NotNull; import tfm.arcs.Arc; +import tfm.arcs.data.ArcData; import tfm.arcs.pdg.ControlDependencyArc; import tfm.arcs.pdg.DataDependencyArc; import tfm.nodes.GraphNode; @@ -21,7 +21,15 @@ import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; +/** + * The Program Dependence Graph represents the statements of a method in + * a graph, connecting statements according to their {@link ControlDependencyArc control} + * and {@link DataDependencyArc data} relationships. You can build one manually or use + * the {@link tfm.visitors.pdg.PDGBuilder PDGBuilder}. + * @see tfm.exec.Config Config (for the available variations of the PDG) + */ public class PDGGraph extends Graph { + public static boolean isRanked = false, isSorted = false; private CFGGraph cfgGraph; @@ -38,7 +46,7 @@ public class PDGGraph extends Graph { return "Entry"; } - public GraphNode addNode(GraphNode node) { + public GraphNode addNode(GraphNode node) { GraphNode vertex = new GraphNode<>(node); super.addVertex(vertex); @@ -58,32 +66,32 @@ public class PDGGraph extends Graph { } @SuppressWarnings("unchecked") - private void addArc(Arc arc) { - super.addEdge(arc); + private void addArc(Arc arc) { + super.addEdge((Arrow) arc); } - public void addControlDependencyArc(GraphNode from, GraphNode to) { + public void addControlDependencyArc(GraphNode from, GraphNode to) { ControlDependencyArc controlDependencyArc = new ControlDependencyArc(from, to); this.addArc(controlDependencyArc); } - public void addDataDependencyArc(GraphNode from, GraphNode to, String variable) { + public void addDataDependencyArc(GraphNode from, GraphNode to, String variable) { DataDependencyArc dataDataDependencyArc = new DataDependencyArc(from, to, variable); this.addArc(dataDataDependencyArc); } - public Set getNodesAtLevel(int level) { + public Set> getNodesAtLevel(int level) { return getVerticies().stream() - .map(vertex -> (GraphNode) vertex) + .map(vertex -> (GraphNode) vertex) .filter(node -> getLevelOf(node) == level) .collect(Collectors.toSet()); } public int getLevels() { return getVerticies().stream() - .map(vertex -> (GraphNode) vertex) + .map(vertex -> (GraphNode) vertex) .max(Comparator.comparingInt(this::getLevelOf)) .map(node -> getLevelOf(node) + 1) .orElse(0); @@ -98,6 +106,7 @@ public class PDGGraph extends Graph { public int getLevelOf(@NotNull GraphNode node) { Optional optionalControlDependencyArc = node.getIncomingArcs().stream() .filter(Arc::isControlDependencyArrow) + .filter(a -> a.getFromNode().getId() < node.getId()) .findFirst() .map(arc -> (ControlDependencyArc) arc); @@ -127,32 +136,36 @@ public class PDGGraph extends Graph { // No level 0 is needed (only one node) for (int i = 0; i < getLevels(); i++) { - Set levelNodes = getNodesAtLevel(i); + Set> levelNodes = getNodesAtLevel(i); if (levelNodes.size() <= 1) { continue; } // rank same - rankedNodes.append("{ rank = same; ") - .append(levelNodes.stream() - .map(node -> String.valueOf(node.getId())) - .collect(Collectors.joining(";"))) - .append(" }") - .append(lineSep); + if (isRanked) { + rankedNodes.append("{ rank = same; ") + .append(levelNodes.stream() + .map(node -> String.valueOf(node.getId())) + .collect(Collectors.joining(";"))) + .append(" }") + .append(lineSep); + } // invisible arrows for ordering - rankedNodes.append(levelNodes.stream() + if (isSorted) { + rankedNodes.append(levelNodes.stream() .sorted(Comparator.comparingInt(GraphNode::getId)) .map(node -> String.valueOf(node.getId())) .collect(Collectors.joining(" -> "))) - .append("[style = invis];") - .append(lineSep); + .append("[style = invis];") + .append(lineSep); + } } String arrows = getArcs().stream() - .sorted(Comparator.comparingInt(arrow -> ((GraphNode) arrow.getFrom()).getId())) + .sorted(Comparator.comparingInt(arrow -> ((GraphNode) arrow.getFrom()).getId())) .map(Arc::toGraphvizRepresentation) .collect(Collectors.joining(lineSep)); @@ -173,22 +186,7 @@ public class PDGGraph extends Graph { throw new NodeNotFoundException(slicingCriterion); } - GraphNode node = optionalGraphNode.get(); - -// // DEPRECATED - Find CFGNode and find last definition of variable -// CFGNode cfgNode = this.cfgGraph.findNodeByASTNode(node.getAstNode()) -// .orElseThrow(() -> new NodeNotFoundException("CFGNode not found")); -// -// Set> definitionNodes = Utils.findLastDefinitionsFrom(cfgNode, slicingCriterion.getVariable()); -// -// Logger.format("Slicing node: %s", node); -// -// // Get slice nodes from definition nodes -// Set sliceNodes = definitionNodes.stream() -// .flatMap(definitionNode -> getSliceNodes(new HashSet<>(), this.findNodeByASTNode(definitionNode.getAstNode()).get()).stream()) -// .collect(Collectors.toSet()); -// -// sliceNodes.add(node.getId()); + GraphNode node = optionalGraphNode.get(); // Simply get slice nodes from GraphNode Set sliceNodes = getSliceNodes(new HashSet<>(), node); @@ -199,7 +197,7 @@ public class PDGGraph extends Graph { astCopy.accept(new PDGBuilder(sliceGraph), sliceGraph.getRootNode()); - for (GraphNode sliceNode : sliceGraph.getNodes()) { + for (GraphNode sliceNode : sliceGraph.getNodes()) { if (!sliceNodes.contains(sliceNode.getId())) { Logger.log("Removing node " + sliceNode.getId()); sliceNode.getAstNode().removeForced(); @@ -207,37 +205,17 @@ public class PDGGraph extends Graph { } } -// for (Arc arc : getArcs()) { -// Optional fromOptional = sliceGraph.findNodeById(arc.getFromNode().getId()); -// Optional toOptional = sliceGraph.findNodeById(arc.getToNode().getId()); -// -// if (fromOptional.isPresent() && toOptional.isPresent()) { -// GraphNode from = fromOptional.get(); -// GraphNode to = toOptional.get(); -// -// if (arc.isControlDependencyArrow()) { -// sliceGraph.addControlDependencyArc(from, to); -// } else { -// DataDependencyArc dataDependencyArc = (DataDependencyArc) arc; -// sliceGraph.addDataDependencyArc(from, to, dataDependencyArc.getData().getVariables().get(0)); -// } -// } -// } - return sliceGraph; } private Set getSliceNodes(Set visited, GraphNode root) { visited.add(root.getId()); - for (Arrow arrow : root.getIncomingArcs()) { - Arc arc = (Arc) arrow; - - GraphNode from = (GraphNode) arc.getFromNode(); + for (Arc arc : root.getIncomingArcs()) { + GraphNode from = arc.getFromNode(); - if (visited.contains(from.getId())) { + if (visited.contains(from.getId())) continue; - } getSliceNodes(visited, from); } diff --git a/src/main/java/tfm/nodes/GraphNode.java b/src/main/java/tfm/nodes/GraphNode.java index 133b4cf..abd1600 100644 --- a/src/main/java/tfm/nodes/GraphNode.java +++ b/src/main/java/tfm/nodes/GraphNode.java @@ -14,6 +14,14 @@ import tfm.variables.VariableExtractor; import java.util.*; import java.util.stream.Collectors; +/** + * Represents a node in the various graphs ({@link tfm.graphs.CFGGraph CFG}, + * {@link tfm.graphs.PDGGraph PDG} and {@link tfm.graphs.SDGGraph SDG}), + * including its AST representation and the connections it has to other nodes + * in the same graph. It can hold a string of characters that will be used + * to represent it. + * @param The type of the AST represented by this node. + */ public class GraphNode extends Vertex { private int id; @@ -135,9 +143,10 @@ public class GraphNode extends Vertex { if (!(o instanceof GraphNode)) return false; - GraphNode other = (GraphNode) o; + GraphNode other = (GraphNode) o; - return Objects.equals(getData(), other.getData()) + return this.getId() == other.getId() + && Objects.equals(getData(), other.getData()) && Objects.equals(astNode, other.astNode); // && Objects.equals(getIncomingArrows(), other.getIncomingArrows()) // && Objects.equals(getOutgoingArrows(), other.getOutgoingArrows()) diff --git a/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java b/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java index 7ceab66..96f91ff 100644 --- a/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java +++ b/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java @@ -1,96 +1,106 @@ package tfm.visitors.pdg; -import com.github.javaparser.ast.stmt.*; -import com.github.javaparser.ast.visitor.VoidVisitorAdapter; +import tfm.arcs.Arc; +import tfm.arcs.data.ArcData; import tfm.graphs.CFGGraph; import tfm.graphs.PDGGraph; import tfm.nodes.GraphNode; -import java.util.stream.Collectors; - -public class ControlDependencyBuilder extends VoidVisitorAdapter { - - private CFGGraph cfgGraph; - private PDGGraph pdgGraph; - - public ControlDependencyBuilder(PDGGraph pdgGraph, CFGGraph cfgGraph) { - this.pdgGraph = pdgGraph; - this.cfgGraph = cfgGraph; +import java.util.*; + +/** + * A simple but slow finder of control dependencies. + *
    + * It has a polynomial complexity (between cubed and n**4) with respect to the number of nodes in the CFG. + * It uses the following definition of control dependence: + *
    + * A node b is control dependent on another node a if and only if b postdominates + * one but not all of the successors of a. + *
    + * A node b postdominates another node a if and only if b appears in every path + * from a to the "Exit" node. + *
    + * There exist better, cheaper approaches that have linear complexity w.r.t. the number of edges in the CFG. + * Usage: pass an empty {@link PDGGraph} and a filled {@link CFGGraph} and then run {@link #analyze()}. + * This builder should only be used once, and then discarded. + */ +public class ControlDependencyBuilder { + private final PDGGraph pdg; + private final CFGGraph cfg; + + public ControlDependencyBuilder(PDGGraph pdg, CFGGraph cfg) { + this.pdg = pdg; + this.cfg = cfg; } - @Override - public void visit(ExpressionStmt expressionStmt, GraphNode parent) { - addNodeAndControlDependency(expressionStmt, parent); + public void analyze() { + Map, GraphNode> nodeMap = new HashMap<>(); + nodeMap.put(cfg.getRootNode(), pdg.getRootNode()); + Set> roots = new HashSet<>(cfg.getNodes()); + roots.remove(cfg.getRootNode()); + Set> cfgNodes = new HashSet<>(cfg.getNodes()); + cfgNodes.removeIf(node -> node.getData().equals("Exit")); + + for (GraphNode node : cfgNodes) + registerNode(node, nodeMap); + + for (GraphNode src : cfgNodes) { + for (GraphNode dest : cfgNodes) { + if (src == dest) continue; + if (hasControlDependence(src, dest)) { + pdg.addControlDependencyArc(nodeMap.get(src), nodeMap.get(dest)); + if (pdg.contains(src)) + roots.remove(dest); + } + } + } + // In the original definition, nodes were dependent by default on the Enter/Start node + for (GraphNode node : roots) + if (!node.getData().equals("Exit")) + pdg.addControlDependencyArc(pdg.getRootNode(), nodeMap.get(node)); } - @Override - public void visit(IfStmt ifStmt, GraphNode parent) { - GraphNode node = addNodeAndControlDependency(ifStmt, parent); - - ifStmt.getThenStmt().accept(this, node); - - ifStmt.getElseStmt().ifPresent(statement -> statement.accept(this, node)); + public void registerNode(GraphNode node, Map, GraphNode> nodeMap) { + if (nodeMap.containsKey(node) || node.getData().equals("Exit")) + return; + GraphNode clone = new GraphNode<>(node.getId(), node.getData(), node.getAstNode()); + nodeMap.put(node, clone); + pdg.addNode(clone); } - @Override - public void visit(WhileStmt whileStmt, GraphNode parent) { - GraphNode node = addNodeAndControlDependency(whileStmt, parent); - - whileStmt.getBody().accept(this, node); + public static boolean hasControlDependence(GraphNode a, GraphNode b) { + int yes = 0; + List> list = a.getOutgoingArcs(); + // Nodes with less than 1 outgoing arc cannot control another node. + if (list.size() < 2) + return false; + for (Arc arc : list) { + GraphNode successor = arc.getToNode(); + if (postdominates(successor, b)) + yes++; + } + int no = list.size() - yes; + return yes > 0 && no > 0; } - @Override - public void visit(ForStmt forStmt, GraphNode parent) { - String initialization = forStmt.getInitialization().stream() - .map(com.github.javaparser.ast.Node::toString) - .collect(Collectors.joining(",")); - - String update = forStmt.getUpdate().stream() - .map(com.github.javaparser.ast.Node::toString) - .collect(Collectors.joining(",")); - - String compare = forStmt.getCompare() - .map(com.github.javaparser.ast.Node::toString) - .orElse("true"); - - - GraphNode forNode = pdgGraph.addNode( - String.format("for (%s;%s;%s)", initialization, compare, update), - forStmt - ); - - pdgGraph.addControlDependencyArc(parent, forNode); - - forStmt.getBody().accept(this, forNode); + public static boolean postdominates(GraphNode a, GraphNode b) { + return postdominates(a, b, new HashSet<>()); } - @Override - public void visit(ForEachStmt forEachStmt, GraphNode parent) { - GraphNode node = addNodeAndControlDependency(forEachStmt, parent); - - forEachStmt.getBody().accept(this, node); - } - - @Override - public void visit(SwitchStmt switchStmt, GraphNode parent) { - GraphNode node = addNodeAndControlDependency(switchStmt, parent); - - switchStmt.getEntries().accept(this, node); - } - - @Override - public void visit(SwitchEntryStmt switchEntryStmt, GraphNode parent) { - GraphNode node = addNodeAndControlDependency(switchEntryStmt, parent); - - switchEntryStmt.getStatements().accept(this, node); - } - - private GraphNode addNodeAndControlDependency(Statement statement, GraphNode parent) { - GraphNode cfgNode = cfgGraph.findNodeByASTNode(statement).get(); - - GraphNode node = pdgGraph.addNode(cfgNode.getData(), cfgNode.getAstNode()); - pdgGraph.addControlDependencyArc(parent, node); - - return node; + private static boolean postdominates(GraphNode a, GraphNode b, Set> visited) { + // Stop w/ success if a == b or a has already been visited + if (a.equals(b) || visited.contains(a)) + return true; + List> outgoing = a.getOutgoingArcs(); + // Stop w/ failure if there are no edges to traverse from a + if (outgoing.size() == 0) + return false; + // Find all possible paths starting from a, if ALL find b, then true, else false + visited.add(a); + for (Arc out : outgoing) { + if (!postdominates(out.getToNode(), b, visited)) + return false; + } + return true; } } diff --git a/src/main/java/tfm/visitors/pdg/PDGBuilder.java b/src/main/java/tfm/visitors/pdg/PDGBuilder.java index cd5553f..17096a3 100644 --- a/src/main/java/tfm/visitors/pdg/PDGBuilder.java +++ b/src/main/java/tfm/visitors/pdg/PDGBuilder.java @@ -14,15 +14,15 @@ import tfm.visitors.cfg.CFGBuilder; *
    * Usage: *
      - *
    1. Create and fill a {@link CFGGraph} for the desired method.
    2. + *
    3. Create an empty {@link CFGGraph}.
    4. *
    5. Create an empty {@link PDGGraph} (optionally passing the {@link CFGGraph} as argument).
    6. *
    7. Create a new {@link PDGBuilder}, passing both graphs as arguments.
    8. *
    9. Accept the builder as a visitor of the {@link MethodDeclaration} you want to analyse using * {@link com.github.javaparser.ast.Node#accept(com.github.javaparser.ast.visitor.VoidVisitor, Object) Node#accept(VoidVisitor, Object)}: * {@code methodDecl.accept(builder, null)}
    10. *
    11. Once the previous step is finished, the complete PDG is saved in - * the object created in the second step. The builder should be discarded - * and not reused.
    12. + * the object created in the second step. The builder should be discarded + * and not reused. *
    */ public class PDGBuilder extends VoidVisitorAdapter> { @@ -60,7 +60,7 @@ public class PDGBuilder extends VoidVisitorAdapter> { // Build control dependency ControlDependencyBuilder controlDependencyBuilder = new ControlDependencyBuilder(pdgGraph, cfgGraph); - methodBody.accept(controlDependencyBuilder, parent); + controlDependencyBuilder.analyze(); // Build data dependency DataDependencyBuilder dataDependencyBuilder = new DataDependencyBuilder(pdgGraph, cfgGraph); -- GitLab From f02c008837fb96312c202f7ba4b559e5ee8515b6 Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Fri, 10 Jan 2020 18:54:15 +0100 Subject: [PATCH 05/27] Support for the PPDG (building only) --- src/main/java/tfm/exec/Config.java | 18 +++++++++++------- src/main/java/tfm/graphs/PDGGraph.java | 7 ------- .../visitors/pdg/ControlDependencyBuilder.java | 7 ++++++- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/main/java/tfm/exec/Config.java b/src/main/java/tfm/exec/Config.java index fc54dd7..a2bc411 100644 --- a/src/main/java/tfm/exec/Config.java +++ b/src/main/java/tfm/exec/Config.java @@ -5,20 +5,24 @@ package tfm.exec; *
    * The Control Flow Graph has different variations, each with its own name or code. *
      - *
    • CFG
    • : the original proposal. It works well with statements, loops and branch instructions. - *
    • ACFG
    • : the augmented CFG; adds non-executable edges to represent unconditional - * jumps such as {@code break}, {@code return}, {@code switch} and much more. + *
    • CFG: the original proposal. It works well with statements, loops and branch instructions.
    • + *
    • ACFG: the augmented CFG; adds non-executable edges to represent unconditional + * jumps such as {@code break}, {@code return}, {@code switch} and much more.
    • *
    * The Program Dependence Graph has variations in a similar fashion. *
      - *
    • PDG
    • : based on the CFG, it computes control and data dependence to connect the nodes. - *
    • APDG
    • : similar to the PDG, but based on the ACFG. The non-executable edges are ignored - * when computing data dependencies. + *
    • PDG: based on the CFG, it computes control and data dependence to connect the nodes.
    • + *
    • APDG: similar to the PDG, but based on the ACFG. The non-executable edges are ignored + * when computing data dependencies.
    • + *
    • PPDG: combines the PDG and the APDG; (1) when computing control dependencies it uses the ACFG + * to find a node's successors, but the CFG for computing the postdominance, and (2) modifies the traversal + * of the graph, disallowing the traversal of edges that reach a pseudo-predicate (those that are the source + * of non-executable edges) if the pseudo-predicate is not the slicing criterion.
    • *
    */ public class Config { public static final int CFG = 0, ACFG = 1; - public static final int PDG = 0, APDG = 1; + public static final int PDG = 0, APDG = 1, PPDG = 2; public static int CFG_TYPE = CFG; public static int PDG_TYPE = PDG; diff --git a/src/main/java/tfm/graphs/PDGGraph.java b/src/main/java/tfm/graphs/PDGGraph.java index 705f962..76ec210 100644 --- a/src/main/java/tfm/graphs/PDGGraph.java +++ b/src/main/java/tfm/graphs/PDGGraph.java @@ -46,13 +46,6 @@ public class PDGGraph extends Graph { return "Entry"; } - public GraphNode addNode(GraphNode node) { - GraphNode vertex = new GraphNode<>(node); - super.addVertex(vertex); - - return vertex; - } - @Override public GraphNode addNode(String instruction, ASTNode node) { return addNode(getNextVertexId(), instruction, node); diff --git a/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java b/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java index 96f91ff..682e951 100644 --- a/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java +++ b/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java @@ -2,11 +2,13 @@ package tfm.visitors.pdg; import tfm.arcs.Arc; import tfm.arcs.data.ArcData; +import tfm.exec.Config; import tfm.graphs.CFGGraph; import tfm.graphs.PDGGraph; import tfm.nodes.GraphNode; import java.util.*; +import java.util.stream.Collectors; /** * A simple but slow finder of control dependencies. @@ -65,7 +67,7 @@ public class ControlDependencyBuilder { return; GraphNode clone = new GraphNode<>(node.getId(), node.getData(), node.getAstNode()); nodeMap.put(node, clone); - pdg.addNode(clone); + pdg.addVertex(clone); } public static boolean hasControlDependence(GraphNode a, GraphNode b) { @@ -92,6 +94,9 @@ public class ControlDependencyBuilder { if (a.equals(b) || visited.contains(a)) return true; List> outgoing = a.getOutgoingArcs(); + // Limit the traversal if it is a PPDG + if (Config.PDG_TYPE == Config.PPDG) + outgoing = outgoing.stream().filter(Arc::isExecutableControlFlowArrow).collect(Collectors.toList()); // Stop w/ failure if there are no edges to traverse from a if (outgoing.size() == 0) return false; -- GitLab From f7f50af259629979ead7a5a2a0bf59504f70e2b2 Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Mon, 13 Jan 2020 19:36:01 +0100 Subject: [PATCH 06/27] Slicing for all PDG variants. API changed from returning a graph to returning a set of `GraphNode#id`s. --- src/main/java/tfm/graphs/Graph.java | 2 +- src/main/java/tfm/graphs/PDGGraph.java | 42 ++++--------------- src/main/java/tfm/graphs/SDGGraph.java | 4 +- .../java/tfm/slicing/GraphNodeCriterion.java | 32 ++++++++++++++ src/main/java/tfm/slicing/Slice.java | 17 ++++---- src/main/java/tfm/utils/ASTUtils.java | 10 +++++ 6 files changed, 63 insertions(+), 44 deletions(-) create mode 100644 src/main/java/tfm/slicing/GraphNodeCriterion.java diff --git a/src/main/java/tfm/graphs/Graph.java b/src/main/java/tfm/graphs/Graph.java index 5ab503d..c39e583 100644 --- a/src/main/java/tfm/graphs/Graph.java +++ b/src/main/java/tfm/graphs/Graph.java @@ -133,7 +133,7 @@ public abstract class Graph extends edg.graphlib.Graph { .anyMatch(node -> Objects.equals(node, graphNode)); } - public abstract Graph slice(SlicingCriterion slicingCriterion); + public abstract Set slice(SlicingCriterion slicingCriterion); /** * Deprecated for incorrect behaviour. Use removeNode instead diff --git a/src/main/java/tfm/graphs/PDGGraph.java b/src/main/java/tfm/graphs/PDGGraph.java index 76ec210..a651064 100644 --- a/src/main/java/tfm/graphs/PDGGraph.java +++ b/src/main/java/tfm/graphs/PDGGraph.java @@ -11,9 +11,7 @@ import tfm.arcs.pdg.DataDependencyArc; import tfm.nodes.GraphNode; import tfm.slicing.SlicingCriterion; import tfm.utils.ASTUtils; -import tfm.utils.Logger; import tfm.utils.NodeNotFoundException; -import tfm.visitors.pdg.PDGBuilder; import java.util.Comparator; import java.util.HashSet; @@ -172,39 +170,19 @@ public class PDGGraph extends Graph { } @Override - public PDGGraph slice(SlicingCriterion slicingCriterion) { - Optional> optionalGraphNode = slicingCriterion.findNode(this); - - if (!optionalGraphNode.isPresent()) { + public Set slice(SlicingCriterion slicingCriterion) { + Optional> node = slicingCriterion.findNode(this); + if (!node.isPresent()) throw new NodeNotFoundException(slicingCriterion); - } - - GraphNode node = optionalGraphNode.get(); - - // Simply get slice nodes from GraphNode - Set sliceNodes = getSliceNodes(new HashSet<>(), node); - - PDGGraph sliceGraph = new PDGGraph(); - - Node astCopy = ASTUtils.cloneAST(node.getAstNode()); - - astCopy.accept(new PDGBuilder(sliceGraph), sliceGraph.getRootNode()); - - for (GraphNode sliceNode : sliceGraph.getNodes()) { - if (!sliceNodes.contains(sliceNode.getId())) { - Logger.log("Removing node " + sliceNode.getId()); - sliceNode.getAstNode().removeForced(); - sliceGraph.removeNode(sliceNode); - } - } - - return sliceGraph; + Set visited = new HashSet<>(); + getSliceNodes(visited, node.get()); + return visited; } - private Set getSliceNodes(Set visited, GraphNode root) { - visited.add(root.getId()); + protected void getSliceNodes(Set visited, GraphNode node) { + visited.add(node.getId()); - for (Arc arc : root.getIncomingArcs()) { + for (Arc arc : node.getIncomingArcs()) { GraphNode from = arc.getFromNode(); if (visited.contains(from.getId())) @@ -212,8 +190,6 @@ public class PDGGraph extends Graph { getSliceNodes(visited, from); } - - return visited; } public CFGGraph getCfgGraph() { diff --git a/src/main/java/tfm/graphs/SDGGraph.java b/src/main/java/tfm/graphs/SDGGraph.java index ec4692b..1c511a8 100644 --- a/src/main/java/tfm/graphs/SDGGraph.java +++ b/src/main/java/tfm/graphs/SDGGraph.java @@ -34,8 +34,8 @@ public class SDGGraph extends Graph { } @Override - public Graph slice(SlicingCriterion slicingCriterion) { - return this; + public Set slice(SlicingCriterion slicingCriterion) { + throw new RuntimeException("Slicing not implemented for the SDG"); } public Map getContextPDGGraphMap() { diff --git a/src/main/java/tfm/slicing/GraphNodeCriterion.java b/src/main/java/tfm/slicing/GraphNodeCriterion.java new file mode 100644 index 0000000..9b65d98 --- /dev/null +++ b/src/main/java/tfm/slicing/GraphNodeCriterion.java @@ -0,0 +1,32 @@ +package tfm.slicing; + +import tfm.graphs.CFGGraph; +import tfm.graphs.PDGGraph; +import tfm.graphs.SDGGraph; +import tfm.nodes.GraphNode; + +import java.util.Optional; + +public class GraphNodeCriterion extends SlicingCriterion { + private final GraphNode node; + + public GraphNodeCriterion(GraphNode node, String variable) { + super(variable); + this.node = node; + } + + @Override + public Optional> findNode(CFGGraph graph) { + return graph.findNodeById(node.getId()); + } + + @Override + public Optional> findNode(PDGGraph graph) { + return graph.findNodeById(node.getId()); + } + + @Override + public Optional> findNode(SDGGraph graph) { + return graph.findNodeById(node.getId()); + } +} diff --git a/src/main/java/tfm/slicing/Slice.java b/src/main/java/tfm/slicing/Slice.java index dca9284..fdfaa94 100644 --- a/src/main/java/tfm/slicing/Slice.java +++ b/src/main/java/tfm/slicing/Slice.java @@ -11,6 +11,7 @@ import tfm.visitors.pdg.PDGBuilder; import java.io.File; import java.io.IOException; +import java.util.Set; public class Slice { @@ -28,13 +29,13 @@ public class Slice { Logger.log("= Starting slice ="); Logger.log("=================="); - PDGGraph sliced = pdgGraph.slice(new LineNumberCriterion(18, "x")); - - PDGLog pdgLog = new PDGLog(sliced); - pdgLog.log(); - pdgLog.generateImages(PROGRAM_NAME + "-sliced"); - pdgLog.openVisualRepresentation(); - - PDGValidator.printPDGProgram("Slice" + PROGRAM_NAME, sliced); +// PDGGraph sliced = pdgGraph.slice(new LineNumberCriterion(18, "x")); +// +// PDGLog pdgLog = new PDGLog(sliced); +// pdgLog.log(); +// pdgLog.generateImages(PROGRAM_NAME + "-sliced"); +// pdgLog.openVisualRepresentation(); +// +// PDGValidator.printPDGProgram("Slice" + PROGRAM_NAME, sliced); } } diff --git a/src/main/java/tfm/utils/ASTUtils.java b/src/main/java/tfm/utils/ASTUtils.java index 788e34e..1c11647 100644 --- a/src/main/java/tfm/utils/ASTUtils.java +++ b/src/main/java/tfm/utils/ASTUtils.java @@ -68,4 +68,14 @@ public class ASTUtils { return entry; return null; } + + public static boolean isPseudoPredicate(Node node) { + return node instanceof BreakStmt + || node instanceof ContinueStmt + || node instanceof ReturnStmt + || node instanceof ThrowStmt + || node instanceof SwitchEntryStmt + || node instanceof TryStmt + || node instanceof CatchClause; + } } -- GitLab From a815ec9fa1b6c1915c38c675b75843af14af3a04 Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Mon, 13 Jan 2020 19:56:40 +0100 Subject: [PATCH 07/27] Replace Config by graph-specific classes Renamed graphs to remove redundant `Graph` at end of class names. --- readme.md | 4 +- .../java/tfm/arcs/cfg/ControlFlowArc.java | 4 +- .../tfm/arcs/pdg/ControlDependencyArc.java | 2 +- .../java/tfm/arcs/pdg/DataDependencyArc.java | 2 +- src/main/java/tfm/exec/CFGLog.java | 15 ++-- src/main/java/tfm/exec/Config.java | 29 -------- src/main/java/tfm/exec/Main.java | 2 +- src/main/java/tfm/exec/PDGLog.java | 35 ++++++--- src/main/java/tfm/exec/SDGLog.java | 8 +-- .../java/tfm/graphbuilding/GraphOptions.java | 30 ++++---- src/main/java/tfm/graphbuilding/Graphs.java | 12 ++-- .../tfm/graphs/{CFGGraph.java => CFG.java} | 18 +++-- .../tfm/graphs/{PDGGraph.java => PDG.java} | 71 ++++++++++++++++--- .../tfm/graphs/{SDGGraph.java => SDG.java} | 18 ++--- src/main/java/tfm/nodes/GraphNode.java | 4 +- src/main/java/tfm/readme.md | 4 +- .../java/tfm/slicing/GraphNodeCriterion.java | 12 ++-- .../java/tfm/slicing/LineNumberCriterion.java | 12 ++-- src/main/java/tfm/slicing/Slice.java | 9 +-- .../java/tfm/slicing/SlicingCriterion.java | 12 ++-- .../java/tfm/validation/PDGValidator.java | 10 +-- .../java/tfm/visitors/cfg/CFGBuilder.java | 28 ++++---- .../pdg/ControlDependencyBuilder.java | 22 +++--- .../visitors/pdg/DataDependencyBuilder.java | 30 ++++---- .../java/tfm/visitors/pdg/PDGBuilder.java | 34 ++++----- .../tfm/visitors/sdg/MethodCallReplacer.java | 13 ++-- .../sdg/MethodCallReplacerVisitor.java | 10 +-- .../java/tfm/visitors/sdg/NewSDGBuilder.java | 17 +++-- .../java/tfm/visitors/sdg/SDGBuilder.java | 34 ++++----- 29 files changed, 266 insertions(+), 235 deletions(-) delete mode 100644 src/main/java/tfm/exec/Config.java rename src/main/java/tfm/graphs/{CFGGraph.java => CFG.java} (87%) rename src/main/java/tfm/graphs/{PDGGraph.java => PDG.java} (80%) rename src/main/java/tfm/graphs/{SDGGraph.java => SDG.java} (86%) diff --git a/readme.md b/readme.md index 5ef10f6..9fd78a3 100644 --- a/readme.md +++ b/readme.md @@ -131,9 +131,9 @@ public PDGGraph getSlice(File program, SlicingCriterion slicingCriterion) { Node astRoot = JavaParser.parse(programFile); - PDGGraph pdgGraph = Graphs.PDG.fromASTNode(astRoot); + PDGGraph pdg = Graphs.PDG.fromASTNode(astRoot); - return pdgGraph.slice(slicingCriterion); + return pdg.slice(slicingCriterion); } ``` diff --git a/src/main/java/tfm/arcs/cfg/ControlFlowArc.java b/src/main/java/tfm/arcs/cfg/ControlFlowArc.java index 74ca504..34f7dbc 100644 --- a/src/main/java/tfm/arcs/cfg/ControlFlowArc.java +++ b/src/main/java/tfm/arcs/cfg/ControlFlowArc.java @@ -5,7 +5,7 @@ import tfm.arcs.data.VoidArcData; import tfm.nodes.GraphNode; /** - * An edge of the {@link tfm.graphs.CFGGraph}, representing the direct + * An edge of the {@link tfm.graphs.CFG}, representing the direct * flow of control. It connects two instructions if, when the source * is executed, one of the possible next instructions is the destination. */ @@ -44,7 +44,7 @@ public class ControlFlowArc extends Arc { } /** - * Represents a non-executable control flow arc, used within the {@link tfm.exec.Config#ACFG}. + * Represents a non-executable control flow arc, used within the {@link tfm.graphs.CFG.ACFG ACFG}. * Initially it had the following meaning: connecting a statement with * the following one as if the source was a {@code nop} command (no operation). *
    diff --git a/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java b/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java index e2b82e5..7633f64 100644 --- a/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java +++ b/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java @@ -5,7 +5,7 @@ import tfm.arcs.data.ArcData; import tfm.nodes.GraphNode; /** - * An arc used in the {@link tfm.graphs.PDGGraph} and {@link tfm.graphs.SDGGraph} + * An arc used in the {@link tfm.graphs.PDG} and {@link tfm.graphs.SDG} * used to represent control dependence between two nodes. The traditional definition of * control dependence is: a node {@code a} is control dependent on node * {@code b} if and only if {@code b} alters the number of times {@code a} is executed. diff --git a/src/main/java/tfm/arcs/pdg/DataDependencyArc.java b/src/main/java/tfm/arcs/pdg/DataDependencyArc.java index 95a3e2e..31519b7 100644 --- a/src/main/java/tfm/arcs/pdg/DataDependencyArc.java +++ b/src/main/java/tfm/arcs/pdg/DataDependencyArc.java @@ -9,7 +9,7 @@ import java.util.Arrays; import java.util.List; /** - * An arc used in the {@link tfm.graphs.PDGGraph} and {@link tfm.graphs.SDGGraph}, + * An arc used in the {@link tfm.graphs.PDG} and {@link tfm.graphs.SDG}, * representing the declaration of some data linked to its usage (of that value). * There is data dependency between two nodes if and only if (1) the source may * declare a variable, (2) the destination may use it, and (3) there is a diff --git a/src/main/java/tfm/exec/CFGLog.java b/src/main/java/tfm/exec/CFGLog.java index ebd6b2f..153728a 100644 --- a/src/main/java/tfm/exec/CFGLog.java +++ b/src/main/java/tfm/exec/CFGLog.java @@ -1,29 +1,22 @@ package tfm.exec; import com.github.javaparser.ast.Node; -import guru.nidi.graphviz.engine.Format; -import guru.nidi.graphviz.engine.Graphviz; -import tfm.graphs.CFGGraph; -import tfm.utils.FileUtil; +import tfm.graphs.CFG; import tfm.visitors.cfg.CFGBuilder; -import java.io.File; -import java.io.IOException; -import java.util.Arrays; - -public class CFGLog extends GraphLog { +public class CFGLog extends GraphLog { public CFGLog() { super(); } - public CFGLog(CFGGraph graph) { + public CFGLog(CFG graph) { super(graph); } @Override public void visit(Node node) { - this.graph = new CFGGraph(); + this.graph = new CFG(); node.accept(new CFGBuilder(graph), null); } } diff --git a/src/main/java/tfm/exec/Config.java b/src/main/java/tfm/exec/Config.java deleted file mode 100644 index a2bc411..0000000 --- a/src/main/java/tfm/exec/Config.java +++ /dev/null @@ -1,29 +0,0 @@ -package tfm.exec; - -/** - * Configuration for the different graphs created in the process of program slicing. - *
    - * The Control Flow Graph has different variations, each with its own name or code. - *
      - *
    • CFG: the original proposal. It works well with statements, loops and branch instructions.
    • - *
    • ACFG: the augmented CFG; adds non-executable edges to represent unconditional - * jumps such as {@code break}, {@code return}, {@code switch} and much more.
    • - *
    - * The Program Dependence Graph has variations in a similar fashion. - *
      - *
    • PDG: based on the CFG, it computes control and data dependence to connect the nodes.
    • - *
    • APDG: similar to the PDG, but based on the ACFG. The non-executable edges are ignored - * when computing data dependencies.
    • - *
    • PPDG: combines the PDG and the APDG; (1) when computing control dependencies it uses the ACFG - * to find a node's successors, but the CFG for computing the postdominance, and (2) modifies the traversal - * of the graph, disallowing the traversal of edges that reach a pseudo-predicate (those that are the source - * of non-executable edges) if the pseudo-predicate is not the slicing criterion.
    • - *
    - */ -public class Config { - public static final int CFG = 0, ACFG = 1; - public static final int PDG = 0, APDG = 1, PPDG = 2; - - public static int CFG_TYPE = CFG; - public static int PDG_TYPE = PDG; -} diff --git a/src/main/java/tfm/exec/Main.java b/src/main/java/tfm/exec/Main.java index 9532105..43556db 100644 --- a/src/main/java/tfm/exec/Main.java +++ b/src/main/java/tfm/exec/Main.java @@ -60,7 +60,7 @@ public class Main { graphLog = new CFGLog(); break; case GraphLog.PDG: - graphLog = new PDGLog(); + graphLog = new PDGLog(PDGLog.PDG); break; case GraphLog.SDG: graphLog = new SDGLog(); diff --git a/src/main/java/tfm/exec/PDGLog.java b/src/main/java/tfm/exec/PDGLog.java index a3efaec..e149dc7 100644 --- a/src/main/java/tfm/exec/PDGLog.java +++ b/src/main/java/tfm/exec/PDGLog.java @@ -1,7 +1,9 @@ package tfm.exec; import guru.nidi.graphviz.engine.Format; -import tfm.graphs.PDGGraph; +import tfm.graphs.PDG; +import tfm.graphs.PDG.APDG; +import tfm.graphs.PDG.PPDG; import tfm.nodes.GraphNode; import tfm.utils.Logger; import tfm.visitors.pdg.PDGBuilder; @@ -10,30 +12,45 @@ import java.io.IOException; import java.util.Comparator; import java.util.stream.Collectors; -public class PDGLog extends GraphLog { +public class PDGLog extends GraphLog { + public static final int PDG = 0, APDG = 1, PPDG = 2; private CFGLog cfgLog; + private int type; - public PDGLog() { + public PDGLog(int type) { this(null); + this.type = type; } - public PDGLog(PDGGraph pdgGraph) { - super(pdgGraph); + public PDGLog(PDG pdg) { + super(pdg); - if (graph != null && graph.getCfgGraph() != null) - cfgLog = new CFGLog(graph.getCfgGraph()); + if (graph != null && graph.getCfg() != null) + cfgLog = new CFGLog(graph.getCfg()); else cfgLog = null; } @Override public void visit(com.github.javaparser.ast.Node node) { - this.graph = new PDGGraph(); + switch (type) { + case PDG: + this.graph = new PDG(); + break; + case APDG: + this.graph = new APDG(); + break; + case PPDG: + this.graph = new PPDG(); + break; + default: + throw new RuntimeException("Invalid type of PDG"); + } node.accept(new PDGBuilder(graph), this.graph.getRootNode()); if (cfgLog == null) { - cfgLog = new CFGLog(graph.getCfgGraph()); + cfgLog = new CFGLog(graph.getCfg()); } } diff --git a/src/main/java/tfm/exec/SDGLog.java b/src/main/java/tfm/exec/SDGLog.java index b88de54..702e7c9 100644 --- a/src/main/java/tfm/exec/SDGLog.java +++ b/src/main/java/tfm/exec/SDGLog.java @@ -1,16 +1,14 @@ package tfm.exec; import com.github.javaparser.ast.Node; -import tfm.graphs.SDGGraph; +import tfm.graphs.SDG; import tfm.visitors.sdg.SDGBuilder; -import java.io.IOException; - -public class SDGLog extends GraphLog { +public class SDGLog extends GraphLog { @Override public void visit(Node node) { - this.graph = new SDGGraph(); + this.graph = new SDG(); SDGBuilder sdgBuilder = new SDGBuilder(this.graph); node.accept(sdgBuilder, null); } diff --git a/src/main/java/tfm/graphbuilding/GraphOptions.java b/src/main/java/tfm/graphbuilding/GraphOptions.java index 2884f49..1293606 100644 --- a/src/main/java/tfm/graphbuilding/GraphOptions.java +++ b/src/main/java/tfm/graphbuilding/GraphOptions.java @@ -1,10 +1,10 @@ package tfm.graphbuilding; import com.github.javaparser.ast.Node; -import tfm.graphs.CFGGraph; +import tfm.graphs.CFG; import tfm.graphs.Graph; -import tfm.graphs.PDGGraph; -import tfm.graphs.SDGGraph; +import tfm.graphs.PDG; +import tfm.graphs.SDG; import tfm.visitors.cfg.CFGBuilder; import tfm.visitors.pdg.PDGBuilder; import tfm.visitors.sdg.SDGBuilder; @@ -23,41 +23,41 @@ public abstract class GraphOptions { protected abstract void buildGraphWithSpecificVisitor(G emptyGraph, Node node); } -class CFGOptions extends GraphOptions { +class CFGOptions extends GraphOptions { @Override - public CFGGraph empty() { - return new CFGGraph(); + public CFG empty() { + return new CFG(); } @Override - protected void buildGraphWithSpecificVisitor(CFGGraph emptyGraph, Node node) { + protected void buildGraphWithSpecificVisitor(CFG emptyGraph, Node node) { node.accept(new CFGBuilder(emptyGraph), null); } } -class PDGOptions extends GraphOptions { +class PDGOptions extends GraphOptions { @Override - public PDGGraph empty() { - return new PDGGraph(); + public PDG empty() { + return new PDG(); } @Override - protected void buildGraphWithSpecificVisitor(PDGGraph emptyGraph, Node node) { + protected void buildGraphWithSpecificVisitor(PDG emptyGraph, Node node) { node.accept(new PDGBuilder(emptyGraph), emptyGraph.getRootNode()); } } -class SDGOptions extends GraphOptions { +class SDGOptions extends GraphOptions { @Override - public SDGGraph empty() { - return new SDGGraph(); + public SDG empty() { + return new SDG(); } @Override - protected void buildGraphWithSpecificVisitor(SDGGraph emptyGraph, Node node) { + protected void buildGraphWithSpecificVisitor(SDG emptyGraph, Node node) { node.accept(new SDGBuilder(emptyGraph), null); } } \ No newline at end of file diff --git a/src/main/java/tfm/graphbuilding/Graphs.java b/src/main/java/tfm/graphbuilding/Graphs.java index 235124c..548bfcd 100644 --- a/src/main/java/tfm/graphbuilding/Graphs.java +++ b/src/main/java/tfm/graphbuilding/Graphs.java @@ -1,13 +1,13 @@ package tfm.graphbuilding; -import tfm.graphs.CFGGraph; -import tfm.graphs.PDGGraph; -import tfm.graphs.SDGGraph; +import tfm.graphs.CFG; +import tfm.graphs.PDG; +import tfm.graphs.SDG; public class Graphs { - public static final GraphOptions CFG = new CFGOptions(); - public static final GraphOptions PDG = new PDGOptions(); - public static final GraphOptions SDG = new SDGOptions(); + public static final GraphOptions CFG = new CFGOptions(); + public static final GraphOptions PDG = new PDGOptions(); + public static final GraphOptions SDG = new SDGOptions(); } \ No newline at end of file diff --git a/src/main/java/tfm/graphs/CFGGraph.java b/src/main/java/tfm/graphs/CFG.java similarity index 87% rename from src/main/java/tfm/graphs/CFGGraph.java rename to src/main/java/tfm/graphs/CFG.java index 0af2cda..1eb6f3c 100644 --- a/src/main/java/tfm/graphs/CFGGraph.java +++ b/src/main/java/tfm/graphs/CFG.java @@ -19,12 +19,12 @@ import java.util.stream.Collectors; * The Control Flow Graph represents the statements of a method in * a graph, displaying the connections between each statement and the ones that * may follow it. You can build one manually or use the {@link tfm.visitors.cfg.CFGBuilder CFGBuilder}. + * The variations of the CFG are implemented as child classes. * @see ControlFlowArc - * @see tfm.exec.Config Config (for the available variations of the CFG) */ -public class CFGGraph extends Graph { +public class CFG extends Graph { - public CFGGraph() { + public CFG() { super(); setRootVertex(new GraphNode<>(getNextVertexId(), getRootNodeData(), new EmptyStmt())); } @@ -47,7 +47,7 @@ public class CFGGraph extends Graph { } @SuppressWarnings("unchecked") - public void addControlFlowEdge(GraphNode from, GraphNode to, boolean executable) { + protected void addControlFlowEdge(GraphNode from, GraphNode to, boolean executable) { if (executable) super.addEdge((Arrow) new ControlFlowArc(from, to)); else @@ -76,8 +76,8 @@ public class CFGGraph extends Graph { } @Override - public Graph slice(SlicingCriterion slicingCriterion) { - return this; + public Set slice(SlicingCriterion slicingCriterion) { + throw new RuntimeException("Can't slice a CFG!"); } public Set> findLastDefinitionsFrom(GraphNode startNode, String variable) { @@ -113,4 +113,10 @@ public class CFGGraph extends Graph { return res; } + + public static class ACFG extends CFG { + public void addNonExecutableControlFlowEdge(GraphNode from, GraphNode to) { + addControlFlowEdge(from, to, false); + } + } } diff --git a/src/main/java/tfm/graphs/PDGGraph.java b/src/main/java/tfm/graphs/PDG.java similarity index 80% rename from src/main/java/tfm/graphs/PDGGraph.java rename to src/main/java/tfm/graphs/PDG.java index a651064..7f927a8 100644 --- a/src/main/java/tfm/graphs/PDGGraph.java +++ b/src/main/java/tfm/graphs/PDG.java @@ -8,6 +8,7 @@ import tfm.arcs.Arc; import tfm.arcs.data.ArcData; import tfm.arcs.pdg.ControlDependencyArc; import tfm.arcs.pdg.DataDependencyArc; +import tfm.graphs.CFG.ACFG; import tfm.nodes.GraphNode; import tfm.slicing.SlicingCriterion; import tfm.utils.ASTUtils; @@ -24,20 +25,20 @@ import java.util.stream.Collectors; * a graph, connecting statements according to their {@link ControlDependencyArc control} * and {@link DataDependencyArc data} relationships. You can build one manually or use * the {@link tfm.visitors.pdg.PDGBuilder PDGBuilder}. - * @see tfm.exec.Config Config (for the available variations of the PDG) + * The variations of the PDG are represented as child types. */ -public class PDGGraph extends Graph { +public class PDG extends Graph { public static boolean isRanked = false, isSorted = false; - private CFGGraph cfgGraph; + private CFG cfg; - public PDGGraph() { + public PDG() { setRootVertex(new GraphNode<>(getNextVertexId(), getRootNodeData(), new MethodDeclaration())); } - public PDGGraph(CFGGraph cfgGraph) { + public PDG(CFG cfg) { this(); - this.cfgGraph = cfgGraph; + this.cfg = cfg; } protected String getRootNodeData() { @@ -110,8 +111,8 @@ public class PDGGraph extends Graph { return 1 + getLevelOf(parent); } - public void setCfgGraph(CFGGraph cfgGraph) { - this.cfgGraph = cfgGraph; + public void setCfg(CFG cfg) { + this.cfg = cfg; } @Override @@ -192,7 +193,57 @@ public class PDGGraph extends Graph { } } - public CFGGraph getCfgGraph() { - return cfgGraph; + public CFG getCfg() { + return cfg; + } + + public static class APDG extends PDG { + public APDG() { + super(); + } + + public APDG(ACFG acfg) { + super(acfg); + } + } + + public static class PPDG extends APDG { + public PPDG() { + super(); + } + + public PPDG(ACFG acfg) { + super(acfg); + } + + @Override + protected void getSliceNodes(Set visited, GraphNode node) { + visited.add(node.getId()); + + for (Arc arc : node.getIncomingArcs()) { + GraphNode from = arc.getFromNode(); + + if (visited.contains(from.getId())) + continue; + + getSliceNodesPPDG(visited, from); + } + } + + protected void getSliceNodesPPDG(Set visited, GraphNode node) { + visited.add(node.getId()); + + if (ASTUtils.isPseudoPredicate(node.getAstNode())) + return; + + for (Arc arc : node.getIncomingArcs()) { + GraphNode from = arc.getFromNode(); + + if (visited.contains(from.getId())) + continue; + + getSliceNodesPPDG(visited, from); + } + } } } diff --git a/src/main/java/tfm/graphs/SDGGraph.java b/src/main/java/tfm/graphs/SDG.java similarity index 86% rename from src/main/java/tfm/graphs/SDGGraph.java rename to src/main/java/tfm/graphs/SDG.java index 1c511a8..2b3b2c6 100644 --- a/src/main/java/tfm/graphs/SDGGraph.java +++ b/src/main/java/tfm/graphs/SDG.java @@ -11,11 +11,11 @@ import tfm.utils.Context; import java.util.*; import java.util.stream.Collectors; -public class SDGGraph extends Graph { +public class SDG extends Graph { - private Map contextPDGGraphMap; + private Map contextPDGGraphMap; - public SDGGraph() { + public SDG() { this.contextPDGGraphMap = new HashMap<>(); } @@ -30,7 +30,7 @@ public class SDGGraph extends Graph { @Override public String toGraphvizRepresentation() { return contextPDGGraphMap.values().stream() - .map(PDGGraph::toGraphvizRepresentation).collect(Collectors.joining("\n")); + .map(PDG::toGraphvizRepresentation).collect(Collectors.joining("\n")); } @Override @@ -38,7 +38,7 @@ public class SDGGraph extends Graph { throw new RuntimeException("Slicing not implemented for the SDG"); } - public Map getContextPDGGraphMap() { + public Map getContextPDGGraphMap() { return contextPDGGraphMap; } @@ -53,12 +53,12 @@ public class SDGGraph extends Graph { .collect(Collectors.toSet()); } - public Collection getPDGs() { + public Collection getPDGs() { return contextPDGGraphMap.values(); } @Deprecated - public void addPDG(PDGGraph pdgGraph, MethodDeclaration methodDeclaration) { + public void addPDG(PDG pdg, MethodDeclaration methodDeclaration) { if (this.rootVertex == null) { this.setRootVertex(new GraphNode<>(getNextVertexId(), methodDeclaration.getNameAsString(), methodDeclaration)); } @@ -73,7 +73,7 @@ public class SDGGraph extends Graph { addVertex(sdgNode); } - for (GraphNode node : pdgGraph.getNodes()) { + for (GraphNode node : pdg.getNodes()) { if (!this.verticies.contains(node)) { GraphNode sdgNode = new GraphNode<>( getNextVertexId(), @@ -91,7 +91,7 @@ public class SDGGraph extends Graph { } } - public void addMethod(MethodDeclaration methodDeclaration, PDGGraph pdgGraph) { + public void addMethod(MethodDeclaration methodDeclaration, PDG pdg) { GraphNode methodRootNode = new GraphNode<>( getNextVertexId(), "ENTER " + methodDeclaration.getDeclarationAsString(false, false, true), diff --git a/src/main/java/tfm/nodes/GraphNode.java b/src/main/java/tfm/nodes/GraphNode.java index abd1600..314260c 100644 --- a/src/main/java/tfm/nodes/GraphNode.java +++ b/src/main/java/tfm/nodes/GraphNode.java @@ -15,8 +15,8 @@ import java.util.*; import java.util.stream.Collectors; /** - * Represents a node in the various graphs ({@link tfm.graphs.CFGGraph CFG}, - * {@link tfm.graphs.PDGGraph PDG} and {@link tfm.graphs.SDGGraph SDG}), + * Represents a node in the various graphs ({@link tfm.graphs.CFG CFG}, + * {@link tfm.graphs.PDG PDG} and {@link tfm.graphs.SDG SDG}), * including its AST representation and the connections it has to other nodes * in the same graph. It can hold a string of characters that will be used * to represent it. diff --git a/src/main/java/tfm/readme.md b/src/main/java/tfm/readme.md index 5ef10f6..9fd78a3 100644 --- a/src/main/java/tfm/readme.md +++ b/src/main/java/tfm/readme.md @@ -131,9 +131,9 @@ public PDGGraph getSlice(File program, SlicingCriterion slicingCriterion) { Node astRoot = JavaParser.parse(programFile); - PDGGraph pdgGraph = Graphs.PDG.fromASTNode(astRoot); + PDGGraph pdg = Graphs.PDG.fromASTNode(astRoot); - return pdgGraph.slice(slicingCriterion); + return pdg.slice(slicingCriterion); } ``` diff --git a/src/main/java/tfm/slicing/GraphNodeCriterion.java b/src/main/java/tfm/slicing/GraphNodeCriterion.java index 9b65d98..173d215 100644 --- a/src/main/java/tfm/slicing/GraphNodeCriterion.java +++ b/src/main/java/tfm/slicing/GraphNodeCriterion.java @@ -1,8 +1,8 @@ package tfm.slicing; -import tfm.graphs.CFGGraph; -import tfm.graphs.PDGGraph; -import tfm.graphs.SDGGraph; +import tfm.graphs.CFG; +import tfm.graphs.PDG; +import tfm.graphs.SDG; import tfm.nodes.GraphNode; import java.util.Optional; @@ -16,17 +16,17 @@ public class GraphNodeCriterion extends SlicingCriterion { } @Override - public Optional> findNode(CFGGraph graph) { + public Optional> findNode(CFG graph) { return graph.findNodeById(node.getId()); } @Override - public Optional> findNode(PDGGraph graph) { + public Optional> findNode(PDG graph) { return graph.findNodeById(node.getId()); } @Override - public Optional> findNode(SDGGraph graph) { + public Optional> findNode(SDG graph) { return graph.findNodeById(node.getId()); } } diff --git a/src/main/java/tfm/slicing/LineNumberCriterion.java b/src/main/java/tfm/slicing/LineNumberCriterion.java index 2b0c246..94f5b02 100644 --- a/src/main/java/tfm/slicing/LineNumberCriterion.java +++ b/src/main/java/tfm/slicing/LineNumberCriterion.java @@ -1,9 +1,9 @@ package tfm.slicing; import com.github.javaparser.ast.Node; -import tfm.graphs.CFGGraph; -import tfm.graphs.PDGGraph; -import tfm.graphs.SDGGraph; +import tfm.graphs.CFG; +import tfm.graphs.PDG; +import tfm.graphs.SDG; import tfm.nodes.GraphNode; import tfm.utils.Logger; @@ -20,12 +20,12 @@ public class LineNumberCriterion extends SlicingCriterion { } @Override - public Optional> findNode(CFGGraph graph) { + public Optional> findNode(CFG graph) { return Optional.empty(); } @Override - public Optional> findNode(PDGGraph graph) { + public Optional> findNode(PDG graph) { // find node by line number return graph.getNodes().stream().filter(node -> { Node astNode = node.getAstNode(); @@ -43,7 +43,7 @@ public class LineNumberCriterion extends SlicingCriterion { } @Override - public Optional> findNode(SDGGraph graph) { + public Optional> findNode(SDG graph) { return Optional.empty(); } diff --git a/src/main/java/tfm/slicing/Slice.java b/src/main/java/tfm/slicing/Slice.java index fdfaa94..dccde5a 100644 --- a/src/main/java/tfm/slicing/Slice.java +++ b/src/main/java/tfm/slicing/Slice.java @@ -2,16 +2,13 @@ package tfm.slicing; import com.github.javaparser.JavaParser; import com.github.javaparser.ast.CompilationUnit; -import tfm.exec.PDGLog; -import tfm.graphs.PDGGraph; +import tfm.graphs.PDG; import tfm.utils.Logger; import tfm.utils.Utils; -import tfm.validation.PDGValidator; import tfm.visitors.pdg.PDGBuilder; import java.io.File; import java.io.IOException; -import java.util.Set; public class Slice { @@ -21,9 +18,9 @@ public class Slice { public static void main(String[] args) throws IOException { CompilationUnit compilationUnit = JavaParser.parse(new File(PROGRAM_FOLDER + PROGRAM_NAME + ".java")); - PDGGraph pdgGraph = new PDGGraph(); + PDG pdg = new PDG(); - compilationUnit.accept(new PDGBuilder(pdgGraph), pdgGraph.getRootNode()); + compilationUnit.accept(new PDGBuilder(pdg), pdg.getRootNode()); Logger.log("=================="); Logger.log("= Starting slice ="); diff --git a/src/main/java/tfm/slicing/SlicingCriterion.java b/src/main/java/tfm/slicing/SlicingCriterion.java index 2574071..b01c357 100644 --- a/src/main/java/tfm/slicing/SlicingCriterion.java +++ b/src/main/java/tfm/slicing/SlicingCriterion.java @@ -1,8 +1,8 @@ package tfm.slicing; -import tfm.graphs.CFGGraph; -import tfm.graphs.PDGGraph; -import tfm.graphs.SDGGraph; +import tfm.graphs.CFG; +import tfm.graphs.PDG; +import tfm.graphs.SDG; import tfm.nodes.GraphNode; import java.util.Optional; @@ -19,9 +19,9 @@ public abstract class SlicingCriterion { return variable; } - public abstract Optional> findNode(CFGGraph graph); - public abstract Optional> findNode(PDGGraph graph); - public abstract Optional> findNode(SDGGraph graph); + public abstract Optional> findNode(CFG graph); + public abstract Optional> findNode(PDG graph); + public abstract Optional> findNode(SDG graph); @Override public String toString() { diff --git a/src/main/java/tfm/validation/PDGValidator.java b/src/main/java/tfm/validation/PDGValidator.java index 48cb5d8..b3207ee 100644 --- a/src/main/java/tfm/validation/PDGValidator.java +++ b/src/main/java/tfm/validation/PDGValidator.java @@ -12,7 +12,7 @@ import com.github.javaparser.ast.stmt.Statement; import com.github.javaparser.ast.type.ArrayType; import com.github.javaparser.ast.type.VoidType; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import tfm.graphs.PDGGraph; +import tfm.graphs.PDG; import tfm.nodes.GraphNode; import tfm.utils.Logger; import tfm.utils.Utils; @@ -63,20 +63,20 @@ public class PDGValidator { } public static boolean generateAndCheck(MethodDeclaration methodDeclaration) { - PDGGraph graph = new PDGGraph(); + PDG graph = new PDG(); methodDeclaration.accept(new PDGBuilder(graph), graph.getRootNode()); return check(methodDeclaration, graph); } - public static boolean check(MethodDeclaration methodDeclaration, PDGGraph graph) { + public static boolean check(MethodDeclaration methodDeclaration, PDG graph) { MethodDeclaration generatedMethod = generateMethod(methodDeclaration, graph); return ProgramComparator.areEqual(methodDeclaration, generatedMethod); } - public static MethodDeclaration generateMethod(MethodDeclaration info, PDGGraph graph) { + public static MethodDeclaration generateMethod(MethodDeclaration info, PDG graph) { MethodDeclaration methodDeclaration = new MethodDeclaration(); methodDeclaration.setName(info.getNameAsString()); @@ -94,7 +94,7 @@ public class PDGValidator { return methodDeclaration; } - public static void printPDGProgram(String fileName, PDGGraph graph) throws FileNotFoundException { + public static void printPDGProgram(String fileName, PDG graph) throws FileNotFoundException { CompilationUnit generatedProgram = new CompilationUnit(); ClassOrInterfaceDeclaration clazz = generatedProgram.addClass(fileName).setPublic(true); diff --git a/src/main/java/tfm/visitors/cfg/CFGBuilder.java b/src/main/java/tfm/visitors/cfg/CFGBuilder.java index e95f9a9..206f34d 100644 --- a/src/main/java/tfm/visitors/cfg/CFGBuilder.java +++ b/src/main/java/tfm/visitors/cfg/CFGBuilder.java @@ -8,21 +8,21 @@ import com.github.javaparser.ast.expr.SimpleName; import com.github.javaparser.ast.stmt.*; import com.github.javaparser.ast.visitor.VoidVisitor; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import tfm.exec.Config; -import tfm.graphs.CFGGraph; +import tfm.graphs.CFG; +import tfm.graphs.CFG.ACFG; import tfm.nodes.GraphNode; import tfm.utils.ASTUtils; import java.util.*; /** - * Populates a {@link CFGGraph}, given one and an AST root node. + * Populates a {@link CFG}, given one and an AST root node. * For now it only accepts {@link MethodDeclaration} as roots, as it disallows * multiple methods. *
    * Usage: *
      - *
    1. Create a new {@link CFGGraph}.
    2. + *
    3. Create a new {@link CFG}.
    4. *
    5. Create a new {@link CFGBuilder}, passing the graph as argument.
    6. *
    7. Accept the builder as a visitor of the {@link MethodDeclaration} you * want to analyse using {@link Node#accept(VoidVisitor, Object)}: {@code methodDecl.accept(builder, null)}
    8. @@ -30,7 +30,8 @@ import java.util.*; * the object created in the first step. The builder should be discarded * and not reused. *
    - * Configuration: this builder can be used to generate both the CFG and ACFG (see {@link Config}). + * Configuration: this builder can be used to generate both the CFG and ACFG, + * depending on the type of the empty graph. * Before performing the visit you should set the configuration to the one you prefer. */ public class CFGBuilder extends VoidVisitorAdapter { @@ -38,7 +39,7 @@ public class CFGBuilder extends VoidVisitorAdapter { private boolean begunMethod = false; /** Stores the CFG representing the method analyzed. */ - private final CFGGraph graph; + private final CFG graph; /** Nodes that haven't yet been connected to another one. * The next node will be the destination, they are the source. */ private final List> hangingNodes = new LinkedList<>(); @@ -57,7 +58,7 @@ public class CFGBuilder extends VoidVisitorAdapter { /** Stack of lists of hanging cases on switch statements */ private final Stack>> switchEntriesStack = new Stack<>(); - public CFGBuilder(CFGGraph graph) { + public CFGBuilder(CFG graph) { this.graph = graph; } @@ -74,8 +75,9 @@ public class CFGBuilder extends VoidVisitorAdapter { private void connectTo(GraphNode node) { for (GraphNode src : hangingNodes) graph.addControlFlowEdge(src, node); + assert nonExecHangingNodes.isEmpty() || graph instanceof ACFG; for (GraphNode src : nonExecHangingNodes) - graph.addControlFlowEdge(src, node, false); + ((ACFG) graph).addNonExecutableControlFlowEdge(src, node); hangingNodes.clear(); nonExecHangingNodes.clear(); hangingNodes.add(node); @@ -250,7 +252,7 @@ public class CFGBuilder extends VoidVisitorAdapter { if (ASTUtils.switchHasDefaultCase(switchStmt)) hangingNodes.remove(cond); List> entries = switchEntriesStack.pop(); - if (Config.CFG_TYPE == Config.ACFG) { + if (graph instanceof ACFG) { GraphNode def = null; for (GraphNode entry : entries) { if (!entry.getAstNode().getLabel().isPresent()) { @@ -286,7 +288,7 @@ public class CFGBuilder extends VoidVisitorAdapter { else breakStack.peek().add(node); hangingNodes.clear(); - if (Config.CFG_TYPE == Config.ACFG) + if (graph instanceof ACFG) nonExecHangingNodes.add(node); } @@ -298,7 +300,7 @@ public class CFGBuilder extends VoidVisitorAdapter { else continueStack.peek().add(node); hangingNodes.clear(); - if (Config.CFG_TYPE == Config.ACFG) + if (graph instanceof ACFG) nonExecHangingNodes.add(node); } @@ -307,7 +309,7 @@ public class CFGBuilder extends VoidVisitorAdapter { GraphNode node = connectTo(returnStmt); returnList.add(node); hangingNodes.clear(); - if (Config.CFG_TYPE == Config.ACFG) + if (graph instanceof ACFG) nonExecHangingNodes.add(node); } @@ -320,7 +322,7 @@ public class CFGBuilder extends VoidVisitorAdapter { hangingNodes.add(graph.getRootNode()); super.visit(methodDeclaration, arg); returnList.stream().filter(node -> !hangingNodes.contains(node)).forEach(hangingNodes::add); - if (Config.CFG_TYPE == Config.ACFG) + if (graph instanceof ACFG) nonExecHangingNodes.add(graph.getRootNode()); connectTo(new EmptyStmt(), "Exit"); } diff --git a/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java b/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java index 682e951..e76924d 100644 --- a/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java +++ b/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java @@ -2,9 +2,9 @@ package tfm.visitors.pdg; import tfm.arcs.Arc; import tfm.arcs.data.ArcData; -import tfm.exec.Config; -import tfm.graphs.CFGGraph; -import tfm.graphs.PDGGraph; +import tfm.graphs.CFG; +import tfm.graphs.PDG; +import tfm.graphs.PDG.PPDG; import tfm.nodes.GraphNode; import java.util.*; @@ -23,14 +23,14 @@ import java.util.stream.Collectors; * from a to the "Exit" node. *
    * There exist better, cheaper approaches that have linear complexity w.r.t. the number of edges in the CFG. - * Usage: pass an empty {@link PDGGraph} and a filled {@link CFGGraph} and then run {@link #analyze()}. + * Usage: pass an empty {@link PDG} and a filled {@link CFG} and then run {@link #analyze()}. * This builder should only be used once, and then discarded. */ public class ControlDependencyBuilder { - private final PDGGraph pdg; - private final CFGGraph cfg; + private final PDG pdg; + private final CFG cfg; - public ControlDependencyBuilder(PDGGraph pdg, CFGGraph cfg) { + public ControlDependencyBuilder(PDG pdg, CFG cfg) { this.pdg = pdg; this.cfg = cfg; } @@ -70,7 +70,7 @@ public class ControlDependencyBuilder { pdg.addVertex(clone); } - public static boolean hasControlDependence(GraphNode a, GraphNode b) { + public boolean hasControlDependence(GraphNode a, GraphNode b) { int yes = 0; List> list = a.getOutgoingArcs(); // Nodes with less than 1 outgoing arc cannot control another node. @@ -85,17 +85,17 @@ public class ControlDependencyBuilder { return yes > 0 && no > 0; } - public static boolean postdominates(GraphNode a, GraphNode b) { + public boolean postdominates(GraphNode a, GraphNode b) { return postdominates(a, b, new HashSet<>()); } - private static boolean postdominates(GraphNode a, GraphNode b, Set> visited) { + private boolean postdominates(GraphNode a, GraphNode b, Set> visited) { // Stop w/ success if a == b or a has already been visited if (a.equals(b) || visited.contains(a)) return true; List> outgoing = a.getOutgoingArcs(); // Limit the traversal if it is a PPDG - if (Config.PDG_TYPE == Config.PPDG) + if (pdg instanceof PPDG) outgoing = outgoing.stream().filter(Arc::isExecutableControlFlowArrow).collect(Collectors.toList()); // Stop w/ failure if there are no edges to traverse from a if (outgoing.size() == 0) diff --git a/src/main/java/tfm/visitors/pdg/DataDependencyBuilder.java b/src/main/java/tfm/visitors/pdg/DataDependencyBuilder.java index d7bd5f1..786abca 100644 --- a/src/main/java/tfm/visitors/pdg/DataDependencyBuilder.java +++ b/src/main/java/tfm/visitors/pdg/DataDependencyBuilder.java @@ -2,8 +2,8 @@ package tfm.visitors.pdg; import com.github.javaparser.ast.stmt.*; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import tfm.graphs.CFGGraph; -import tfm.graphs.PDGGraph; +import tfm.graphs.CFG; +import tfm.graphs.PDG; import tfm.nodes.GraphNode; import tfm.variables.VariableExtractor; @@ -12,12 +12,12 @@ import java.util.Set; public class DataDependencyBuilder extends VoidVisitorAdapter { - private CFGGraph cfgGraph; - private PDGGraph pdgGraph; + private CFG cfg; + private PDG pdg; - public DataDependencyBuilder(PDGGraph pdgGraph, CFGGraph cfgGraph) { - this.pdgGraph = pdgGraph; - this.cfgGraph = cfgGraph; + public DataDependencyBuilder(PDG pdg, CFG cfg) { + this.pdg = pdg; + this.cfg = cfg; } @Override @@ -43,7 +43,7 @@ public class DataDependencyBuilder extends VoidVisitorAdapter { @Override public void visit(ForStmt forStmt, Void ignored) { - GraphNode forNode = pdgGraph.findNodeByASTNode(forStmt).get(); + GraphNode forNode = pdg.findNodeByASTNode(forStmt).get(); forStmt.getInitialization().stream() .map(ExpressionStmt::new) @@ -80,7 +80,7 @@ public class DataDependencyBuilder extends VoidVisitorAdapter { } private void buildDataDependency(Statement statement) { - buildDataDependency(pdgGraph.findNodeByASTNode(statement).get()); + buildDataDependency(pdg.findNodeByASTNode(statement).get()); } private void buildDataDependency(GraphNode node) { @@ -88,7 +88,7 @@ public class DataDependencyBuilder extends VoidVisitorAdapter { .setOnVariableUseListener(variable -> { node.addUsedVariable(variable); - Optional> nodeOptional = cfgGraph.findNodeByASTNode(node.getAstNode()); + Optional> nodeOptional = cfg.findNodeByASTNode(node.getAstNode()); if (!nodeOptional.isPresent()) { return; @@ -96,11 +96,11 @@ public class DataDependencyBuilder extends VoidVisitorAdapter { GraphNode cfgNode = nodeOptional.get(); - Set> lastDefinitions = cfgGraph.findLastDefinitionsFrom(cfgNode, variable); + Set> lastDefinitions = cfg.findLastDefinitionsFrom(cfgNode, variable); for (GraphNode definitionNode : lastDefinitions) { - pdgGraph.findNodeByASTNode(definitionNode.getAstNode()) - .ifPresent(pdgNode -> pdgGraph.addDataDependencyArc(pdgNode, node, variable)); + pdg.findNodeByASTNode(definitionNode.getAstNode()) + .ifPresent(pdgNode -> pdg.addDataDependencyArc(pdgNode, node, variable)); } }) .setOnVariableDefinitionListener(node::addDefinedVariable) @@ -114,13 +114,13 @@ public class DataDependencyBuilder extends VoidVisitorAdapter { .setOnVariableUseListener(variable -> { forNode.addUsedVariable(variable); - Optional> nodeOptional = cfgGraph.findNodeByASTNode(statement); + Optional> nodeOptional = cfg.findNodeByASTNode(statement); if (!nodeOptional.isPresent()) { return; } - pdgGraph.addDataDependencyArc(forNode, forNode, variable); + pdg.addDataDependencyArc(forNode, forNode, variable); }) .setOnVariableDefinitionListener(forNode::addDefinedVariable) .setOnVariableDeclarationListener(forNode::addDeclaredVariable) diff --git a/src/main/java/tfm/visitors/pdg/PDGBuilder.java b/src/main/java/tfm/visitors/pdg/PDGBuilder.java index 17096a3..3a30dde 100644 --- a/src/main/java/tfm/visitors/pdg/PDGBuilder.java +++ b/src/main/java/tfm/visitors/pdg/PDGBuilder.java @@ -3,19 +3,19 @@ package tfm.visitors.pdg; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.stmt.BlockStmt; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import tfm.graphs.CFGGraph; -import tfm.graphs.PDGGraph; +import tfm.graphs.CFG; +import tfm.graphs.PDG; import tfm.nodes.GraphNode; import tfm.visitors.cfg.CFGBuilder; /** - * Populates a {@link PDGGraph}, given a complete {@link CFGGraph}, an empty {@link PDGGraph} and an AST root node. + * Populates a {@link PDG}, given a complete {@link CFG}, an empty {@link PDG} and an AST root node. * For now it only accepts {@link MethodDeclaration} as root, as it can only receive a single CFG. *
    * Usage: *
      - *
    1. Create an empty {@link CFGGraph}.
    2. - *
    3. Create an empty {@link PDGGraph} (optionally passing the {@link CFGGraph} as argument).
    4. + *
    5. Create an empty {@link CFG}.
    6. + *
    7. Create an empty {@link PDG} (optionally passing the {@link CFG} as argument).
    8. *
    9. Create a new {@link PDGBuilder}, passing both graphs as arguments.
    10. *
    11. Accept the builder as a visitor of the {@link MethodDeclaration} you want to analyse using * {@link com.github.javaparser.ast.Node#accept(com.github.javaparser.ast.visitor.VoidVisitor, Object) Node#accept(VoidVisitor, Object)}: @@ -27,11 +27,11 @@ import tfm.visitors.cfg.CFGBuilder; */ public class PDGBuilder extends VoidVisitorAdapter> { - private PDGGraph pdgGraph; - private CFGGraph cfgGraph; + private PDG pdg; + private CFG cfg; - public PDGBuilder(PDGGraph pdgGraph) { - this(pdgGraph, new CFGGraph() { + public PDGBuilder(PDG pdg) { + this(pdg, new CFG() { @Override protected String getRootNodeData() { return "Start"; @@ -39,11 +39,11 @@ public class PDGBuilder extends VoidVisitorAdapter> { }); } - public PDGBuilder(PDGGraph pdgGraph, CFGGraph cfgGraph) { - this.pdgGraph = pdgGraph; - this.cfgGraph = cfgGraph; + public PDGBuilder(PDG pdg, CFG cfg) { + this.pdg = pdg; + this.cfg = cfg; - this.pdgGraph.setCfgGraph(cfgGraph); + this.pdg.setCfg(cfg); } public void visit(MethodDeclaration methodDeclaration, GraphNode parent) { @@ -51,19 +51,19 @@ public class PDGBuilder extends VoidVisitorAdapter> { return; // Assign the method declaration to the root node of the PDG graph - this.pdgGraph.getRootNode().setAstNode(methodDeclaration); + this.pdg.getRootNode().setAstNode(methodDeclaration); BlockStmt methodBody = methodDeclaration.getBody().get(); // build CFG - methodDeclaration.accept(new CFGBuilder(cfgGraph), null); + methodDeclaration.accept(new CFGBuilder(cfg), null); // Build control dependency - ControlDependencyBuilder controlDependencyBuilder = new ControlDependencyBuilder(pdgGraph, cfgGraph); + ControlDependencyBuilder controlDependencyBuilder = new ControlDependencyBuilder(pdg, cfg); controlDependencyBuilder.analyze(); // Build data dependency - DataDependencyBuilder dataDependencyBuilder = new DataDependencyBuilder(pdgGraph, cfgGraph); + DataDependencyBuilder dataDependencyBuilder = new DataDependencyBuilder(pdg, cfg); methodBody.accept(dataDependencyBuilder, null); } } diff --git a/src/main/java/tfm/visitors/sdg/MethodCallReplacer.java b/src/main/java/tfm/visitors/sdg/MethodCallReplacer.java index 01b853f..4613134 100644 --- a/src/main/java/tfm/visitors/sdg/MethodCallReplacer.java +++ b/src/main/java/tfm/visitors/sdg/MethodCallReplacer.java @@ -1,20 +1,17 @@ package tfm.visitors.sdg; -import com.github.javaparser.ast.body.MethodDeclaration; -import tfm.graphs.PDGGraph; -import tfm.graphs.SDGGraph; -import tfm.utils.Context; +import tfm.graphs.SDG; public class MethodCallReplacer { - private SDGGraph sdgGraph; + private SDG sdg; - public MethodCallReplacer(SDGGraph sdgGraph) { - this.sdgGraph = sdgGraph; + public MethodCallReplacer(SDG sdg) { + this.sdg = sdg; } public void replace() { - this.sdgGraph.getContextPDGGraphMap() + this.sdg.getContextPDGGraphMap() .forEach((context, pdgGraph) -> { if (!context.getCurrentMethod().isPresent()) { return; // Should NOT happen diff --git a/src/main/java/tfm/visitors/sdg/MethodCallReplacerVisitor.java b/src/main/java/tfm/visitors/sdg/MethodCallReplacerVisitor.java index eb32ef0..1eec815 100644 --- a/src/main/java/tfm/visitors/sdg/MethodCallReplacerVisitor.java +++ b/src/main/java/tfm/visitors/sdg/MethodCallReplacerVisitor.java @@ -9,7 +9,7 @@ import com.github.javaparser.ast.expr.VariableDeclarationExpr; import com.github.javaparser.ast.stmt.ExpressionStmt; import com.github.javaparser.ast.type.Type; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import tfm.graphs.PDGGraph; +import tfm.graphs.PDG; import tfm.nodes.GraphNode; import tfm.utils.Context; import tfm.utils.Logger; @@ -21,10 +21,10 @@ import java.util.stream.Collectors; public class MethodCallReplacerVisitor extends VoidVisitorAdapter { - private PDGGraph pdgGraph; + private PDG pdg; - public MethodCallReplacerVisitor(PDGGraph pdgGraph) { - this.pdgGraph = pdgGraph; + public MethodCallReplacerVisitor(PDG pdg) { + this.pdg = pdg; } @Override @@ -57,7 +57,7 @@ public class MethodCallReplacerVisitor extends VoidVisitorAdapter { if (!Objects.equals(scopeName, currentClass.getNameAsString())) { // Check if 'scopeName' is a variable - List> declarations = pdgGraph.findDeclarationsOfVariable(scopeName); + List> declarations = pdg.findDeclarationsOfVariable(scopeName); if (declarations.isEmpty()) { // It is a static method call of another class. We do nothing diff --git a/src/main/java/tfm/visitors/sdg/NewSDGBuilder.java b/src/main/java/tfm/visitors/sdg/NewSDGBuilder.java index 8938632..bf510e0 100644 --- a/src/main/java/tfm/visitors/sdg/NewSDGBuilder.java +++ b/src/main/java/tfm/visitors/sdg/NewSDGBuilder.java @@ -4,18 +4,17 @@ import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import javassist.expr.MethodCall; import tfm.graphbuilding.Graphs; -import tfm.graphs.PDGGraph; -import tfm.graphs.SDGGraph; +import tfm.graphs.PDG; +import tfm.graphs.SDG; import tfm.utils.Context; public class NewSDGBuilder extends VoidVisitorAdapter { - SDGGraph sdgGraph; + SDG sdg; - public NewSDGBuilder(SDGGraph sdgGraph) { - this.sdgGraph = sdgGraph; + public NewSDGBuilder(SDG sdg) { + this.sdg = sdg; } @Override @@ -27,9 +26,9 @@ public class NewSDGBuilder extends VoidVisitorAdapter { context.setCurrentMethod(methodDeclaration); // Build PDG and add to SDGGraph - PDGGraph pdgGraph = Graphs.PDG.fromASTNode(methodDeclaration); + PDG pdg = Graphs.PDG.fromASTNode(methodDeclaration); - sdgGraph.addMethod(methodDeclaration, pdgGraph); + sdg.addMethod(methodDeclaration, pdg); } @Override @@ -52,7 +51,7 @@ public class NewSDGBuilder extends VoidVisitorAdapter { // Once every PDG is built, expand method call nodes of each one // and link them to the corresponding method declaration node - MethodCallReplacer methodCallReplacer = new MethodCallReplacer(sdgGraph); + MethodCallReplacer methodCallReplacer = new MethodCallReplacer(sdg); methodCallReplacer.replace(); diff --git a/src/main/java/tfm/visitors/sdg/SDGBuilder.java b/src/main/java/tfm/visitors/sdg/SDGBuilder.java index 9a51186..3f24384 100644 --- a/src/main/java/tfm/visitors/sdg/SDGBuilder.java +++ b/src/main/java/tfm/visitors/sdg/SDGBuilder.java @@ -11,8 +11,8 @@ import com.github.javaparser.ast.stmt.ExpressionStmt; import com.github.javaparser.ast.stmt.Statement; import com.github.javaparser.ast.type.Type; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import tfm.graphs.PDGGraph; -import tfm.graphs.SDGGraph; +import tfm.graphs.PDG; +import tfm.graphs.SDG; import tfm.nodes.GraphNode; import tfm.visitors.pdg.PDGBuilder; @@ -28,15 +28,15 @@ import java.util.Optional; */ public class SDGBuilder extends VoidVisitorAdapter { - SDGGraph sdgGraph; - List pdgGraphs; + SDG sdg; + List pdgs; private ClassOrInterfaceDeclaration currentClass; private CompilationUnit currentCompilationUnit; - public SDGBuilder(SDGGraph sdgGraph) { - this.sdgGraph = sdgGraph; - this.pdgGraphs = new ArrayList<>(); + public SDGBuilder(SDG sdg) { + this.sdg = sdg; + this.pdgs = new ArrayList<>(); } @Override @@ -45,8 +45,8 @@ public class SDGBuilder extends VoidVisitorAdapter { return; - if (sdgGraph.isEmpty()) { - sdgGraph.setRootVertex( + if (sdg.isEmpty()) { + sdg.setRootVertex( new GraphNode<>( 0, "ENTER " + methodDeclaration.getNameAsString(), @@ -57,9 +57,9 @@ public class SDGBuilder extends VoidVisitorAdapter { // sdgGraph.addMethod(methodDeclaration); } - PDGGraph pdgGraph = new PDGGraph(); + PDG pdg = new PDG(); - PDGBuilder PDGBuilder = new PDGBuilder(pdgGraph) { + PDGBuilder PDGBuilder = new PDGBuilder(pdg) { @Override public void visit(MethodCallExpr methodCallExpr, GraphNode parent) { if (methodCallExpr.getScope().isPresent()) { @@ -71,7 +71,7 @@ public class SDGBuilder extends VoidVisitorAdapter { if (!Objects.equals(scopeName, currentClassName)) { // Check if 'scopeName' is a variable - List> declarations = sdgGraph.findDeclarationsOfVariable(scopeName); + List> declarations = sdg.findDeclarationsOfVariable(scopeName); if (declarations.isEmpty()) { // It is a static method call of another class. We don't do anything @@ -117,12 +117,12 @@ public class SDGBuilder extends VoidVisitorAdapter { } }; - PDGBuilder.visit(methodDeclaration, pdgGraph.getRootNode()); + PDGBuilder.visit(methodDeclaration, pdg.getRootNode()); - sdgGraph.addNode(methodDeclaration.getNameAsString(), methodDeclaration); + sdg.addNode(methodDeclaration.getNameAsString(), methodDeclaration); - pdgGraph.getNodes().stream().skip(1).forEach(pdgNode -> { + pdg.getNodes().stream().skip(1).forEach(pdgNode -> { Statement statement = (Statement) pdgNode.getAstNode(); if (statement.isExpressionStmt()) { @@ -140,11 +140,11 @@ public class SDGBuilder extends VoidVisitorAdapter { - sdgGraph.addPDG(pdgGraph, methodDeclaration); + sdg.addPDG(pdg, methodDeclaration); methodDeclaration.accept(this, ignored); - pdgGraphs.add(pdgGraph); + pdgs.add(pdg); } @Override -- GitLab From 0e6acf9090bbcbdaabd6b78ca46a19f4b4887a10 Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Tue, 14 Jan 2020 10:07:01 +0100 Subject: [PATCH 08/27] Tests comparing the APDG and the PPDG. Each method is graphed, and then all possible slices are compared. --- .gitmodules | 3 + pom.xml | 6 + src/main/java/tfm/exec/PDGLog.java | 12 +- src/test/java/tfm/FileFinder.java | 39 ++++++ src/test/java/tfm/HandCraftedGraphs.java | 93 +++++++++++++ src/test/java/tfm/PDGTests.java | 131 ++++++++++++++++++ .../Sergio.java => carlos/Problem1.java} | 2 +- src/test/res/carlos/Problem2.java | 11 ++ src/test/res/carlos/Problem3.java | 20 +++ src/test/res/java-slicing-benchmarks | 1 + src/test/res/papers/SergioContinue.java | 11 -- 11 files changed, 316 insertions(+), 13 deletions(-) create mode 100644 .gitmodules create mode 100644 src/test/java/tfm/FileFinder.java create mode 100644 src/test/java/tfm/HandCraftedGraphs.java create mode 100644 src/test/java/tfm/PDGTests.java rename src/test/res/{papers/Sergio.java => carlos/Problem1.java} (92%) create mode 100644 src/test/res/carlos/Problem2.java create mode 100644 src/test/res/carlos/Problem3.java create mode 160000 src/test/res/java-slicing-benchmarks delete mode 100644 src/test/res/papers/SergioContinue.java diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..46394f3 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/test/res/java-slicing-benchmarks"] + path = src/test/res/java-slicing-benchmarks + url = kaz:repos/java-slicing-benchmarks.git diff --git a/pom.xml b/pom.xml index 71c6c4f..08390f2 100644 --- a/pom.xml +++ b/pom.xml @@ -47,5 +47,11 @@ 1.3.0 + + org.junit.jupiter + junit-jupiter + RELEASE + test + \ No newline at end of file diff --git a/src/main/java/tfm/exec/PDGLog.java b/src/main/java/tfm/exec/PDGLog.java index e149dc7..2b280d1 100644 --- a/src/main/java/tfm/exec/PDGLog.java +++ b/src/main/java/tfm/exec/PDGLog.java @@ -73,11 +73,21 @@ public class PDGLog extends GraphLog { @Override public void generateImages(String imageName, Format format) throws IOException { - super.generateImages(imageName + "-pdg", format); + super.generateImages(imageName + "-" + getExtra(), format); if (cfgLog != null) cfgLog.generateImages(imageName + "-cfg", format); } + private String getExtra() { + if (graph instanceof PPDG) + return "ppdg"; + else if (graph instanceof APDG) + return "apdg"; + else if (graph instanceof PDG) + return "pdg"; + throw new RuntimeException("invalid or null graph type"); + } + @Override public void openVisualRepresentation() throws IOException { super.openVisualRepresentation(); diff --git a/src/test/java/tfm/FileFinder.java b/src/test/java/tfm/FileFinder.java new file mode 100644 index 0000000..30700ff --- /dev/null +++ b/src/test/java/tfm/FileFinder.java @@ -0,0 +1,39 @@ +package tfm; + +import com.github.javaparser.JavaParser; +import com.github.javaparser.ast.body.MethodDeclaration; +import org.junit.jupiter.params.provider.Arguments; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +public class FileFinder { + public static Collection findFiles(File directory, String suffix) throws FileNotFoundException { + Collection res = new ArrayList<>(); + File[] files = directory.listFiles(); + if (files == null) return Collections.emptyList(); + for (File f : files) { + if (f.getName().endsWith(suffix)) + for (MethodDeclaration m : methodsOf(f)) + res.add(Arguments.of(f, m.getNameAsString(), m)); + if (f.isDirectory()) + res.addAll(findFiles(f, suffix)); + } + return res; + } + + public static Arguments[] findAllMethodDeclarations() throws FileNotFoundException { + Collection args = findFiles(new File("./src/test/res/"), ".java"); + args.add(Arguments.of(new File("./src/test/res/invalid/problem1"), "problem1", HandCraftedGraphs.problem1WithGotos())); + args.add(Arguments.of(new File("./src/test/res/invalid/problem1continue"), "problem1", HandCraftedGraphs.problem1ContinueWithGotos())); + return args.toArray(new Arguments[0]); + } + + private static List methodsOf(File file) throws FileNotFoundException { + return JavaParser.parse(file).findAll(MethodDeclaration.class); + } +} diff --git a/src/test/java/tfm/HandCraftedGraphs.java b/src/test/java/tfm/HandCraftedGraphs.java new file mode 100644 index 0000000..599f458 --- /dev/null +++ b/src/test/java/tfm/HandCraftedGraphs.java @@ -0,0 +1,93 @@ +package tfm; + +import com.github.javaparser.ast.expr.MethodCallExpr; +import com.github.javaparser.ast.stmt.ContinueStmt; +import com.github.javaparser.ast.stmt.EmptyStmt; +import com.github.javaparser.ast.stmt.IfStmt; +import com.github.javaparser.ast.stmt.WhileStmt; +import tfm.graphs.CFG.ACFG; +import tfm.graphs.PDG.APDG; +import tfm.graphs.PDG.PPDG; +import tfm.nodes.GraphNode; +import tfm.visitors.pdg.ControlDependencyBuilder; + +public class HandCraftedGraphs { + public static APDG problem1WithGotos() { + // Generate the control flow of a graph + ACFG cfg = new ACFG(); + GraphNode wx = cfg.addNode("while (X)", new WhileStmt()); + GraphNode ify = cfg.addNode("L: if (Y)", new IfStmt()); + GraphNode ifz = cfg.addNode("if (Z)", new IfStmt()); + GraphNode a = cfg.addNode("A();", new MethodCallExpr("A")); + GraphNode b = cfg.addNode("B();", new MethodCallExpr("B")); + GraphNode c = cfg.addNode("C();", new MethodCallExpr("C")); + GraphNode d = cfg.addNode("D();", new MethodCallExpr("D")); + GraphNode g1 = cfg.addNode("goto L;", new ContinueStmt("L")); + GraphNode g2 = cfg.addNode("goto L;", new ContinueStmt("L")); + + GraphNode end = cfg.addNode("Exit", new EmptyStmt()); + + cfg.addControlFlowEdge(cfg.getRootNode(), wx); + cfg.addControlFlowEdge(wx, ify); + cfg.addControlFlowEdge(wx, d); + cfg.addControlFlowEdge(ify, ifz); + cfg.addControlFlowEdge(ify, c); + cfg.addControlFlowEdge(ifz, a); + cfg.addControlFlowEdge(ifz, b); + cfg.addControlFlowEdge(a, g1); + cfg.addControlFlowEdge(b, g2); + cfg.addControlFlowEdge(c, wx); + cfg.addControlFlowEdge(d, end); + cfg.addNonExecutableControlFlowEdge(g1, b); + cfg.addControlFlowEdge(g1, ify); + cfg.addNonExecutableControlFlowEdge(g2, c); + cfg.addControlFlowEdge(g2, ify); + cfg.addNonExecutableControlFlowEdge(cfg.getRootNode(), end); + + PPDG pdg = new PPDG(cfg); + ControlDependencyBuilder gen = new ControlDependencyBuilder(pdg, cfg); + gen.analyze(); + return pdg; + } + + public static APDG problem1ContinueWithGotos() { + // Generate the control flow of a graph + ACFG cfg = new ACFG(); + GraphNode wx = cfg.addNode("while (X)", new WhileStmt()); + GraphNode ify = cfg.addNode("L: if (Y)", new IfStmt()); + GraphNode ifz = cfg.addNode("if (Z)", new IfStmt()); + GraphNode a = cfg.addNode("A();", new MethodCallExpr("A")); + GraphNode b = cfg.addNode("B();", new MethodCallExpr("B")); + GraphNode c = cfg.addNode("C();", new MethodCallExpr("C")); + GraphNode d = cfg.addNode("D();", new MethodCallExpr("D")); + GraphNode g1 = cfg.addNode("goto L1;", new ContinueStmt("L")); + GraphNode g2 = cfg.addNode("goto L2;", new ContinueStmt("L")); + GraphNode g3 = cfg.addNode("goto L3;", new ContinueStmt("L")); + + GraphNode end = cfg.addNode("Exit", new EmptyStmt()); + + cfg.addControlFlowEdge(cfg.getRootNode(), wx); + cfg.addControlFlowEdge(wx, ify); + cfg.addControlFlowEdge(wx, d); + cfg.addControlFlowEdge(ify, ifz); + cfg.addControlFlowEdge(ify, c); + cfg.addControlFlowEdge(ifz, a); + cfg.addControlFlowEdge(ifz, b); + cfg.addControlFlowEdge(a, g1); + cfg.addControlFlowEdge(b, g3); + cfg.addControlFlowEdge(c, wx); + cfg.addControlFlowEdge(d, end); + cfg.addNonExecutableControlFlowEdge(g1, b); + cfg.addControlFlowEdge(g1, ify); + cfg.addNonExecutableControlFlowEdge(g2, c); + cfg.addControlFlowEdge(g2, ify); + cfg.addNonExecutableControlFlowEdge(g3, g2); + cfg.addControlFlowEdge(g3, ify); + cfg.addNonExecutableControlFlowEdge(cfg.getRootNode(), end); + + PPDG pdg = new PPDG(cfg); + ControlDependencyBuilder gen = new ControlDependencyBuilder(pdg, cfg); + gen.analyze(); + return pdg; + } +} diff --git a/src/test/java/tfm/PDGTests.java b/src/test/java/tfm/PDGTests.java new file mode 100644 index 0000000..0aae216 --- /dev/null +++ b/src/test/java/tfm/PDGTests.java @@ -0,0 +1,131 @@ +package tfm; + +import com.github.javaparser.JavaParser; +import com.github.javaparser.ast.Node; +import com.github.javaparser.ast.body.MethodDeclaration; +import com.github.javaparser.ast.stmt.ThrowStmt; +import com.github.javaparser.ast.stmt.TryStmt; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import tfm.exec.GraphLog; +import tfm.exec.PDGLog; +import tfm.graphs.CFG.ACFG; +import tfm.graphs.PDG; +import tfm.graphs.PDG.APDG; +import tfm.graphs.PDG.PPDG; +import tfm.nodes.GraphNode; +import tfm.slicing.GraphNodeCriterion; +import tfm.slicing.SlicingCriterion; +import tfm.utils.Logger; +import tfm.visitors.cfg.CFGBuilder; +import tfm.visitors.pdg.ControlDependencyBuilder; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Set; +import java.util.stream.Collectors; + +public class PDGTests { + static { + JavaParser.getStaticConfiguration().setAttributeComments(false); + } + + private boolean error = false; + + @ParameterizedTest(name = "[{index}] {0} ({1})") + @MethodSource("tfm.FileFinder#findAllMethodDeclarations") + public void ppdgTest(File file, String methodName, MethodDeclaration root) throws IOException { + runPdg(file, root, PDGLog.PPDG); + } + + @ParameterizedTest(name = "[{index}] {0} ({1})") + @MethodSource("tfm.FileFinder#findAllMethodDeclarations") + public void apdgTest(File file, String methodName, MethodDeclaration root) throws IOException { + runPdg(file, root, PDGLog.APDG); + } + + @ParameterizedTest(name = "[{index}] {0} ({1})") + @MethodSource("tfm.FileFinder#findAllMethodDeclarations") + public void pdgTest(File file, String methodName, MethodDeclaration root) throws IOException { + runPdg(file, root, PDGLog.PDG); + } + + private void runPdg(File file, Node root, int type) throws IOException { + GraphLog graphLog = new PDGLog(type); + graphLog.visit(root); + graphLog.log(); + try { + graphLog.generateImages(file.getPath()); + } catch (Exception e) { + System.err.println("Could not generate PNG"); + System.err.println(e.getMessage()); + } + } + + @ParameterizedTest(name = "[{index}] {0} ({1})") + @MethodSource("tfm.FileFinder#findAllMethodDeclarations") + public void pdgCompare(File file, String methodName, MethodDeclaration root) throws IOException { + ControlDependencyBuilder ctrlDepBuilder; + + if (containsUnsupportedStatements(root)) { + System.err.println("Contains unsupported instructions"); + } + + // Create APDG + ACFG acfg = new ACFG(); + root.accept(new CFGBuilder(acfg), null); + APDG apdg = new APDG(acfg); + ctrlDepBuilder = new ControlDependencyBuilder(apdg, acfg); + ctrlDepBuilder.analyze(); + + // Create PPDG + PPDG ppdg = new PPDG(acfg); + ctrlDepBuilder = new ControlDependencyBuilder(ppdg, acfg); + ctrlDepBuilder.analyze(); + + // Compare + Logger.log("COMPARE APDG and PPDG"); + compareGraphs(apdg, ppdg); + assert !error; + } + + public static boolean containsUnsupportedStatements(Node node) { + return node.findFirst(TryStmt.class).isPresent() + || node.findFirst(ThrowStmt.class).isPresent(); + } + + + /** Slices both graphs on every possible node and compares the result */ + public void compareGraphs(PDG pdg1, PDG pdg2) { + for (GraphNode node : pdg1.getNodes().stream() + .sorted(Comparator.comparingInt(GraphNode::getId)) + .collect(Collectors.toList())) { + if (node.getAstNode() instanceof MethodDeclaration) + continue; + SlicingCriterion sc = new GraphNodeCriterion(node, "x"); + Set slice1 = pdg1.slice(sc); + Set slice2 = pdg2.slice(sc); + Logger.log("Slicing on " + node.getId()); + boolean ok = slice1.equals(slice2); + if (!ok) { + Logger.log("FAILED!"); + error = true; + } + printSlices(pdg1, slice1, slice2); + } + } + + @SafeVarargs + public final void printSlices(PDG pdg, Set... slices) { + pdg.getNodes().stream() + .sorted(Comparator.comparingInt(GraphNode::getId)) + .forEach(n -> Logger.format("%3d: %s %s", + n.getId(), + Arrays.stream(slices) + .map(s -> s.contains(n.getId()) ? "x" : " ") + .reduce((a, b) -> a + " " + b), + n.getData())); + } +} diff --git a/src/test/res/papers/Sergio.java b/src/test/res/carlos/Problem1.java similarity index 92% rename from src/test/res/papers/Sergio.java rename to src/test/res/carlos/Problem1.java index b9bd607..7260874 100644 --- a/src/test/res/papers/Sergio.java +++ b/src/test/res/carlos/Problem1.java @@ -1,4 +1,4 @@ -public class Test { +public class Problem1 { public static void main(String[] args) { while (X) { if (Y) { diff --git a/src/test/res/carlos/Problem2.java b/src/test/res/carlos/Problem2.java new file mode 100644 index 0000000..89533f5 --- /dev/null +++ b/src/test/res/carlos/Problem2.java @@ -0,0 +1,11 @@ +public class Problem2 { + public static void main(String[] args) { + int a = 0; + while (a >= 0) { + if (a > 10) + break; + a++; + } + System.out.println(a); + } +} \ No newline at end of file diff --git a/src/test/res/carlos/Problem3.java b/src/test/res/carlos/Problem3.java new file mode 100644 index 0000000..955ea04 --- /dev/null +++ b/src/test/res/carlos/Problem3.java @@ -0,0 +1,20 @@ +public class Problem3 { + public static int x; + + public static void main() throws Exception { + x = 0; + try { + f(); + } catch (Exception e) { + log("error"); + } + x = 1; + f(); + } + + public static void f() { + if (x % 2 == 0) + throw new Exception("error!"); + log("x = " + x); + } +} \ No newline at end of file diff --git a/src/test/res/java-slicing-benchmarks b/src/test/res/java-slicing-benchmarks new file mode 160000 index 0000000..cc21305 --- /dev/null +++ b/src/test/res/java-slicing-benchmarks @@ -0,0 +1 @@ +Subproject commit cc21305fd85556362c596aeed4155f1effaf181d diff --git a/src/test/res/papers/SergioContinue.java b/src/test/res/papers/SergioContinue.java deleted file mode 100644 index cb68a46..0000000 --- a/src/test/res/papers/SergioContinue.java +++ /dev/null @@ -1,11 +0,0 @@ -public class Test { - public static void main(String[] args) { - while (X) { - if (Y) { - if (Z) { - - } - } - } - } -} \ No newline at end of file -- GitLab From 7deec96a4a72facd2d2801eb828432d2decd91bd Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Wed, 15 Jan 2020 10:43:43 +0100 Subject: [PATCH 09/27] Slicing: representation and transformation to code. --- src/main/java/tfm/exec/PDGLog.java | 40 +++++- src/main/java/tfm/graphs/CFG.java | 5 - src/main/java/tfm/graphs/Graph.java | 2 - src/main/java/tfm/graphs/PDG.java | 37 +++--- src/main/java/tfm/graphs/SDG.java | 6 +- src/main/java/tfm/slicing/Slice.java | 77 ++++++++---- .../java/tfm/slicing/SliceAstVisitor.java | 118 ++++++++++++++++++ src/main/java/tfm/slicing/Sliceable.java | 5 + .../java/tfm/visitors/cfg/CFGBuilder.java | 4 +- 9 files changed, 235 insertions(+), 59 deletions(-) create mode 100644 src/main/java/tfm/slicing/SliceAstVisitor.java create mode 100644 src/main/java/tfm/slicing/Sliceable.java diff --git a/src/main/java/tfm/exec/PDGLog.java b/src/main/java/tfm/exec/PDGLog.java index 2b280d1..9c18845 100644 --- a/src/main/java/tfm/exec/PDGLog.java +++ b/src/main/java/tfm/exec/PDGLog.java @@ -1,8 +1,13 @@ package tfm.exec; import guru.nidi.graphviz.engine.Format; +import tfm.graphs.CFG; +import tfm.graphs.CFG.ACFG; +import tfm.graphs.CFG.ECFG; import tfm.graphs.PDG; import tfm.graphs.PDG.APDG; +import tfm.graphs.PDG.EPDG; +import tfm.graphs.PDG.EPPDG; import tfm.graphs.PDG.PPDG; import tfm.nodes.GraphNode; import tfm.utils.Logger; @@ -13,7 +18,7 @@ import java.util.Comparator; import java.util.stream.Collectors; public class PDGLog extends GraphLog { - public static final int PDG = 0, APDG = 1, PPDG = 2; + public static final int PDG = 0, APDG = 1, PPDG = 2, EPDG = 3, EPPDG = 4; private CFGLog cfgLog; private int type; @@ -36,18 +41,29 @@ public class PDGLog extends GraphLog { switch (type) { case PDG: this.graph = new PDG(); + this.graph.setCfg(new CFG()); break; case APDG: this.graph = new APDG(); + this.graph.setCfg(new ACFG()); break; case PPDG: this.graph = new PPDG(); + this.graph.setCfg(new ACFG()); + break; + case EPDG: + this.graph = new EPDG(); + this.graph.setCfg(new ECFG()); + break; + case EPPDG: + this.graph = new EPPDG(); + this.graph.setCfg(new ECFG()); break; default: throw new RuntimeException("Invalid type of PDG"); } - node.accept(new PDGBuilder(graph), this.graph.getRootNode()); + node.accept(new PDGBuilder(graph, graph.getCfg()), this.graph.getRootNode()); if (cfgLog == null) { cfgLog = new CFGLog(graph.getCfg()); @@ -75,17 +91,31 @@ public class PDGLog extends GraphLog { public void generateImages(String imageName, Format format) throws IOException { super.generateImages(imageName + "-" + getExtra(), format); if (cfgLog != null) - cfgLog.generateImages(imageName + "-cfg", format); + cfgLog.generateImages(imageName + "-" + getExtraCFG(), format); + } + + private String getExtraCFG() { + if (graph.getCfg() instanceof ECFG) + return "ecfg"; + else if (graph.getCfg() instanceof ACFG) + return "acfg"; + else if (graph.getCfg() instanceof CFG) + return "cfg"; + throw new RuntimeException("invalid or null cfg graph type"); } private String getExtra() { - if (graph instanceof PPDG) + if (graph instanceof EPPDG) + return "eppdg"; + else if (graph instanceof EPDG) + return "epdg"; + else if (graph instanceof PPDG) return "ppdg"; else if (graph instanceof APDG) return "apdg"; else if (graph instanceof PDG) return "pdg"; - throw new RuntimeException("invalid or null graph type"); + throw new RuntimeException("invalid or null pdg graph type"); } @Override diff --git a/src/main/java/tfm/graphs/CFG.java b/src/main/java/tfm/graphs/CFG.java index 1eb6f3c..f2ce814 100644 --- a/src/main/java/tfm/graphs/CFG.java +++ b/src/main/java/tfm/graphs/CFG.java @@ -75,11 +75,6 @@ public class CFG extends Graph { "}"; } - @Override - public Set slice(SlicingCriterion slicingCriterion) { - throw new RuntimeException("Can't slice a CFG!"); - } - public Set> findLastDefinitionsFrom(GraphNode startNode, String variable) { if (!this.contains(startNode)) { throw new NodeNotFoundException(startNode, this); diff --git a/src/main/java/tfm/graphs/Graph.java b/src/main/java/tfm/graphs/Graph.java index c39e583..a27141f 100644 --- a/src/main/java/tfm/graphs/Graph.java +++ b/src/main/java/tfm/graphs/Graph.java @@ -133,8 +133,6 @@ public abstract class Graph extends edg.graphlib.Graph { .anyMatch(node -> Objects.equals(node, graphNode)); } - public abstract Set slice(SlicingCriterion slicingCriterion); - /** * Deprecated for incorrect behaviour. Use removeNode instead */ diff --git a/src/main/java/tfm/graphs/PDG.java b/src/main/java/tfm/graphs/PDG.java index 7f927a8..a25e3fb 100644 --- a/src/main/java/tfm/graphs/PDG.java +++ b/src/main/java/tfm/graphs/PDG.java @@ -10,12 +10,13 @@ import tfm.arcs.pdg.ControlDependencyArc; import tfm.arcs.pdg.DataDependencyArc; import tfm.graphs.CFG.ACFG; import tfm.nodes.GraphNode; +import tfm.slicing.Slice; +import tfm.slicing.Sliceable; import tfm.slicing.SlicingCriterion; import tfm.utils.ASTUtils; import tfm.utils.NodeNotFoundException; import java.util.Comparator; -import java.util.HashSet; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -27,7 +28,7 @@ import java.util.stream.Collectors; * the {@link tfm.visitors.pdg.PDGBuilder PDGBuilder}. * The variations of the PDG are represented as child types. */ -public class PDG extends Graph { +public class PDG extends Graph implements Sliceable { public static boolean isRanked = false, isSorted = false; private CFG cfg; @@ -171,25 +172,25 @@ public class PDG extends Graph { } @Override - public Set slice(SlicingCriterion slicingCriterion) { + public Slice slice(SlicingCriterion slicingCriterion) { Optional> node = slicingCriterion.findNode(this); if (!node.isPresent()) throw new NodeNotFoundException(slicingCriterion); - Set visited = new HashSet<>(); - getSliceNodes(visited, node.get()); - return visited; + Slice slice = new Slice(); + getSliceNodes(slice, node.get()); + return slice; } - protected void getSliceNodes(Set visited, GraphNode node) { - visited.add(node.getId()); + protected void getSliceNodes(Slice slice, GraphNode node) { + slice.add(node); for (Arc arc : node.getIncomingArcs()) { GraphNode from = arc.getFromNode(); - if (visited.contains(from.getId())) + if (slice.contains(from)) continue; - getSliceNodes(visited, from); + getSliceNodes(slice, from); } } @@ -217,21 +218,21 @@ public class PDG extends Graph { } @Override - protected void getSliceNodes(Set visited, GraphNode node) { - visited.add(node.getId()); + protected void getSliceNodes(Slice slice, GraphNode node) { + slice.add(node); for (Arc arc : node.getIncomingArcs()) { GraphNode from = arc.getFromNode(); - if (visited.contains(from.getId())) + if (slice.contains(from)) continue; - getSliceNodesPPDG(visited, from); + getSliceNodesPPDG(slice, from); } } - protected void getSliceNodesPPDG(Set visited, GraphNode node) { - visited.add(node.getId()); + protected void getSliceNodesPPDG(Slice slice, GraphNode node) { + slice.add(node); if (ASTUtils.isPseudoPredicate(node.getAstNode())) return; @@ -239,10 +240,10 @@ public class PDG extends Graph { for (Arc arc : node.getIncomingArcs()) { GraphNode from = arc.getFromNode(); - if (visited.contains(from.getId())) + if (slice.contains(from)) continue; - getSliceNodesPPDG(visited, from); + getSliceNodesPPDG(slice, from); } } } diff --git a/src/main/java/tfm/graphs/SDG.java b/src/main/java/tfm/graphs/SDG.java index 2b3b2c6..b26e2d1 100644 --- a/src/main/java/tfm/graphs/SDG.java +++ b/src/main/java/tfm/graphs/SDG.java @@ -5,13 +5,15 @@ import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.body.Parameter; import com.github.javaparser.ast.stmt.EmptyStmt; import tfm.nodes.GraphNode; +import tfm.slicing.Slice; +import tfm.slicing.Sliceable; import tfm.slicing.SlicingCriterion; import tfm.utils.Context; import java.util.*; import java.util.stream.Collectors; -public class SDG extends Graph { +public class SDG extends Graph implements Sliceable { private Map contextPDGGraphMap; @@ -34,7 +36,7 @@ public class SDG extends Graph { } @Override - public Set slice(SlicingCriterion slicingCriterion) { + public Slice slice(SlicingCriterion slicingCriterion) { throw new RuntimeException("Slicing not implemented for the SDG"); } diff --git a/src/main/java/tfm/slicing/Slice.java b/src/main/java/tfm/slicing/Slice.java index dccde5a..2a8b844 100644 --- a/src/main/java/tfm/slicing/Slice.java +++ b/src/main/java/tfm/slicing/Slice.java @@ -1,38 +1,65 @@ package tfm.slicing; -import com.github.javaparser.JavaParser; -import com.github.javaparser.ast.CompilationUnit; -import tfm.graphs.PDG; -import tfm.utils.Logger; -import tfm.utils.Utils; -import tfm.visitors.pdg.PDGBuilder; +import com.github.javaparser.ast.Node; +import com.github.javaparser.ast.body.MethodDeclaration; +import com.github.javaparser.ast.visitor.CloneVisitor; +import com.github.javaparser.ast.visitor.Visitable; +import tfm.nodes.GraphNode; -import java.io.File; -import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; public class Slice { + private final Map> map = new HashMap<>(); + private final Set nodes = new HashSet<>(); - public static final String PROGRAM_FOLDER = Utils.PROGRAMS_FOLDER + "pdg/"; - public static final String PROGRAM_NAME = "Example2"; + public Slice() {} - public static void main(String[] args) throws IOException { - CompilationUnit compilationUnit = JavaParser.parse(new File(PROGRAM_FOLDER + PROGRAM_NAME + ".java")); + public void add(GraphNode node) { + assert !map.containsKey(node.getId()); + map.put(node.getId(), node); + nodes.add(node.getAstNode()); + } + + public boolean contains(GraphNode node) { + return map.containsKey(node.getId()); + } + + public boolean contains(Node node) { + return nodes.contains(node); + } - PDG pdg = new PDG(); + @Override + public int hashCode() { + return map.hashCode(); + } - compilationUnit.accept(new PDGBuilder(pdg), pdg.getRootNode()); + @Override + public boolean equals(Object obj) { + return obj instanceof Slice && map.equals(((Slice) obj).map); + } - Logger.log("=================="); - Logger.log("= Starting slice ="); - Logger.log("=================="); + public Node getAst() { + List> methods = map.values().stream().filter(e -> e.getAstNode() instanceof MethodDeclaration).collect(Collectors.toList()); + if (methods.size() == 1) { + Optional secondNode = map.keySet().stream() + .sorted(Integer::compareTo).skip(1).findFirst(); + assert secondNode.isPresent(); + Node n = map.get(secondNode.get()).getAstNode(); + assert !(n instanceof MethodDeclaration); + while (!(n instanceof MethodDeclaration) && n.getParentNode().isPresent()) + n = n.getParentNode().get(); + assert n instanceof MethodDeclaration; + return getMethodAst(n); + } else if (methods.size() > 1) + throw new RuntimeException("Not implemented"); + throw new RuntimeException("No method found in the slice"); + } -// PDGGraph sliced = pdgGraph.slice(new LineNumberCriterion(18, "x")); -// -// PDGLog pdgLog = new PDGLog(sliced); -// pdgLog.log(); -// pdgLog.generateImages(PROGRAM_NAME + "-sliced"); -// pdgLog.openVisualRepresentation(); -// -// PDGValidator.printPDGProgram("Slice" + PROGRAM_NAME, sliced); + private MethodDeclaration getMethodAst(Node node) { + Visitable clone = node.accept(new CloneVisitor(), null); + assert clone instanceof MethodDeclaration; + clone.accept(new SliceAstVisitor(), this); + return ((MethodDeclaration) clone); } } diff --git a/src/main/java/tfm/slicing/SliceAstVisitor.java b/src/main/java/tfm/slicing/SliceAstVisitor.java new file mode 100644 index 0000000..63f187c --- /dev/null +++ b/src/main/java/tfm/slicing/SliceAstVisitor.java @@ -0,0 +1,118 @@ +package tfm.slicing; + +import com.github.javaparser.ast.Node; +import com.github.javaparser.ast.NodeList; +import com.github.javaparser.ast.expr.BooleanLiteralExpr; +import com.github.javaparser.ast.nodeTypes.NodeWithBody; +import com.github.javaparser.ast.stmt.*; +import com.github.javaparser.ast.visitor.ModifierVisitor; +import com.github.javaparser.ast.visitor.Visitable; + +import java.util.stream.Collectors; + +public class SliceAstVisitor extends ModifierVisitor { + @Override + public Visitable visit(BreakStmt n, Slice arg) { + return arg.contains(n) ? n : null; + } + + @Override + public Visitable visit(ContinueStmt n, Slice arg) { + return arg.contains(n) ? n : null; + } + + @Override + public Visitable visit(DoStmt n, Slice arg) { + boolean keep = arg.contains(n); + super.visit(n, arg); + fillBody(n); + return keep ? n : null; + } + + @Override + public Visitable visit(ForEachStmt n, Slice arg) { + boolean keep = arg.contains(n); + super.visit(n, arg); + fillBody(n); + return keep ? n : null; + } + + @Override + public Visitable visit(ForStmt n, Slice arg) { + boolean keep = arg.contains(n); + super.visit(n, arg); + n.setInitialization(new NodeList<>(n.getInitialization().stream() + .filter(arg::contains).collect(Collectors.toList()))); + n.setUpdate(new NodeList<>(n.getUpdate().stream() + .filter(arg::contains).collect(Collectors.toList()))); + fillBody(n); + if (keep) + return n; + if (n.getInitialization().isEmpty() && n.getUpdate().isEmpty()) + return null; + return new ForStmt(n.getInitialization(), new BooleanLiteralExpr(false), + n.getUpdate(), n.getBody()); + } + + @Override + public Visitable visit(WhileStmt n, Slice arg) { + boolean keep = arg.contains(n); + super.visit(n, arg); + fillBody(n); + return keep ? n : null; + } + + @Override + public Visitable visit(IfStmt n, Slice arg) { + boolean keep = arg.contains(n); + super.visit(n, arg); + if (n.getThenStmt() == null) + n.setThenStmt(new EmptyStmt()); + return keep ? n : null; + } + + @Override + public Visitable visit(LabeledStmt n, Slice arg) { + super.visit(n, arg); + return n.getStatement() != null ? n : null; + } + + @Override + public Visitable visit(ReturnStmt n, Slice arg) { + return arg.contains(n) ? n : null; + } + + @Override + public Visitable visit(ThrowStmt n, Slice arg) { + return arg.contains(n) ? n : null; + } + + @Override + public Visitable visit(SwitchEntryStmt n, Slice arg) { + boolean keep = arg.contains(n); + super.visit(n, arg); + if (!n.getStatements().isEmpty()) + return n; + return keep ? n : null; + } + + @Override + public Visitable visit(SwitchStmt n, Slice arg) { + boolean keep = arg.contains(n); + super.visit(n, arg); + return keep ? n : null; + } + + @Override + public Visitable visit(ExpressionStmt n, Slice arg) { + return arg.contains(n) ? n : null; + } + + private void fillBody(Node n) { + if (!(n instanceof NodeWithBody)) + return; + NodeWithBody nb = ((NodeWithBody) n); + if (nb.getBody() == null) + nb.setBody(new EmptyStmt()); + } +} diff --git a/src/main/java/tfm/slicing/Sliceable.java b/src/main/java/tfm/slicing/Sliceable.java new file mode 100644 index 0000000..c13101e --- /dev/null +++ b/src/main/java/tfm/slicing/Sliceable.java @@ -0,0 +1,5 @@ +package tfm.slicing; + +public interface Sliceable { + Slice slice(SlicingCriterion sc); +} diff --git a/src/main/java/tfm/visitors/cfg/CFGBuilder.java b/src/main/java/tfm/visitors/cfg/CFGBuilder.java index 206f34d..572f31b 100644 --- a/src/main/java/tfm/visitors/cfg/CFGBuilder.java +++ b/src/main/java/tfm/visitors/cfg/CFGBuilder.java @@ -178,7 +178,7 @@ public class CFGBuilder extends VoidVisitorAdapter { continueStack.push(new LinkedList<>()); // Initialization - forStmt.getInitialization().forEach(expression -> new ExpressionStmt(expression).accept(this, arg)); + forStmt.getInitialization().forEach(this::connectTo); // Condition Expression condition = forStmt.getCompare().orElse(new BooleanLiteralExpr(true)); @@ -186,7 +186,7 @@ public class CFGBuilder extends VoidVisitorAdapter { // Body and update expressions forStmt.getBody().accept(this, arg); - forStmt.getUpdate().forEach(e -> new ExpressionStmt(e).accept(this, arg)); + forStmt.getUpdate().forEach(this::connectTo); // Condition if body contained anything hangingNodes.addAll(continueStack.pop()); -- GitLab From 74def367fc01e08350d99b298c7209b457040dd3 Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Wed, 15 Jan 2020 18:31:38 +0100 Subject: [PATCH 10/27] PDGTests: accept any number of PDGs and save slices to disk --- src/test/java/tfm/FileFinder.java | 7 ++- src/test/java/tfm/PDGTests.java | 96 ++++++++++++++++++++++++------- 2 files changed, 80 insertions(+), 23 deletions(-) diff --git a/src/test/java/tfm/FileFinder.java b/src/test/java/tfm/FileFinder.java index 30700ff..30399ea 100644 --- a/src/test/java/tfm/FileFinder.java +++ b/src/test/java/tfm/FileFinder.java @@ -12,6 +12,9 @@ import java.util.Collections; import java.util.List; public class FileFinder { + private static final String TEST_FILES = "./src/test/res/"; + private static final String DOT_JAVA = ".java"; + public static Collection findFiles(File directory, String suffix) throws FileNotFoundException { Collection res = new ArrayList<>(); File[] files = directory.listFiles(); @@ -27,9 +30,7 @@ public class FileFinder { } public static Arguments[] findAllMethodDeclarations() throws FileNotFoundException { - Collection args = findFiles(new File("./src/test/res/"), ".java"); - args.add(Arguments.of(new File("./src/test/res/invalid/problem1"), "problem1", HandCraftedGraphs.problem1WithGotos())); - args.add(Arguments.of(new File("./src/test/res/invalid/problem1continue"), "problem1", HandCraftedGraphs.problem1ContinueWithGotos())); + Collection args = findFiles(new File(TEST_FILES), DOT_JAVA); return args.toArray(new Arguments[0]); } diff --git a/src/test/java/tfm/PDGTests.java b/src/test/java/tfm/PDGTests.java index 0aae216..7d0a895 100644 --- a/src/test/java/tfm/PDGTests.java +++ b/src/test/java/tfm/PDGTests.java @@ -1,7 +1,9 @@ package tfm; import com.github.javaparser.JavaParser; +import com.github.javaparser.ast.Modifier; import com.github.javaparser.ast.Node; +import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.stmt.ThrowStmt; import com.github.javaparser.ast.stmt.TryStmt; @@ -9,12 +11,14 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import tfm.exec.GraphLog; import tfm.exec.PDGLog; +import tfm.graphs.CFG; import tfm.graphs.CFG.ACFG; import tfm.graphs.PDG; import tfm.graphs.PDG.APDG; import tfm.graphs.PDG.PPDG; import tfm.nodes.GraphNode; import tfm.slicing.GraphNodeCriterion; +import tfm.slicing.Slice; import tfm.slicing.SlicingCriterion; import tfm.utils.Logger; import tfm.visitors.cfg.CFGBuilder; @@ -22,9 +26,11 @@ import tfm.visitors.pdg.ControlDependencyBuilder; import java.io.File; import java.io.IOException; +import java.io.PrintWriter; import java.util.Arrays; import java.util.Comparator; -import java.util.Set; +import java.util.LinkedList; +import java.util.List; import java.util.stream.Collectors; public class PDGTests { @@ -37,27 +43,27 @@ public class PDGTests { @ParameterizedTest(name = "[{index}] {0} ({1})") @MethodSource("tfm.FileFinder#findAllMethodDeclarations") public void ppdgTest(File file, String methodName, MethodDeclaration root) throws IOException { - runPdg(file, root, PDGLog.PPDG); + runPdg(file, methodName, root, PDGLog.PPDG); } @ParameterizedTest(name = "[{index}] {0} ({1})") @MethodSource("tfm.FileFinder#findAllMethodDeclarations") public void apdgTest(File file, String methodName, MethodDeclaration root) throws IOException { - runPdg(file, root, PDGLog.APDG); + runPdg(file, methodName, root, PDGLog.APDG); } @ParameterizedTest(name = "[{index}] {0} ({1})") @MethodSource("tfm.FileFinder#findAllMethodDeclarations") public void pdgTest(File file, String methodName, MethodDeclaration root) throws IOException { - runPdg(file, root, PDGLog.PDG); + runPdg(file, methodName, root, PDGLog.PDG); } - private void runPdg(File file, Node root, int type) throws IOException { + private void runPdg(File file, String methodName, Node root, int type) throws IOException { GraphLog graphLog = new PDGLog(type); graphLog.visit(root); graphLog.log(); try { - graphLog.generateImages(file.getPath()); + graphLog.generateImages(file.getPath() + "-" + methodName); } catch (Exception e) { System.err.println("Could not generate PNG"); System.err.println(e.getMessage()); @@ -73,6 +79,13 @@ public class PDGTests { System.err.println("Contains unsupported instructions"); } + // Create PDG + CFG cfg = new CFG(); + root.accept(new CFGBuilder(cfg), null); + PDG pdg = new PDG(cfg); + ctrlDepBuilder = new ControlDependencyBuilder(pdg, cfg); + ctrlDepBuilder.analyze(); + // Create APDG ACFG acfg = new ACFG(); root.accept(new CFGBuilder(acfg), null); @@ -85,9 +98,27 @@ public class PDGTests { ctrlDepBuilder = new ControlDependencyBuilder(ppdg, acfg); ctrlDepBuilder.analyze(); + // Print graphs (commented to decrease the test's time) + String filePathNoExt = file.getPath().substring(0, file.getPath().lastIndexOf('.')); +// String name = filePathNoExt + "/" + methodName; +// new PDGLog(pdg).generateImages(name); +// new PDGLog(apdg).generateImages(name); +// new PDGLog(ppdg).generateImages(name); + // Compare - Logger.log("COMPARE APDG and PPDG"); - compareGraphs(apdg, ppdg); + List slicedMethods = compareGraphs(pdg, apdg, ppdg); + + // Write sliced methods to a java file. + ClassOrInterfaceDeclaration clazz = new ClassOrInterfaceDeclaration(); + slicedMethods.forEach(clazz::addMember); + clazz.setName(methodName); + clazz.setModifier(Modifier.Keyword.PUBLIC, true); + try (PrintWriter pw = new PrintWriter(new File("./out/" + filePathNoExt + "/" + methodName + ".java"))) { + pw.println(clazz); + } catch (Exception e) { + Logger.log("Error! Could not write classes to file"); + } + assert !error; } @@ -98,34 +129,59 @@ public class PDGTests { /** Slices both graphs on every possible node and compares the result */ - public void compareGraphs(PDG pdg1, PDG pdg2) { - for (GraphNode node : pdg1.getNodes().stream() + public List compareGraphs(PDG... pdgs) { + List slicedMethods = new LinkedList<>(); + assert pdgs.length > 0; + for (GraphNode node : pdgs[0].getNodes().stream() .sorted(Comparator.comparingInt(GraphNode::getId)) .collect(Collectors.toList())) { + // Skip start of graph if (node.getAstNode() instanceof MethodDeclaration) continue; + + // Perform slices SlicingCriterion sc = new GraphNodeCriterion(node, "x"); - Set slice1 = pdg1.slice(sc); - Set slice2 = pdg2.slice(sc); + Slice[] slices = Arrays.stream(pdgs).map(p -> p.slice(sc)).toArray(Slice[]::new); + + // Compare slices + boolean ok = true; + Slice referenceSlice = slices[0]; + for (Slice slice : slices) { + ok = referenceSlice.equals(slice); + error |= !ok; + if (!ok) break; + } + + // Display slice Logger.log("Slicing on " + node.getId()); - boolean ok = slice1.equals(slice2); - if (!ok) { + if (!ok) Logger.log("FAILED!"); - error = true; + printSlices(pdgs[0], slices); + + // Save slices as MethodDeclaration + int i = 0; + for (Slice s : slices) { + i++; + try { + MethodDeclaration m = ((MethodDeclaration) s.getAst()); + m.setName(m.getName() + "_slice" + node.getId() + "_pdg" + i); + slicedMethods.add(m); + } catch (RuntimeException e) { + Logger.log("Error: " + e.getMessage()); + } } - printSlices(pdg1, slice1, slice2); } + return slicedMethods; } - @SafeVarargs - public final void printSlices(PDG pdg, Set... slices) { + public final void printSlices(PDG pdg, Slice... slices) { pdg.getNodes().stream() .sorted(Comparator.comparingInt(GraphNode::getId)) .forEach(n -> Logger.format("%3d: %s %s", n.getId(), Arrays.stream(slices) - .map(s -> s.contains(n.getId()) ? "x" : " ") - .reduce((a, b) -> a + " " + b), + .map(s -> s.contains(n) ? "x" : " ") + .reduce((a, b) -> a + " " + b).orElse("--error--"), n.getData())); } } -- GitLab From bca373cc5361ff5539bb8f2e6e47e41593687880 Mon Sep 17 00:00:00 2001 From: Javier Costa Date: Sun, 19 Jan 2020 20:31:59 +0100 Subject: [PATCH 11/27] JGraphT without visitors --- .gitignore | 1 + src/main/java/tfm/arcs/Arc.java | 65 +++---- .../java/tfm/arcs/cfg/ControlFlowArc.java | 10 +- src/main/java/tfm/arcs/data/ArcData.java | 8 - .../java/tfm/arcs/data/VariableArcData.java | 37 ---- src/main/java/tfm/arcs/data/VoidArcData.java | 18 -- .../tfm/arcs/pdg/ControlDependencyArc.java | 14 +- .../java/tfm/arcs/pdg/DataDependencyArc.java | 33 +--- src/main/java/tfm/graphs/CFGGraph.java | 21 +- src/main/java/tfm/graphs/Graph.java | 137 +++++-------- src/main/java/tfm/graphs/JGraph.java | 12 -- src/main/java/tfm/graphs/PDGGraph.java | 78 +++----- src/main/java/tfm/graphs/SDGGraph.java | 18 +- src/main/java/tfm/nodes/CFGNode.java | 26 --- src/main/java/tfm/nodes/GraphNode.java | 95 +++------ src/main/java/tfm/nodes/JNode.java | 135 ------------- src/main/java/tfm/nodes/MethodCallNode.java | 7 +- src/main/java/tfm/nodes/PDGNode.java | 92 --------- src/main/java/tfm/nodes/SDGNode.java | 28 --- src/main/java/tfm/scopes/IfElseScope.java | 64 ------ src/main/java/tfm/scopes/Scope.java | 46 ----- src/main/java/tfm/scopes/ScopeHolder.java | 183 ------------------ src/main/java/tfm/scopes/VariableScope.java | 156 --------------- 23 files changed, 154 insertions(+), 1130 deletions(-) delete mode 100644 src/main/java/tfm/arcs/data/ArcData.java delete mode 100644 src/main/java/tfm/arcs/data/VariableArcData.java delete mode 100644 src/main/java/tfm/arcs/data/VoidArcData.java delete mode 100644 src/main/java/tfm/graphs/JGraph.java delete mode 100644 src/main/java/tfm/nodes/CFGNode.java delete mode 100644 src/main/java/tfm/nodes/JNode.java delete mode 100644 src/main/java/tfm/nodes/PDGNode.java delete mode 100644 src/main/java/tfm/nodes/SDGNode.java delete mode 100644 src/main/java/tfm/scopes/IfElseScope.java delete mode 100644 src/main/java/tfm/scopes/Scope.java delete mode 100644 src/main/java/tfm/scopes/ScopeHolder.java delete mode 100644 src/main/java/tfm/scopes/VariableScope.java diff --git a/.gitignore b/.gitignore index d947638..77901fe 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .idea/ target/ out/ +.settings \ No newline at end of file diff --git a/src/main/java/tfm/arcs/Arc.java b/src/main/java/tfm/arcs/Arc.java index 5c13d31..8a2be34 100644 --- a/src/main/java/tfm/arcs/Arc.java +++ b/src/main/java/tfm/arcs/Arc.java @@ -1,15 +1,21 @@ package tfm.arcs; -import tfm.arcs.data.ArcData; +import org.jgrapht.graph.DefaultEdge;; import tfm.nodes.GraphNode; import java.util.Objects; +import java.util.Optional; -public abstract class Arc extends edg.graphlib.Arrow { +public abstract class Arc extends DefaultEdge { - @SuppressWarnings("unchecked") - public Arc(GraphNode from, GraphNode to) { - super((edg.graphlib.Vertex) from, (edg.graphlib.Vertex) to); + private String variable; + + public Arc() { + + } + + public Arc(String variable) { + this.variable = variable; } public abstract boolean isControlFlowArrow(); @@ -18,18 +24,14 @@ public abstract class Arc extends edg.graphlib.Arrow %s}", - getData(), - getFrom(), - getTo() - ); + public Optional getVariable() { + return Optional.ofNullable(this.variable); } - public String toGraphvizRepresentation() { - GraphNode from = (GraphNode) getFrom(); - GraphNode to = (GraphNode) getTo(); + @Override + public String toString() { + GraphNode from = (GraphNode) getSource(); + GraphNode to = (GraphNode) getTarget(); return String.format("%s -> %s", from.getId(), @@ -37,36 +39,21 @@ public abstract class Arc extends edg.graphlib.Arrow getFromNode() { - return (GraphNode) super.getFrom(); - } - - public GraphNode getToNode() { - return (GraphNode) super.getTo(); - } - - @Override - public int hashCode() { - return Objects.hashCode(getData()) + getFrom().hashCode() + getTo().hashCode(); + public String toGraphvizRepresentation() { + return toString(); } @Override public boolean equals(Object o) { - if (this == o) - return true; - - if (!(o instanceof Arc)) + if (this != o) { return false; + } - Arc arc = (Arc) o; - - GraphNode from = (GraphNode) arc.getFrom(); - GraphNode from2 = (GraphNode) getFrom(); - GraphNode to = (GraphNode) getTo(); - GraphNode to2 = (GraphNode) arc.getTo(); + return Objects.equals(variable, ((Arc) o).variable); + } - return Objects.equals(arc.getData(), getData()) && - Objects.equals(from.getId(), from2.getId()) && - Objects.equals(to.getId(), to2.getId()); + @Override + public int hashCode() { + return Objects.hash(variable, getSource(), getTarget()); } } diff --git a/src/main/java/tfm/arcs/cfg/ControlFlowArc.java b/src/main/java/tfm/arcs/cfg/ControlFlowArc.java index f51233c..8cd15b0 100644 --- a/src/main/java/tfm/arcs/cfg/ControlFlowArc.java +++ b/src/main/java/tfm/arcs/cfg/ControlFlowArc.java @@ -4,10 +4,9 @@ import tfm.arcs.Arc; import tfm.arcs.data.VoidArcData; import tfm.nodes.GraphNode; -public class ControlFlowArc extends Arc { +public class ControlFlowArc extends Arc { - public ControlFlowArc(GraphNode from, GraphNode to) { - super(from, to); + public ControlFlowArc() { } @Override @@ -27,10 +26,7 @@ public class ControlFlowArc extends Arc { @Override public String toString() { - return String.format("ControlFlowArc{%s -> %s}", - getFromNode().getId(), - getToNode().getId() - ); + return String.format("ControlFlowArc{%s}", super.toString()); } } diff --git a/src/main/java/tfm/arcs/data/ArcData.java b/src/main/java/tfm/arcs/data/ArcData.java deleted file mode 100644 index a20b654..0000000 --- a/src/main/java/tfm/arcs/data/ArcData.java +++ /dev/null @@ -1,8 +0,0 @@ -package tfm.arcs.data; - -public abstract class ArcData { - - public abstract boolean isVoid(); - - public abstract boolean isVariable(); -} diff --git a/src/main/java/tfm/arcs/data/VariableArcData.java b/src/main/java/tfm/arcs/data/VariableArcData.java deleted file mode 100644 index 0ce2e49..0000000 --- a/src/main/java/tfm/arcs/data/VariableArcData.java +++ /dev/null @@ -1,37 +0,0 @@ -package tfm.arcs.data; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; - -public class VariableArcData extends ArcData { - private List variables; - - public VariableArcData(String... variables) { - this(Arrays.asList(variables)); - } - - public VariableArcData(Collection variables) { - this.variables = new ArrayList<>(variables); - } - - public List getVariables() { - return variables; - } - - @Override - public boolean isVoid() { - return false; - } - - @Override - public boolean isVariable() { - return true; - } - - @Override - public String toString() { - return variables.toString(); - } -} diff --git a/src/main/java/tfm/arcs/data/VoidArcData.java b/src/main/java/tfm/arcs/data/VoidArcData.java deleted file mode 100644 index de5d824..0000000 --- a/src/main/java/tfm/arcs/data/VoidArcData.java +++ /dev/null @@ -1,18 +0,0 @@ -package tfm.arcs.data; - -public class VoidArcData extends ArcData { - @Override - public boolean isVoid() { - return true; - } - - @Override - public boolean isVariable() { - return false; - } - - @Override - public String toString() { - return "void"; - } -} diff --git a/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java b/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java index 6d7c79b..501e5f4 100644 --- a/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java +++ b/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java @@ -4,10 +4,13 @@ import tfm.arcs.Arc; import tfm.arcs.data.ArcData; import tfm.nodes.GraphNode; -public class ControlDependencyArc extends Arc { +public class ControlDependencyArc extends Arc { - public ControlDependencyArc(GraphNode from, GraphNode to) { - super(from, to); + public ControlDependencyArc(String variable) { + super(variable); + } + + public ControlDependencyArc() { } @Override @@ -27,9 +30,6 @@ public class ControlDependencyArc extends Arc { @Override public String toString() { - return String.format("ControlDependencyArc{%s -> %s}", - ((GraphNode) getFrom()).getId(), - ((GraphNode) getTo()).getId() - ); + return String.format("ControlDependencyArc{%s}", super.toString()); } } diff --git a/src/main/java/tfm/arcs/pdg/DataDependencyArc.java b/src/main/java/tfm/arcs/pdg/DataDependencyArc.java index 11e8ac0..80b0996 100644 --- a/src/main/java/tfm/arcs/pdg/DataDependencyArc.java +++ b/src/main/java/tfm/arcs/pdg/DataDependencyArc.java @@ -1,26 +1,13 @@ package tfm.arcs.pdg; import tfm.arcs.Arc; -import tfm.arcs.data.VariableArcData; -import tfm.nodes.GraphNode; +public class DataDependencyArc extends Arc { -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -public class DataDependencyArc extends Arc { - - public DataDependencyArc(GraphNode from, GraphNode to, String variable, String... variables) { - super(from, to); - - List variablesList = new ArrayList<>(variables.length + 1); - - variablesList.add(variable); - variablesList.addAll(Arrays.asList(variables)); - - VariableArcData variableArcData = new VariableArcData(variablesList); + public DataDependencyArc() { + } - setData(variableArcData); + public DataDependencyArc(String variable) { + super(variable); } @Override @@ -40,15 +27,15 @@ public class DataDependencyArc extends Arc { @Override public String toString() { - return String.format("DataDependencyArc{%s, %s -> %s}", - getData(), - getFromNode().getId(), - getToNode().getId()); + return String.format("DataDependencyArc{%s}", super.toString()); } @Override public String toGraphvizRepresentation() { - return String.format("%s [style=dashed, color=red, label=\"%s\"];", super.toGraphvizRepresentation(), getData().toString()); + return String.format("%s [style=dashed, color=red%s];", + super.toGraphvizRepresentation(), + getVariable().map(variable -> String.format(", label=\"%s\"", variable)).orElse("") + ); } } diff --git a/src/main/java/tfm/graphs/CFGGraph.java b/src/main/java/tfm/graphs/CFGGraph.java index 8faf9e3..f1e7acb 100644 --- a/src/main/java/tfm/graphs/CFGGraph.java +++ b/src/main/java/tfm/graphs/CFGGraph.java @@ -1,7 +1,6 @@ package tfm.graphs; import com.github.javaparser.ast.Node; -import com.github.javaparser.ast.stmt.EmptyStmt; import edg.graphlib.Arrow; import tfm.arcs.Arc; import tfm.arcs.cfg.ControlFlowArc; @@ -19,7 +18,6 @@ public class CFGGraph extends Graph { public CFGGraph() { super(); - setRootVertex(new GraphNode<>(getNextVertexId(), getRootNodeData(), new EmptyStmt())); } @Override @@ -30,14 +28,9 @@ public class CFGGraph extends Graph { return vertex; } - - protected String getRootNodeData() { - return "Start"; - } - @SuppressWarnings("unchecked") - public void addControlFlowEdge(GraphNode from, GraphNode to) { - super.addEdge((Arrow) new ControlFlowArc(from, to)); + public void addControlFlowEdge(GraphNode from, GraphNode to) { + super.addEdge(from, to); } @Override @@ -50,9 +43,9 @@ public class CFGGraph extends Graph { .collect(Collectors.joining(lineSep)); String arrows = - getArrows().stream() - .sorted(Comparator.comparingInt(arrow -> ((GraphNode) arrow.getFrom()).getId())) - .map(arrow -> ((Arc) arrow).toGraphvizRepresentation()) + getArcs().stream() + .sorted(Comparator.comparingInt(arc -> this.getEdgeSource(arc).getId())) + .map(Arc::toGraphvizRepresentation) .collect(Collectors.joining(lineSep)); return "digraph g{" + lineSep + @@ -86,10 +79,10 @@ public class CFGGraph extends Graph { Set> res = new HashSet<>(); - for (Arc arc : currentNode.getIncomingArcs()) { + for (Arc arc : incomingEdgesOf(currentNode)) { ControlFlowArc controlFlowArc = (ControlFlowArc) arc; - GraphNode from = controlFlowArc.getFromNode(); + GraphNode from = this.getEdgeSource(controlFlowArc); // Logger.log("Arrow from node: " + from); diff --git a/src/main/java/tfm/graphs/Graph.java b/src/main/java/tfm/graphs/Graph.java index 5ab503d..e337690 100644 --- a/src/main/java/tfm/graphs/Graph.java +++ b/src/main/java/tfm/graphs/Graph.java @@ -1,10 +1,8 @@ package tfm.graphs; import com.github.javaparser.ast.Node; -import edg.graphlib.Arrow; -import edg.graphlib.Vertex; +import org.jgrapht.graph.DefaultDirectedGraph; import tfm.arcs.Arc; -import tfm.arcs.data.ArcData; import tfm.nodes.GraphNode; import tfm.slicing.SlicingCriterion; @@ -12,82 +10,63 @@ import java.util.*; import java.util.stream.Collectors; /** - * A graphlib Graph without cost and data in arcs + * * */ -public abstract class Graph extends edg.graphlib.Graph { +public abstract class Graph extends DefaultDirectedGraph, Arc> { private int nextVertexId = 0; -// public final static class NodeId { -// private static int nextVertexId = 0; -// -// private int id; -// -// private NodeId(int id) { -// this.id = id; -// } -// -// static synchronized NodeId getVertexId() { -// return new NodeId(nextVertexId++); -// } -// -// public int getId() { -// return id; -// } -// -// @Override -// public String toString() { -// return String.valueOf(id); -// } -// } - public Graph() { - super(); + super(null, null, false); + } + + private GraphNode addNode(GraphNode node) { + this.addVertex(node); + + return node; + } + + private GraphNode addNode(int id, String instruction, ASTNode node) { + GraphNode newNode = new GraphNode<>(id, instruction, node); + + return this.addNode(newNode); + } + + public GraphNode addNode(String instruction, ASTNode node) { + return this.addNode(getNextVertexId(), instruction, node); } /** - Library fix: if a node had an edge to itself resulted in 2 outgoing nodes instead of 1 outgoing and 1 incoming + * Adds the given node to the graph. + * + * One must be careful with this method, as the given node will have + * an id and arcs corresponding to the graph in which it was created, and may not fit + * in the current graph. + * + * @param node the node to add to the graph + * @param copyId whether to copy the id node or not + * @param copyArcs whether to copy the arcs of the node or not + * @return the node instance added to the graph */ - @Override - public boolean addEdge(Arrow arrow) { - Vertex from = arrow.getFrom(); - Vertex to = arrow.getTo(); - int cost = arrow.getCost(); - ArcData data = arrow.getData(); - - if (!verticies.contains(from)) - throw new IllegalArgumentException(String.format("from (%s) is not in graph", from)); - if (!verticies.contains(to)) - throw new IllegalArgumentException(String.format("to (%s) is not in graph", to)); - - List> es2 = from.findEdges(to); - - for (Arrow e2 : es2) { - if (e2 != null && cost == e2.getCost() && - ((data == null && e2.getData() == null) || - (data != null && data.equals(e2.getData())))) - return false; - } - - // FIX - if (Objects.equals(from, to)) { - from.getOutgoingArrows().add(arrow); - from.getIncomingArrows().add(arrow); + public GraphNode addNode(GraphNode node, boolean copyId, boolean copyArcs) { + GraphNode res = node; + + if (copyId && copyArcs) { + this.addVertex(node); + } else if (copyId) { + res = this.addNode(node.getId(), node.getInstruction(), node.getAstNode()); + } else if (copyArcs) { + res = new GraphNode<>(node); + res.setId(getNextVertexId()); + + this.addVertex(res); } else { - from.addEdge(arrow); - to.addEdge(arrow); + res = this.addNode(node.getInstruction(), node.getAstNode()); } - edges.add(arrow); - return true; - } - @SuppressWarnings("unchecked") - public GraphNode getRootNode() { - return (GraphNode) super.getRootVertex(); + return res; } - public abstract GraphNode addNode(String instruction, ASTNode node); - @SuppressWarnings("unchecked") public Optional> findNodeByASTNode(ASTNode astNode) { return getNodes().stream() @@ -102,17 +81,12 @@ public abstract class Graph extends edg.graphlib.Graph { .findFirst(); } - @SuppressWarnings("unchecked") public Set> getNodes() { - return getVerticies().stream() - .map(vertex -> (GraphNode) vertex) - .collect(Collectors.toSet()); + return vertexSet(); } - public Set> getArcs() { - return getArrows().stream() - .map(arrow -> (Arc) arrow) - .collect(Collectors.toSet()); + public Set getArcs() { + return edgeSet(); } public String toString() { @@ -129,26 +103,13 @@ public abstract class Graph extends edg.graphlib.Graph { } public boolean contains(GraphNode graphNode) { - return getNodes().stream() - .anyMatch(node -> Objects.equals(node, graphNode)); + return super.containsVertex(graphNode); } public abstract Graph slice(SlicingCriterion slicingCriterion); - /** - * Deprecated for incorrect behaviour. Use removeNode instead - */ - @Override - @Deprecated - public boolean removeVertex(Vertex vertex) { - throw new UnsupportedOperationException("Deprecated method. Use removeNode instead"); - } - public void removeNode(GraphNode node) { - verticies.remove(node); - - edges.removeAll(node.getOutgoingArcs()); - edges.removeAll(node.getIncomingArcs()); + removeVertex(node); } public List> findDeclarationsOfVariable(String variable) { diff --git a/src/main/java/tfm/graphs/JGraph.java b/src/main/java/tfm/graphs/JGraph.java deleted file mode 100644 index 5fe88f8..0000000 --- a/src/main/java/tfm/graphs/JGraph.java +++ /dev/null @@ -1,12 +0,0 @@ -package tfm.graphs; - -import org.jgrapht.graph.DefaultDirectedGraph; -import tfm.arcs.Arc; -import tfm.nodes.JNode; - -public class JGraph extends DefaultDirectedGraph, Arc> { - - public JGraph() { - super(null, null, false); - } -} diff --git a/src/main/java/tfm/graphs/PDGGraph.java b/src/main/java/tfm/graphs/PDGGraph.java index 7cd03b4..d163a8f 100644 --- a/src/main/java/tfm/graphs/PDGGraph.java +++ b/src/main/java/tfm/graphs/PDGGraph.java @@ -2,7 +2,6 @@ package tfm.graphs; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.MethodDeclaration; -import com.github.javaparser.ast.stmt.EmptyStmt; import edg.graphlib.Arrow; import org.jetbrains.annotations.NotNull; import tfm.arcs.Arc; @@ -15,10 +14,7 @@ import tfm.utils.Logger; import tfm.utils.NodeNotFoundException; import tfm.visitors.pdg.PDGBuilder; -import java.util.Comparator; -import java.util.HashSet; -import java.util.Optional; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; public class PDGGraph extends Graph { @@ -26,64 +22,40 @@ public class PDGGraph extends Graph { private CFGGraph cfgGraph; public PDGGraph() { - setRootVertex(new GraphNode<>(getNextVertexId(), getRootNodeData(), new MethodDeclaration())); + super(); } public PDGGraph(CFGGraph cfgGraph) { - this(); + super(); this.cfgGraph = cfgGraph; } - protected String getRootNodeData() { - return "Entry"; - } - - public GraphNode addNode(GraphNode node) { - GraphNode vertex = new GraphNode<>(node); - super.addVertex(vertex); - - return vertex; - } - - @Override - public GraphNode addNode(String instruction, ASTNode node) { - return addNode(getNextVertexId(), instruction, node); - } + public GraphNode getRootNode() { + Iterator> iterator = this.getNodesAtLevel(0).iterator(); - public GraphNode addNode(int id, String instruction, ASTNode node) { - GraphNode vertex = new GraphNode<>(id, instruction, node); - super.addVertex(vertex); - - return vertex; - } + if (iterator.hasNext()) { + return iterator.next(); + } - @SuppressWarnings("unchecked") - private void addArc(Arc arc) { - super.addEdge(arc); + return null; } - public void addControlDependencyArc(GraphNode from, GraphNode to) { - ControlDependencyArc controlDependencyArc = new ControlDependencyArc(from, to); - - this.addArc(controlDependencyArc); + public void addControlDependencyArc(GraphNode from, GraphNode to) { + this.addEdge(from, to); } - public void addDataDependencyArc(GraphNode from, GraphNode to, String variable) { - DataDependencyArc dataDataDependencyArc = new DataDependencyArc(from, to, variable); - - this.addArc(dataDataDependencyArc); + public void addDataDependencyArc(GraphNode from, GraphNode to, String variable) { + this.addEdge(from, to, new DataDependencyArc(variable)); } - public Set getNodesAtLevel(int level) { - return getVerticies().stream() - .map(vertex -> (GraphNode) vertex) + public Set> getNodesAtLevel(int level) { + return getNodes().stream() .filter(node -> getLevelOf(node) == level) .collect(Collectors.toSet()); } public int getLevels() { - return getVerticies().stream() - .map(vertex -> (GraphNode) vertex) + return getNodes().stream() .max(Comparator.comparingInt(this::getLevelOf)) .map(node -> getLevelOf(node) + 1) .orElse(0); @@ -96,7 +68,7 @@ public class PDGGraph extends Graph { } public int getLevelOf(@NotNull GraphNode node) { - Optional optionalControlDependencyArc = node.getIncomingArcs().stream() + Optional optionalControlDependencyArc = incomingEdgesOf(node).stream() .filter(Arc::isControlDependencyArrow) .findFirst() .map(arc -> (ControlDependencyArc) arc); @@ -105,7 +77,7 @@ public class PDGGraph extends Graph { return 0; } - GraphNode parent = optionalControlDependencyArc.get().getFromNode(); + GraphNode parent = this.getEdgeSource(optionalControlDependencyArc.get()); return 1 + getLevelOf(parent); } @@ -127,7 +99,7 @@ public class PDGGraph extends Graph { // No level 0 is needed (only one node) for (int i = 0; i < getLevels(); i++) { - Set levelNodes = getNodesAtLevel(i); + Set> levelNodes = getNodesAtLevel(i); if (levelNodes.size() <= 1) { continue; @@ -152,7 +124,7 @@ public class PDGGraph extends Graph { String arrows = getArcs().stream() - .sorted(Comparator.comparingInt(arrow -> ((GraphNode) arrow.getFrom()).getId())) + .sorted(Comparator.comparingInt(arc -> this.getEdgeSource(arc).getId())) .map(Arc::toGraphvizRepresentation) .collect(Collectors.joining(lineSep)); @@ -197,9 +169,9 @@ public class PDGGraph extends Graph { Node astCopy = ASTUtils.cloneAST(node.getAstNode()); - astCopy.accept(new PDGBuilder(sliceGraph), sliceGraph.getRootNode()); + astCopy.accept(new PDGBuilder(sliceGraph), sliceGraph.getNodesAtLevel(0).iterator().next()); - for (GraphNode sliceNode : sliceGraph.getNodes()) { + for (GraphNode sliceNode : sliceGraph.getNodes()) { if (!sliceNodes.contains(sliceNode.getId())) { Logger.log("Removing node " + sliceNode.getId()); sliceNode.getAstNode().removeForced(); @@ -230,10 +202,8 @@ public class PDGGraph extends Graph { private Set getSliceNodes(Set visited, GraphNode root) { visited.add(root.getId()); - for (Arrow arrow : root.getIncomingArcs()) { - Arc arc = (Arc) arrow; - - GraphNode from = (GraphNode) arc.getFromNode(); + for (Arc arc : incomingEdgesOf(root)) { + GraphNode from = this.getEdgeSource(arc); if (visited.contains(from.getId())) { continue; diff --git a/src/main/java/tfm/graphs/SDGGraph.java b/src/main/java/tfm/graphs/SDGGraph.java index ec4692b..4aa8752 100644 --- a/src/main/java/tfm/graphs/SDGGraph.java +++ b/src/main/java/tfm/graphs/SDGGraph.java @@ -19,14 +19,6 @@ public class SDGGraph extends Graph { this.contextPDGGraphMap = new HashMap<>(); } - @Override - public GraphNode addNode(String instruction, ASTNode node) { - GraphNode sdgNode = new GraphNode<>(getNextVertexId(), instruction, node); - super.addVertex(sdgNode); - - return sdgNode; - } - @Override public String toGraphvizRepresentation() { return contextPDGGraphMap.values().stream() @@ -59,10 +51,6 @@ public class SDGGraph extends Graph { @Deprecated public void addPDG(PDGGraph pdgGraph, MethodDeclaration methodDeclaration) { - if (this.rootVertex == null) { - this.setRootVertex(new GraphNode<>(getNextVertexId(), methodDeclaration.getNameAsString(), methodDeclaration)); - } - for (Parameter parameter : methodDeclaration.getParameters()) { GraphNode sdgNode = new GraphNode<>( getNextVertexId(), @@ -74,13 +62,11 @@ public class SDGGraph extends Graph { } for (GraphNode node : pdgGraph.getNodes()) { - if (!this.verticies.contains(node)) { + if (!this.contains(node)) { GraphNode sdgNode = new GraphNode<>( getNextVertexId(), - node.getData(), + node.getInstruction(), node.getAstNode(), - node.getIncomingArcs(), - node.getOutgoingArcs(), node.getDeclaredVariables(), node.getDefinedVariables(), node.getUsedVariables() diff --git a/src/main/java/tfm/nodes/CFGNode.java b/src/main/java/tfm/nodes/CFGNode.java deleted file mode 100644 index 75e4b1c..0000000 --- a/src/main/java/tfm/nodes/CFGNode.java +++ /dev/null @@ -1,26 +0,0 @@ -package tfm.nodes; - -import com.github.javaparser.ast.Node; - -import java.util.stream.Collectors; - -@Deprecated -public class CFGNode extends GraphNode { - - public > CFGNode(N1 node) { - super(node); - } - - public CFGNode(int nextVertexId, String rootNodeData, N node) { - super(nextVertexId, rootNodeData, node); - } - - @Override - public String toString() { - return String.format("CFGNode{id: %s, in: %s, out: %s", - getId(), - getIncomingArcs().stream().map(arc -> arc.getFromNode().getId()).collect(Collectors.toList()), - getOutgoingArcs().stream().map(arc -> arc.getToNode().getId()).collect(Collectors.toList()) - ); - } -} diff --git a/src/main/java/tfm/nodes/GraphNode.java b/src/main/java/tfm/nodes/GraphNode.java index 133b4cf..b1ed794 100644 --- a/src/main/java/tfm/nodes/GraphNode.java +++ b/src/main/java/tfm/nodes/GraphNode.java @@ -2,21 +2,17 @@ package tfm.nodes; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.stmt.Statement; -import edg.graphlib.Arrow; -import edg.graphlib.Vertex; import org.checkerframework.checker.nullness.qual.NonNull; import org.jetbrains.annotations.NotNull; -import tfm.arcs.Arc; -import tfm.arcs.data.ArcData; import tfm.utils.Utils; import tfm.variables.VariableExtractor; import java.util.*; -import java.util.stream.Collectors; -public class GraphNode extends Vertex { +public class GraphNode { private int id; + private String instruction; protected N astNode; @@ -27,23 +23,19 @@ public class GraphNode extends Vertex { public > GraphNode(N1 node) { this( node.getId(), - node.getData(), + node.getInstruction(), node.getAstNode(), - node.getIncomingArcs(), - node.getOutgoingArcs(), node.getDeclaredVariables(), node.getDefinedVariables(), node.getUsedVariables() ); } - public GraphNode(int id, String representation, @NotNull N astNode) { + public GraphNode(int id, String instruction, @NotNull N astNode) { this( id, - representation, + instruction, astNode, - Utils.emptyList(), - Utils.emptyList(), Utils.emptySet(), Utils.emptySet(), Utils.emptySet() @@ -52,27 +44,20 @@ public class GraphNode extends Vertex { public GraphNode( int id, - String representation, + String instruction, @NonNull N astNode, - Collection> incomingArcs, - Collection> outgoingArcs, Set declaredVariables, Set definedVariables, Set usedVariables ) { - super(null, representation); - this.id = id; - + this.instruction = instruction; this.astNode = astNode; this.declaredVariables = declaredVariables; this.definedVariables = definedVariables; this.usedVariables = usedVariables; - this.setIncomingArcs(incomingArcs); - this.setOutgoingArcs(outgoingArcs); - if (astNode instanceof Statement) { extractVariables((Statement) astNode); } @@ -95,11 +80,10 @@ public class GraphNode extends Vertex { } public String toString() { - return String.format("GraphNode{id: %s, data: '%s', in: %s, out: %s}", + return String.format("GraphNode{id: %s, instruction: '%s'}", getId(), - getData(), - getIncomingArcs().stream().map(arc -> arc.getFromNode().getId()).collect(Collectors.toList()), - getOutgoingArcs().stream().map(arc -> arc.getToNode().getId()).collect(Collectors.toList())); + getInstruction() + ); } public N getAstNode() { @@ -135,17 +119,20 @@ public class GraphNode extends Vertex { if (!(o instanceof GraphNode)) return false; - GraphNode other = (GraphNode) o; + GraphNode other = (GraphNode) o; - return Objects.equals(getData(), other.getData()) + return Objects.equals(getId(), other.getId()) + && Objects.equals(getInstruction(), other.getInstruction()) && Objects.equals(astNode, other.astNode); -// && Objects.equals(getIncomingArrows(), other.getIncomingArrows()) -// && Objects.equals(getOutgoingArrows(), other.getOutgoingArrows()) -// && Objects.equals(getName(), other.getName()) ID IS ALWAYS UNIQUE, SO IT WILL NEVER BE THE SAME + } + + @Override + public int hashCode() { + return Objects.hash(getId(), getInstruction(), getAstNode()); } public String toGraphvizRepresentation() { - String text = getData().replace("\\", "\\\\") + String text = getInstruction().replace("\\", "\\\\") .replace("\"", "\\\""); return String.format("%s[label=\"%s: %s\"];", getId(), getId(), text); } @@ -162,47 +149,11 @@ public class GraphNode extends Vertex { return usedVariables; } - public List> getIncomingArcs() { - return super.getIncomingArrows().stream() - .map(arrow -> (Arc) arrow) - .collect(Collectors.toList()); + public String getInstruction() { + return instruction; } - public List> getOutgoingArcs() { - return super.getOutgoingArrows().stream() - .map(arrow -> (Arc) arrow) - .collect(Collectors.toList()); - } - - public , C extends Collection> void setIncomingArcs(C arcs) { - for (A arc : arcs) { - this.addIncomingEdge(arc.getFrom(), arc.getCost()); - } - } - - public , C extends Collection> void setOutgoingArcs(C arcs) { - for (A arc : arcs) { - this.addOutgoingEdge(arc.getTo(), arc.getCost()); - } - } - - /** - * Deprecated. Use getIncomingArcs instead - * @throws UnsupportedOperationException - */ - @Deprecated - @Override - public List> getIncomingArrows() { - return super.getIncomingArrows(); - } - - /** - * Deprecated. Use getOutgoingArcs instead - * @throws UnsupportedOperationException - */ - @Deprecated - @Override - public List> getOutgoingArrows() { - return super.getOutgoingArrows(); + public void setInstruction(String instruction) { + this.instruction = instruction; } } diff --git a/src/main/java/tfm/nodes/JNode.java b/src/main/java/tfm/nodes/JNode.java deleted file mode 100644 index 534f433..0000000 --- a/src/main/java/tfm/nodes/JNode.java +++ /dev/null @@ -1,135 +0,0 @@ -package tfm.nodes; - -import com.github.javaparser.ast.Node; -import org.checkerframework.checker.nullness.qual.NonNull; -import tfm.utils.Utils; -import tfm.variables.VariableExtractor; - -import java.util.Objects; -import java.util.Optional; -import java.util.Set; - -public class JNode { - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public String getRepresentation() { - return representation; - } - - public void setRepresentation(String representation) { - this.representation = representation; - } - - public ASTNode getAstNode() { - return astNode; - } - - public void setAstNode(ASTNode astNode) { - this.astNode = astNode; - } - - public Set getDeclaredVariables() { - return declaredVariables; - } - - public Set getDefinedVariables() { - return definedVariables; - } - - public Set getUsedVariables() { - return usedVariables; - } - - private int id; - private String representation; - - protected ASTNode astNode; - protected Set declaredVariables; - protected Set definedVariables; - protected Set usedVariables; - - - public JNode(@NonNull JNode node) { - this(node.id, node.representation, node.astNode, node.declaredVariables, node.definedVariables, node.usedVariables); - } - - public JNode(int id, @NonNull String representation, @NonNull ASTNode astNode) { - this(id, representation, astNode, Utils.emptySet(), Utils.emptySet(), Utils.emptySet()); - - extractVariables(astNode); - } - - public JNode(int id, @NonNull String representation, @NonNull ASTNode astNode, Set declaredVariables, Set definedVariables, Set usedVariables) { - this.id = id; - this.representation = representation; - this.astNode = astNode; - this.declaredVariables = declaredVariables; - this.definedVariables = definedVariables; - this.usedVariables = usedVariables; - } - - private void extractVariables(ASTNode astNode) { - new VariableExtractor() - .setOnVariableDeclarationListener(variable -> this.declaredVariables.add(variable)) - .setOnVariableDefinitionListener(variable -> this.definedVariables.add(variable)) - .setOnVariableUseListener(variable -> this.usedVariables.add(variable)) - .visit(astNode); - } - - public void addDeclaredVariable(String variable) { - declaredVariables.add(variable); - } - - public void addDefinedVariable(String variable) { - definedVariables.add(variable); - } - - public void addUsedVariable(String variable) { - usedVariables.add(variable); - } - - public Optional getFileLineNumber() { - return astNode.getBegin() - .map(begin -> begin.line); - } - - @Override - public int hashCode() { - return id + astNode.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj == this) { - return true; - } - - if (!(obj instanceof JNode)) { - return false; - } - - JNode jNode = (JNode) obj; - - return jNode.id == id && Objects.equals(jNode.astNode, astNode); - } - - @Override - public String toString() { - return String.format("JNode{id: %s, repr: %s, astNodeClass: %s}", - id, - representation, - astNode.getClass().getName() - ); - } - - public String toGraphvizRepresentation() { - return String.format("%s[label=\"%s: %s\"];", getId(), getId(), getRepresentation()); - } -} diff --git a/src/main/java/tfm/nodes/MethodCallNode.java b/src/main/java/tfm/nodes/MethodCallNode.java index b241c5c..89ff4af 100644 --- a/src/main/java/tfm/nodes/MethodCallNode.java +++ b/src/main/java/tfm/nodes/MethodCallNode.java @@ -1,12 +1,9 @@ package tfm.nodes; import com.github.javaparser.ast.stmt.ExpressionStmt; -import edg.graphlib.Arrow; import org.checkerframework.checker.nullness.qual.NonNull; -import tfm.arcs.data.ArcData; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import java.util.Set; @@ -30,8 +27,8 @@ public class MethodCallNode extends GraphNode { this.outParameters = new ArrayList<>(); } - public MethodCallNode(int id, String representation, @NonNull ExpressionStmt node, Collection> incomingArcs, Collection> outgoingArcs, Set declaredVariables, Set definedVariables, Set usedVariables) { - super(id, representation, node, incomingArcs, outgoingArcs, declaredVariables, definedVariables, usedVariables); + public MethodCallNode(int id, String representation, @NonNull ExpressionStmt node, Set declaredVariables, Set definedVariables, Set usedVariables) { + super(id, representation, node, declaredVariables, definedVariables, usedVariables); this.inParameters = new ArrayList<>(); this.outParameters = new ArrayList<>(); diff --git a/src/main/java/tfm/nodes/PDGNode.java b/src/main/java/tfm/nodes/PDGNode.java deleted file mode 100644 index fe8c5be..0000000 --- a/src/main/java/tfm/nodes/PDGNode.java +++ /dev/null @@ -1,92 +0,0 @@ -package tfm.nodes; - -import com.github.javaparser.ast.Node; -import edg.graphlib.Arrow; -import org.checkerframework.checker.nullness.qual.NonNull; -import tfm.arcs.Arc; -import tfm.arcs.data.ArcData; -import tfm.arcs.pdg.ControlDependencyArc; -import tfm.utils.Logger; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -@Deprecated -public class PDGNode extends GraphNode { - - public PDGNode(int id, String data, N node) { - super(id, data, node); - } - - public PDGNode(int id, String representation, @NonNull N node, Collection> incomingArcs, Collection> outgoingArcs, Set declaredVariables, Set definedVariables, Set usedVariables) { - super(id, representation, node, incomingArcs, outgoingArcs, declaredVariables, definedVariables, usedVariables); - } - - public > PDGNode(N1 node) { - super(node); - } - - public String toString() { - List dataFrom = new ArrayList<>(); - List dataTo = new ArrayList<>(); - List controlFrom = new ArrayList<>(); - List controlTo = new ArrayList<>(); - - getIncomingArcs().forEach(arrow -> { - Logger.log(arrow); - Arc arc = (Arc) arrow; - GraphNode from = (GraphNode) arc.getFrom(); - - if (arc.isDataDependencyArrow()) { - dataFrom.add(from.getId()); - } else if (arc.isControlDependencyArrow()) { - controlFrom.add(from.getId()); - } - - }); - - getOutgoingArcs().forEach(arrow -> { - Arc arc = (Arc) arrow; - GraphNode to = (GraphNode) arc.getTo(); - - if (arc.isDataDependencyArrow()) { - dataTo.add(to.getId()); - } else if (arc.isControlDependencyArrow()) { - controlTo.add(to.getId()); - } - - }); - - return String.format("PDGNode{id: %s, data: %s, dataFrom: %s, dataTo: %s, controlFrom: %s, controlTo: %s}", - getId(), - getData(), - dataFrom, - dataTo, - controlFrom, - controlTo - ); - } - - public List getControlDependencies() { - return getIncomingArcs().stream() - .filter(arrow -> ((Arc) arrow).isControlDependencyArrow()) - .map(arc -> (ControlDependencyArc) arc) - .collect(Collectors.toList()); - } - - public int getLevel() { - return getLevel(this); - } - - private int getLevel(PDGNode node) { - List dependencies = node.getControlDependencies(); - - if (dependencies.isEmpty()) - return 0; - - return 1 + getLevel((PDGNode) dependencies.get(0).getFrom()); - } -} diff --git a/src/main/java/tfm/nodes/SDGNode.java b/src/main/java/tfm/nodes/SDGNode.java deleted file mode 100644 index 79a4120..0000000 --- a/src/main/java/tfm/nodes/SDGNode.java +++ /dev/null @@ -1,28 +0,0 @@ -package tfm.nodes; - -import com.github.javaparser.ast.Node; -import edg.graphlib.Arrow; -import org.checkerframework.checker.nullness.qual.NonNull; -import tfm.arcs.data.ArcData; - -import java.util.Collection; -import java.util.Set; - -@Deprecated -public class SDGNode extends GraphNode { - - public > SDGNode(N1 node) { - super(node); - } - - public SDGNode(int id, String representation, N node) { - super(id, representation, node); - } - public SDGNode(int id, String representation, @NonNull N node, Collection> incomingArcs, Collection> outgoingArcs, Set declaredVariables, Set definedVariables, Set usedVariables) { - super(id, representation, node, incomingArcs, outgoingArcs, declaredVariables, definedVariables, usedVariables); - } - - public String toString() { - return String.format("SDGNode{id: %s, data: %s, "); - } -} diff --git a/src/main/java/tfm/scopes/IfElseScope.java b/src/main/java/tfm/scopes/IfElseScope.java deleted file mode 100644 index 765b7f0..0000000 --- a/src/main/java/tfm/scopes/IfElseScope.java +++ /dev/null @@ -1,64 +0,0 @@ -package tfm.scopes; - -import tfm.nodes.GraphNode; -import tfm.variables.actions.VariableDefinition; - -import java.util.List; -import java.util.stream.Collectors; - -public class IfElseScope extends ScopeHolder { - - private VariableScope expressionScope; - private ScopeHolder thenScope; - private ScopeHolder elseScope; - - public IfElseScope(N node) { - super(node); - - this.expressionScope = new VariableScope<>(node); - this.thenScope = new ScopeHolder<>(node); - this.elseScope = new ScopeHolder<>(node); - - addSubscope(expressionScope); // expression - addSubscope(thenScope); // then - addSubscope(elseScope); // else - } - - public VariableScope getExpressionScope() { - return expressionScope; - } - - public ScopeHolder getThenScope() { - return thenScope; - } - - public ScopeHolder getElseScope() { - return elseScope; - } - - @Override - public void addVariableUse(String variable, N node) { - getExpressionScope().addVariableUse(variable, node); - } - - @Override - public List> getFirstDefinitions(String variable) { - return getSubscopes().stream() - .flatMap(scope -> scope.getFirstDefinitions(variable).stream()) - .collect(Collectors.toList()); - } - - @Override - public List> getLastDefinitions(String variable) { - return getSubscopes().stream() - .flatMap(scope -> scope.getLastDefinitions(variable).stream()) - .collect(Collectors.toList()); - } - - @Override - public List> getLastDefinitionsBeforeNode(String variable, N node) { - return getSubscopes().stream() - .flatMap(scope -> scope.getLastDefinitionsBeforeNode(variable, node).stream()) - .collect(Collectors.toList()); - } -} diff --git a/src/main/java/tfm/scopes/Scope.java b/src/main/java/tfm/scopes/Scope.java deleted file mode 100644 index 9d56e90..0000000 --- a/src/main/java/tfm/scopes/Scope.java +++ /dev/null @@ -1,46 +0,0 @@ -package tfm.scopes; - -import tfm.nodes.GraphNode; -import tfm.variables.actions.VariableDeclaration; -import tfm.variables.actions.VariableDefinition; -import tfm.variables.actions.VariableUse; - -import java.util.List; -import java.util.Set; - -public abstract class Scope { - - protected N root; - - protected Scope(N root) { - this.root = root; - } - - public N getRoot() { - return root; - } - - public abstract void addVariableDeclaration(String variable, N context); - public abstract void addVariableDefinition(String variable, N context); - public abstract void addVariableUse(String variable, N context); - - public abstract boolean isVariableDeclared(String variable); - public abstract boolean isVariableDefined(String variable); - public abstract boolean isVariableUsed(String variable); - - public abstract List> getVariableDeclarations(String variable); - public abstract List> getVariableDefinitions(String variable); - public abstract List> getVariableUses(String variable); - - public abstract Set getDeclaredVariables(); - public abstract Set getDefinedVariables(); - public abstract Set getUsedVariables(); - - - public abstract List> getVariableUsesBeforeNode(String variable, N node); - - public abstract List> getFirstDefinitions(String variable); - public abstract List> getLastDefinitions(String variable); - public abstract List> getLastDefinitionsBeforeNode(String variable, N node); -} - diff --git a/src/main/java/tfm/scopes/ScopeHolder.java b/src/main/java/tfm/scopes/ScopeHolder.java deleted file mode 100644 index a5a4780..0000000 --- a/src/main/java/tfm/scopes/ScopeHolder.java +++ /dev/null @@ -1,183 +0,0 @@ -package tfm.scopes; - -import tfm.nodes.GraphNode; -import tfm.variables.actions.VariableDeclaration; -import tfm.variables.actions.VariableDefinition; -import tfm.variables.actions.VariableUse; - -import java.util.*; -import java.util.stream.Collectors; - -public class ScopeHolder extends Scope { - - private Queue> subscopes; - - public ScopeHolder(N root) { - super(root); - - subscopes = Collections.asLifoQueue(new ArrayDeque<>()); - } - - private Optional> getLastScope() { - if (subscopes.isEmpty()) - return Optional.empty(); - - return Optional.of(subscopes.peek()); - } - - @Override - public void addVariableDeclaration(String variable, N context) { - Optional> optionalScope = getLastScope(); - - boolean newScope = !optionalScope.isPresent(); - - Scope scope = optionalScope.orElse(new VariableScope<>(context)); - - scope.addVariableDeclaration(variable, context); - - if (newScope) { - addSubscope(scope); - } - } - - @Override - public void addVariableDefinition(String variable, N context) { - Optional> optionalScope = getLastScope(); - - boolean newScope = !optionalScope.isPresent(); - - Scope scope = optionalScope.orElse(new VariableScope<>(context)); - - scope.addVariableDefinition(variable, context); - - if (newScope) { - addSubscope(scope); - } - } - - @Override - public void addVariableUse(String variable, N context) { - Optional> optionalScope = getLastScope(); - - boolean newScope = !optionalScope.isPresent(); - - Scope scope = optionalScope.orElse(new VariableScope<>(context)); - - scope.addVariableUse(variable, context); - - if (newScope) { - addSubscope(scope); - } - } - - public Queue> getSubscopes() { - return subscopes; - } - - public void addSubscope(Scope subscope) { - subscopes.add(subscope); - } - - @Override - public boolean isVariableDeclared(String variable) { - return subscopes.stream().anyMatch(subscope -> subscope.isVariableDeclared(variable)); - } - - @Override - public boolean isVariableDefined(String variable) { - return subscopes.stream().anyMatch(subscope -> subscope.isVariableDefined(variable)); - } - - @Override - public boolean isVariableUsed(String variable) { - return subscopes.stream().anyMatch(subscope -> subscope.isVariableUsed(variable)); - } - - @Override - public List> getVariableDeclarations(String variable) { - return subscopes.stream() - .flatMap(scope -> scope.getVariableDeclarations(variable).stream()) - .collect(Collectors.toList()); - } - - @Override - public List> getVariableDefinitions(String variable) { - return subscopes.stream() - .flatMap(scope -> scope.getVariableDefinitions(variable).stream()) - .collect(Collectors.toList()); - } - - @Override - public List> getVariableUses(String variable) { - return subscopes.stream() - .flatMap(scope -> scope.getVariableUses(variable).stream()) - .collect(Collectors.toList()); - } - - @Override - public Set getDeclaredVariables() { - return subscopes.stream() - .flatMap(scope -> scope.getDeclaredVariables().stream()) - .collect(Collectors.toSet()); - } - - @Override - public Set getDefinedVariables() { - return subscopes.stream() - .flatMap(scope -> scope.getDefinedVariables().stream()) - .collect(Collectors.toSet()); - } - - @Override - public Set getUsedVariables() { - return subscopes.stream() - .flatMap(scope -> scope.getUsedVariables().stream()) - .collect(Collectors.toSet()); - } - - @Override - public List> getVariableUsesBeforeNode(String variable, N node) { - return subscopes.stream() - .filter(_scope -> _scope.isVariableUsed(variable) && _scope.root.getId() <= node.getId()) - .flatMap(scope -> scope.getVariableUsesBeforeNode(variable, node).stream()) - .collect(Collectors.toList()); - } - - @Override - public List> getFirstDefinitions(String variable) { - Optional> scope = subscopes.stream() - .filter(_scope -> _scope.isVariableDefined(variable)) - .reduce((first, second) -> second); - - if (!scope.isPresent()) - return new ArrayList<>(0); - - return scope.get().getFirstDefinitions(variable); - } - - @Override - public List> getLastDefinitions(String variable) { - Optional> scope = subscopes.stream() - .filter(_scope -> _scope.isVariableDefined(variable)) - .findFirst(); - - if (!scope.isPresent()) - return new ArrayList<>(0); - - return scope.get().getLastDefinitions(variable); - } - - @Override - public List> getLastDefinitionsBeforeNode(String variable, N node) { - Optional> scope = subscopes.stream() - .filter(_scope -> _scope.isVariableDefined(variable) && _scope.root.getId() <= node.getId()) - .findFirst(); - - if (!scope.isPresent()) - return new ArrayList<>(0); - - return scope.get().getLastDefinitions(variable); - } - - -} diff --git a/src/main/java/tfm/scopes/VariableScope.java b/src/main/java/tfm/scopes/VariableScope.java deleted file mode 100644 index d8af5df..0000000 --- a/src/main/java/tfm/scopes/VariableScope.java +++ /dev/null @@ -1,156 +0,0 @@ -package tfm.scopes; - -import tfm.nodes.GraphNode; -import tfm.variables.actions.VariableAction; -import tfm.variables.actions.VariableDeclaration; -import tfm.variables.actions.VariableDefinition; -import tfm.variables.actions.VariableUse; - -import java.util.*; - -public class VariableScope extends Scope { - - private Map>> variableDeclarations; - private Map>> variableDefinitions; - private Map>> variableUses; - - public VariableScope(N root) { - super(root); - - variableDeclarations = new HashMap<>(); - variableDefinitions = new HashMap<>(); - variableUses = new HashMap<>(); - } - - @Override - public boolean isVariableDeclared(String variable) { - return variableDeclarations.containsKey(variable); - } - - @Override - public boolean isVariableDefined(String variable) { - return variableDefinitions.containsKey(variable); - } - - @Override - public boolean isVariableUsed(String variable) { - return variableUses.containsKey(variable); - } - - @Override - public List> getVariableDeclarations(String variable) { - return new ArrayList<>(variableDeclarations.getOrDefault(variable, new ArrayList<>())); - } - - @Override - public List> getVariableDefinitions(String variable) { - return new ArrayList<>(variableDefinitions.getOrDefault(variable, new ArrayList<>())); - } - - @Override - public List> getVariableUses(String variable) { - return new ArrayList<>(variableUses.getOrDefault(variable, new ArrayList<>())); - } - - @Override - public Set getDeclaredVariables() { - return new HashSet<>(variableDeclarations.keySet()); - } - - @Override - public Set getDefinedVariables() { - return new HashSet<>(variableDefinitions.keySet()); - } - - @Override - public Set getUsedVariables() { - return new HashSet<>(variableUses.keySet()); - } - - @Override - public List> getVariableUsesBeforeNode(String variable, N node) { - List> res = getVariableUses(variable); - - if (res.isEmpty()) - return res; - - return res.stream() - .filter(variableUse -> variableUse.getNode().getId() <= node.getId()) - .max(Comparator.comparingInt(variableUse -> variableUse.getNode().getId())) - .map(variableUse -> new ArrayList<>(Collections.singletonList(variableUse))) - .orElseGet(ArrayList::new); - } - - @Override - public List> getFirstDefinitions(String variable) { - List> res = getVariableDefinitions(variable); - - if (res.isEmpty()) - return res; - - return res.subList(0, 1); - } - - @Override - public List> getLastDefinitions(String variable) { - List> res = getVariableDefinitions(variable); - - if (res.isEmpty()) - return res; - - return res.subList(res.size() - 1, res.size()); - } - - @Override - public List> getLastDefinitionsBeforeNode(String variable, N node) { - List> res = getVariableDefinitions(variable); - - if (res.isEmpty()) - return res; - - return res.stream() - .filter(variableDefinition -> variableDefinition.getNode().getId() <= node.getId()) - .max(Comparator.comparingInt(variableDefinition -> variableDefinition.getNode().getId())) - .map(variableDefinition -> new ArrayList<>(Collections.singletonList(variableDefinition))) - .orElseGet(ArrayList::new); - } - - @Override - public void addVariableDeclaration(String variable, N context) { - appendValue(variableDeclarations, variable, new VariableDeclaration<>(variable, context)); - } - - @Override - public void addVariableDefinition(String variable, N context) { - appendValue(variableDefinitions, variable, new VariableDefinition<>(variable, context)); - } - - @Override - public void addVariableUse(String variable, N context) { - appendValue(variableUses, variable, new VariableUse<>(variable, context)); - } - - private > void appendValue(Map> map, String variable, E action) { - List value = map.getOrDefault(variable, new ArrayList<>()); - - boolean exists = !value.isEmpty(); - - value.add(action); - - if (!exists) { - map.put(variable, value); - } - } - - private > void appendValues(Map> map, String variable, List actions) { - List value = map.getOrDefault(variable, new ArrayList<>()); - - boolean exists = !value.isEmpty(); - - value.addAll(actions); - - if (!exists) { - map.put(variable, value); - } - } -} -- GitLab From 95abb1585df67b161f3f330f46aaf0b6d78ec7a1 Mon Sep 17 00:00:00 2001 From: Javier Costa Date: Mon, 20 Jan 2020 02:53:03 +0100 Subject: [PATCH 12/27] Using JGraphT, removed all graphlib + cleaned + improved API --- pom.xml | 6 + src/main/java/tfm/arcs/Arc.java | 14 +- .../java/tfm/arcs/cfg/ControlFlowArc.java | 2 - .../tfm/arcs/pdg/ControlDependencyArc.java | 2 - src/main/java/tfm/exec/GraphLog.java | 24 +- src/main/java/tfm/exec/Main.java | 6 +- src/main/java/tfm/exec/PDGLog.java | 2 +- src/main/java/tfm/exec/SDGLog.java | 2 - .../java/tfm/graphbuilding/GraphOptions.java | 2 +- src/main/java/tfm/graphs/CFGGraph.java | 14 +- src/main/java/tfm/graphs/Graph.java | 140 ++++++++-- .../java/tfm/graphs/GraphWithRootNode.java | 32 +++ src/main/java/tfm/graphs/PDGGraph.java | 22 +- src/main/java/tfm/graphs/SDGGraph.java | 6 +- src/main/java/tfm/nodes/GraphNode.java | 72 ++--- src/main/java/tfm/nodes/MethodCallNode.java | 2 +- src/main/java/tfm/slicing/Slice.java | 2 +- src/main/java/tfm/utils/ASTUtils.java | 1 - src/main/java/tfm/utils/NodeFactory.java | 61 +++++ .../java/tfm/validation/PDGValidator.java | 2 +- .../java/tfm/visitors/cfg/CFGBuilder.java | 58 ++-- .../pdg/ControlDependencyBuilder.java | 21 +- .../java/tfm/visitors/pdg/PDGBuilder.java | 22 +- .../java/tfm/visitors/pdg/PDGVisitor.java | 253 ------------------ .../tfm/visitors/sdg/MethodCallReplacer.java | 3 - .../java/tfm/visitors/sdg/NewSDGBuilder.java | 1 - .../java/tfm/visitors/sdg/SDGBuilder.java | 12 +- 27 files changed, 343 insertions(+), 441 deletions(-) create mode 100644 src/main/java/tfm/graphs/GraphWithRootNode.java create mode 100644 src/main/java/tfm/utils/NodeFactory.java delete mode 100644 src/main/java/tfm/visitors/pdg/PDGVisitor.java diff --git a/pom.xml b/pom.xml index 2963592..c0aa410 100644 --- a/pom.xml +++ b/pom.xml @@ -41,5 +41,11 @@ 1.3.0 + + org.jgrapht + jgrapht-io + 1.3.0 + + \ No newline at end of file diff --git a/src/main/java/tfm/arcs/Arc.java b/src/main/java/tfm/arcs/Arc.java index 8a2be34..3f35cf5 100644 --- a/src/main/java/tfm/arcs/Arc.java +++ b/src/main/java/tfm/arcs/Arc.java @@ -1,6 +1,6 @@ package tfm.arcs; -import org.jgrapht.graph.DefaultEdge;; +import org.jgrapht.graph.DefaultEdge; import tfm.nodes.GraphNode; import java.util.Objects; @@ -30,6 +30,10 @@ public abstract class Arc extends DefaultEdge { @Override public String toString() { + return toGraphvizRepresentation(); + } + + public String toGraphvizRepresentation() { GraphNode from = (GraphNode) getSource(); GraphNode to = (GraphNode) getTarget(); @@ -39,14 +43,10 @@ public abstract class Arc extends DefaultEdge { ); } - public String toGraphvizRepresentation() { - return toString(); - } - @Override public boolean equals(Object o) { - if (this != o) { - return false; + if (this == o) { + return true; } return Objects.equals(variable, ((Arc) o).variable); diff --git a/src/main/java/tfm/arcs/cfg/ControlFlowArc.java b/src/main/java/tfm/arcs/cfg/ControlFlowArc.java index 8cd15b0..ff78a8d 100644 --- a/src/main/java/tfm/arcs/cfg/ControlFlowArc.java +++ b/src/main/java/tfm/arcs/cfg/ControlFlowArc.java @@ -1,8 +1,6 @@ package tfm.arcs.cfg; import tfm.arcs.Arc; -import tfm.arcs.data.VoidArcData; -import tfm.nodes.GraphNode; public class ControlFlowArc extends Arc { diff --git a/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java b/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java index 501e5f4..85a233a 100644 --- a/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java +++ b/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java @@ -1,8 +1,6 @@ package tfm.arcs.pdg; import tfm.arcs.Arc; -import tfm.arcs.data.ArcData; -import tfm.nodes.GraphNode; public class ControlDependencyArc extends Arc { diff --git a/src/main/java/tfm/exec/GraphLog.java b/src/main/java/tfm/exec/GraphLog.java index a3d38fa..d08b499 100644 --- a/src/main/java/tfm/exec/GraphLog.java +++ b/src/main/java/tfm/exec/GraphLog.java @@ -1,11 +1,20 @@ package tfm.exec; import com.github.javaparser.ast.Node; +import org.jgrapht.io.ComponentNameProvider; +import org.jgrapht.io.DOTExporter; +import org.jgrapht.io.ExportException; +import org.jgrapht.io.GraphExporter; +import tfm.arcs.Arc; import tfm.graphs.Graph; +import tfm.nodes.GraphNode; import tfm.utils.FileUtil; import tfm.utils.Logger; -import java.io.*; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Writer; public abstract class GraphLog { public enum Format { @@ -73,8 +82,19 @@ public abstract class GraphLog { generated = true; File tmpDot = File.createTempFile("graph-source-", ".dot"); tmpDot.deleteOnExit(); + try (Writer w = new FileWriter(tmpDot)) { - w.write(graph.toGraphvizRepresentation()); +// w.write(graph.toGraphvizRepresentation()); + + // JGraphT DOT export + GraphExporter, Arc> exporter = new DOTExporter<>( + component -> String.valueOf(component.getId()), + GraphNode::getInstruction, + component -> component.getVariable().orElse("")); + + exporter.exportGraph(graph, w); + } catch (ExportException e) { + e.printStackTrace(); } ProcessBuilder pb = new ProcessBuilder("dot", tmpDot.getAbsolutePath(), "-T" + format.getExt(), diff --git a/src/main/java/tfm/exec/Main.java b/src/main/java/tfm/exec/Main.java index 9532105..963e00f 100644 --- a/src/main/java/tfm/exec/Main.java +++ b/src/main/java/tfm/exec/Main.java @@ -13,7 +13,7 @@ import java.util.Optional; public class Main { - public static final String PROGRAM = Utils.PROGRAMS_FOLDER + "sdg/Example1.java"; + public static final String PROGRAM = Utils.PROGRAMS_FOLDER + "cfg/Eval_4.java"; public static final String GRAPH = GraphLog.SDG; public static final String METHOD = "main"; @@ -45,6 +45,10 @@ public class Main { long tt = tf - t0; + graphLog.graph.modifyNode(12, node -> { + node.setInstruction("hahhdh"); + }); + graphLog.log(); graphLog.openVisualRepresentation(); diff --git a/src/main/java/tfm/exec/PDGLog.java b/src/main/java/tfm/exec/PDGLog.java index a712abe..099daa6 100644 --- a/src/main/java/tfm/exec/PDGLog.java +++ b/src/main/java/tfm/exec/PDGLog.java @@ -29,7 +29,7 @@ public class PDGLog extends GraphLog { public void visit(com.github.javaparser.ast.Node node) { this.graph = new PDGGraph(); - node.accept(new PDGBuilder(graph), this.graph.getRootNode()); + node.accept(new PDGBuilder(graph), null); if (cfgLog == null) { cfgLog = new CFGLog(graph.getCfgGraph()); diff --git a/src/main/java/tfm/exec/SDGLog.java b/src/main/java/tfm/exec/SDGLog.java index b88de54..16978ae 100644 --- a/src/main/java/tfm/exec/SDGLog.java +++ b/src/main/java/tfm/exec/SDGLog.java @@ -4,8 +4,6 @@ import com.github.javaparser.ast.Node; import tfm.graphs.SDGGraph; import tfm.visitors.sdg.SDGBuilder; -import java.io.IOException; - public class SDGLog extends GraphLog { @Override diff --git a/src/main/java/tfm/graphbuilding/GraphOptions.java b/src/main/java/tfm/graphbuilding/GraphOptions.java index 2884f49..b7d2486 100644 --- a/src/main/java/tfm/graphbuilding/GraphOptions.java +++ b/src/main/java/tfm/graphbuilding/GraphOptions.java @@ -45,7 +45,7 @@ class PDGOptions extends GraphOptions { @Override protected void buildGraphWithSpecificVisitor(PDGGraph emptyGraph, Node node) { - node.accept(new PDGBuilder(emptyGraph), emptyGraph.getRootNode()); + node.accept(new PDGBuilder(emptyGraph), null); } } diff --git a/src/main/java/tfm/graphs/CFGGraph.java b/src/main/java/tfm/graphs/CFGGraph.java index f1e7acb..fb706e0 100644 --- a/src/main/java/tfm/graphs/CFGGraph.java +++ b/src/main/java/tfm/graphs/CFGGraph.java @@ -1,7 +1,7 @@ package tfm.graphs; import com.github.javaparser.ast.Node; -import edg.graphlib.Arrow; +import com.github.javaparser.ast.stmt.EmptyStmt; import tfm.arcs.Arc; import tfm.arcs.cfg.ControlFlowArc; import tfm.nodes.GraphNode; @@ -14,23 +14,19 @@ import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; -public class CFGGraph extends Graph { +public class CFGGraph extends GraphWithRootNode { public CFGGraph() { super(); } @Override - public GraphNode addNode(String instruction, ASTNode node) { - GraphNode vertex = new GraphNode<>(getNextVertexId(), instruction, node); - this.addVertex(vertex); - - return vertex; + protected GraphNode buildRootNode() { + return new GraphNode<>(getNextVertexId(), "Start", new EmptyStmt()); } - @SuppressWarnings("unchecked") public void addControlFlowEdge(GraphNode from, GraphNode to) { - super.addEdge(from, to); + super.addEdge(from, to, new ControlFlowArc()); } @Override diff --git a/src/main/java/tfm/graphs/Graph.java b/src/main/java/tfm/graphs/Graph.java index e337690..2c820ef 100644 --- a/src/main/java/tfm/graphs/Graph.java +++ b/src/main/java/tfm/graphs/Graph.java @@ -1,12 +1,17 @@ package tfm.graphs; import com.github.javaparser.ast.Node; +import com.github.javaparser.ast.stmt.Statement; +import org.checkerframework.checker.nullness.qual.NonNull; import org.jgrapht.graph.DefaultDirectedGraph; import tfm.arcs.Arc; import tfm.nodes.GraphNode; import tfm.slicing.SlicingCriterion; +import tfm.utils.NodeFactory; +import tfm.variables.VariableExtractor; import java.util.*; +import java.util.function.Consumer; import java.util.stream.Collectors; /** @@ -27,7 +32,7 @@ public abstract class Graph extends DefaultDirectedGraph, Arc> { } private GraphNode addNode(int id, String instruction, ASTNode node) { - GraphNode newNode = new GraphNode<>(id, instruction, node); + GraphNode newNode = NodeFactory.graphNode(id, instruction, node); return this.addNode(newNode); } @@ -40,31 +45,26 @@ public abstract class Graph extends DefaultDirectedGraph, Arc> { * Adds the given node to the graph. * * One must be careful with this method, as the given node will have - * an id and arcs corresponding to the graph in which it was created, and may not fit + * an id corresponding to the graph in which it was created, and may not fit * in the current graph. * * @param node the node to add to the graph - * @param copyId whether to copy the id node or not - * @param copyArcs whether to copy the arcs of the node or not + * @param copyId whether to copy the node id or generate a new one * @return the node instance added to the graph */ - public GraphNode addNode(GraphNode node, boolean copyId, boolean copyArcs) { - GraphNode res = node; - - if (copyId && copyArcs) { - this.addVertex(node); - } else if (copyId) { - res = this.addNode(node.getId(), node.getInstruction(), node.getAstNode()); - } else if (copyArcs) { - res = new GraphNode<>(node); - res.setId(getNextVertexId()); - - this.addVertex(res); - } else { - res = this.addNode(node.getInstruction(), node.getAstNode()); - } - - return res; + public GraphNode addNode(GraphNode node, boolean copyId) { + GraphNode copy = NodeFactory.computedGraphNode( + copyId ? node.getId() : getNextVertexId(), + node.getInstruction(), + node.getAstNode(), + node.getDeclaredVariables(), + node.getDefinedVariables(), + node.getUsedVariables() + ); + + this.addVertex(copy); + + return copy; } @SuppressWarnings("unchecked") @@ -117,4 +117,102 @@ public abstract class Graph extends DefaultDirectedGraph, Arc> { .filter(node -> node.getDeclaredVariables().contains(variable)) .collect(Collectors.toList()); } + + public boolean isEmpty() { + return this.getNodes().size() == 0; + } + + /** + * Modifies a current node in the graph by the changes done in the MutableGraphNode instance + * inside the function passed as parameter + * + * @param id the id of the node to be modified + * @param modifyFn a consumer which takes a MutableGraphNode as parameter + */ + public void modifyNode(int id, Consumer> modifyFn) { + this.findNodeById(id).ifPresent(node -> { + Set incomingArcs = new HashSet<>(incomingEdgesOf(node)); + Set outgoingArcs = new HashSet<>(outgoingEdgesOf(node)); + + this.removeNode(node); + + MutableGraphNode modifiedNode = new MutableGraphNode<>((GraphNode) node); + + modifyFn.accept(modifiedNode); + + GraphNode newNode = modifiedNode.toGraphNode(); + + this.addVertex(newNode); + + for (Arc incomingArc : incomingArcs) { + GraphNode from = getEdgeSource(incomingArc); + this.addEdge(from, newNode, incomingArc); + } + + for (Arc outgoingArc : outgoingArcs) { + GraphNode to = getEdgeTarget(outgoingArc); + this.addEdge(newNode, to, outgoingArc); + } + }); + } + + public static class MutableGraphNode { + private int id; + private String instruction; + private ASTNode astNode; + private Set declaredVariables; + private Set definedVariables; + private Set usedVariables; + + private boolean mustCompute; + + MutableGraphNode(GraphNode node) { + this.id = node.getId(); + this.instruction = node.getInstruction(); + this.astNode = node.getAstNode(); + this.declaredVariables = node.getDeclaredVariables(); + this.definedVariables = node.getDefinedVariables(); + this.usedVariables = node.getUsedVariables(); + } + + GraphNode toGraphNode() { + return mustCompute + ? NodeFactory.graphNode(id, instruction, astNode) + : NodeFactory.computedGraphNode( + id, + instruction, + astNode, + declaredVariables, + definedVariables, + usedVariables + ); + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getInstruction() { + return instruction; + } + + public void setInstruction(String instruction) { + this.instruction = instruction; + } + + public ASTNode getAstNode() { + return astNode; + } + + public void setAstNode(ASTNode astNode) { + this.astNode = astNode; + + // If the AST node changes, we need to compute all variables for it + mustCompute = true; + } + } } diff --git a/src/main/java/tfm/graphs/GraphWithRootNode.java b/src/main/java/tfm/graphs/GraphWithRootNode.java new file mode 100644 index 0000000..d80c776 --- /dev/null +++ b/src/main/java/tfm/graphs/GraphWithRootNode.java @@ -0,0 +1,32 @@ +package tfm.graphs; + +import tfm.nodes.GraphNode; + +import java.util.Objects; + +public abstract class GraphWithRootNode extends Graph { + + protected GraphNode rootNode; + + public GraphWithRootNode() { + super(); + + this.rootNode = buildRootNode(); + this.addVertex(rootNode); + } + + protected abstract GraphNode buildRootNode(); + + public GraphNode getRootNode() { + return rootNode; + } + + @Override + public boolean removeVertex(GraphNode graphNode) { + if (Objects.equals(graphNode, rootNode)) { + return false; + } + + return super.removeVertex(graphNode); + } +} diff --git a/src/main/java/tfm/graphs/PDGGraph.java b/src/main/java/tfm/graphs/PDGGraph.java index d163a8f..3e90520 100644 --- a/src/main/java/tfm/graphs/PDGGraph.java +++ b/src/main/java/tfm/graphs/PDGGraph.java @@ -2,7 +2,6 @@ package tfm.graphs; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.MethodDeclaration; -import edg.graphlib.Arrow; import org.jetbrains.annotations.NotNull; import tfm.arcs.Arc; import tfm.arcs.pdg.ControlDependencyArc; @@ -17,7 +16,7 @@ import tfm.visitors.pdg.PDGBuilder; import java.util.*; import java.util.stream.Collectors; -public class PDGGraph extends Graph { +public class PDGGraph extends GraphWithRootNode { private CFGGraph cfgGraph; @@ -25,23 +24,18 @@ public class PDGGraph extends Graph { super(); } + @Override + protected GraphNode buildRootNode() { + return new GraphNode<>(getNextVertexId(), "ENTER", new MethodDeclaration()); + } + public PDGGraph(CFGGraph cfgGraph) { super(); this.cfgGraph = cfgGraph; } - public GraphNode getRootNode() { - Iterator> iterator = this.getNodesAtLevel(0).iterator(); - - if (iterator.hasNext()) { - return iterator.next(); - } - - return null; - } - public void addControlDependencyArc(GraphNode from, GraphNode to) { - this.addEdge(from, to); + this.addEdge(from, to, new ControlDependencyArc()); } public void addDataDependencyArc(GraphNode from, GraphNode to, String variable) { @@ -169,7 +163,7 @@ public class PDGGraph extends Graph { Node astCopy = ASTUtils.cloneAST(node.getAstNode()); - astCopy.accept(new PDGBuilder(sliceGraph), sliceGraph.getNodesAtLevel(0).iterator().next()); + astCopy.accept(new PDGBuilder(sliceGraph), null); for (GraphNode sliceNode : sliceGraph.getNodes()) { if (!sliceNodes.contains(sliceNode.getId())) { diff --git a/src/main/java/tfm/graphs/SDGGraph.java b/src/main/java/tfm/graphs/SDGGraph.java index 4aa8752..1167e1a 100644 --- a/src/main/java/tfm/graphs/SDGGraph.java +++ b/src/main/java/tfm/graphs/SDGGraph.java @@ -1,6 +1,5 @@ package tfm.graphs; -import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.body.Parameter; import com.github.javaparser.ast.stmt.EmptyStmt; @@ -8,7 +7,10 @@ import tfm.nodes.GraphNode; import tfm.slicing.SlicingCriterion; import tfm.utils.Context; -import java.util.*; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; public class SDGGraph extends Graph { diff --git a/src/main/java/tfm/nodes/GraphNode.java b/src/main/java/tfm/nodes/GraphNode.java index b1ed794..a92cdf6 100644 --- a/src/main/java/tfm/nodes/GraphNode.java +++ b/src/main/java/tfm/nodes/GraphNode.java @@ -9,27 +9,20 @@ import tfm.variables.VariableExtractor; import java.util.*; +/** + * Immutable class that represents an AST node inside a CFG, PDG or SDG. + * + * @param the AST node that represents + */ public class GraphNode { - private int id; - private String instruction; + private final int id; + private final String instruction; + private final N astNode; - protected N astNode; - - protected Set declaredVariables; - protected Set definedVariables; - protected Set usedVariables; - - public > GraphNode(N1 node) { - this( - node.getId(), - node.getInstruction(), - node.getAstNode(), - node.getDeclaredVariables(), - node.getDefinedVariables(), - node.getUsedVariables() - ); - } + private final Set declaredVariables; + private final Set definedVariables; + private final Set usedVariables; public GraphNode(int id, String instruction, @NotNull N astNode) { this( @@ -40,49 +33,46 @@ public class GraphNode { Utils.emptySet(), Utils.emptySet() ); + + if (astNode instanceof Statement) { + extractVariables((Statement) astNode); + } } public GraphNode( int id, String instruction, @NonNull N astNode, - Set declaredVariables, - Set definedVariables, - Set usedVariables + Collection declaredVariables, + Collection definedVariables, + Collection usedVariables ) { this.id = id; this.instruction = instruction; this.astNode = astNode; - this.declaredVariables = declaredVariables; - this.definedVariables = definedVariables; - this.usedVariables = usedVariables; - - if (astNode instanceof Statement) { - extractVariables((Statement) astNode); - } + this.declaredVariables = new HashSet<>(declaredVariables); + this.definedVariables = new HashSet<>(definedVariables); + this.usedVariables = new HashSet<>(usedVariables); } private void extractVariables(@NonNull Statement statement) { new VariableExtractor() - .setOnVariableDeclarationListener(variable -> this.declaredVariables.add(variable)) - .setOnVariableDefinitionListener(variable -> this.definedVariables.add(variable)) - .setOnVariableUseListener(variable -> this.usedVariables.add(variable)) + .setOnVariableDeclarationListener(this.declaredVariables::add) + .setOnVariableDefinitionListener(this.definedVariables::add) + .setOnVariableUseListener(this.usedVariables::add) .visit(statement); } - public void setId(int id) { - this.id = id; - } - public int getId() { return id; } public String toString() { - return String.format("GraphNode{id: %s, instruction: '%s'}", + return String.format("GraphNode{id: %s, instruction: '%s', astNodeType: %s}", getId(), - getInstruction() + getInstruction(), + getAstNode().getClass().getSimpleName() ); } @@ -90,10 +80,6 @@ public class GraphNode { return astNode; } - public void setAstNode(N node) { - this.astNode = node; - } - public Optional getFileLineNumber() { return astNode.getBegin() .map(begin -> begin.line); @@ -152,8 +138,4 @@ public class GraphNode { public String getInstruction() { return instruction; } - - public void setInstruction(String instruction) { - this.instruction = instruction; - } } diff --git a/src/main/java/tfm/nodes/MethodCallNode.java b/src/main/java/tfm/nodes/MethodCallNode.java index 89ff4af..95f0479 100644 --- a/src/main/java/tfm/nodes/MethodCallNode.java +++ b/src/main/java/tfm/nodes/MethodCallNode.java @@ -14,7 +14,7 @@ public class MethodCallNode extends GraphNode { private List outParameters; public > MethodCallNode(N1 node) { - super(node); + super(node.getId(), node.getInstruction(), node.getAstNode()); this.inParameters = new ArrayList<>(); this.outParameters = new ArrayList<>(); diff --git a/src/main/java/tfm/slicing/Slice.java b/src/main/java/tfm/slicing/Slice.java index dca9284..15b4f50 100644 --- a/src/main/java/tfm/slicing/Slice.java +++ b/src/main/java/tfm/slicing/Slice.java @@ -22,7 +22,7 @@ public class Slice { PDGGraph pdgGraph = new PDGGraph(); - compilationUnit.accept(new PDGBuilder(pdgGraph), pdgGraph.getRootNode()); + compilationUnit.accept(new PDGBuilder(pdgGraph), null); Logger.log("=================="); Logger.log("= Starting slice ="); diff --git a/src/main/java/tfm/utils/ASTUtils.java b/src/main/java/tfm/utils/ASTUtils.java index a8e7031..0ec3b1b 100644 --- a/src/main/java/tfm/utils/ASTUtils.java +++ b/src/main/java/tfm/utils/ASTUtils.java @@ -1,6 +1,5 @@ package tfm.utils; -import com.github.javaparser.Position; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.NodeList; import com.github.javaparser.ast.stmt.BlockStmt; diff --git a/src/main/java/tfm/utils/NodeFactory.java b/src/main/java/tfm/utils/NodeFactory.java new file mode 100644 index 0000000..585fea7 --- /dev/null +++ b/src/main/java/tfm/utils/NodeFactory.java @@ -0,0 +1,61 @@ +package tfm.utils; + +import com.github.javaparser.ast.Node; +import tfm.nodes.GraphNode; + +import java.util.Collection; + +public class NodeFactory { + + /** + * Returns a computed GraphNode (i.e. a GraphNode with computed the + * declared, defined and used variables in its AST node) + * + * @param id the id of the node + * @param instruction the instruction that represents + * @param node the node of the AST that represents + * @param declaredVariables the set of declared variables + * @param definedVariables the set of defined variables + * @param usedVariables the set of used variables + * @param the type of the AST node + * @return a new GraphNode + */ + public static GraphNode computedGraphNode( + int id, + String instruction, + ASTNode node, + Collection declaredVariables, + Collection definedVariables, + Collection usedVariables + ) { + return new GraphNode<>( + id, + instruction, + node, + declaredVariables, + definedVariables, + usedVariables + ); + } + + /** + * Returns a GraphNode computing the declared, defined and used variables in its AST node + * + * @param id the id of the node + * @param instruction the instruction that represents + * @param node the node of the AST that represents + * @param the type of the AST node + * @return a new GraphNode + */ + public static GraphNode graphNode( + int id, + String instruction, + ASTNode node + ) { + return new GraphNode<>( + id, + instruction, + node + ); + } +} diff --git a/src/main/java/tfm/validation/PDGValidator.java b/src/main/java/tfm/validation/PDGValidator.java index 48cb5d8..f4d3f20 100644 --- a/src/main/java/tfm/validation/PDGValidator.java +++ b/src/main/java/tfm/validation/PDGValidator.java @@ -65,7 +65,7 @@ public class PDGValidator { public static boolean generateAndCheck(MethodDeclaration methodDeclaration) { PDGGraph graph = new PDGGraph(); - methodDeclaration.accept(new PDGBuilder(graph), graph.getRootNode()); + methodDeclaration.accept(new PDGBuilder(graph), null); return check(methodDeclaration, graph); } diff --git a/src/main/java/tfm/visitors/cfg/CFGBuilder.java b/src/main/java/tfm/visitors/cfg/CFGBuilder.java index 633aad8..7c74b95 100644 --- a/src/main/java/tfm/visitors/cfg/CFGBuilder.java +++ b/src/main/java/tfm/visitors/cfg/CFGBuilder.java @@ -15,8 +15,8 @@ public class CFGBuilder extends VoidVisitorAdapter { private CFGGraph graph; - private Queue lastParentNodes; - private List bodyBreaks; + private Queue> lastParentNodes; + private List> bodyBreaks; public CFGBuilder(CFGGraph graph) { this.graph = graph; @@ -33,25 +33,14 @@ public class CFGBuilder extends VoidVisitorAdapter { public void visit(ExpressionStmt expressionStmt, Void arg) { String expression = expressionStmt.toString().replace("\"", "\\\""); - GraphNode nextNode = addNodeAndArcs(expression, expressionStmt); + GraphNode nextNode = addNodeAndArcs(expression, expressionStmt); lastParentNodes.add(nextNode); } -// @Override -// public void visit(VariableDeclarationExpr variableDeclarationExpr, Void arg) { -// GraphNode nextNode = addNodeAndArcs(variableDeclarationExpr.toString()); -// -// lastParentNodes.add(nextNode); -// -// Logger.log(variableDeclarationExpr); -// -// super.visit(variableDeclarationExpr, arg); -// } - @Override public void visit(IfStmt ifStmt, Void arg) { - GraphNode ifCondition = addNodeAndArcs( + GraphNode ifCondition = addNodeAndArcs( String.format("if (%s)", ifStmt.getCondition().toString()), ifStmt ); @@ -61,7 +50,7 @@ public class CFGBuilder extends VoidVisitorAdapter { // Visit "then" ifStmt.getThenStmt().accept(this, arg); - Queue lastThenNodes = new ArrayDeque<>(lastParentNodes); + Queue> lastThenNodes = new ArrayDeque<>(lastParentNodes); if (ifStmt.hasElseBranch()) { lastParentNodes.clear(); @@ -77,7 +66,7 @@ public class CFGBuilder extends VoidVisitorAdapter { @Override public void visit(WhileStmt whileStmt, Void arg) { - GraphNode whileCondition = addNodeAndArcs( + GraphNode whileCondition = addNodeAndArcs( String.format("while (%s)", whileStmt.getCondition().toString()), whileStmt ); @@ -101,7 +90,7 @@ public class CFGBuilder extends VoidVisitorAdapter { body.accept(this, arg); - GraphNode doWhileNode = addNodeAndArcs( + GraphNode doWhileNode = addNodeAndArcs( String.format("while (%s)", doStmt.getCondition()), doStmt ); @@ -120,19 +109,10 @@ public class CFGBuilder extends VoidVisitorAdapter { @Override public void visit(ForStmt forStmt, Void arg) { -// String inizialization = forStmt.getInitialization().stream() -// .map(GraphNode::toString) -// .collect(Collectors.joining(",")); -// -// String update = forStmt.getUpdate().stream() -// .map(GraphNode::toString) -// .collect(Collectors.joining(",")); - Expression comparison = forStmt.getCompare().orElse(new BooleanLiteralExpr(true)); -// forStmt.getInitialization().forEach(expression -> new ExpressionStmt(expression).accept(this, null)); - GraphNode forNode = addNodeAndArcs( + GraphNode forNode = addNodeAndArcs( String.format("for (;%s;)", comparison), forStmt ); @@ -156,7 +136,7 @@ public class CFGBuilder extends VoidVisitorAdapter { @Override public void visit(ForEachStmt forEachStmt, Void arg) { - GraphNode foreachNode = addNodeAndArcs( + GraphNode foreachNode = addNodeAndArcs( String.format("for (%s : %s)", forEachStmt.getVariable(), forEachStmt.getIterable()), forEachStmt ); @@ -176,23 +156,23 @@ public class CFGBuilder extends VoidVisitorAdapter { @Override public void visit(SwitchStmt switchStmt, Void arg) { - GraphNode switchNode = addNodeAndArcs( + GraphNode switchNode = addNodeAndArcs( String.format("switch (%s)", switchStmt.getSelector()), switchStmt ); lastParentNodes.add(switchNode); - List allEntryBreaks = new ArrayList<>(); + List> allEntryBreaks = new ArrayList<>(); - List lastEntryStatementsWithNoBreak = new ArrayList<>(); + List> lastEntryStatementsWithNoBreak = new ArrayList<>(); switchStmt.getEntries().forEach(switchEntryStmt -> { String label = switchEntryStmt.getLabel() .map(expression -> "case " + expression) .orElse("default"); - GraphNode switchEntryNode = addNodeAndArcs(label, switchEntryStmt); + GraphNode switchEntryNode = addNodeAndArcs(label, switchEntryStmt); lastParentNodes.add(switchEntryNode); lastParentNodes.addAll(lastEntryStatementsWithNoBreak); @@ -226,14 +206,14 @@ public class CFGBuilder extends VoidVisitorAdapter { public void visit(ContinueStmt continueStmt, Void arg) { Statement continuableStatement = ASTUtils.findFirstAncestorStatementFrom(continueStmt, ASTUtils::isLoop); - GraphNode continuableNode = graph.findNodeByASTNode(continuableStatement).get(); + GraphNode continuableNode = graph.findNodeByASTNode(continuableStatement).get(); lastParentNodes.forEach(parentNode -> graph.addControlFlowEdge(parentNode, continuableNode)); } @Override public void visit(ReturnStmt returnStmt, Void arg) { - GraphNode node = addNodeAndArcs( + GraphNode node = addNodeAndArcs( returnStmt.toString(), returnStmt ); @@ -243,7 +223,7 @@ public class CFGBuilder extends VoidVisitorAdapter { @Override public void visit(MethodDeclaration methodDeclaration, Void arg) { - if (!lastParentNodes.isEmpty() && Objects.equals(lastParentNodes.peek().getData(), "Stop")) { + if (!lastParentNodes.isEmpty() && Objects.equals(lastParentNodes.peek().getInstruction(), "Stop")) { throw new IllegalStateException("CFG is only allowed for one method, not multiple!"); } @@ -252,10 +232,10 @@ public class CFGBuilder extends VoidVisitorAdapter { lastParentNodes.add(addNodeAndArcs("Stop", new EmptyStmt())); } - private GraphNode addNodeAndArcs(String nodeData, Statement statement) { - GraphNode node = graph.addNode(nodeData, statement); + private GraphNode addNodeAndArcs(String nodeData, Statement statement) { + GraphNode node = graph.addNode(nodeData, statement); - GraphNode parent = lastParentNodes.poll(); // ALWAYS exists a parent + GraphNode parent = lastParentNodes.poll(); // ALWAYS exists a parent graph.addControlFlowEdge(parent, node); while (!lastParentNodes.isEmpty()) { diff --git a/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java b/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java index 7ceab66..4a267ec 100644 --- a/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java +++ b/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java @@ -5,10 +5,12 @@ import com.github.javaparser.ast.visitor.VoidVisitorAdapter; import tfm.graphs.CFGGraph; import tfm.graphs.PDGGraph; import tfm.nodes.GraphNode; +import tfm.utils.Logger; +import java.util.Objects; import java.util.stream.Collectors; -public class ControlDependencyBuilder extends VoidVisitorAdapter { +public class ControlDependencyBuilder extends VoidVisitorAdapter> { private CFGGraph cfgGraph; private PDGGraph pdgGraph; @@ -25,7 +27,7 @@ public class ControlDependencyBuilder extends VoidVisitorAdapter { @Override public void visit(IfStmt ifStmt, GraphNode parent) { - GraphNode node = addNodeAndControlDependency(ifStmt, parent); + GraphNode node = addNodeAndControlDependency(ifStmt, parent); ifStmt.getThenStmt().accept(this, node); @@ -34,7 +36,7 @@ public class ControlDependencyBuilder extends VoidVisitorAdapter { @Override public void visit(WhileStmt whileStmt, GraphNode parent) { - GraphNode node = addNodeAndControlDependency(whileStmt, parent); + GraphNode node = addNodeAndControlDependency(whileStmt, parent); whileStmt.getBody().accept(this, node); } @@ -54,7 +56,7 @@ public class ControlDependencyBuilder extends VoidVisitorAdapter { .orElse("true"); - GraphNode forNode = pdgGraph.addNode( + GraphNode forNode = pdgGraph.addNode( String.format("for (%s;%s;%s)", initialization, compare, update), forStmt ); @@ -66,29 +68,28 @@ public class ControlDependencyBuilder extends VoidVisitorAdapter { @Override public void visit(ForEachStmt forEachStmt, GraphNode parent) { - GraphNode node = addNodeAndControlDependency(forEachStmt, parent); + GraphNode node = addNodeAndControlDependency(forEachStmt, parent); forEachStmt.getBody().accept(this, node); } @Override public void visit(SwitchStmt switchStmt, GraphNode parent) { - GraphNode node = addNodeAndControlDependency(switchStmt, parent); + GraphNode node = addNodeAndControlDependency(switchStmt, parent); switchStmt.getEntries().accept(this, node); } @Override public void visit(SwitchEntryStmt switchEntryStmt, GraphNode parent) { - GraphNode node = addNodeAndControlDependency(switchEntryStmt, parent); + GraphNode node = addNodeAndControlDependency(switchEntryStmt, parent); switchEntryStmt.getStatements().accept(this, node); } - private GraphNode addNodeAndControlDependency(Statement statement, GraphNode parent) { + private GraphNode addNodeAndControlDependency(Statement statement, GraphNode parent) { GraphNode cfgNode = cfgGraph.findNodeByASTNode(statement).get(); - - GraphNode node = pdgGraph.addNode(cfgNode.getData(), cfgNode.getAstNode()); + GraphNode node = pdgGraph.addNode(cfgNode.getInstruction(), cfgNode.getAstNode()); pdgGraph.addControlDependencyArc(parent, node); return node; diff --git a/src/main/java/tfm/visitors/pdg/PDGBuilder.java b/src/main/java/tfm/visitors/pdg/PDGBuilder.java index 37aff8c..1e59487 100644 --- a/src/main/java/tfm/visitors/pdg/PDGBuilder.java +++ b/src/main/java/tfm/visitors/pdg/PDGBuilder.java @@ -1,26 +1,19 @@ package tfm.visitors.pdg; -import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.stmt.BlockStmt; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; import tfm.graphs.CFGGraph; import tfm.graphs.PDGGraph; -import tfm.nodes.GraphNode; import tfm.visitors.cfg.CFGBuilder; -public class PDGBuilder extends VoidVisitorAdapter> { +public class PDGBuilder extends VoidVisitorAdapter { private PDGGraph pdgGraph; private CFGGraph cfgGraph; public PDGBuilder(PDGGraph pdgGraph) { - this(pdgGraph, new CFGGraph() { - @Override - protected String getRootNodeData() { - return "Start"; - } - }); + this(pdgGraph, new CFGGraph()); } public PDGBuilder(PDGGraph pdgGraph, CFGGraph cfgGraph) { @@ -30,12 +23,15 @@ public class PDGBuilder extends VoidVisitorAdapter> { this.pdgGraph.setCfgGraph(cfgGraph); } - public void visit(MethodDeclaration methodDeclaration, GraphNode parent) { + public void visit(MethodDeclaration methodDeclaration, Void empty) { if (!methodDeclaration.getBody().isPresent()) return; - // Assign the method declaration to the root node of the PDG graph - this.pdgGraph.getRootNode().setAstNode(methodDeclaration); + // Assign the method declaration to the root node of the PDG graph. Here parent will always be the root node + this.pdgGraph.modifyNode(pdgGraph.getRootNode().getId(), mutableGraphNode -> { + mutableGraphNode.setInstruction("ENTER " + methodDeclaration.getNameAsString()); + mutableGraphNode.setAstNode(methodDeclaration); + }); BlockStmt methodBody = methodDeclaration.getBody().get(); @@ -44,7 +40,7 @@ public class PDGBuilder extends VoidVisitorAdapter> { // Build control dependency ControlDependencyBuilder controlDependencyBuilder = new ControlDependencyBuilder(pdgGraph, cfgGraph); - methodBody.accept(controlDependencyBuilder, parent); + methodBody.accept(controlDependencyBuilder, pdgGraph.getRootNode()); // Build data dependency DataDependencyBuilder dataDependencyBuilder = new DataDependencyBuilder(pdgGraph, cfgGraph); diff --git a/src/main/java/tfm/visitors/pdg/PDGVisitor.java b/src/main/java/tfm/visitors/pdg/PDGVisitor.java deleted file mode 100644 index 6599e2e..0000000 --- a/src/main/java/tfm/visitors/pdg/PDGVisitor.java +++ /dev/null @@ -1,253 +0,0 @@ -package tfm.visitors.pdg; - -import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import tfm.nodes.GraphNode; -import tfm.scopes.ScopeHolder; - -@Deprecated -public class PDGVisitor extends VoidVisitorAdapter>> { - -// private VariableSet variableSet; - -// protected PDGGraph graph; -// protected ScopeHolder globalScope; -// -// public PDGVisitor(PDGGraph graph, ScopeHolder scopeHolder) { -// this.graph = graph; -// this.globalScope = scopeHolder; -// } -// -// @Override -// public void visit(ExpressionStmt n, ScopeHolder scope) { -// Expression expression = n.getExpression(); -// -// PDGNode expressionNode = graph.addNode(expression.toString(), n); -// -// graph.addControlDependencyArc(scope.getRoot(), expressionNode); -// -// VariableScope expressionScope = new VariableScope<>(expressionNode); -// -// new VariableExtractor() -// .setOnVariableDeclarationListener(variable -> -// expressionScope.addVariableDeclaration(variable, expressionNode) -// ).setOnVariableDefinitionListener(variable -> -// expressionScope.addVariableDefinition(variable, expressionNode) -// ).setOnVariableUseListener(variable -> { -// expressionScope.addVariableUse(variable, expressionNode); -// -// Scope searchScope = scope.isVariableDefined(variable) ? scope : globalScope; -// -// searchScope.getLastDefinitions(variable) -// .forEach(variableDefinition -> graph.addDataDependencyArc( -// variableDefinition.getNode(), -// expressionNode, -// variable -// )); -// }) -// .visit(expression); -// -// scope.addSubscope(expressionScope); -// } -// -// @Override -// public void visit(IfStmt ifStmt, ScopeHolder scope) { -// PDGNode ifNode = graph.addNode( -// String.format("if (%s)", ifStmt.getCondition().toString()), -// ifStmt -// ); -// -// graph.addControlDependencyArc(scope.getRoot(), ifNode); -// -// ScopeHolder ifScope = ifStmt.hasElseBranch() ? new IfElseScope<>(ifNode) : new ScopeHolder<>(ifNode); -// -// new VariableExtractor() -// .setOnVariableUseListener(variable -> { -// ifScope.addVariableUse(variable, ifNode); -// -// Scope searchScope = scope.isVariableDefined(variable) ? scope : globalScope; -// -// searchScope.getLastDefinitions(variable) -// .forEach(variableDefinition -> -// graph.addDataDependencyArc( -// variableDefinition.getNode(), -// ifNode, -// variable -// ) -// ); -// }) -// .visit(ifStmt.getCondition()); -// -// if (!ifStmt.hasElseBranch()) { -// ifStmt.getThenStmt().accept(this, ifScope); -// } else { -// @SuppressWarnings("unchecked") -// IfElseScope ifElseScope = (IfElseScope) ifScope; -// -// ifStmt.getThenStmt().accept(this, ifElseScope.getThenScope()); -// ifStmt.getElseStmt().get().accept(this, ifElseScope.getElseScope()); -// } -// -// scope.addSubscope(ifScope); -// } -// -// @Override -// public void visit(WhileStmt whileStmt, ScopeHolder scope) { -// // assert whileStmt.getBegin().isPresent(); -// -// PDGNode whileNode = graph.addNode( -// String.format("while (%s)", whileStmt.getCondition().toString()), -// whileStmt -// ); -// -// graph.addControlDependencyArc(scope.getRoot(), whileNode); -// -// ScopeHolder whileScope = new ScopeHolder<>(whileNode); -// -// new VariableExtractor() -// .setOnVariableUseListener(variable -> { -// whileScope.addVariableUse(variable, whileNode); -// -// Scope searchScope = scope.isVariableDefined(variable) ? scope : globalScope; -// -// searchScope.getLastDefinitions(variable) -// .forEach(variableDefinition -> graph.addDataDependencyArc( -// variableDefinition.getNode(), -// whileNode, -// variable -// )); -// }) -// .visit(whileStmt.getCondition()); -// -// whileStmt.getBody().accept(this, whileScope); -// -// buildLoopDataDependencies(whileScope); -// -// scope.addSubscope(whileScope); -// } -// -// private void buildLoopDataDependencies(ScopeHolder scope) { -// scope.getDefinedVariables() -// .forEach(variable -> { -// List> firstDef = scope.getFirstDefinitions(variable); -// List> lastDef = scope.getLastDefinitions(variable); -// -// Set usesFromLastDef = new HashSet<>(); -// -// firstDef.forEach(variableDefinition -> { -// scope.getVariableUsesBeforeNode(variable, variableDefinition.getNode()) -// .forEach(use -> { -// if (!usesFromLastDef.contains(use.getNode().getId())) { -// lastDef.forEach(def -> graph.addDataDependencyArc( -// def.getNode(), -// use.getNode(), -// variable) -// ); -// -// usesFromLastDef.add(use.getNode().getId()); -// } -// }); -// }); -// }); -// } - -// @Override -// public void visit(ForStmt forStmt, PDGNode node) { -// // Add initialization nodes -// forStmt.getInitialization().stream() -// .map(expression -> graph.addNode(expression.toString())) -// .forEach(pdgVertex -> graph.addControlDependencyArc(parent, pdgVertex)); -// -// // Add condition node -// Expression condition = forStmt.getCompare().orElse(new BooleanLiteralExpr(true)); -// PDGNode conditionNode = graph.addNode(condition.toString()); -// -// graph.addControlDependencyArc(parent, conditionNode); -// -// // Visit for -// super.visit(forStmt, conditionNode); -// -// // Add update vertex -// forStmt.getUpdate().stream() -// .map(expression -> graph.addNode(expression.toString())) -// .forEach(pdgVertex -> graph.addControlDependencyArc(conditionNode, pdgVertex)); -// } - -// @Override -// public void visit(ForEachStmt forEachStmt, ScopeHolder scope) { -// // Initializer -// VariableDeclarationExpr iterator = new VariableDeclarationExpr( -// new VariableDeclarator( -// JavaParser.parseClassOrInterfaceType("Iterator"), -// "iterator", -// new ConditionalExpr( -// new MethodCallExpr( -// new MethodCallExpr( -// forEachStmt.getIterable(), -// "getClass" -// ), -// "isArray" -// ), -// new MethodCallExpr( -// new NameExpr("Arrays"), -// "asList", -// new NodeList<>( -// forEachStmt.getIterable() -// ) -// ), -// new CastExpr( -// JavaParser.parseClassOrInterfaceType("Iterable"), -// new CastExpr( -// JavaParser.parseClassOrInterfaceType("Object"), -// forEachStmt.getIterable() -// ) -// ) -// ) -// ) -// ); -// -// // Compare -// MethodCallExpr iteratorHasNext = new MethodCallExpr( -// new NameExpr("iterator"), -// "hasNext" -// ); -// -// // Body -// Type variableType = forEachStmt.getVariable().getCommonType(); -// String variableName = forEachStmt.getVariable().getVariables().get(0).getNameAsString(); -// -// BlockStmt foreachBody = Utils.blockWrapper(forEachStmt.getBody()); -// foreachBody.getStatements().addFirst( -// new ExpressionStmt( -// new VariableDeclarationExpr( -// new VariableDeclarator( -// variableType, -// variableName, -// new CastExpr( -// variableType, -// new MethodCallExpr( -// new NameExpr("iterator"), -// "next" -// ) -// ) -// ) -// ) -// ) -// ); -// -// new ForStmt(new NodeList<>(iterator), iteratorHasNext, new NodeList<>(), foreachBody) -// .accept(this, parent); - - -// } - -// @Override -// public void visit(SwitchStmt switchStmt, PDGNode node) { -// PDGNode switchNode = graph.addNode(switchStmt.toString()); -// -// graph.addControlDependencyArc(parent, switchNode); -// -// switchStmt.getSelector().accept(this, parent); -// switchStmt.getEntries() -// .forEach(switchEntryStmt -> switchEntryStmt.accept(this, switchNode)); -// } -} diff --git a/src/main/java/tfm/visitors/sdg/MethodCallReplacer.java b/src/main/java/tfm/visitors/sdg/MethodCallReplacer.java index 01b853f..93137fd 100644 --- a/src/main/java/tfm/visitors/sdg/MethodCallReplacer.java +++ b/src/main/java/tfm/visitors/sdg/MethodCallReplacer.java @@ -1,9 +1,6 @@ package tfm.visitors.sdg; -import com.github.javaparser.ast.body.MethodDeclaration; -import tfm.graphs.PDGGraph; import tfm.graphs.SDGGraph; -import tfm.utils.Context; public class MethodCallReplacer { diff --git a/src/main/java/tfm/visitors/sdg/NewSDGBuilder.java b/src/main/java/tfm/visitors/sdg/NewSDGBuilder.java index 8938632..3e81151 100644 --- a/src/main/java/tfm/visitors/sdg/NewSDGBuilder.java +++ b/src/main/java/tfm/visitors/sdg/NewSDGBuilder.java @@ -4,7 +4,6 @@ import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import javassist.expr.MethodCall; import tfm.graphbuilding.Graphs; import tfm.graphs.PDGGraph; import tfm.graphs.SDGGraph; diff --git a/src/main/java/tfm/visitors/sdg/SDGBuilder.java b/src/main/java/tfm/visitors/sdg/SDGBuilder.java index 9a51186..f2c85ff 100644 --- a/src/main/java/tfm/visitors/sdg/SDGBuilder.java +++ b/src/main/java/tfm/visitors/sdg/SDGBuilder.java @@ -46,13 +46,7 @@ public class SDGBuilder extends VoidVisitorAdapter { if (sdgGraph.isEmpty()) { - sdgGraph.setRootVertex( - new GraphNode<>( - 0, - "ENTER " + methodDeclaration.getNameAsString(), - methodDeclaration - ) - ); + sdgGraph.addNode("ENTER " + methodDeclaration.getNameAsString(), methodDeclaration); } else { // sdgGraph.addMethod(methodDeclaration); } @@ -61,7 +55,7 @@ public class SDGBuilder extends VoidVisitorAdapter { PDGBuilder PDGBuilder = new PDGBuilder(pdgGraph) { @Override - public void visit(MethodCallExpr methodCallExpr, GraphNode parent) { + public void visit(MethodCallExpr methodCallExpr, Void empty) { if (methodCallExpr.getScope().isPresent()) { String scopeName = methodCallExpr.getScope().get().toString(); @@ -117,7 +111,7 @@ public class SDGBuilder extends VoidVisitorAdapter { } }; - PDGBuilder.visit(methodDeclaration, pdgGraph.getRootNode()); + PDGBuilder.visit(methodDeclaration, null); sdgGraph.addNode(methodDeclaration.getNameAsString(), methodDeclaration); -- GitLab From 37705607f1e82ded8ee23046b805f004e5282c37 Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Mon, 20 Jan 2020 12:45:57 +0100 Subject: [PATCH 13/27] Fix dot generation --- src/main/java/tfm/visitors/cfg/CFGBuilder.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/tfm/visitors/cfg/CFGBuilder.java b/src/main/java/tfm/visitors/cfg/CFGBuilder.java index 7c74b95..25fa8c1 100644 --- a/src/main/java/tfm/visitors/cfg/CFGBuilder.java +++ b/src/main/java/tfm/visitors/cfg/CFGBuilder.java @@ -31,9 +31,7 @@ public class CFGBuilder extends VoidVisitorAdapter { @Override public void visit(ExpressionStmt expressionStmt, Void arg) { - String expression = expressionStmt.toString().replace("\"", "\\\""); - - GraphNode nextNode = addNodeAndArcs(expression, expressionStmt); + GraphNode nextNode = addNodeAndArcs(expressionStmt.toString(), expressionStmt); lastParentNodes.add(nextNode); } -- GitLab From 8f07088a63aebb9d35799f0b6e655a7070ce9048 Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Mon, 20 Jan 2020 13:22:32 +0100 Subject: [PATCH 14/27] Fixes DOT generation implementation. * Adds API `asXArc` and `isXArc` to Arc. * Adds Sliceable interface for graphs. * Removed old DOT methods (toGraphvizRepresentation) * Removed representation-related methods from graphs. * Removed unnecessary methods. --- pom.xml | 6 + src/main/java/tfm/arcs/Arc.java | 68 ++++++---- .../java/tfm/arcs/cfg/ControlFlowArc.java | 22 --- .../tfm/arcs/pdg/ControlDependencyArc.java | 25 ---- .../java/tfm/arcs/pdg/DataDependencyArc.java | 41 +++--- src/main/java/tfm/exec/GraphLog.java | 40 ++---- src/main/java/tfm/exec/Main.java | 4 - src/main/java/tfm/exec/PDGLog.java | 2 +- src/main/java/tfm/graphs/CFGGraph.java | 52 +------- src/main/java/tfm/graphs/Graph.java | 47 +++---- src/main/java/tfm/graphs/PDGGraph.java | 126 +----------------- src/main/java/tfm/graphs/SDGGraph.java | 18 +-- src/main/java/tfm/graphs/Sliceable.java | 7 + src/main/java/tfm/nodes/GraphNode.java | 11 -- .../java/tfm/slicing/LineNumberCriterion.java | 2 +- .../java/tfm/validation/PDGValidator.java | 33 ++--- .../pdg/ControlDependencyBuilder.java | 2 - .../java/tfm/visitors/sdg/SDGBuilder.java | 2 +- 18 files changed, 137 insertions(+), 371 deletions(-) create mode 100644 src/main/java/tfm/graphs/Sliceable.java diff --git a/pom.xml b/pom.xml index c0aa410..b99904e 100644 --- a/pom.xml +++ b/pom.xml @@ -47,5 +47,11 @@ 1.3.0 + + org.junit.jupiter + junit-jupiter + 5.5.2 + test + \ No newline at end of file diff --git a/src/main/java/tfm/arcs/Arc.java b/src/main/java/tfm/arcs/Arc.java index 3f35cf5..143c900 100644 --- a/src/main/java/tfm/arcs/Arc.java +++ b/src/main/java/tfm/arcs/Arc.java @@ -1,59 +1,79 @@ package tfm.arcs; import org.jgrapht.graph.DefaultEdge; +import org.jgrapht.io.Attribute; +import tfm.arcs.cfg.ControlFlowArc; +import tfm.arcs.pdg.ControlDependencyArc; +import tfm.arcs.pdg.DataDependencyArc; import tfm.nodes.GraphNode; +import java.util.HashMap; +import java.util.Map; import java.util.Objects; -import java.util.Optional; public abstract class Arc extends DefaultEdge { - - private String variable; - public Arc() { } - public Arc(String variable) { - this.variable = variable; + public final boolean isControlFlowArc() { + return this instanceof ControlFlowArc; } - public abstract boolean isControlFlowArrow(); + public final ControlFlowArc asControlFlowArc() { + if (isControlFlowArc()) + return (ControlFlowArc) this; + throw new UnsupportedOperationException("Not a ControlFlowArc"); + } - public abstract boolean isControlDependencyArrow(); + public final boolean isControlDependencyArc() { + return this instanceof ControlDependencyArc; + } - public abstract boolean isDataDependencyArrow(); + public final ControlDependencyArc asControlDependencyArc() { + if (isControlDependencyArc()) + return (ControlDependencyArc) this; + throw new UnsupportedOperationException("Not a ControlDependencyArc"); + } - public Optional getVariable() { - return Optional.ofNullable(this.variable); + public final boolean isDataDependencyArc() { + return this instanceof DataDependencyArc; + } + + public final DataDependencyArc asDataDependencyArc() { + if (isDataDependencyArc()) + return (DataDependencyArc) this; + throw new UnsupportedOperationException("Not a DataDependencyArc"); } @Override public String toString() { - return toGraphvizRepresentation(); + return String.format("%s{%d -> %d}", getClass().getName(), + ((GraphNode) getSource()).getId(), ((GraphNode) getTarget()).getId()); } - public String toGraphvizRepresentation() { - GraphNode from = (GraphNode) getSource(); - GraphNode to = (GraphNode) getTarget(); + public String getLabel() { + return ""; + } - return String.format("%s -> %s", - from.getId(), - to.getId() - ); + public Map getDotAttributes() { + return new HashMap<>(); } @Override public boolean equals(Object o) { - if (this == o) { + if (this == o) return true; - } - - return Objects.equals(variable, ((Arc) o).variable); + if (o == null) + return false; + if (!o.getClass().equals(this.getClass())) + return false; + return Objects.equals(getSource(), ((Arc) o).getSource()) && + Objects.equals(getTarget(), ((Arc) o).getTarget()); } @Override public int hashCode() { - return Objects.hash(variable, getSource(), getTarget()); + return Objects.hash(getClass(), getSource(), getTarget()); } } diff --git a/src/main/java/tfm/arcs/cfg/ControlFlowArc.java b/src/main/java/tfm/arcs/cfg/ControlFlowArc.java index ff78a8d..5abdda3 100644 --- a/src/main/java/tfm/arcs/cfg/ControlFlowArc.java +++ b/src/main/java/tfm/arcs/cfg/ControlFlowArc.java @@ -3,28 +3,6 @@ package tfm.arcs.cfg; import tfm.arcs.Arc; public class ControlFlowArc extends Arc { - public ControlFlowArc() { } - - @Override - public boolean isControlFlowArrow() { - return true; - } - - @Override - public boolean isControlDependencyArrow() { - return false; - } - - @Override - public boolean isDataDependencyArrow() { - return false; - } - - @Override - public String toString() { - return String.format("ControlFlowArc{%s}", super.toString()); - } - } diff --git a/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java b/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java index 85a233a..914401e 100644 --- a/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java +++ b/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java @@ -3,31 +3,6 @@ package tfm.arcs.pdg; import tfm.arcs.Arc; public class ControlDependencyArc extends Arc { - - public ControlDependencyArc(String variable) { - super(variable); - } - public ControlDependencyArc() { } - - @Override - public boolean isControlFlowArrow() { - return false; - } - - @Override - public boolean isControlDependencyArrow() { - return true; - } - - @Override - public boolean isDataDependencyArrow() { - return false; - } - - @Override - public String toString() { - return String.format("ControlDependencyArc{%s}", super.toString()); - } } diff --git a/src/main/java/tfm/arcs/pdg/DataDependencyArc.java b/src/main/java/tfm/arcs/pdg/DataDependencyArc.java index 80b0996..9806f85 100644 --- a/src/main/java/tfm/arcs/pdg/DataDependencyArc.java +++ b/src/main/java/tfm/arcs/pdg/DataDependencyArc.java @@ -1,41 +1,30 @@ package tfm.arcs.pdg; +import org.jgrapht.io.Attribute; +import org.jgrapht.io.DefaultAttribute; import tfm.arcs.Arc; -public class DataDependencyArc extends Arc { - public DataDependencyArc() { - } +import java.util.Map; - public DataDependencyArc(String variable) { - super(variable); - } - - @Override - public boolean isControlFlowArrow() { - return false; - } - - @Override - public boolean isControlDependencyArrow() { - return false; - } +public class DataDependencyArc extends Arc { + private final String variable; - @Override - public boolean isDataDependencyArrow() { - return true; + public DataDependencyArc(String variable) { + super(); + this.variable = variable; } @Override - public String toString() { - return String.format("DataDependencyArc{%s}", super.toString()); + public String getLabel() { + return variable; } @Override - public String toGraphvizRepresentation() { - return String.format("%s [style=dashed, color=red%s];", - super.toGraphvizRepresentation(), - getVariable().map(variable -> String.format(", label=\"%s\"", variable)).orElse("") - ); + public Map getDotAttributes() { + Map map = super.getDotAttributes(); + map.put("style", DefaultAttribute.createAttribute("dashed")); + map.put("color", DefaultAttribute.createAttribute("red")); + return map; } } diff --git a/src/main/java/tfm/exec/GraphLog.java b/src/main/java/tfm/exec/GraphLog.java index d08b499..43f39ad 100644 --- a/src/main/java/tfm/exec/GraphLog.java +++ b/src/main/java/tfm/exec/GraphLog.java @@ -1,20 +1,11 @@ package tfm.exec; import com.github.javaparser.ast.Node; -import org.jgrapht.io.ComponentNameProvider; -import org.jgrapht.io.DOTExporter; -import org.jgrapht.io.ExportException; -import org.jgrapht.io.GraphExporter; -import tfm.arcs.Arc; import tfm.graphs.Graph; -import tfm.nodes.GraphNode; import tfm.utils.FileUtil; import tfm.utils.Logger; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.Writer; +import java.io.*; public abstract class GraphLog { public enum Format { @@ -64,8 +55,11 @@ public abstract class GraphLog { "* GRAPHVIZ *\n" + "****************************" ); - Logger.log(graph.toGraphvizRepresentation()); - Logger.log(); + try (StringWriter stringWriter = new StringWriter()) { + graph.getDOTExporter().exportGraph(graph, stringWriter); + stringWriter.append('\n'); + Logger.log(stringWriter.toString()); + } } public void generateImages() throws IOException { @@ -81,29 +75,21 @@ public abstract class GraphLog { this.format = format; generated = true; File tmpDot = File.createTempFile("graph-source-", ".dot"); - tmpDot.deleteOnExit(); + // Graph -> DOT -> file try (Writer w = new FileWriter(tmpDot)) { -// w.write(graph.toGraphvizRepresentation()); - - // JGraphT DOT export - GraphExporter, Arc> exporter = new DOTExporter<>( - component -> String.valueOf(component.getId()), - GraphNode::getInstruction, - component -> component.getVariable().orElse("")); - - exporter.exportGraph(graph, w); - } catch (ExportException e) { - e.printStackTrace(); + graph.getDOTExporter().exportGraph(graph, w); } + // Execute dot ProcessBuilder pb = new ProcessBuilder("dot", tmpDot.getAbsolutePath(), "-T" + format.getExt(), "-o", getImageFile().getAbsolutePath()); try { int result = pb.start().waitFor(); - if (result != 0) { - Logger.log("Image generation failed"); - } + if (result == 0) + tmpDot.deleteOnExit(); + else + Logger.log("Image generation failed, try running \"" + pb.toString() + "\" on your terminal."); } catch (InterruptedException e) { Logger.log("Image generation failed\n" + e.getMessage()); } diff --git a/src/main/java/tfm/exec/Main.java b/src/main/java/tfm/exec/Main.java index 963e00f..d604251 100644 --- a/src/main/java/tfm/exec/Main.java +++ b/src/main/java/tfm/exec/Main.java @@ -45,10 +45,6 @@ public class Main { long tt = tf - t0; - graphLog.graph.modifyNode(12, node -> { - node.setInstruction("hahhdh"); - }); - graphLog.log(); graphLog.openVisualRepresentation(); diff --git a/src/main/java/tfm/exec/PDGLog.java b/src/main/java/tfm/exec/PDGLog.java index 099daa6..d369fb5 100644 --- a/src/main/java/tfm/exec/PDGLog.java +++ b/src/main/java/tfm/exec/PDGLog.java @@ -41,7 +41,7 @@ public class PDGLog extends GraphLog { super.log(); Logger.log("Nodes with variable info"); - Logger.log(graph.getNodes().stream() + Logger.log(graph.vertexSet().stream() .sorted(Comparator.comparingInt(GraphNode::getId)) .map(node -> String.format("GraphNode { id: %s, declared: %s, defined: %s, used: %s }", diff --git a/src/main/java/tfm/graphs/CFGGraph.java b/src/main/java/tfm/graphs/CFGGraph.java index fb706e0..f21e4d8 100644 --- a/src/main/java/tfm/graphs/CFGGraph.java +++ b/src/main/java/tfm/graphs/CFGGraph.java @@ -1,18 +1,15 @@ package tfm.graphs; -import com.github.javaparser.ast.Node; import com.github.javaparser.ast.stmt.EmptyStmt; +import org.jgrapht.io.DOTExporter; import tfm.arcs.Arc; import tfm.arcs.cfg.ControlFlowArc; import tfm.nodes.GraphNode; -import tfm.slicing.SlicingCriterion; import tfm.utils.NodeNotFoundException; -import java.util.Comparator; import java.util.HashSet; import java.util.Objects; import java.util.Set; -import java.util.stream.Collectors; public class CFGGraph extends GraphWithRootNode { @@ -29,75 +26,32 @@ public class CFGGraph extends GraphWithRootNode { super.addEdge(from, to, new ControlFlowArc()); } - @Override - public String toGraphvizRepresentation() { - String lineSep = System.lineSeparator(); - - String nodes = getNodes().stream() - .sorted(Comparator.comparingInt(GraphNode::getId)) - .map(GraphNode::toGraphvizRepresentation) - .collect(Collectors.joining(lineSep)); - - String arrows = - getArcs().stream() - .sorted(Comparator.comparingInt(arc -> this.getEdgeSource(arc).getId())) - .map(Arc::toGraphvizRepresentation) - .collect(Collectors.joining(lineSep)); - - return "digraph g{" + lineSep + - nodes + lineSep + - arrows + lineSep + - "}"; - } - - @Override - public Graph slice(SlicingCriterion slicingCriterion) { - return this; - } - public Set> findLastDefinitionsFrom(GraphNode startNode, String variable) { -// Logger.log("======================================================="); -// Logger.log("Starting from " + startNode); -// Logger.log("Looking for variable " + variable); -// Logger.log(cfgGraph.toString()); - - if (!this.contains(startNode)) { + if (!this.containsVertex(startNode)) throw new NodeNotFoundException(startNode, this); - } - return findLastDefinitionsFrom(new HashSet<>(), startNode, startNode, variable); } private Set> findLastDefinitionsFrom(Set visited, GraphNode startNode, GraphNode currentNode, String variable) { visited.add(currentNode.getId()); -// Logger.log("On " + currentNode); - Set> res = new HashSet<>(); for (Arc arc : incomingEdgesOf(currentNode)) { - ControlFlowArc controlFlowArc = (ControlFlowArc) arc; + ControlFlowArc controlFlowArc = arc.asControlFlowArc(); GraphNode from = this.getEdgeSource(controlFlowArc); -// Logger.log("Arrow from node: " + from); - if (!Objects.equals(startNode, from) && visited.contains(from.getId())) { -// Logger.log("It's already visited. Continuing..."); continue; } if (from.getDefinedVariables().contains(variable)) { -// Logger.log("Contains defined variable: " + variable); res.add(from); } else { -// Logger.log("Doesn't contain the variable, searching inside it"); res.addAll(findLastDefinitionsFrom(visited, startNode, from, variable)); } } - -// Logger.format("Done with node %s", currentNode.getId()); - return res; } } diff --git a/src/main/java/tfm/graphs/Graph.java b/src/main/java/tfm/graphs/Graph.java index 2c820ef..fcd246e 100644 --- a/src/main/java/tfm/graphs/Graph.java +++ b/src/main/java/tfm/graphs/Graph.java @@ -1,14 +1,11 @@ package tfm.graphs; import com.github.javaparser.ast.Node; -import com.github.javaparser.ast.stmt.Statement; -import org.checkerframework.checker.nullness.qual.NonNull; import org.jgrapht.graph.DefaultDirectedGraph; +import org.jgrapht.io.DOTExporter; import tfm.arcs.Arc; import tfm.nodes.GraphNode; -import tfm.slicing.SlicingCriterion; import tfm.utils.NodeFactory; -import tfm.variables.VariableExtractor; import java.util.*; import java.util.function.Consumer; @@ -69,57 +66,47 @@ public abstract class Graph extends DefaultDirectedGraph, Arc> { @SuppressWarnings("unchecked") public Optional> findNodeByASTNode(ASTNode astNode) { - return getNodes().stream() + return vertexSet().stream() .filter(node -> Objects.equals(node.getAstNode(), astNode)) .findFirst() .map(node -> (GraphNode) node); } public Optional> findNodeById(int id) { - return getNodes().stream() + return vertexSet().stream() .filter(node -> Objects.equals(node.getId(), id)) .findFirst(); } - public Set> getNodes() { - return vertexSet(); - } - - public Set getArcs() { - return edgeSet(); - } - + @Override public String toString() { - return getNodes().stream() + return vertexSet().stream() .sorted(Comparator.comparingInt(GraphNode::getId)) .map(GraphNode::toString) .collect(Collectors.joining(System.lineSeparator())); } - public abstract String toGraphvizRepresentation(); - protected synchronized int getNextVertexId() { return nextVertexId++; } - public boolean contains(GraphNode graphNode) { - return super.containsVertex(graphNode); - } - - public abstract Graph slice(SlicingCriterion slicingCriterion); - - public void removeNode(GraphNode node) { - removeVertex(node); - } - public List> findDeclarationsOfVariable(String variable) { - return getNodes().stream() + return vertexSet().stream() .filter(node -> node.getDeclaredVariables().contains(variable)) .collect(Collectors.toList()); } public boolean isEmpty() { - return this.getNodes().size() == 0; + return this.vertexSet().isEmpty(); + } + + public DOTExporter, Arc> getDOTExporter() { + return new DOTExporter<>( + graphNode -> String.valueOf(graphNode.getId()), + GraphNode::getInstruction, + Arc::getLabel, + null, + Arc::getDotAttributes); } /** @@ -134,7 +121,7 @@ public abstract class Graph extends DefaultDirectedGraph, Arc> { Set incomingArcs = new HashSet<>(incomingEdgesOf(node)); Set outgoingArcs = new HashSet<>(outgoingEdgesOf(node)); - this.removeNode(node); + this.removeVertex(node); MutableGraphNode modifiedNode = new MutableGraphNode<>((GraphNode) node); diff --git a/src/main/java/tfm/graphs/PDGGraph.java b/src/main/java/tfm/graphs/PDGGraph.java index 3e90520..1cf2061 100644 --- a/src/main/java/tfm/graphs/PDGGraph.java +++ b/src/main/java/tfm/graphs/PDGGraph.java @@ -2,7 +2,7 @@ package tfm.graphs; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.MethodDeclaration; -import org.jetbrains.annotations.NotNull; +import org.jgrapht.io.DOTExporter; import tfm.arcs.Arc; import tfm.arcs.pdg.ControlDependencyArc; import tfm.arcs.pdg.DataDependencyArc; @@ -14,9 +14,8 @@ import tfm.utils.NodeNotFoundException; import tfm.visitors.pdg.PDGBuilder; import java.util.*; -import java.util.stream.Collectors; -public class PDGGraph extends GraphWithRootNode { +public class PDGGraph extends GraphWithRootNode implements Sliceable { private CFGGraph cfgGraph; @@ -42,95 +41,10 @@ public class PDGGraph extends GraphWithRootNode { this.addEdge(from, to, new DataDependencyArc(variable)); } - public Set> getNodesAtLevel(int level) { - return getNodes().stream() - .filter(node -> getLevelOf(node) == level) - .collect(Collectors.toSet()); - } - - public int getLevels() { - return getNodes().stream() - .max(Comparator.comparingInt(this::getLevelOf)) - .map(node -> getLevelOf(node) + 1) - .orElse(0); - } - - public int getLevelOf(int nodeId) { - return findNodeById(nodeId) - .map(this::getLevelOf) - .orElseThrow(() -> new NodeNotFoundException("Node with id " + nodeId + " not found in PDG graph")); - } - - public int getLevelOf(@NotNull GraphNode node) { - Optional optionalControlDependencyArc = incomingEdgesOf(node).stream() - .filter(Arc::isControlDependencyArrow) - .findFirst() - .map(arc -> (ControlDependencyArc) arc); - - if (!optionalControlDependencyArc.isPresent()) { - return 0; - } - - GraphNode parent = this.getEdgeSource(optionalControlDependencyArc.get()); - - return 1 + getLevelOf(parent); - } - public void setCfgGraph(CFGGraph cfgGraph) { this.cfgGraph = cfgGraph; } - @Override - public String toGraphvizRepresentation() { - String lineSep = System.lineSeparator(); - - String nodesDeclaration = getNodes().stream() - .sorted(Comparator.comparingInt(GraphNode::getId)) - .map(GraphNode::toGraphvizRepresentation) - .collect(Collectors.joining(lineSep)); - - StringBuilder rankedNodes = new StringBuilder(); - - // No level 0 is needed (only one node) - for (int i = 0; i < getLevels(); i++) { - Set> levelNodes = getNodesAtLevel(i); - - if (levelNodes.size() <= 1) { - continue; - } - - // rank same - rankedNodes.append("{ rank = same; ") - .append(levelNodes.stream() - .map(node -> String.valueOf(node.getId())) - .collect(Collectors.joining(";"))) - .append(" }") - .append(lineSep); - - // invisible arrows for ordering - rankedNodes.append(levelNodes.stream() - .sorted(Comparator.comparingInt(GraphNode::getId)) - .map(node -> String.valueOf(node.getId())) - .collect(Collectors.joining(" -> "))) - .append("[style = invis];") - .append(lineSep); - } - - String arrows = - getArcs().stream() - .sorted(Comparator.comparingInt(arc -> this.getEdgeSource(arc).getId())) - .map(Arc::toGraphvizRepresentation) - .collect(Collectors.joining(lineSep)); - - - return "digraph g{" + lineSep + - "splines=true;" + lineSep + - nodesDeclaration + lineSep + - arrows + lineSep + - rankedNodes.toString() + - "}"; - } - @Override public PDGGraph slice(SlicingCriterion slicingCriterion) { Optional> optionalGraphNode = slicingCriterion.findNode(this); @@ -141,21 +55,6 @@ public class PDGGraph extends GraphWithRootNode { GraphNode node = optionalGraphNode.get(); -// // DEPRECATED - Find CFGNode and find last definition of variable -// CFGNode cfgNode = this.cfgGraph.findNodeByASTNode(node.getAstNode()) -// .orElseThrow(() -> new NodeNotFoundException("CFGNode not found")); -// -// Set> definitionNodes = Utils.findLastDefinitionsFrom(cfgNode, slicingCriterion.getVariable()); -// -// Logger.format("Slicing node: %s", node); -// -// // Get slice nodes from definition nodes -// Set sliceNodes = definitionNodes.stream() -// .flatMap(definitionNode -> getSliceNodes(new HashSet<>(), this.findNodeByASTNode(definitionNode.getAstNode()).get()).stream()) -// .collect(Collectors.toSet()); -// -// sliceNodes.add(node.getId()); - // Simply get slice nodes from GraphNode Set sliceNodes = getSliceNodes(new HashSet<>(), node); @@ -165,31 +64,14 @@ public class PDGGraph extends GraphWithRootNode { astCopy.accept(new PDGBuilder(sliceGraph), null); - for (GraphNode sliceNode : sliceGraph.getNodes()) { + for (GraphNode sliceNode : sliceGraph.vertexSet()) { if (!sliceNodes.contains(sliceNode.getId())) { Logger.log("Removing node " + sliceNode.getId()); sliceNode.getAstNode().removeForced(); - sliceGraph.removeNode(sliceNode); + sliceGraph.removeVertex(sliceNode); } } -// for (Arc arc : getArcs()) { -// Optional fromOptional = sliceGraph.findNodeById(arc.getFromNode().getId()); -// Optional toOptional = sliceGraph.findNodeById(arc.getToNode().getId()); -// -// if (fromOptional.isPresent() && toOptional.isPresent()) { -// GraphNode from = fromOptional.get(); -// GraphNode to = toOptional.get(); -// -// if (arc.isControlDependencyArrow()) { -// sliceGraph.addControlDependencyArc(from, to); -// } else { -// DataDependencyArc dataDependencyArc = (DataDependencyArc) arc; -// sliceGraph.addDataDependencyArc(from, to, dataDependencyArc.getData().getVariables().get(0)); -// } -// } -// } - return sliceGraph; } diff --git a/src/main/java/tfm/graphs/SDGGraph.java b/src/main/java/tfm/graphs/SDGGraph.java index 1167e1a..66be5a0 100644 --- a/src/main/java/tfm/graphs/SDGGraph.java +++ b/src/main/java/tfm/graphs/SDGGraph.java @@ -3,6 +3,8 @@ package tfm.graphs; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.body.Parameter; import com.github.javaparser.ast.stmt.EmptyStmt; +import org.jgrapht.io.DOTExporter; +import tfm.arcs.Arc; import tfm.nodes.GraphNode; import tfm.slicing.SlicingCriterion; import tfm.utils.Context; @@ -13,7 +15,7 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; -public class SDGGraph extends Graph { +public class SDGGraph extends Graph implements Sliceable { private Map contextPDGGraphMap; @@ -22,14 +24,8 @@ public class SDGGraph extends Graph { } @Override - public String toGraphvizRepresentation() { - return contextPDGGraphMap.values().stream() - .map(PDGGraph::toGraphvizRepresentation).collect(Collectors.joining("\n")); - } - - @Override - public Graph slice(SlicingCriterion slicingCriterion) { - return this; + public SDGGraph slice(SlicingCriterion slicingCriterion) { + throw new IllegalStateException("Not implemented (yet)"); } public Map getContextPDGGraphMap() { @@ -63,8 +59,8 @@ public class SDGGraph extends Graph { addVertex(sdgNode); } - for (GraphNode node : pdgGraph.getNodes()) { - if (!this.contains(node)) { + for (GraphNode node : pdgGraph.vertexSet()) { + if (!this.containsVertex(node)) { GraphNode sdgNode = new GraphNode<>( getNextVertexId(), node.getInstruction(), diff --git a/src/main/java/tfm/graphs/Sliceable.java b/src/main/java/tfm/graphs/Sliceable.java new file mode 100644 index 0000000..3edf64a --- /dev/null +++ b/src/main/java/tfm/graphs/Sliceable.java @@ -0,0 +1,7 @@ +package tfm.graphs; + +import tfm.slicing.SlicingCriterion; + +public interface Sliceable { + G slice(SlicingCriterion sc); +} diff --git a/src/main/java/tfm/nodes/GraphNode.java b/src/main/java/tfm/nodes/GraphNode.java index a92cdf6..5361195 100644 --- a/src/main/java/tfm/nodes/GraphNode.java +++ b/src/main/java/tfm/nodes/GraphNode.java @@ -80,11 +80,6 @@ public class GraphNode { return astNode; } - public Optional getFileLineNumber() { - return astNode.getBegin() - .map(begin -> begin.line); - } - public void addDeclaredVariable(String variable) { declaredVariables.add(variable); } @@ -117,12 +112,6 @@ public class GraphNode { return Objects.hash(getId(), getInstruction(), getAstNode()); } - public String toGraphvizRepresentation() { - String text = getInstruction().replace("\\", "\\\\") - .replace("\"", "\\\""); - return String.format("%s[label=\"%s: %s\"];", getId(), getId(), text); - } - public Set getDeclaredVariables() { return declaredVariables; } diff --git a/src/main/java/tfm/slicing/LineNumberCriterion.java b/src/main/java/tfm/slicing/LineNumberCriterion.java index 2b0c246..901bcc5 100644 --- a/src/main/java/tfm/slicing/LineNumberCriterion.java +++ b/src/main/java/tfm/slicing/LineNumberCriterion.java @@ -27,7 +27,7 @@ public class LineNumberCriterion extends SlicingCriterion { @Override public Optional> findNode(PDGGraph graph) { // find node by line number - return graph.getNodes().stream().filter(node -> { + return graph.vertexSet().stream().filter(node -> { Node astNode = node.getAstNode(); if (!astNode.getBegin().isPresent() || !astNode.getEnd().isPresent()) diff --git a/src/main/java/tfm/validation/PDGValidator.java b/src/main/java/tfm/validation/PDGValidator.java index f4d3f20..2679189 100644 --- a/src/main/java/tfm/validation/PDGValidator.java +++ b/src/main/java/tfm/validation/PDGValidator.java @@ -76,22 +76,25 @@ public class PDGValidator { return ProgramComparator.areEqual(methodDeclaration, generatedMethod); } + @Deprecated public static MethodDeclaration generateMethod(MethodDeclaration info, PDGGraph graph) { - MethodDeclaration methodDeclaration = new MethodDeclaration(); - - methodDeclaration.setName(info.getNameAsString()); - methodDeclaration.setModifiers(info.getModifiers()); - methodDeclaration.setType(info.getType()); - methodDeclaration.setParameters(info.getParameters()); - - BlockStmt methodBody = new BlockStmt(); - methodDeclaration.setBody(methodBody); - - graph.getNodesAtLevel(1).stream() - .sorted(Comparator.comparingInt(GraphNode::getId)) - .forEach(node -> methodBody.addStatement((Statement) node.getAstNode())); - - return methodDeclaration; + // TODO: this does not work properly, replace or remove + throw new IllegalStateException("Deprecated method"); +// MethodDeclaration methodDeclaration = new MethodDeclaration(); +// +// methodDeclaration.setName(info.getNameAsString()); +// methodDeclaration.setModifiers(info.getModifiers()); +// methodDeclaration.setType(info.getType()); +// methodDeclaration.setParameters(info.getParameters()); +// +// BlockStmt methodBody = new BlockStmt(); +// methodDeclaration.setBody(methodBody); +// +// graph.getNodesAtLevel(1).stream() +// .sorted(Comparator.comparingInt(GraphNode::getId)) +// .forEach(node -> methodBody.addStatement((Statement) node.getAstNode())); +// +// return methodDeclaration; } public static void printPDGProgram(String fileName, PDGGraph graph) throws FileNotFoundException { diff --git a/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java b/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java index 4a267ec..f4ee2b8 100644 --- a/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java +++ b/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java @@ -5,9 +5,7 @@ import com.github.javaparser.ast.visitor.VoidVisitorAdapter; import tfm.graphs.CFGGraph; import tfm.graphs.PDGGraph; import tfm.nodes.GraphNode; -import tfm.utils.Logger; -import java.util.Objects; import java.util.stream.Collectors; public class ControlDependencyBuilder extends VoidVisitorAdapter> { diff --git a/src/main/java/tfm/visitors/sdg/SDGBuilder.java b/src/main/java/tfm/visitors/sdg/SDGBuilder.java index f2c85ff..9662844 100644 --- a/src/main/java/tfm/visitors/sdg/SDGBuilder.java +++ b/src/main/java/tfm/visitors/sdg/SDGBuilder.java @@ -116,7 +116,7 @@ public class SDGBuilder extends VoidVisitorAdapter { sdgGraph.addNode(methodDeclaration.getNameAsString(), methodDeclaration); - pdgGraph.getNodes().stream().skip(1).forEach(pdgNode -> { + pdgGraph.vertexSet().stream().skip(1).forEach(pdgNode -> { Statement statement = (Statement) pdgNode.getAstNode(); if (statement.isExpressionStmt()) { -- GitLab From 6ed533e71fd264fefe5c864b856b5c40a58353bc Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Mon, 20 Jan 2020 15:10:10 +0100 Subject: [PATCH 15/27] Remove graphlib.jar and graphlib from maven. --- lib/graphlib.jar | Bin 22438 -> 0 bytes pom.xml | 1 - 2 files changed, 1 deletion(-) delete mode 100644 lib/graphlib.jar diff --git a/lib/graphlib.jar b/lib/graphlib.jar deleted file mode 100644 index cf0e9844307d1dff58335a2e6f3500c532f7d58d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22438 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%0D8Lb!KHd(-7EB`>2aL*Ux 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 diff --git a/pom.xml b/pom.xml index b99904e..53b3a44 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,6 @@ - com.github.javaparser javaparser-symbol-solver-core -- GitLab From 6bb53029839b10359b2fef4d0db7588ddb677c01 Mon Sep 17 00:00:00 2001 From: Javier Costa Date: Wed, 22 Jan 2020 14:56:43 +0100 Subject: [PATCH 16/27] build root node on demand --- src/main/java/tfm/graphs/CFGGraph.java | 8 +--- src/main/java/tfm/graphs/Graph.java | 9 ++++- .../java/tfm/graphs/GraphWithRootNode.java | 38 ++++++++++++++----- src/main/java/tfm/graphs/PDGGraph.java | 7 +--- .../java/tfm/visitors/cfg/CFGBuilder.java | 12 +++--- .../java/tfm/visitors/pdg/PDGBuilder.java | 14 +++---- 6 files changed, 53 insertions(+), 35 deletions(-) diff --git a/src/main/java/tfm/graphs/CFGGraph.java b/src/main/java/tfm/graphs/CFGGraph.java index f21e4d8..445fcb4 100644 --- a/src/main/java/tfm/graphs/CFGGraph.java +++ b/src/main/java/tfm/graphs/CFGGraph.java @@ -1,5 +1,6 @@ package tfm.graphs; +import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.stmt.EmptyStmt; import org.jgrapht.io.DOTExporter; import tfm.arcs.Arc; @@ -11,17 +12,12 @@ import java.util.HashSet; import java.util.Objects; import java.util.Set; -public class CFGGraph extends GraphWithRootNode { +public class CFGGraph extends GraphWithRootNode { public CFGGraph() { super(); } - @Override - protected GraphNode buildRootNode() { - return new GraphNode<>(getNextVertexId(), "Start", new EmptyStmt()); - } - public void addControlFlowEdge(GraphNode from, GraphNode to) { super.addEdge(from, to, new ControlFlowArc()); } diff --git a/src/main/java/tfm/graphs/Graph.java b/src/main/java/tfm/graphs/Graph.java index fcd246e..7e2603c 100644 --- a/src/main/java/tfm/graphs/Graph.java +++ b/src/main/java/tfm/graphs/Graph.java @@ -16,10 +16,17 @@ import java.util.stream.Collectors; * */ public abstract class Graph extends DefaultDirectedGraph, Arc> { - private int nextVertexId = 0; + protected static final int DEFAULT_VERTEX_START_ID = 0; + + private int nextVertexId; public Graph() { + this(DEFAULT_VERTEX_START_ID); + } + + protected Graph(int vertexStartId) { super(null, null, false); + this.nextVertexId = vertexStartId; } private GraphNode addNode(GraphNode node) { diff --git a/src/main/java/tfm/graphs/GraphWithRootNode.java b/src/main/java/tfm/graphs/GraphWithRootNode.java index d80c776..9630a2b 100644 --- a/src/main/java/tfm/graphs/GraphWithRootNode.java +++ b/src/main/java/tfm/graphs/GraphWithRootNode.java @@ -1,24 +1,44 @@ package tfm.graphs; +import com.github.javaparser.ast.Node; import tfm.nodes.GraphNode; +import tfm.utils.NodeFactory; import java.util.Objects; +import java.util.Optional; -public abstract class GraphWithRootNode extends Graph { +public abstract class GraphWithRootNode extends Graph { - protected GraphNode rootNode; + protected final int ROOT_NODE_ID = 0; - public GraphWithRootNode() { - super(); + protected GraphNode rootNode; - this.rootNode = buildRootNode(); - this.addVertex(rootNode); + public GraphWithRootNode() { + super(1); } - protected abstract GraphNode buildRootNode(); + /** + * Builds the root node with the given instruction and AST node. + * If the root node already exists, just returns false + * + * @param instruction the instruction string + * @param rootNodeAst the AST node + * @return true if the root node is created, false otherwise + */ + public boolean buildRootNode(String instruction, ASTRootNode rootNodeAst) { + if (rootNode != null) { + return false; + } + + GraphNode root = NodeFactory.graphNode(ROOT_NODE_ID, instruction, rootNodeAst); + this.rootNode = root; + this.addVertex(root); + + return true; + } - public GraphNode getRootNode() { - return rootNode; + public Optional> getRootNode() { + return Optional.ofNullable(rootNode); } @Override diff --git a/src/main/java/tfm/graphs/PDGGraph.java b/src/main/java/tfm/graphs/PDGGraph.java index 1cf2061..a19a9c4 100644 --- a/src/main/java/tfm/graphs/PDGGraph.java +++ b/src/main/java/tfm/graphs/PDGGraph.java @@ -15,7 +15,7 @@ import tfm.visitors.pdg.PDGBuilder; import java.util.*; -public class PDGGraph extends GraphWithRootNode implements Sliceable { +public class PDGGraph extends GraphWithRootNode implements Sliceable { private CFGGraph cfgGraph; @@ -23,11 +23,6 @@ public class PDGGraph extends GraphWithRootNode implements Sliceable { super(); } - @Override - protected GraphNode buildRootNode() { - return new GraphNode<>(getNextVertexId(), "ENTER", new MethodDeclaration()); - } - public PDGGraph(CFGGraph cfgGraph) { super(); this.cfgGraph = cfgGraph; diff --git a/src/main/java/tfm/visitors/cfg/CFGBuilder.java b/src/main/java/tfm/visitors/cfg/CFGBuilder.java index 25fa8c1..c0ba5d5 100644 --- a/src/main/java/tfm/visitors/cfg/CFGBuilder.java +++ b/src/main/java/tfm/visitors/cfg/CFGBuilder.java @@ -20,11 +20,7 @@ public class CFGBuilder extends VoidVisitorAdapter { public CFGBuilder(CFGGraph graph) { this.graph = graph; - this.lastParentNodes = Collections.asLifoQueue( - new ArrayDeque<>( - Collections.singletonList(graph.getRootNode()) - ) - ); + this.lastParentNodes = Collections.asLifoQueue(new ArrayDeque<>()); this.bodyBreaks = new ArrayList<>(); } @@ -225,6 +221,12 @@ public class CFGBuilder extends VoidVisitorAdapter { throw new IllegalStateException("CFG is only allowed for one method, not multiple!"); } + this.graph.buildRootNode("Start", methodDeclaration); + + assert this.graph.getRootNode().isPresent(); + + lastParentNodes.add(this.graph.getRootNode().get()); + super.visit(methodDeclaration, arg); lastParentNodes.add(addNodeAndArcs("Stop", new EmptyStmt())); diff --git a/src/main/java/tfm/visitors/pdg/PDGBuilder.java b/src/main/java/tfm/visitors/pdg/PDGBuilder.java index 1e59487..09ad2f8 100644 --- a/src/main/java/tfm/visitors/pdg/PDGBuilder.java +++ b/src/main/java/tfm/visitors/pdg/PDGBuilder.java @@ -27,20 +27,18 @@ public class PDGBuilder extends VoidVisitorAdapter { if (!methodDeclaration.getBody().isPresent()) return; - // Assign the method declaration to the root node of the PDG graph. Here parent will always be the root node - this.pdgGraph.modifyNode(pdgGraph.getRootNode().getId(), mutableGraphNode -> { - mutableGraphNode.setInstruction("ENTER " + methodDeclaration.getNameAsString()); - mutableGraphNode.setAstNode(methodDeclaration); - }); + this.pdgGraph.buildRootNode("ENTER " + methodDeclaration.getNameAsString(), methodDeclaration); - BlockStmt methodBody = methodDeclaration.getBody().get(); + assert this.pdgGraph.getRootNode().isPresent(); // build CFG - methodBody.accept(new CFGBuilder(cfgGraph), null); + methodDeclaration.accept(new CFGBuilder(cfgGraph), null); + + BlockStmt methodBody = methodDeclaration.getBody().get(); // Build control dependency ControlDependencyBuilder controlDependencyBuilder = new ControlDependencyBuilder(pdgGraph, cfgGraph); - methodBody.accept(controlDependencyBuilder, pdgGraph.getRootNode()); + methodBody.accept(controlDependencyBuilder, pdgGraph.getRootNode().get()); // Build data dependency DataDependencyBuilder dataDependencyBuilder = new DataDependencyBuilder(pdgGraph, cfgGraph); -- GitLab From 9ba2e8d164dd2ea746b29207efb1e8c63769a8a8 Mon Sep 17 00:00:00 2001 From: Javier Costa Date: Wed, 22 Jan 2020 15:04:26 +0100 Subject: [PATCH 17/27] NodeFactory to create new nodes + GraphNode constructors package private --- src/main/java/tfm/graphs/Graph.java | 2 +- src/main/java/tfm/graphs/GraphWithRootNode.java | 2 +- src/main/java/tfm/graphs/SDGGraph.java | 7 ++++--- src/main/java/tfm/nodes/GraphNode.java | 4 ++-- src/main/java/tfm/{utils => nodes}/NodeFactory.java | 13 ++++++++++++- 5 files changed, 20 insertions(+), 8 deletions(-) rename src/main/java/tfm/{utils => nodes}/NodeFactory.java (73%) diff --git a/src/main/java/tfm/graphs/Graph.java b/src/main/java/tfm/graphs/Graph.java index 7e2603c..ce739be 100644 --- a/src/main/java/tfm/graphs/Graph.java +++ b/src/main/java/tfm/graphs/Graph.java @@ -5,7 +5,7 @@ import org.jgrapht.graph.DefaultDirectedGraph; import org.jgrapht.io.DOTExporter; import tfm.arcs.Arc; import tfm.nodes.GraphNode; -import tfm.utils.NodeFactory; +import tfm.nodes.NodeFactory; import java.util.*; import java.util.function.Consumer; diff --git a/src/main/java/tfm/graphs/GraphWithRootNode.java b/src/main/java/tfm/graphs/GraphWithRootNode.java index 9630a2b..76d01e6 100644 --- a/src/main/java/tfm/graphs/GraphWithRootNode.java +++ b/src/main/java/tfm/graphs/GraphWithRootNode.java @@ -2,7 +2,7 @@ package tfm.graphs; import com.github.javaparser.ast.Node; import tfm.nodes.GraphNode; -import tfm.utils.NodeFactory; +import tfm.nodes.NodeFactory; import java.util.Objects; import java.util.Optional; diff --git a/src/main/java/tfm/graphs/SDGGraph.java b/src/main/java/tfm/graphs/SDGGraph.java index 66be5a0..6da8faf 100644 --- a/src/main/java/tfm/graphs/SDGGraph.java +++ b/src/main/java/tfm/graphs/SDGGraph.java @@ -6,6 +6,7 @@ import com.github.javaparser.ast.stmt.EmptyStmt; import org.jgrapht.io.DOTExporter; import tfm.arcs.Arc; import tfm.nodes.GraphNode; +import tfm.nodes.NodeFactory; import tfm.slicing.SlicingCriterion; import tfm.utils.Context; @@ -50,7 +51,7 @@ public class SDGGraph extends Graph implements Sliceable { @Deprecated public void addPDG(PDGGraph pdgGraph, MethodDeclaration methodDeclaration) { for (Parameter parameter : methodDeclaration.getParameters()) { - GraphNode sdgNode = new GraphNode<>( + GraphNode sdgNode = NodeFactory.graphNode( getNextVertexId(), String.format("%s = %s_in", parameter.getNameAsString(), parameter.getNameAsString()), new EmptyStmt() @@ -61,7 +62,7 @@ public class SDGGraph extends Graph implements Sliceable { for (GraphNode node : pdgGraph.vertexSet()) { if (!this.containsVertex(node)) { - GraphNode sdgNode = new GraphNode<>( + GraphNode sdgNode = NodeFactory.computedGraphNode( getNextVertexId(), node.getInstruction(), node.getAstNode(), @@ -76,7 +77,7 @@ public class SDGGraph extends Graph implements Sliceable { } public void addMethod(MethodDeclaration methodDeclaration, PDGGraph pdgGraph) { - GraphNode methodRootNode = new GraphNode<>( + GraphNode methodRootNode = NodeFactory.graphNode( getNextVertexId(), "ENTER " + methodDeclaration.getDeclarationAsString(false, false, true), methodDeclaration diff --git a/src/main/java/tfm/nodes/GraphNode.java b/src/main/java/tfm/nodes/GraphNode.java index 5361195..1afa440 100644 --- a/src/main/java/tfm/nodes/GraphNode.java +++ b/src/main/java/tfm/nodes/GraphNode.java @@ -24,7 +24,7 @@ public class GraphNode { private final Set definedVariables; private final Set usedVariables; - public GraphNode(int id, String instruction, @NotNull N astNode) { + GraphNode(int id, String instruction, @NotNull N astNode) { this( id, instruction, @@ -39,7 +39,7 @@ public class GraphNode { } } - public GraphNode( + GraphNode( int id, String instruction, @NonNull N astNode, diff --git a/src/main/java/tfm/utils/NodeFactory.java b/src/main/java/tfm/nodes/NodeFactory.java similarity index 73% rename from src/main/java/tfm/utils/NodeFactory.java rename to src/main/java/tfm/nodes/NodeFactory.java index 585fea7..92047af 100644 --- a/src/main/java/tfm/utils/NodeFactory.java +++ b/src/main/java/tfm/nodes/NodeFactory.java @@ -1,9 +1,11 @@ -package tfm.utils; +package tfm.nodes; import com.github.javaparser.ast.Node; +import org.checkerframework.checker.nullness.qual.NonNull; import tfm.nodes.GraphNode; import java.util.Collection; +import java.util.Objects; public class NodeFactory { @@ -28,6 +30,12 @@ public class NodeFactory { Collection definedVariables, Collection usedVariables ) { + Objects.requireNonNull(instruction, "Instruction cannot be null!"); + Objects.requireNonNull(node, "AST Node cannot be null"); + Objects.requireNonNull(declaredVariables, "declared variables collection cannot be null!"); + Objects.requireNonNull(definedVariables, "defined variables collection cannot be null"); + Objects.requireNonNull(usedVariables, "Used variables collection cannot be null!"); + return new GraphNode<>( id, instruction, @@ -52,6 +60,9 @@ public class NodeFactory { String instruction, ASTNode node ) { + Objects.requireNonNull(instruction, "Instruction cannot be null!"); + Objects.requireNonNull(node, "AST Node cannot be null"); + return new GraphNode<>( id, instruction, -- GitLab From 0d6593ad93d34abeab8788ea4ca74f42223c5256 Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Thu, 23 Jan 2020 14:42:59 +0100 Subject: [PATCH 18/27] Renamed graphs and replaced @NonNull with @NotNull Also optimized imports --- readme.md | 4 +-- src/main/java/tfm/exec/CFGLog.java | 8 ++--- src/main/java/tfm/exec/PDGLog.java | 19 +++++------ src/main/java/tfm/exec/SDGLog.java | 6 ++-- .../java/tfm/graphbuilding/GraphOptions.java | 30 ++++++++--------- src/main/java/tfm/graphbuilding/Graphs.java | 12 +++---- .../tfm/graphs/{CFGGraph.java => CFG.java} | 6 ++-- .../tfm/graphs/{PDGGraph.java => PDG.java} | 27 ++++++++-------- .../tfm/graphs/{SDGGraph.java => SDG.java} | 20 ++++++------ src/main/java/tfm/nodes/GraphNode.java | 10 +++--- src/main/java/tfm/nodes/NodeFactory.java | 2 -- src/main/java/tfm/readme.md | 4 +-- .../java/tfm/slicing/LineNumberCriterion.java | 12 +++---- src/main/java/tfm/slicing/Slice.java | 8 ++--- .../java/tfm/slicing/SlicingCriterion.java | 12 +++---- .../java/tfm/validation/PDGValidator.java | 14 +++----- .../java/tfm/visitors/cfg/CFGBuilder.java | 6 ++-- .../pdg/ControlDependencyBuilder.java | 24 +++++++------- .../visitors/pdg/DataDependencyBuilder.java | 30 ++++++++--------- .../java/tfm/visitors/pdg/PDGBuilder.java | 32 +++++++++---------- .../tfm/visitors/sdg/MethodCallReplacer.java | 10 +++--- .../sdg/MethodCallReplacerVisitor.java | 10 +++--- .../java/tfm/visitors/sdg/NewSDGBuilder.java | 16 +++++----- .../java/tfm/visitors/sdg/SDGBuilder.java | 32 +++++++++---------- 24 files changed, 174 insertions(+), 180 deletions(-) rename src/main/java/tfm/graphs/{CFGGraph.java => CFG.java} (89%) rename src/main/java/tfm/graphs/{PDGGraph.java => PDG.java} (79%) rename src/main/java/tfm/graphs/{SDGGraph.java => SDG.java} (81%) diff --git a/readme.md b/readme.md index 5ef10f6..9fd78a3 100644 --- a/readme.md +++ b/readme.md @@ -131,9 +131,9 @@ public PDGGraph getSlice(File program, SlicingCriterion slicingCriterion) { Node astRoot = JavaParser.parse(programFile); - PDGGraph pdgGraph = Graphs.PDG.fromASTNode(astRoot); + PDGGraph pdg = Graphs.PDG.fromASTNode(astRoot); - return pdgGraph.slice(slicingCriterion); + return pdg.slice(slicingCriterion); } ``` diff --git a/src/main/java/tfm/exec/CFGLog.java b/src/main/java/tfm/exec/CFGLog.java index e04a483..153728a 100644 --- a/src/main/java/tfm/exec/CFGLog.java +++ b/src/main/java/tfm/exec/CFGLog.java @@ -1,22 +1,22 @@ package tfm.exec; import com.github.javaparser.ast.Node; -import tfm.graphs.CFGGraph; +import tfm.graphs.CFG; import tfm.visitors.cfg.CFGBuilder; -public class CFGLog extends GraphLog { +public class CFGLog extends GraphLog { public CFGLog() { super(); } - public CFGLog(CFGGraph graph) { + public CFGLog(CFG graph) { super(graph); } @Override public void visit(Node node) { - this.graph = new CFGGraph(); + this.graph = new CFG(); node.accept(new CFGBuilder(graph), null); } } diff --git a/src/main/java/tfm/exec/PDGLog.java b/src/main/java/tfm/exec/PDGLog.java index d369fb5..991681d 100644 --- a/src/main/java/tfm/exec/PDGLog.java +++ b/src/main/java/tfm/exec/PDGLog.java @@ -1,6 +1,7 @@ package tfm.exec; -import tfm.graphs.PDGGraph; +import com.github.javaparser.ast.Node; +import tfm.graphs.PDG; import tfm.nodes.GraphNode; import tfm.utils.Logger; import tfm.visitors.pdg.PDGBuilder; @@ -9,7 +10,7 @@ import java.io.IOException; import java.util.Comparator; import java.util.stream.Collectors; -public class PDGLog extends GraphLog { +public class PDGLog extends GraphLog { private CFGLog cfgLog; @@ -17,22 +18,22 @@ public class PDGLog extends GraphLog { this(null); } - public PDGLog(PDGGraph pdgGraph) { - super(pdgGraph); + public PDGLog(PDG pdg) { + super(pdg); - if (graph != null && graph.getCfgGraph() != null) - cfgLog = new CFGLog(graph.getCfgGraph()); + if (graph != null && graph.getCfg() != null) + cfgLog = new CFGLog(graph.getCfg()); else cfgLog = null; } @Override - public void visit(com.github.javaparser.ast.Node node) { - this.graph = new PDGGraph(); + public void visit(Node node) { + this.graph = new PDG(); node.accept(new PDGBuilder(graph), null); if (cfgLog == null) { - cfgLog = new CFGLog(graph.getCfgGraph()); + cfgLog = new CFGLog(graph.getCfg()); } } diff --git a/src/main/java/tfm/exec/SDGLog.java b/src/main/java/tfm/exec/SDGLog.java index 16978ae..702e7c9 100644 --- a/src/main/java/tfm/exec/SDGLog.java +++ b/src/main/java/tfm/exec/SDGLog.java @@ -1,14 +1,14 @@ package tfm.exec; import com.github.javaparser.ast.Node; -import tfm.graphs.SDGGraph; +import tfm.graphs.SDG; import tfm.visitors.sdg.SDGBuilder; -public class SDGLog extends GraphLog { +public class SDGLog extends GraphLog { @Override public void visit(Node node) { - this.graph = new SDGGraph(); + this.graph = new SDG(); SDGBuilder sdgBuilder = new SDGBuilder(this.graph); node.accept(sdgBuilder, null); } diff --git a/src/main/java/tfm/graphbuilding/GraphOptions.java b/src/main/java/tfm/graphbuilding/GraphOptions.java index b7d2486..31e7fe7 100644 --- a/src/main/java/tfm/graphbuilding/GraphOptions.java +++ b/src/main/java/tfm/graphbuilding/GraphOptions.java @@ -1,10 +1,10 @@ package tfm.graphbuilding; import com.github.javaparser.ast.Node; -import tfm.graphs.CFGGraph; +import tfm.graphs.CFG; import tfm.graphs.Graph; -import tfm.graphs.PDGGraph; -import tfm.graphs.SDGGraph; +import tfm.graphs.PDG; +import tfm.graphs.SDG; import tfm.visitors.cfg.CFGBuilder; import tfm.visitors.pdg.PDGBuilder; import tfm.visitors.sdg.SDGBuilder; @@ -23,41 +23,41 @@ public abstract class GraphOptions { protected abstract void buildGraphWithSpecificVisitor(G emptyGraph, Node node); } -class CFGOptions extends GraphOptions { +class CFGOptions extends GraphOptions { @Override - public CFGGraph empty() { - return new CFGGraph(); + public CFG empty() { + return new CFG(); } @Override - protected void buildGraphWithSpecificVisitor(CFGGraph emptyGraph, Node node) { + protected void buildGraphWithSpecificVisitor(CFG emptyGraph, Node node) { node.accept(new CFGBuilder(emptyGraph), null); } } -class PDGOptions extends GraphOptions { +class PDGOptions extends GraphOptions { @Override - public PDGGraph empty() { - return new PDGGraph(); + public PDG empty() { + return new PDG(); } @Override - protected void buildGraphWithSpecificVisitor(PDGGraph emptyGraph, Node node) { + protected void buildGraphWithSpecificVisitor(PDG emptyGraph, Node node) { node.accept(new PDGBuilder(emptyGraph), null); } } -class SDGOptions extends GraphOptions { +class SDGOptions extends GraphOptions { @Override - public SDGGraph empty() { - return new SDGGraph(); + public SDG empty() { + return new SDG(); } @Override - protected void buildGraphWithSpecificVisitor(SDGGraph emptyGraph, Node node) { + protected void buildGraphWithSpecificVisitor(SDG emptyGraph, Node node) { node.accept(new SDGBuilder(emptyGraph), null); } } \ No newline at end of file diff --git a/src/main/java/tfm/graphbuilding/Graphs.java b/src/main/java/tfm/graphbuilding/Graphs.java index 235124c..548bfcd 100644 --- a/src/main/java/tfm/graphbuilding/Graphs.java +++ b/src/main/java/tfm/graphbuilding/Graphs.java @@ -1,13 +1,13 @@ package tfm.graphbuilding; -import tfm.graphs.CFGGraph; -import tfm.graphs.PDGGraph; -import tfm.graphs.SDGGraph; +import tfm.graphs.CFG; +import tfm.graphs.PDG; +import tfm.graphs.SDG; public class Graphs { - public static final GraphOptions CFG = new CFGOptions(); - public static final GraphOptions PDG = new PDGOptions(); - public static final GraphOptions SDG = new SDGOptions(); + public static final GraphOptions CFG = new CFGOptions(); + public static final GraphOptions PDG = new PDGOptions(); + public static final GraphOptions SDG = new SDGOptions(); } \ No newline at end of file diff --git a/src/main/java/tfm/graphs/CFGGraph.java b/src/main/java/tfm/graphs/CFG.java similarity index 89% rename from src/main/java/tfm/graphs/CFGGraph.java rename to src/main/java/tfm/graphs/CFG.java index 445fcb4..3677921 100644 --- a/src/main/java/tfm/graphs/CFGGraph.java +++ b/src/main/java/tfm/graphs/CFG.java @@ -1,8 +1,6 @@ package tfm.graphs; import com.github.javaparser.ast.body.MethodDeclaration; -import com.github.javaparser.ast.stmt.EmptyStmt; -import org.jgrapht.io.DOTExporter; import tfm.arcs.Arc; import tfm.arcs.cfg.ControlFlowArc; import tfm.nodes.GraphNode; @@ -12,9 +10,9 @@ import java.util.HashSet; import java.util.Objects; import java.util.Set; -public class CFGGraph extends GraphWithRootNode { +public class CFG extends GraphWithRootNode { - public CFGGraph() { + public CFG() { super(); } diff --git a/src/main/java/tfm/graphs/PDGGraph.java b/src/main/java/tfm/graphs/PDG.java similarity index 79% rename from src/main/java/tfm/graphs/PDGGraph.java rename to src/main/java/tfm/graphs/PDG.java index a19a9c4..98fad8e 100644 --- a/src/main/java/tfm/graphs/PDGGraph.java +++ b/src/main/java/tfm/graphs/PDG.java @@ -2,7 +2,6 @@ package tfm.graphs; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.MethodDeclaration; -import org.jgrapht.io.DOTExporter; import tfm.arcs.Arc; import tfm.arcs.pdg.ControlDependencyArc; import tfm.arcs.pdg.DataDependencyArc; @@ -13,19 +12,21 @@ import tfm.utils.Logger; import tfm.utils.NodeNotFoundException; import tfm.visitors.pdg.PDGBuilder; -import java.util.*; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; -public class PDGGraph extends GraphWithRootNode implements Sliceable { +public class PDG extends GraphWithRootNode implements Sliceable { - private CFGGraph cfgGraph; + private CFG cfg; - public PDGGraph() { + public PDG() { super(); } - public PDGGraph(CFGGraph cfgGraph) { + public PDG(CFG cfg) { super(); - this.cfgGraph = cfgGraph; + this.cfg = cfg; } public void addControlDependencyArc(GraphNode from, GraphNode to) { @@ -36,12 +37,12 @@ public class PDGGraph extends GraphWithRootNode implements Sl this.addEdge(from, to, new DataDependencyArc(variable)); } - public void setCfgGraph(CFGGraph cfgGraph) { - this.cfgGraph = cfgGraph; + public void setCfg(CFG cfg) { + this.cfg = cfg; } @Override - public PDGGraph slice(SlicingCriterion slicingCriterion) { + public PDG slice(SlicingCriterion slicingCriterion) { Optional> optionalGraphNode = slicingCriterion.findNode(this); if (!optionalGraphNode.isPresent()) { @@ -53,7 +54,7 @@ public class PDGGraph extends GraphWithRootNode implements Sl // Simply get slice nodes from GraphNode Set sliceNodes = getSliceNodes(new HashSet<>(), node); - PDGGraph sliceGraph = new PDGGraph(); + PDG sliceGraph = new PDG(); Node astCopy = ASTUtils.cloneAST(node.getAstNode()); @@ -86,7 +87,7 @@ public class PDGGraph extends GraphWithRootNode implements Sl return visited; } - public CFGGraph getCfgGraph() { - return cfgGraph; + public CFG getCfg() { + return cfg; } } diff --git a/src/main/java/tfm/graphs/SDGGraph.java b/src/main/java/tfm/graphs/SDG.java similarity index 81% rename from src/main/java/tfm/graphs/SDGGraph.java rename to src/main/java/tfm/graphs/SDG.java index 6da8faf..6ba940e 100644 --- a/src/main/java/tfm/graphs/SDGGraph.java +++ b/src/main/java/tfm/graphs/SDG.java @@ -3,8 +3,6 @@ package tfm.graphs; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.body.Parameter; import com.github.javaparser.ast.stmt.EmptyStmt; -import org.jgrapht.io.DOTExporter; -import tfm.arcs.Arc; import tfm.nodes.GraphNode; import tfm.nodes.NodeFactory; import tfm.slicing.SlicingCriterion; @@ -16,20 +14,20 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; -public class SDGGraph extends Graph implements Sliceable { +public class SDG extends Graph implements Sliceable { - private Map contextPDGGraphMap; + private Map contextPDGGraphMap; - public SDGGraph() { + public SDG() { this.contextPDGGraphMap = new HashMap<>(); } @Override - public SDGGraph slice(SlicingCriterion slicingCriterion) { + public SDG slice(SlicingCriterion slicingCriterion) { throw new IllegalStateException("Not implemented (yet)"); } - public Map getContextPDGGraphMap() { + public Map getContextPDGGraphMap() { return contextPDGGraphMap; } @@ -44,12 +42,12 @@ public class SDGGraph extends Graph implements Sliceable { .collect(Collectors.toSet()); } - public Collection getPDGs() { + public Collection getPDGs() { return contextPDGGraphMap.values(); } @Deprecated - public void addPDG(PDGGraph pdgGraph, MethodDeclaration methodDeclaration) { + public void addPDG(PDG pdg, MethodDeclaration methodDeclaration) { for (Parameter parameter : methodDeclaration.getParameters()) { GraphNode sdgNode = NodeFactory.graphNode( getNextVertexId(), @@ -60,7 +58,7 @@ public class SDGGraph extends Graph implements Sliceable { addVertex(sdgNode); } - for (GraphNode node : pdgGraph.vertexSet()) { + for (GraphNode node : pdg.vertexSet()) { if (!this.containsVertex(node)) { GraphNode sdgNode = NodeFactory.computedGraphNode( getNextVertexId(), @@ -76,7 +74,7 @@ public class SDGGraph extends Graph implements Sliceable { } } - public void addMethod(MethodDeclaration methodDeclaration, PDGGraph pdgGraph) { + public void addMethod(MethodDeclaration methodDeclaration, PDG pdg) { GraphNode methodRootNode = NodeFactory.graphNode( getNextVertexId(), "ENTER " + methodDeclaration.getDeclarationAsString(false, false, true), diff --git a/src/main/java/tfm/nodes/GraphNode.java b/src/main/java/tfm/nodes/GraphNode.java index 1afa440..c011359 100644 --- a/src/main/java/tfm/nodes/GraphNode.java +++ b/src/main/java/tfm/nodes/GraphNode.java @@ -2,12 +2,14 @@ package tfm.nodes; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.stmt.Statement; -import org.checkerframework.checker.nullness.qual.NonNull; import org.jetbrains.annotations.NotNull; import tfm.utils.Utils; import tfm.variables.VariableExtractor; -import java.util.*; +import java.util.Collection; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; /** * Immutable class that represents an AST node inside a CFG, PDG or SDG. @@ -42,7 +44,7 @@ public class GraphNode { GraphNode( int id, String instruction, - @NonNull N astNode, + @NotNull N astNode, Collection declaredVariables, Collection definedVariables, Collection usedVariables @@ -56,7 +58,7 @@ public class GraphNode { this.usedVariables = new HashSet<>(usedVariables); } - private void extractVariables(@NonNull Statement statement) { + private void extractVariables(@NotNull Statement statement) { new VariableExtractor() .setOnVariableDeclarationListener(this.declaredVariables::add) .setOnVariableDefinitionListener(this.definedVariables::add) diff --git a/src/main/java/tfm/nodes/NodeFactory.java b/src/main/java/tfm/nodes/NodeFactory.java index 92047af..7d4f96e 100644 --- a/src/main/java/tfm/nodes/NodeFactory.java +++ b/src/main/java/tfm/nodes/NodeFactory.java @@ -1,8 +1,6 @@ package tfm.nodes; import com.github.javaparser.ast.Node; -import org.checkerframework.checker.nullness.qual.NonNull; -import tfm.nodes.GraphNode; import java.util.Collection; import java.util.Objects; diff --git a/src/main/java/tfm/readme.md b/src/main/java/tfm/readme.md index 5ef10f6..9fd78a3 100644 --- a/src/main/java/tfm/readme.md +++ b/src/main/java/tfm/readme.md @@ -131,9 +131,9 @@ public PDGGraph getSlice(File program, SlicingCriterion slicingCriterion) { Node astRoot = JavaParser.parse(programFile); - PDGGraph pdgGraph = Graphs.PDG.fromASTNode(astRoot); + PDGGraph pdg = Graphs.PDG.fromASTNode(astRoot); - return pdgGraph.slice(slicingCriterion); + return pdg.slice(slicingCriterion); } ``` diff --git a/src/main/java/tfm/slicing/LineNumberCriterion.java b/src/main/java/tfm/slicing/LineNumberCriterion.java index 901bcc5..355398c 100644 --- a/src/main/java/tfm/slicing/LineNumberCriterion.java +++ b/src/main/java/tfm/slicing/LineNumberCriterion.java @@ -1,9 +1,9 @@ package tfm.slicing; import com.github.javaparser.ast.Node; -import tfm.graphs.CFGGraph; -import tfm.graphs.PDGGraph; -import tfm.graphs.SDGGraph; +import tfm.graphs.CFG; +import tfm.graphs.PDG; +import tfm.graphs.SDG; import tfm.nodes.GraphNode; import tfm.utils.Logger; @@ -20,12 +20,12 @@ public class LineNumberCriterion extends SlicingCriterion { } @Override - public Optional> findNode(CFGGraph graph) { + public Optional> findNode(CFG graph) { return Optional.empty(); } @Override - public Optional> findNode(PDGGraph graph) { + public Optional> findNode(PDG graph) { // find node by line number return graph.vertexSet().stream().filter(node -> { Node astNode = node.getAstNode(); @@ -43,7 +43,7 @@ public class LineNumberCriterion extends SlicingCriterion { } @Override - public Optional> findNode(SDGGraph graph) { + public Optional> findNode(SDG graph) { return Optional.empty(); } diff --git a/src/main/java/tfm/slicing/Slice.java b/src/main/java/tfm/slicing/Slice.java index 15b4f50..034c6ec 100644 --- a/src/main/java/tfm/slicing/Slice.java +++ b/src/main/java/tfm/slicing/Slice.java @@ -3,7 +3,7 @@ package tfm.slicing; import com.github.javaparser.JavaParser; import com.github.javaparser.ast.CompilationUnit; import tfm.exec.PDGLog; -import tfm.graphs.PDGGraph; +import tfm.graphs.PDG; import tfm.utils.Logger; import tfm.utils.Utils; import tfm.validation.PDGValidator; @@ -20,15 +20,15 @@ public class Slice { public static void main(String[] args) throws IOException { CompilationUnit compilationUnit = JavaParser.parse(new File(PROGRAM_FOLDER + PROGRAM_NAME + ".java")); - PDGGraph pdgGraph = new PDGGraph(); + PDG pdg = new PDG(); - compilationUnit.accept(new PDGBuilder(pdgGraph), null); + compilationUnit.accept(new PDGBuilder(pdg), null); Logger.log("=================="); Logger.log("= Starting slice ="); Logger.log("=================="); - PDGGraph sliced = pdgGraph.slice(new LineNumberCriterion(18, "x")); + PDG sliced = pdg.slice(new LineNumberCriterion(18, "x")); PDGLog pdgLog = new PDGLog(sliced); pdgLog.log(); diff --git a/src/main/java/tfm/slicing/SlicingCriterion.java b/src/main/java/tfm/slicing/SlicingCriterion.java index 2574071..b01c357 100644 --- a/src/main/java/tfm/slicing/SlicingCriterion.java +++ b/src/main/java/tfm/slicing/SlicingCriterion.java @@ -1,8 +1,8 @@ package tfm.slicing; -import tfm.graphs.CFGGraph; -import tfm.graphs.PDGGraph; -import tfm.graphs.SDGGraph; +import tfm.graphs.CFG; +import tfm.graphs.PDG; +import tfm.graphs.SDG; import tfm.nodes.GraphNode; import java.util.Optional; @@ -19,9 +19,9 @@ public abstract class SlicingCriterion { return variable; } - public abstract Optional> findNode(CFGGraph graph); - public abstract Optional> findNode(PDGGraph graph); - public abstract Optional> findNode(SDGGraph graph); + public abstract Optional> findNode(CFG graph); + public abstract Optional> findNode(PDG graph); + public abstract Optional> findNode(SDG graph); @Override public String toString() { diff --git a/src/main/java/tfm/validation/PDGValidator.java b/src/main/java/tfm/validation/PDGValidator.java index 2679189..43e0241 100644 --- a/src/main/java/tfm/validation/PDGValidator.java +++ b/src/main/java/tfm/validation/PDGValidator.java @@ -7,13 +7,10 @@ import com.github.javaparser.ast.NodeList; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.body.Parameter; -import com.github.javaparser.ast.stmt.BlockStmt; -import com.github.javaparser.ast.stmt.Statement; import com.github.javaparser.ast.type.ArrayType; import com.github.javaparser.ast.type.VoidType; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import tfm.graphs.PDGGraph; -import tfm.nodes.GraphNode; +import tfm.graphs.PDG; import tfm.utils.Logger; import tfm.utils.Utils; import tfm.visitors.pdg.PDGBuilder; @@ -21,7 +18,6 @@ import tfm.visitors.pdg.PDGBuilder; import java.io.File; import java.io.FileNotFoundException; import java.io.PrintWriter; -import java.util.Comparator; import java.util.Objects; import java.util.Optional; @@ -63,21 +59,21 @@ public class PDGValidator { } public static boolean generateAndCheck(MethodDeclaration methodDeclaration) { - PDGGraph graph = new PDGGraph(); + PDG graph = new PDG(); methodDeclaration.accept(new PDGBuilder(graph), null); return check(methodDeclaration, graph); } - public static boolean check(MethodDeclaration methodDeclaration, PDGGraph graph) { + public static boolean check(MethodDeclaration methodDeclaration, PDG graph) { MethodDeclaration generatedMethod = generateMethod(methodDeclaration, graph); return ProgramComparator.areEqual(methodDeclaration, generatedMethod); } @Deprecated - public static MethodDeclaration generateMethod(MethodDeclaration info, PDGGraph graph) { + public static MethodDeclaration generateMethod(MethodDeclaration info, PDG graph) { // TODO: this does not work properly, replace or remove throw new IllegalStateException("Deprecated method"); // MethodDeclaration methodDeclaration = new MethodDeclaration(); @@ -97,7 +93,7 @@ public class PDGValidator { // return methodDeclaration; } - public static void printPDGProgram(String fileName, PDGGraph graph) throws FileNotFoundException { + public static void printPDGProgram(String fileName, PDG graph) throws FileNotFoundException { CompilationUnit generatedProgram = new CompilationUnit(); ClassOrInterfaceDeclaration clazz = generatedProgram.addClass(fileName).setPublic(true); diff --git a/src/main/java/tfm/visitors/cfg/CFGBuilder.java b/src/main/java/tfm/visitors/cfg/CFGBuilder.java index c0ba5d5..b3ea34c 100644 --- a/src/main/java/tfm/visitors/cfg/CFGBuilder.java +++ b/src/main/java/tfm/visitors/cfg/CFGBuilder.java @@ -5,7 +5,7 @@ import com.github.javaparser.ast.expr.BooleanLiteralExpr; import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.stmt.*; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import tfm.graphs.CFGGraph; +import tfm.graphs.CFG; import tfm.nodes.GraphNode; import tfm.utils.ASTUtils; @@ -13,12 +13,12 @@ import java.util.*; public class CFGBuilder extends VoidVisitorAdapter { - private CFGGraph graph; + private CFG graph; private Queue> lastParentNodes; private List> bodyBreaks; - public CFGBuilder(CFGGraph graph) { + public CFGBuilder(CFG graph) { this.graph = graph; this.lastParentNodes = Collections.asLifoQueue(new ArrayDeque<>()); diff --git a/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java b/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java index f4ee2b8..75c1b1e 100644 --- a/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java +++ b/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java @@ -2,20 +2,20 @@ package tfm.visitors.pdg; import com.github.javaparser.ast.stmt.*; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import tfm.graphs.CFGGraph; -import tfm.graphs.PDGGraph; +import tfm.graphs.CFG; +import tfm.graphs.PDG; import tfm.nodes.GraphNode; import java.util.stream.Collectors; public class ControlDependencyBuilder extends VoidVisitorAdapter> { - private CFGGraph cfgGraph; - private PDGGraph pdgGraph; + private CFG cfg; + private PDG pdg; - public ControlDependencyBuilder(PDGGraph pdgGraph, CFGGraph cfgGraph) { - this.pdgGraph = pdgGraph; - this.cfgGraph = cfgGraph; + public ControlDependencyBuilder(PDG pdg, CFG cfg) { + this.pdg = pdg; + this.cfg = cfg; } @Override @@ -54,12 +54,12 @@ public class ControlDependencyBuilder extends VoidVisitorAdapter> { .orElse("true"); - GraphNode forNode = pdgGraph.addNode( + GraphNode forNode = pdg.addNode( String.format("for (%s;%s;%s)", initialization, compare, update), forStmt ); - pdgGraph.addControlDependencyArc(parent, forNode); + pdg.addControlDependencyArc(parent, forNode); forStmt.getBody().accept(this, forNode); } @@ -86,9 +86,9 @@ public class ControlDependencyBuilder extends VoidVisitorAdapter> { } private GraphNode addNodeAndControlDependency(Statement statement, GraphNode parent) { - GraphNode cfgNode = cfgGraph.findNodeByASTNode(statement).get(); - GraphNode node = pdgGraph.addNode(cfgNode.getInstruction(), cfgNode.getAstNode()); - pdgGraph.addControlDependencyArc(parent, node); + GraphNode cfgNode = cfg.findNodeByASTNode(statement).get(); + GraphNode node = pdg.addNode(cfgNode.getInstruction(), cfgNode.getAstNode()); + pdg.addControlDependencyArc(parent, node); return node; } diff --git a/src/main/java/tfm/visitors/pdg/DataDependencyBuilder.java b/src/main/java/tfm/visitors/pdg/DataDependencyBuilder.java index d7bd5f1..786abca 100644 --- a/src/main/java/tfm/visitors/pdg/DataDependencyBuilder.java +++ b/src/main/java/tfm/visitors/pdg/DataDependencyBuilder.java @@ -2,8 +2,8 @@ package tfm.visitors.pdg; import com.github.javaparser.ast.stmt.*; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import tfm.graphs.CFGGraph; -import tfm.graphs.PDGGraph; +import tfm.graphs.CFG; +import tfm.graphs.PDG; import tfm.nodes.GraphNode; import tfm.variables.VariableExtractor; @@ -12,12 +12,12 @@ import java.util.Set; public class DataDependencyBuilder extends VoidVisitorAdapter { - private CFGGraph cfgGraph; - private PDGGraph pdgGraph; + private CFG cfg; + private PDG pdg; - public DataDependencyBuilder(PDGGraph pdgGraph, CFGGraph cfgGraph) { - this.pdgGraph = pdgGraph; - this.cfgGraph = cfgGraph; + public DataDependencyBuilder(PDG pdg, CFG cfg) { + this.pdg = pdg; + this.cfg = cfg; } @Override @@ -43,7 +43,7 @@ public class DataDependencyBuilder extends VoidVisitorAdapter { @Override public void visit(ForStmt forStmt, Void ignored) { - GraphNode forNode = pdgGraph.findNodeByASTNode(forStmt).get(); + GraphNode forNode = pdg.findNodeByASTNode(forStmt).get(); forStmt.getInitialization().stream() .map(ExpressionStmt::new) @@ -80,7 +80,7 @@ public class DataDependencyBuilder extends VoidVisitorAdapter { } private void buildDataDependency(Statement statement) { - buildDataDependency(pdgGraph.findNodeByASTNode(statement).get()); + buildDataDependency(pdg.findNodeByASTNode(statement).get()); } private void buildDataDependency(GraphNode node) { @@ -88,7 +88,7 @@ public class DataDependencyBuilder extends VoidVisitorAdapter { .setOnVariableUseListener(variable -> { node.addUsedVariable(variable); - Optional> nodeOptional = cfgGraph.findNodeByASTNode(node.getAstNode()); + Optional> nodeOptional = cfg.findNodeByASTNode(node.getAstNode()); if (!nodeOptional.isPresent()) { return; @@ -96,11 +96,11 @@ public class DataDependencyBuilder extends VoidVisitorAdapter { GraphNode cfgNode = nodeOptional.get(); - Set> lastDefinitions = cfgGraph.findLastDefinitionsFrom(cfgNode, variable); + Set> lastDefinitions = cfg.findLastDefinitionsFrom(cfgNode, variable); for (GraphNode definitionNode : lastDefinitions) { - pdgGraph.findNodeByASTNode(definitionNode.getAstNode()) - .ifPresent(pdgNode -> pdgGraph.addDataDependencyArc(pdgNode, node, variable)); + pdg.findNodeByASTNode(definitionNode.getAstNode()) + .ifPresent(pdgNode -> pdg.addDataDependencyArc(pdgNode, node, variable)); } }) .setOnVariableDefinitionListener(node::addDefinedVariable) @@ -114,13 +114,13 @@ public class DataDependencyBuilder extends VoidVisitorAdapter { .setOnVariableUseListener(variable -> { forNode.addUsedVariable(variable); - Optional> nodeOptional = cfgGraph.findNodeByASTNode(statement); + Optional> nodeOptional = cfg.findNodeByASTNode(statement); if (!nodeOptional.isPresent()) { return; } - pdgGraph.addDataDependencyArc(forNode, forNode, variable); + pdg.addDataDependencyArc(forNode, forNode, variable); }) .setOnVariableDefinitionListener(forNode::addDefinedVariable) .setOnVariableDeclarationListener(forNode::addDeclaredVariable) diff --git a/src/main/java/tfm/visitors/pdg/PDGBuilder.java b/src/main/java/tfm/visitors/pdg/PDGBuilder.java index 09ad2f8..104294a 100644 --- a/src/main/java/tfm/visitors/pdg/PDGBuilder.java +++ b/src/main/java/tfm/visitors/pdg/PDGBuilder.java @@ -3,45 +3,45 @@ package tfm.visitors.pdg; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.stmt.BlockStmt; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import tfm.graphs.CFGGraph; -import tfm.graphs.PDGGraph; +import tfm.graphs.CFG; +import tfm.graphs.PDG; import tfm.visitors.cfg.CFGBuilder; public class PDGBuilder extends VoidVisitorAdapter { - private PDGGraph pdgGraph; - private CFGGraph cfgGraph; + private PDG pdg; + private CFG cfg; - public PDGBuilder(PDGGraph pdgGraph) { - this(pdgGraph, new CFGGraph()); + public PDGBuilder(PDG pdg) { + this(pdg, new CFG()); } - public PDGBuilder(PDGGraph pdgGraph, CFGGraph cfgGraph) { - this.pdgGraph = pdgGraph; - this.cfgGraph = cfgGraph; + public PDGBuilder(PDG pdg, CFG cfg) { + this.pdg = pdg; + this.cfg = cfg; - this.pdgGraph.setCfgGraph(cfgGraph); + this.pdg.setCfg(cfg); } public void visit(MethodDeclaration methodDeclaration, Void empty) { if (!methodDeclaration.getBody().isPresent()) return; - this.pdgGraph.buildRootNode("ENTER " + methodDeclaration.getNameAsString(), methodDeclaration); + this.pdg.buildRootNode("ENTER " + methodDeclaration.getNameAsString(), methodDeclaration); - assert this.pdgGraph.getRootNode().isPresent(); + assert this.pdg.getRootNode().isPresent(); // build CFG - methodDeclaration.accept(new CFGBuilder(cfgGraph), null); + methodDeclaration.accept(new CFGBuilder(cfg), null); BlockStmt methodBody = methodDeclaration.getBody().get(); // Build control dependency - ControlDependencyBuilder controlDependencyBuilder = new ControlDependencyBuilder(pdgGraph, cfgGraph); - methodBody.accept(controlDependencyBuilder, pdgGraph.getRootNode().get()); + ControlDependencyBuilder controlDependencyBuilder = new ControlDependencyBuilder(pdg, cfg); + methodBody.accept(controlDependencyBuilder, pdg.getRootNode().get()); // Build data dependency - DataDependencyBuilder dataDependencyBuilder = new DataDependencyBuilder(pdgGraph, cfgGraph); + DataDependencyBuilder dataDependencyBuilder = new DataDependencyBuilder(pdg, cfg); methodBody.accept(dataDependencyBuilder, null); } } diff --git a/src/main/java/tfm/visitors/sdg/MethodCallReplacer.java b/src/main/java/tfm/visitors/sdg/MethodCallReplacer.java index 93137fd..4613134 100644 --- a/src/main/java/tfm/visitors/sdg/MethodCallReplacer.java +++ b/src/main/java/tfm/visitors/sdg/MethodCallReplacer.java @@ -1,17 +1,17 @@ package tfm.visitors.sdg; -import tfm.graphs.SDGGraph; +import tfm.graphs.SDG; public class MethodCallReplacer { - private SDGGraph sdgGraph; + private SDG sdg; - public MethodCallReplacer(SDGGraph sdgGraph) { - this.sdgGraph = sdgGraph; + public MethodCallReplacer(SDG sdg) { + this.sdg = sdg; } public void replace() { - this.sdgGraph.getContextPDGGraphMap() + this.sdg.getContextPDGGraphMap() .forEach((context, pdgGraph) -> { if (!context.getCurrentMethod().isPresent()) { return; // Should NOT happen diff --git a/src/main/java/tfm/visitors/sdg/MethodCallReplacerVisitor.java b/src/main/java/tfm/visitors/sdg/MethodCallReplacerVisitor.java index eb32ef0..1eec815 100644 --- a/src/main/java/tfm/visitors/sdg/MethodCallReplacerVisitor.java +++ b/src/main/java/tfm/visitors/sdg/MethodCallReplacerVisitor.java @@ -9,7 +9,7 @@ import com.github.javaparser.ast.expr.VariableDeclarationExpr; import com.github.javaparser.ast.stmt.ExpressionStmt; import com.github.javaparser.ast.type.Type; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import tfm.graphs.PDGGraph; +import tfm.graphs.PDG; import tfm.nodes.GraphNode; import tfm.utils.Context; import tfm.utils.Logger; @@ -21,10 +21,10 @@ import java.util.stream.Collectors; public class MethodCallReplacerVisitor extends VoidVisitorAdapter { - private PDGGraph pdgGraph; + private PDG pdg; - public MethodCallReplacerVisitor(PDGGraph pdgGraph) { - this.pdgGraph = pdgGraph; + public MethodCallReplacerVisitor(PDG pdg) { + this.pdg = pdg; } @Override @@ -57,7 +57,7 @@ public class MethodCallReplacerVisitor extends VoidVisitorAdapter { if (!Objects.equals(scopeName, currentClass.getNameAsString())) { // Check if 'scopeName' is a variable - List> declarations = pdgGraph.findDeclarationsOfVariable(scopeName); + List> declarations = pdg.findDeclarationsOfVariable(scopeName); if (declarations.isEmpty()) { // It is a static method call of another class. We do nothing diff --git a/src/main/java/tfm/visitors/sdg/NewSDGBuilder.java b/src/main/java/tfm/visitors/sdg/NewSDGBuilder.java index 3e81151..bf510e0 100644 --- a/src/main/java/tfm/visitors/sdg/NewSDGBuilder.java +++ b/src/main/java/tfm/visitors/sdg/NewSDGBuilder.java @@ -5,16 +5,16 @@ import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; import tfm.graphbuilding.Graphs; -import tfm.graphs.PDGGraph; -import tfm.graphs.SDGGraph; +import tfm.graphs.PDG; +import tfm.graphs.SDG; import tfm.utils.Context; public class NewSDGBuilder extends VoidVisitorAdapter { - SDGGraph sdgGraph; + SDG sdg; - public NewSDGBuilder(SDGGraph sdgGraph) { - this.sdgGraph = sdgGraph; + public NewSDGBuilder(SDG sdg) { + this.sdg = sdg; } @Override @@ -26,9 +26,9 @@ public class NewSDGBuilder extends VoidVisitorAdapter { context.setCurrentMethod(methodDeclaration); // Build PDG and add to SDGGraph - PDGGraph pdgGraph = Graphs.PDG.fromASTNode(methodDeclaration); + PDG pdg = Graphs.PDG.fromASTNode(methodDeclaration); - sdgGraph.addMethod(methodDeclaration, pdgGraph); + sdg.addMethod(methodDeclaration, pdg); } @Override @@ -51,7 +51,7 @@ public class NewSDGBuilder extends VoidVisitorAdapter { // Once every PDG is built, expand method call nodes of each one // and link them to the corresponding method declaration node - MethodCallReplacer methodCallReplacer = new MethodCallReplacer(sdgGraph); + MethodCallReplacer methodCallReplacer = new MethodCallReplacer(sdg); methodCallReplacer.replace(); diff --git a/src/main/java/tfm/visitors/sdg/SDGBuilder.java b/src/main/java/tfm/visitors/sdg/SDGBuilder.java index 9662844..dabf2fd 100644 --- a/src/main/java/tfm/visitors/sdg/SDGBuilder.java +++ b/src/main/java/tfm/visitors/sdg/SDGBuilder.java @@ -11,8 +11,8 @@ import com.github.javaparser.ast.stmt.ExpressionStmt; import com.github.javaparser.ast.stmt.Statement; import com.github.javaparser.ast.type.Type; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import tfm.graphs.PDGGraph; -import tfm.graphs.SDGGraph; +import tfm.graphs.PDG; +import tfm.graphs.SDG; import tfm.nodes.GraphNode; import tfm.visitors.pdg.PDGBuilder; @@ -28,15 +28,15 @@ import java.util.Optional; */ public class SDGBuilder extends VoidVisitorAdapter { - SDGGraph sdgGraph; - List pdgGraphs; + SDG sdg; + List pdgs; private ClassOrInterfaceDeclaration currentClass; private CompilationUnit currentCompilationUnit; - public SDGBuilder(SDGGraph sdgGraph) { - this.sdgGraph = sdgGraph; - this.pdgGraphs = new ArrayList<>(); + public SDGBuilder(SDG sdg) { + this.sdg = sdg; + this.pdgs = new ArrayList<>(); } @Override @@ -45,15 +45,15 @@ public class SDGBuilder extends VoidVisitorAdapter { return; - if (sdgGraph.isEmpty()) { - sdgGraph.addNode("ENTER " + methodDeclaration.getNameAsString(), methodDeclaration); + if (sdg.isEmpty()) { + sdg.addNode("ENTER " + methodDeclaration.getNameAsString(), methodDeclaration); } else { // sdgGraph.addMethod(methodDeclaration); } - PDGGraph pdgGraph = new PDGGraph(); + PDG pdg = new PDG(); - PDGBuilder PDGBuilder = new PDGBuilder(pdgGraph) { + PDGBuilder PDGBuilder = new PDGBuilder(pdg) { @Override public void visit(MethodCallExpr methodCallExpr, Void empty) { if (methodCallExpr.getScope().isPresent()) { @@ -65,7 +65,7 @@ public class SDGBuilder extends VoidVisitorAdapter { if (!Objects.equals(scopeName, currentClassName)) { // Check if 'scopeName' is a variable - List> declarations = sdgGraph.findDeclarationsOfVariable(scopeName); + List> declarations = sdg.findDeclarationsOfVariable(scopeName); if (declarations.isEmpty()) { // It is a static method call of another class. We don't do anything @@ -114,9 +114,9 @@ public class SDGBuilder extends VoidVisitorAdapter { PDGBuilder.visit(methodDeclaration, null); - sdgGraph.addNode(methodDeclaration.getNameAsString(), methodDeclaration); + sdg.addNode(methodDeclaration.getNameAsString(), methodDeclaration); - pdgGraph.vertexSet().stream().skip(1).forEach(pdgNode -> { + pdg.vertexSet().stream().skip(1).forEach(pdgNode -> { Statement statement = (Statement) pdgNode.getAstNode(); if (statement.isExpressionStmt()) { @@ -134,11 +134,11 @@ public class SDGBuilder extends VoidVisitorAdapter { - sdgGraph.addPDG(pdgGraph, methodDeclaration); + sdg.addPDG(pdg, methodDeclaration); methodDeclaration.accept(this, ignored); - pdgGraphs.add(pdgGraph); + pdgs.add(pdg); } @Override -- GitLab From 2b465f8db94b4c923d3eac9fb7c32eef103579e9 Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Thu, 23 Jan 2020 14:55:32 +0100 Subject: [PATCH 19/27] Updated readme.md with the changes to the API Deleted copy of readme.md in ./src/main/java/tfm --- readme.md | 54 ++++++++----- src/main/java/tfm/readme.md | 153 ------------------------------------ 2 files changed, 35 insertions(+), 172 deletions(-) delete mode 100644 src/main/java/tfm/readme.md diff --git a/readme.md b/readme.md index 9fd78a3..357cd4e 100644 --- a/readme.md +++ b/readme.md @@ -34,9 +34,9 @@ Find `Slice` class (`tfm/slicing`), set the program path and execute. The sliced ## Structure -Graphs are built using a library called `graphlib`, located in `lib/graphlib.jar`. This library is old and has some issues I had to fix... +Graphs are built using a library called `JGraphT`. -The main class is the `Graph` class, which extends from `graphlib`'s `Graph` class. This class includes some behaviour fixes, and some general interest methods (like `toString`, `toGraphvizRepresentation`, etc.) +The main class is the `Graph` class, which extends from `JGraphT`'s `DefaultDirectedGraph` class. This class includes some general interest methods (like `toString`, etc.) Every graph has a set of nodes and arrows. `GraphNode` and `Arc` classes are used to represent them respectively. @@ -104,7 +104,7 @@ Forget about the `tfm/scopes` folder, it was an idea I had to discard and it has ### General -- Switch to a (much) better graph library like [JGraphT](https://jgrapht.org/). It also supports graph visualization +- Switch to a (much) better graph library like [JGraphT](https://jgrapht.org/). It also supports graph visualization (done). - Performance review - Make a test suite (test graph building, slicing, etc.) - Add support to more Java language features (lambdas, etc.) @@ -114,28 +114,44 @@ Forget about the `tfm/scopes` folder, it was an idea I had to discard and it has ### Build a CFG from a program ```java -public CFGGraph buildCFG(File programFile) { - JavaParser.getStaticConfiguration().setAttributeComments(false); // Always disable comments, just in case - - Node astRoot = JavaParser.parse(programFile); - - return Graphs.CFG.fromASTNode(astRoot); // Creates a new graph representing the program +public class Example { + public CFG buildCFG(File programFile) { + // Always disable attribution of comments, just in case + JavaParser.getStaticConfiguration().setAttributeComments(false); + + Node astRoot = JavaParser.parse(programFile); + Optional optMethod = astRoot.findFirst(MethodDeclaration.class); + if (!optMethod.isPresent) + throw new RuntimeException("No method could be found"); + + // Creates a new graph representing the program + CFG cfg = new CFG(); + cfg.build(optMethod.get()); + return cfg; + } } ``` ### Get a slice of the PDG of a program ```java -public PDGGraph getSlice(File program, SlicingCriterion slicingCriterion) { - JavaParser.getStaticConfiguration().setAttributeComments(false); // Always disable comments, just in case - - Node astRoot = JavaParser.parse(programFile); - - PDGGraph pdg = Graphs.PDG.fromASTNode(astRoot); - - return pdg.slice(slicingCriterion); +public class Example { + public PDGGraph getSlice(File program, SlicingCriterion slicingCriterion) { + // Always disable attribution of comments, just in case + JavaParser.getStaticConfiguration().setAttributeComments(false); + + Node astRoot = JavaParser.parse(programFile); + Optional optMethod = astRoot.findFirst(MethodDeclaration.class); + if (!optMethod.isPresent) + throw new RuntimeException("No method could be found"); + + // Creates a new graph representing the program + PDG pdg = new PDG(); + pdg.build(optMethod.get()); + // Slice PDG + return pdg.slice(slicingCriterion); + } } - ``` ## Workflow @@ -143,7 +159,7 @@ public PDGGraph getSlice(File program, SlicingCriterion slicingCriterion) { - Branches: - `master` (only for stable versions) - `develop` (main branch) - - `` + - `-name` 1. Discover a new feature/fix 2. Open an issue describing it and assign it diff --git a/src/main/java/tfm/readme.md b/src/main/java/tfm/readme.md deleted file mode 100644 index 9fd78a3..0000000 --- a/src/main/java/tfm/readme.md +++ /dev/null @@ -1,153 +0,0 @@ -# TFM - -- [TFM](#tfm) - - [Introduction](#introduction) - - [Quick start](#quick-start) - - [Build a graph](#build-a-graph) - - [Slice a program](#slice-a-program) - - [Structure](#structure) - - [Summary](#summary) - - [Current state](#current-state) - - [Graphs](#graphs) - - [Statements covered](#statements-covered) - - [To do list](#to-do-list) - - [SDG](#sdg) - - [General](#general) - - [Code samples](#code-samples) - - [Build a CFG from a program](#build-a-cfg-from-a-program) - - [Get a slice of the PDG of a program](#get-a-slice-of-the-pdg-of-a-program) - - [Workflow](#workflow) - -## Introduction - -The main goal of this work is to develop a Java slicer. This is done by building a System Dependence Graph of the program being sliced - -## Quick start - -### Build a graph - -Find `Main` class (`tfm/exec`), modify static fields of the class (the program being analyzed, the graph to build, etc.) and execute it. You will find the output in `tfm/out` as a png image - -### Slice a program - -Find `Slice` class (`tfm/slicing`), set the program path and execute. The sliced program will be in `tfm/out` - -## Structure - -Graphs are built using a library called `graphlib`, located in `lib/graphlib.jar`. This library is old and has some issues I had to fix... - -The main class is the `Graph` class, which extends from `graphlib`'s `Graph` class. This class includes some behaviour fixes, and some general interest methods (like `toString`, `toGraphvizRepresentation`, etc.) - -Every graph has a set of nodes and arrows. `GraphNode` and `Arc` classes are used to represent them respectively. - -A set of visitors is implemented for many things, such as graph building, data dependence building, etc... (available in `tfm/visitors`) - -A bunch of programs are written in `tfm/programs`, you can write more there. - -Some naive testing is implemented in the `tfm/validation` folder. Currently, a PDG can be compared with a program to check their equality. - -Some util methods are available in `tfm/utils` (such as AST utils, logger, etc.) - -Forget about the `tfm/scopes` folder, it was an idea I had to discard and it has to be deleted. - -### Summary - -- Graphs (`tfm/graphs`) - - CFGGraph - - PDGGraph - - SDGGraph - -- Nodes (`tfm/nodes`) - - ~~CFGNode, PDGNode, SDGNode~~ (_Deprecated_) - - GraphNode - - MethodCallNode (_idk if this is necessary, maybe it can be deleted_) - -- Arcs (`tfm/arcs`) - - ControlFlowArc - - DataDependencyArc - - ControlDependencyArc - -- Visitors (`tfm/visitors`) - - CFGBuilder - - ~~PDGVisitor~~ (_Deprecated, it was an intent to build a PDG with no CFG needed_) - - PDGBuilder - - ControlDependencyBuilder - - DataDependencyBuilder - - SDGBuilder (_Probably deprecated_) - - NewSDGBuilder -**Work in progress**- - - MethodCallReplacerVisitor (_Replaces method call nodes with in and out variable nodes_) -**Work in progress**- - -## Current state - -### Graphs - -- CFG: Done! -- PDG: Done! -- SDG: PDGs are built for each method - -### Statements covered - -- Expressions (ExpressionStmt) -- If (IfStmt) -- While, DoWhile (WhileStmt, DoStmt) -- For, Foreach (ForStmt, ForeachStmt) -- Switch (SwitchStmt, SwitchEntryStmt) -- Break (BreakStmt) -- Continue (ContinueStmt) - -## To do list - -### SDG - -- Replace method call nodes with in and out variables nodes and build arrows for them -- Build summary arrows - -### General - -- Switch to a (much) better graph library like [JGraphT](https://jgrapht.org/). It also supports graph visualization -- Performance review -- Make a test suite (test graph building, slicing, etc.) -- Add support to more Java language features (lambdas, etc.) - -## Code samples - -### Build a CFG from a program - -```java -public CFGGraph buildCFG(File programFile) { - JavaParser.getStaticConfiguration().setAttributeComments(false); // Always disable comments, just in case - - Node astRoot = JavaParser.parse(programFile); - - return Graphs.CFG.fromASTNode(astRoot); // Creates a new graph representing the program -} -``` - -### Get a slice of the PDG of a program - -```java -public PDGGraph getSlice(File program, SlicingCriterion slicingCriterion) { - JavaParser.getStaticConfiguration().setAttributeComments(false); // Always disable comments, just in case - - Node astRoot = JavaParser.parse(programFile); - - PDGGraph pdg = Graphs.PDG.fromASTNode(astRoot); - - return pdg.slice(slicingCriterion); -} - -``` - -## Workflow - -- Branches: - - `master` (only for stable versions) - - `develop` (main branch) - - `` - -1. Discover a new feature/fix -2. Open an issue describing it and assign it -4. Create a new branch from `develop` with the same name as the issue number (e.g. for issue #12 the new branch is called `12`) -5. Write the solution to the issue -6. Once resolved, open a pull request from the issue branch to `develop` branch -7. Finally, when pull request is merged, remove branch \ No newline at end of file -- GitLab From 17af8cad17eff15263f016ab078d220b36ea9283 Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Thu, 23 Jan 2020 18:37:29 +0100 Subject: [PATCH 20/27] Small fixes * Tests creates the root node of the PDG * Data dependency ignores nonexecutable edges * Non-executable edges are displayed as dashed * Small bug in the implementation of `CFGBuilder` --- src/main/java/tfm/arcs/Arc.java | 4 ---- src/main/java/tfm/arcs/cfg/ControlFlowArc.java | 15 ++++++++++----- .../java/tfm/arcs/pdg/ControlDependencyArc.java | 2 -- src/main/java/tfm/graphs/CFG.java | 6 +++--- src/main/java/tfm/graphs/CFGBuilder.java | 2 +- src/test/java/tfm/PDGTests.java | 3 +++ 6 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/main/java/tfm/arcs/Arc.java b/src/main/java/tfm/arcs/Arc.java index 7a94977..6dc746e 100644 --- a/src/main/java/tfm/arcs/Arc.java +++ b/src/main/java/tfm/arcs/Arc.java @@ -12,10 +12,6 @@ import java.util.Map; import java.util.Objects; public abstract class Arc extends DefaultEdge { - public Arc() { - - } - /** @see tfm.arcs.cfg.ControlFlowArc */ public final boolean isControlFlowArc() { return this instanceof ControlFlowArc; diff --git a/src/main/java/tfm/arcs/cfg/ControlFlowArc.java b/src/main/java/tfm/arcs/cfg/ControlFlowArc.java index 7ac0568..85e0de1 100644 --- a/src/main/java/tfm/arcs/cfg/ControlFlowArc.java +++ b/src/main/java/tfm/arcs/cfg/ControlFlowArc.java @@ -1,17 +1,18 @@ package tfm.arcs.cfg; +import org.jgrapht.io.Attribute; +import org.jgrapht.io.DefaultAttribute; import tfm.arcs.Arc; import tfm.graphs.augmented.ACFG; +import java.util.Map; + /** * An edge of the {@link tfm.graphs.CFG}, representing the direct * flow of control. It connects two instructions if, when the source * is executed, one of the possible next instructions is the destination. */ public class ControlFlowArc extends Arc { - public ControlFlowArc() { - } - /** * Represents a non-executable control flow arc, used within the {@link ACFG ACFG}. * Initially it had the following meaning: connecting a statement with @@ -20,8 +21,12 @@ public class ControlFlowArc extends Arc { * It is used to improve control dependence, and it should be skipped when * computing data dependence and other analyses. */ - public final static class NonExecutable extends ControlFlowArc { - public NonExecutable() { + public static final class NonExecutable extends ControlFlowArc { + @Override + public Map getDotAttributes() { + Map map = super.getDotAttributes(); + map.put("style", DefaultAttribute.createAttribute("dashed")); + return map; } } } diff --git a/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java b/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java index e63f53c..16178d3 100644 --- a/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java +++ b/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java @@ -9,6 +9,4 @@ import tfm.arcs.Arc; * {@code b} if and only if {@code b} alters the number of times {@code a} is executed. */ public class ControlDependencyArc extends Arc { - public ControlDependencyArc() { - } } diff --git a/src/main/java/tfm/graphs/CFG.java b/src/main/java/tfm/graphs/CFG.java index 471935b..7ab1be7 100644 --- a/src/main/java/tfm/graphs/CFG.java +++ b/src/main/java/tfm/graphs/CFG.java @@ -44,9 +44,9 @@ public class CFG extends GraphWithRootNode { Set> res = new HashSet<>(); for (Arc arc : incomingEdgesOf(currentNode)) { - ControlFlowArc controlFlowArc = arc.asControlFlowArc(); - - GraphNode from = this.getEdgeSource(controlFlowArc); + if (!arc.isExecutableControlFlowArc()) + continue; + GraphNode from = getEdgeSource(arc); if (!Objects.equals(startNode, from) && visited.contains(from.getId())) { continue; diff --git a/src/main/java/tfm/graphs/CFGBuilder.java b/src/main/java/tfm/graphs/CFGBuilder.java index 1910296..ff16786 100644 --- a/src/main/java/tfm/graphs/CFGBuilder.java +++ b/src/main/java/tfm/graphs/CFGBuilder.java @@ -108,7 +108,7 @@ public class CFGBuilder extends VoidVisitorAdapter { hangingNodes.addAll(breakMap.remove(n.getLabel())); // Remove the label from the continue map; the list should have been emptied // in the corresponding loop. - if (continueMap.remove(n.getLabel()).isEmpty()) + if (!continueMap.remove(n.getLabel()).isEmpty()) throw new IllegalStateException("Labeled loop has not cleared its list of continue statements!"); } diff --git a/src/test/java/tfm/PDGTests.java b/src/test/java/tfm/PDGTests.java index c2dbeae..e68aff8 100644 --- a/src/test/java/tfm/PDGTests.java +++ b/src/test/java/tfm/PDGTests.java @@ -82,6 +82,7 @@ public class PDGTests { CFG cfg = new CFG(); cfg.build(root); PDG pdg = new PDG(cfg); + pdg.buildRootNode("ENTER " + methodName, root); ctrlDepBuilder = new ControlDependencyBuilder(pdg, cfg); ctrlDepBuilder.analyze(); @@ -89,11 +90,13 @@ public class PDGTests { ACFG acfg = new ACFG(); acfg.build(root); APDG apdg = new APDG(acfg); + apdg.buildRootNode("ENTER " + methodName, root); ctrlDepBuilder = new ControlDependencyBuilder(apdg, acfg); ctrlDepBuilder.analyze(); // Create PPDG PPDG ppdg = new PPDG(acfg); + ppdg.buildRootNode("ENTER " + methodName, root); ctrlDepBuilder = new ControlDependencyBuilder(ppdg, acfg); ctrlDepBuilder.analyze(); -- GitLab From eca0b61bd0ac71b03eabb0520ca605e08dd03789 Mon Sep 17 00:00:00 2001 From: Javier Costa Date: Thu, 23 Jan 2020 22:20:46 +0100 Subject: [PATCH 21/27] Equals and hashCode in DataDependencyArc --- .../java/tfm/arcs/pdg/DataDependencyArc.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/main/java/tfm/arcs/pdg/DataDependencyArc.java b/src/main/java/tfm/arcs/pdg/DataDependencyArc.java index 183a571..ce60c99 100644 --- a/src/main/java/tfm/arcs/pdg/DataDependencyArc.java +++ b/src/main/java/tfm/arcs/pdg/DataDependencyArc.java @@ -5,6 +5,7 @@ import org.jgrapht.io.DefaultAttribute; import tfm.arcs.Arc; import java.util.Map; +import java.util.Objects; /** * An arc used in the {@link tfm.graphs.PDG} and {@link tfm.graphs.SDG}, @@ -33,5 +34,27 @@ public class DataDependencyArc extends Arc { map.put("color", DefaultAttribute.createAttribute("red")); return map; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (!(o instanceof DataDependencyArc)) { + return false; + } + + DataDependencyArc other = (DataDependencyArc) o; + + return Objects.equals(variable, other.variable) + && Objects.equals(getSource(), other.getSource()) + && Objects.equals(getTarget(), other.getTarget()); + } + + @Override + public int hashCode() { + return Objects.hash(variable, getSource(), getTarget()); + } } -- GitLab From 4168d9e26f3fe71642219bf710170c45dcb28e57 Mon Sep 17 00:00:00 2001 From: Javier Costa Date: Thu, 23 Jan 2020 22:24:16 +0100 Subject: [PATCH 22/27] Removed graphbuilding and visitors package + structured graphs package --- .../java/tfm/arcs/cfg/ControlFlowArc.java | 3 +- .../tfm/arcs/pdg/ControlDependencyArc.java | 4 +- .../java/tfm/arcs/pdg/DataDependencyArc.java | 4 +- src/main/java/tfm/exec/CFGLog.java | 2 +- src/main/java/tfm/exec/Main.java | 6 +- src/main/java/tfm/exec/PDGLog.java | 2 +- src/main/java/tfm/exec/SDGLog.java | 2 +- .../java/tfm/graphbuilding/GraphOptions.java | 76 ----------- src/main/java/tfm/graphbuilding/Graphs.java | 13 -- src/main/java/tfm/graphs/augmented/ACFG.java | 4 +- .../tfm/graphs/augmented/ACFGBuilder.java | 2 +- src/main/java/tfm/graphs/augmented/APDG.java | 2 +- src/main/java/tfm/graphs/{ => cfg}/CFG.java | 3 +- .../java/tfm/graphs/{ => cfg}/CFGBuilder.java | 2 +- .../pdg/ControlDependencyBuilder.java | 6 +- .../pdg/DataDependencyBuilder.java | 8 +- src/main/java/tfm/graphs/{ => pdg}/PDG.java | 5 +- .../java/tfm/graphs/{ => pdg}/PDGBuilder.java | 5 +- .../sdg/MethodCallReplacer.java | 6 +- .../sdg/MethodCallReplacerVisitor.java | 6 +- .../sdg/NewSDGBuilder.java | 11 +- src/main/java/tfm/graphs/{ => sdg}/SDG.java | 5 +- .../java/tfm/graphs/{ => sdg}/SDGBuilder.java | 5 +- src/main/java/tfm/nodes/GraphNode.java | 7 +- .../java/tfm/slicing/GraphNodeCriterion.java | 6 +- .../java/tfm/slicing/LineNumberCriterion.java | 6 +- .../java/tfm/slicing/SlicingCriterion.java | 6 +- .../java/tfm/validation/PDGValidator.java | 119 ------------------ .../tfm/validation/ProgramComparator.java | 24 ---- .../sdg/MethodDeclarationReplacer.java | 4 - src/test/java/tfm/HandCraftedGraphs.java | 2 +- src/test/java/tfm/PDGTests.java | 6 +- 32 files changed, 69 insertions(+), 293 deletions(-) delete mode 100644 src/main/java/tfm/graphbuilding/GraphOptions.java delete mode 100644 src/main/java/tfm/graphbuilding/Graphs.java rename src/main/java/tfm/graphs/{ => cfg}/CFG.java (97%) rename src/main/java/tfm/graphs/{ => cfg}/CFGBuilder.java (99%) rename src/main/java/tfm/{visitors => graphs}/pdg/ControlDependencyBuilder.java (98%) rename src/main/java/tfm/{visitors => graphs}/pdg/DataDependencyBuilder.java (96%) rename src/main/java/tfm/graphs/{ => pdg}/PDG.java (94%) rename src/main/java/tfm/graphs/{ => pdg}/PDGBuilder.java (94%) rename src/main/java/tfm/{visitors => graphs}/sdg/MethodCallReplacer.java (85%) rename src/main/java/tfm/{visitors => graphs}/sdg/MethodCallReplacerVisitor.java (97%) rename src/main/java/tfm/{visitors => graphs}/sdg/NewSDGBuilder.java (88%) rename src/main/java/tfm/graphs/{ => sdg}/SDG.java (96%) rename src/main/java/tfm/graphs/{ => sdg}/SDGBuilder.java (98%) delete mode 100644 src/main/java/tfm/validation/PDGValidator.java delete mode 100644 src/main/java/tfm/validation/ProgramComparator.java delete mode 100644 src/main/java/tfm/visitors/sdg/MethodDeclarationReplacer.java diff --git a/src/main/java/tfm/arcs/cfg/ControlFlowArc.java b/src/main/java/tfm/arcs/cfg/ControlFlowArc.java index 85e0de1..4a5f23f 100644 --- a/src/main/java/tfm/arcs/cfg/ControlFlowArc.java +++ b/src/main/java/tfm/arcs/cfg/ControlFlowArc.java @@ -4,11 +4,12 @@ import org.jgrapht.io.Attribute; import org.jgrapht.io.DefaultAttribute; import tfm.arcs.Arc; import tfm.graphs.augmented.ACFG; +import tfm.graphs.cfg.CFG; import java.util.Map; /** - * An edge of the {@link tfm.graphs.CFG}, representing the direct + * An edge of the {@link CFG}, representing the direct * flow of control. It connects two instructions if, when the source * is executed, one of the possible next instructions is the destination. */ diff --git a/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java b/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java index 16178d3..969d9f8 100644 --- a/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java +++ b/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java @@ -1,9 +1,11 @@ package tfm.arcs.pdg; import tfm.arcs.Arc; +import tfm.graphs.pdg.PDG; +import tfm.graphs.sdg.SDG; /** - * An arc used in the {@link tfm.graphs.PDG} and {@link tfm.graphs.SDG} + * An arc used in the {@link PDG} and {@link SDG} * used to represent control dependence between two nodes. The traditional definition of * control dependence is: a node {@code a} is control dependent on node * {@code b} if and only if {@code b} alters the number of times {@code a} is executed. diff --git a/src/main/java/tfm/arcs/pdg/DataDependencyArc.java b/src/main/java/tfm/arcs/pdg/DataDependencyArc.java index ce60c99..6c006b6 100644 --- a/src/main/java/tfm/arcs/pdg/DataDependencyArc.java +++ b/src/main/java/tfm/arcs/pdg/DataDependencyArc.java @@ -3,12 +3,14 @@ package tfm.arcs.pdg; import org.jgrapht.io.Attribute; import org.jgrapht.io.DefaultAttribute; import tfm.arcs.Arc; +import tfm.graphs.pdg.PDG; +import tfm.graphs.sdg.SDG; import java.util.Map; import java.util.Objects; /** - * An arc used in the {@link tfm.graphs.PDG} and {@link tfm.graphs.SDG}, + * An arc used in the {@link PDG} and {@link SDG}, * representing the declaration of some data linked to its usage (of that value). * There is data dependency between two nodes if and only if (1) the source may * declare a variable, (2) the destination may use it, and (3) there is a diff --git a/src/main/java/tfm/exec/CFGLog.java b/src/main/java/tfm/exec/CFGLog.java index 7284ac8..3969535 100644 --- a/src/main/java/tfm/exec/CFGLog.java +++ b/src/main/java/tfm/exec/CFGLog.java @@ -1,6 +1,6 @@ package tfm.exec; -import tfm.graphs.CFG; +import tfm.graphs.cfg.CFG; public class CFGLog extends GraphLog { public CFGLog() { diff --git a/src/main/java/tfm/exec/Main.java b/src/main/java/tfm/exec/Main.java index 56706cd..51b9e8e 100644 --- a/src/main/java/tfm/exec/Main.java +++ b/src/main/java/tfm/exec/Main.java @@ -3,10 +3,10 @@ package tfm.exec; import com.github.javaparser.JavaParser; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.MethodDeclaration; -import tfm.graphs.CFG; +import tfm.graphs.cfg.CFG; import tfm.graphs.Graph; -import tfm.graphs.PDG; -import tfm.graphs.SDG; +import tfm.graphs.pdg.PDG; +import tfm.graphs.sdg.SDG; import tfm.utils.Logger; import tfm.utils.Utils; diff --git a/src/main/java/tfm/exec/PDGLog.java b/src/main/java/tfm/exec/PDGLog.java index 4983136..6634a78 100644 --- a/src/main/java/tfm/exec/PDGLog.java +++ b/src/main/java/tfm/exec/PDGLog.java @@ -1,6 +1,6 @@ package tfm.exec; -import tfm.graphs.PDG; +import tfm.graphs.pdg.PDG; import tfm.nodes.GraphNode; import tfm.utils.Logger; diff --git a/src/main/java/tfm/exec/SDGLog.java b/src/main/java/tfm/exec/SDGLog.java index c61e416..cdeae27 100644 --- a/src/main/java/tfm/exec/SDGLog.java +++ b/src/main/java/tfm/exec/SDGLog.java @@ -1,6 +1,6 @@ package tfm.exec; -import tfm.graphs.SDG; +import tfm.graphs.sdg.SDG; public class SDGLog extends GraphLog { public SDGLog() { diff --git a/src/main/java/tfm/graphbuilding/GraphOptions.java b/src/main/java/tfm/graphbuilding/GraphOptions.java deleted file mode 100644 index 9e7d6cb..0000000 --- a/src/main/java/tfm/graphbuilding/GraphOptions.java +++ /dev/null @@ -1,76 +0,0 @@ -package tfm.graphbuilding; - -import com.github.javaparser.ast.CompilationUnit; -import com.github.javaparser.ast.Node; -import com.github.javaparser.ast.NodeList; -import com.github.javaparser.ast.body.MethodDeclaration; -import tfm.graphs.CFG; -import tfm.graphs.Graph; -import tfm.graphs.PDG; -import tfm.graphs.SDG; - -public abstract class GraphOptions { - public abstract G empty(); - - public G fromASTNode(Node node) { - G emptyGraph = empty(); - - buildGraphWithSpecificVisitor(emptyGraph, node); - - return emptyGraph; - } - - protected abstract void buildGraphWithSpecificVisitor(G emptyGraph, Node node); -} - -class CFGOptions extends GraphOptions { - - @Override - public CFG empty() { - return new CFG(); - } - - @Override - protected void buildGraphWithSpecificVisitor(CFG emptyGraph, Node node) { - if (node instanceof MethodDeclaration) { - emptyGraph.build((MethodDeclaration) node); - } else { - for (Node n : node.getChildNodes()) - buildGraphWithSpecificVisitor(emptyGraph, n); - } - } -} - -class PDGOptions extends GraphOptions { - - @Override - public PDG empty() { - return new PDG(); - } - - @Override - protected void buildGraphWithSpecificVisitor(PDG emptyGraph, Node node) { - if (node instanceof MethodDeclaration) { - emptyGraph.build((MethodDeclaration) node); - } else { - for (Node n : node.getChildNodes()) - buildGraphWithSpecificVisitor(emptyGraph, n); - } - } -} - -class SDGOptions extends GraphOptions { - - @Override - public SDG empty() { - return new SDG(); - } - - @Override - protected void buildGraphWithSpecificVisitor(SDG emptyGraph, Node node) { - if (node instanceof CompilationUnit) - emptyGraph.build(new NodeList<>(((CompilationUnit) node))); - else - throw new IllegalStateException("The node needs to be a CompilationUnit"); - } -} \ No newline at end of file diff --git a/src/main/java/tfm/graphbuilding/Graphs.java b/src/main/java/tfm/graphbuilding/Graphs.java deleted file mode 100644 index 548bfcd..0000000 --- a/src/main/java/tfm/graphbuilding/Graphs.java +++ /dev/null @@ -1,13 +0,0 @@ -package tfm.graphbuilding; - -import tfm.graphs.CFG; -import tfm.graphs.PDG; -import tfm.graphs.SDG; - -public class Graphs { - - public static final GraphOptions CFG = new CFGOptions(); - public static final GraphOptions PDG = new PDGOptions(); - public static final GraphOptions SDG = new SDGOptions(); - -} \ No newline at end of file diff --git a/src/main/java/tfm/graphs/augmented/ACFG.java b/src/main/java/tfm/graphs/augmented/ACFG.java index 3b57f50..b05e44e 100644 --- a/src/main/java/tfm/graphs/augmented/ACFG.java +++ b/src/main/java/tfm/graphs/augmented/ACFG.java @@ -1,8 +1,8 @@ package tfm.graphs.augmented; import tfm.arcs.cfg.ControlFlowArc; -import tfm.graphs.CFG; -import tfm.graphs.CFGBuilder; +import tfm.graphs.cfg.CFG; +import tfm.graphs.cfg.CFGBuilder; import tfm.nodes.GraphNode; public class ACFG extends CFG { diff --git a/src/main/java/tfm/graphs/augmented/ACFGBuilder.java b/src/main/java/tfm/graphs/augmented/ACFGBuilder.java index 4885046..d250d09 100644 --- a/src/main/java/tfm/graphs/augmented/ACFGBuilder.java +++ b/src/main/java/tfm/graphs/augmented/ACFGBuilder.java @@ -6,7 +6,7 @@ import com.github.javaparser.ast.expr.BooleanLiteralExpr; import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.stmt.*; import com.github.javaparser.ast.visitor.VoidVisitor; -import tfm.graphs.CFGBuilder; +import tfm.graphs.cfg.CFGBuilder; import tfm.nodes.GraphNode; import tfm.utils.ASTUtils; diff --git a/src/main/java/tfm/graphs/augmented/APDG.java b/src/main/java/tfm/graphs/augmented/APDG.java index 58b3ea3..9807418 100644 --- a/src/main/java/tfm/graphs/augmented/APDG.java +++ b/src/main/java/tfm/graphs/augmented/APDG.java @@ -1,6 +1,6 @@ package tfm.graphs.augmented; -import tfm.graphs.PDG; +import tfm.graphs.pdg.PDG; public class APDG extends PDG { public APDG() { diff --git a/src/main/java/tfm/graphs/CFG.java b/src/main/java/tfm/graphs/cfg/CFG.java similarity index 97% rename from src/main/java/tfm/graphs/CFG.java rename to src/main/java/tfm/graphs/cfg/CFG.java index 7ab1be7..5d15f19 100644 --- a/src/main/java/tfm/graphs/CFG.java +++ b/src/main/java/tfm/graphs/cfg/CFG.java @@ -1,8 +1,9 @@ -package tfm.graphs; +package tfm.graphs.cfg; import com.github.javaparser.ast.body.MethodDeclaration; import tfm.arcs.Arc; import tfm.arcs.cfg.ControlFlowArc; +import tfm.graphs.GraphWithRootNode; import tfm.nodes.GraphNode; import tfm.utils.NodeNotFoundException; diff --git a/src/main/java/tfm/graphs/CFGBuilder.java b/src/main/java/tfm/graphs/cfg/CFGBuilder.java similarity index 99% rename from src/main/java/tfm/graphs/CFGBuilder.java rename to src/main/java/tfm/graphs/cfg/CFGBuilder.java index ff16786..56f0996 100644 --- a/src/main/java/tfm/graphs/CFGBuilder.java +++ b/src/main/java/tfm/graphs/cfg/CFGBuilder.java @@ -1,4 +1,4 @@ -package tfm.graphs; +package tfm.graphs.cfg; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.MethodDeclaration; diff --git a/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java b/src/main/java/tfm/graphs/pdg/ControlDependencyBuilder.java similarity index 98% rename from src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java rename to src/main/java/tfm/graphs/pdg/ControlDependencyBuilder.java index a79c343..18eb56b 100644 --- a/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java +++ b/src/main/java/tfm/graphs/pdg/ControlDependencyBuilder.java @@ -1,8 +1,8 @@ -package tfm.visitors.pdg; +package tfm.graphs.pdg; import tfm.arcs.Arc; -import tfm.graphs.CFG; -import tfm.graphs.PDG; +import tfm.graphs.cfg.CFG; +import tfm.graphs.pdg.PDG; import tfm.graphs.augmented.PPDG; import tfm.nodes.GraphNode; import tfm.nodes.NodeFactory; diff --git a/src/main/java/tfm/visitors/pdg/DataDependencyBuilder.java b/src/main/java/tfm/graphs/pdg/DataDependencyBuilder.java similarity index 96% rename from src/main/java/tfm/visitors/pdg/DataDependencyBuilder.java rename to src/main/java/tfm/graphs/pdg/DataDependencyBuilder.java index 786abca..7972730 100644 --- a/src/main/java/tfm/visitors/pdg/DataDependencyBuilder.java +++ b/src/main/java/tfm/graphs/pdg/DataDependencyBuilder.java @@ -1,16 +1,16 @@ -package tfm.visitors.pdg; +package tfm.graphs.pdg; import com.github.javaparser.ast.stmt.*; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import tfm.graphs.CFG; -import tfm.graphs.PDG; +import tfm.graphs.cfg.CFG; +import tfm.graphs.pdg.PDG; import tfm.nodes.GraphNode; import tfm.variables.VariableExtractor; import java.util.Optional; import java.util.Set; -public class DataDependencyBuilder extends VoidVisitorAdapter { +class DataDependencyBuilder extends VoidVisitorAdapter { private CFG cfg; private PDG pdg; diff --git a/src/main/java/tfm/graphs/PDG.java b/src/main/java/tfm/graphs/pdg/PDG.java similarity index 94% rename from src/main/java/tfm/graphs/PDG.java rename to src/main/java/tfm/graphs/pdg/PDG.java index 5655a8f..df79831 100644 --- a/src/main/java/tfm/graphs/PDG.java +++ b/src/main/java/tfm/graphs/pdg/PDG.java @@ -1,9 +1,12 @@ -package tfm.graphs; +package tfm.graphs.pdg; import com.github.javaparser.ast.body.MethodDeclaration; import tfm.arcs.Arc; import tfm.arcs.pdg.ControlDependencyArc; import tfm.arcs.pdg.DataDependencyArc; +import tfm.graphs.GraphWithRootNode; +import tfm.graphs.Sliceable; +import tfm.graphs.cfg.CFG; import tfm.nodes.GraphNode; import tfm.slicing.Slice; import tfm.slicing.SlicingCriterion; diff --git a/src/main/java/tfm/graphs/PDGBuilder.java b/src/main/java/tfm/graphs/pdg/PDGBuilder.java similarity index 94% rename from src/main/java/tfm/graphs/PDGBuilder.java rename to src/main/java/tfm/graphs/pdg/PDGBuilder.java index fab424a..1aee653 100644 --- a/src/main/java/tfm/graphs/PDGBuilder.java +++ b/src/main/java/tfm/graphs/pdg/PDGBuilder.java @@ -1,9 +1,8 @@ -package tfm.graphs; +package tfm.graphs.pdg; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.stmt.BlockStmt; -import tfm.visitors.pdg.ControlDependencyBuilder; -import tfm.visitors.pdg.DataDependencyBuilder; +import tfm.graphs.cfg.CFG; /** * Populates a {@link PDG}, given a complete {@link CFG}, an empty {@link PDG} and an AST root node. diff --git a/src/main/java/tfm/visitors/sdg/MethodCallReplacer.java b/src/main/java/tfm/graphs/sdg/MethodCallReplacer.java similarity index 85% rename from src/main/java/tfm/visitors/sdg/MethodCallReplacer.java rename to src/main/java/tfm/graphs/sdg/MethodCallReplacer.java index 4613134..1dc5bb0 100644 --- a/src/main/java/tfm/visitors/sdg/MethodCallReplacer.java +++ b/src/main/java/tfm/graphs/sdg/MethodCallReplacer.java @@ -1,8 +1,6 @@ -package tfm.visitors.sdg; +package tfm.graphs.sdg; -import tfm.graphs.SDG; - -public class MethodCallReplacer { +class MethodCallReplacer { private SDG sdg; diff --git a/src/main/java/tfm/visitors/sdg/MethodCallReplacerVisitor.java b/src/main/java/tfm/graphs/sdg/MethodCallReplacerVisitor.java similarity index 97% rename from src/main/java/tfm/visitors/sdg/MethodCallReplacerVisitor.java rename to src/main/java/tfm/graphs/sdg/MethodCallReplacerVisitor.java index 1eec815..f48547e 100644 --- a/src/main/java/tfm/visitors/sdg/MethodCallReplacerVisitor.java +++ b/src/main/java/tfm/graphs/sdg/MethodCallReplacerVisitor.java @@ -1,4 +1,4 @@ -package tfm.visitors.sdg; +package tfm.graphs.sdg; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; @@ -9,7 +9,7 @@ import com.github.javaparser.ast.expr.VariableDeclarationExpr; import com.github.javaparser.ast.stmt.ExpressionStmt; import com.github.javaparser.ast.type.Type; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import tfm.graphs.PDG; +import tfm.graphs.pdg.PDG; import tfm.nodes.GraphNode; import tfm.utils.Context; import tfm.utils.Logger; @@ -19,7 +19,7 @@ import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; -public class MethodCallReplacerVisitor extends VoidVisitorAdapter { +class MethodCallReplacerVisitor extends VoidVisitorAdapter { private PDG pdg; diff --git a/src/main/java/tfm/visitors/sdg/NewSDGBuilder.java b/src/main/java/tfm/graphs/sdg/NewSDGBuilder.java similarity index 88% rename from src/main/java/tfm/visitors/sdg/NewSDGBuilder.java rename to src/main/java/tfm/graphs/sdg/NewSDGBuilder.java index bf510e0..b170a56 100644 --- a/src/main/java/tfm/visitors/sdg/NewSDGBuilder.java +++ b/src/main/java/tfm/graphs/sdg/NewSDGBuilder.java @@ -1,15 +1,13 @@ -package tfm.visitors.sdg; +package tfm.graphs.sdg; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import tfm.graphbuilding.Graphs; -import tfm.graphs.PDG; -import tfm.graphs.SDG; +import tfm.graphs.pdg.PDG; import tfm.utils.Context; -public class NewSDGBuilder extends VoidVisitorAdapter { +class NewSDGBuilder extends VoidVisitorAdapter { SDG sdg; @@ -26,7 +24,8 @@ public class NewSDGBuilder extends VoidVisitorAdapter { context.setCurrentMethod(methodDeclaration); // Build PDG and add to SDGGraph - PDG pdg = Graphs.PDG.fromASTNode(methodDeclaration); + PDG pdg = new PDG(); + pdg.build(methodDeclaration); sdg.addMethod(methodDeclaration, pdg); } diff --git a/src/main/java/tfm/graphs/SDG.java b/src/main/java/tfm/graphs/sdg/SDG.java similarity index 96% rename from src/main/java/tfm/graphs/SDG.java rename to src/main/java/tfm/graphs/sdg/SDG.java index cc10297..30f7d36 100644 --- a/src/main/java/tfm/graphs/SDG.java +++ b/src/main/java/tfm/graphs/sdg/SDG.java @@ -1,10 +1,13 @@ -package tfm.graphs; +package tfm.graphs.sdg; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.NodeList; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.body.Parameter; import com.github.javaparser.ast.stmt.EmptyStmt; +import tfm.graphs.Buildable; +import tfm.graphs.Graph; +import tfm.graphs.pdg.PDG; import tfm.nodes.GraphNode; import tfm.nodes.NodeFactory; import tfm.slicing.Slice; diff --git a/src/main/java/tfm/graphs/SDGBuilder.java b/src/main/java/tfm/graphs/sdg/SDGBuilder.java similarity index 98% rename from src/main/java/tfm/graphs/SDGBuilder.java rename to src/main/java/tfm/graphs/sdg/SDGBuilder.java index 7a67bdf..6b1fddf 100644 --- a/src/main/java/tfm/graphs/SDGBuilder.java +++ b/src/main/java/tfm/graphs/sdg/SDGBuilder.java @@ -1,4 +1,4 @@ -package tfm.graphs; +package tfm.graphs.sdg; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; @@ -7,6 +7,7 @@ import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.ast.stmt.Statement; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; +import tfm.graphs.pdg.PDG; import java.util.ArrayList; import java.util.List; @@ -16,7 +17,7 @@ import java.util.List; * Asumimos que procesamos 1 archivo con una o más clases donde el primer método de la primera clase es el main * */ -public class SDGBuilder extends VoidVisitorAdapter { +class SDGBuilder extends VoidVisitorAdapter { SDG sdg; List pdgs; diff --git a/src/main/java/tfm/nodes/GraphNode.java b/src/main/java/tfm/nodes/GraphNode.java index a5dc20f..43c7646 100644 --- a/src/main/java/tfm/nodes/GraphNode.java +++ b/src/main/java/tfm/nodes/GraphNode.java @@ -3,6 +3,9 @@ package tfm.nodes; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.stmt.Statement; import org.jetbrains.annotations.NotNull; +import tfm.graphs.cfg.CFG; +import tfm.graphs.pdg.PDG; +import tfm.graphs.sdg.SDG; import tfm.utils.Utils; import tfm.variables.VariableExtractor; @@ -12,8 +15,8 @@ import java.util.Objects; import java.util.Set; /** - * Represents a node in the various graphs ({@link tfm.graphs.CFG CFG}, - * {@link tfm.graphs.PDG PDG} and {@link tfm.graphs.SDG SDG}), + * Represents a node in the various graphs ({@link CFG CFG}, + * {@link PDG PDG} and {@link SDG SDG}), * including its AST representation and the connections it has to other nodes * in the same graph. It can hold a string of characters that will be used * to represent it. diff --git a/src/main/java/tfm/slicing/GraphNodeCriterion.java b/src/main/java/tfm/slicing/GraphNodeCriterion.java index 173d215..927435c 100644 --- a/src/main/java/tfm/slicing/GraphNodeCriterion.java +++ b/src/main/java/tfm/slicing/GraphNodeCriterion.java @@ -1,8 +1,8 @@ package tfm.slicing; -import tfm.graphs.CFG; -import tfm.graphs.PDG; -import tfm.graphs.SDG; +import tfm.graphs.cfg.CFG; +import tfm.graphs.pdg.PDG; +import tfm.graphs.sdg.SDG; import tfm.nodes.GraphNode; import java.util.Optional; diff --git a/src/main/java/tfm/slicing/LineNumberCriterion.java b/src/main/java/tfm/slicing/LineNumberCriterion.java index 355398c..3eb8ead 100644 --- a/src/main/java/tfm/slicing/LineNumberCriterion.java +++ b/src/main/java/tfm/slicing/LineNumberCriterion.java @@ -1,9 +1,9 @@ package tfm.slicing; import com.github.javaparser.ast.Node; -import tfm.graphs.CFG; -import tfm.graphs.PDG; -import tfm.graphs.SDG; +import tfm.graphs.cfg.CFG; +import tfm.graphs.pdg.PDG; +import tfm.graphs.sdg.SDG; import tfm.nodes.GraphNode; import tfm.utils.Logger; diff --git a/src/main/java/tfm/slicing/SlicingCriterion.java b/src/main/java/tfm/slicing/SlicingCriterion.java index b01c357..d42d7be 100644 --- a/src/main/java/tfm/slicing/SlicingCriterion.java +++ b/src/main/java/tfm/slicing/SlicingCriterion.java @@ -1,8 +1,8 @@ package tfm.slicing; -import tfm.graphs.CFG; -import tfm.graphs.PDG; -import tfm.graphs.SDG; +import tfm.graphs.cfg.CFG; +import tfm.graphs.pdg.PDG; +import tfm.graphs.sdg.SDG; import tfm.nodes.GraphNode; import java.util.Optional; diff --git a/src/main/java/tfm/validation/PDGValidator.java b/src/main/java/tfm/validation/PDGValidator.java deleted file mode 100644 index 957291e..0000000 --- a/src/main/java/tfm/validation/PDGValidator.java +++ /dev/null @@ -1,119 +0,0 @@ -package tfm.validation; - -import com.github.javaparser.JavaParser; -import com.github.javaparser.ast.CompilationUnit; -import com.github.javaparser.ast.Modifier; -import com.github.javaparser.ast.NodeList; -import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; -import com.github.javaparser.ast.body.MethodDeclaration; -import com.github.javaparser.ast.body.Parameter; -import com.github.javaparser.ast.type.ArrayType; -import com.github.javaparser.ast.type.VoidType; -import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import tfm.graphs.PDG; -import tfm.utils.Logger; -import tfm.utils.Utils; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.PrintWriter; -import java.util.Objects; -import java.util.Optional; - -public class PDGValidator { - - private static final String PROGRAM_FOLDER = Utils.PROGRAMS_FOLDER + "pdg"; - private static final String PROGRAM_NAME = "Example2"; - private static final String METHOD_NAME = "main"; - - public static void main(String[] args) throws FileNotFoundException { - JavaParser.getStaticConfiguration().setAttributeComments(false); - - CompilationUnit originalProgram = JavaParser.parse(new File(String.format("%s/%s.java", PROGRAM_FOLDER, PROGRAM_NAME))); - - if (METHOD_NAME.isEmpty()) { - originalProgram.accept(new VoidVisitorAdapter() { - @Override - public void visit(MethodDeclaration n, Void arg) { - Logger.format("On method: %s. Generating and comparing...", n.getNameAsString()); - boolean check = generateAndCheck(n); - - Logger.format("Result: %s", check ? "equal" : "not equal"); - } - }, null); - } else { - Optional optionalTarget = originalProgram.findFirst(MethodDeclaration.class, - methodDeclaration -> Objects.equals(methodDeclaration.getNameAsString(), METHOD_NAME)); - - if (!optionalTarget.isPresent()) { - throw new RuntimeException(String.format("Method '%s' not found", METHOD_NAME)); - } - - Logger.format("On method: %s. Generating and comparing...", METHOD_NAME); - - boolean check = generateAndCheck(optionalTarget.get()); - - Logger.format("Result: %s", check ? "equal" : "not equal"); - } - } - - public static boolean generateAndCheck(MethodDeclaration methodDeclaration) { - PDG graph = new PDG(); - graph.build(methodDeclaration); - return check(methodDeclaration, graph); - } - - public static boolean check(MethodDeclaration methodDeclaration, PDG graph) { - MethodDeclaration generatedMethod = generateMethod(methodDeclaration, graph); - - return ProgramComparator.areEqual(methodDeclaration, generatedMethod); - } - - @Deprecated - public static MethodDeclaration generateMethod(MethodDeclaration info, PDG graph) { - // TODO: this does not work properly, replace or remove - throw new IllegalStateException("Deprecated method"); -// MethodDeclaration methodDeclaration = new MethodDeclaration(); -// -// methodDeclaration.setName(info.getNameAsString()); -// methodDeclaration.setModifiers(info.getModifiers()); -// methodDeclaration.setType(info.getType()); -// methodDeclaration.setParameters(info.getParameters()); -// -// BlockStmt methodBody = new BlockStmt(); -// methodDeclaration.setBody(methodBody); -// -// graph.getNodesAtLevel(1).stream() -// .sorted(Comparator.comparingInt(GraphNode::getId)) -// .forEach(node -> methodBody.addStatement((Statement) node.getAstNode())); -// -// return methodDeclaration; - } - - public static void printPDGProgram(String fileName, PDG graph) throws FileNotFoundException { - CompilationUnit generatedProgram = new CompilationUnit(); - ClassOrInterfaceDeclaration clazz = generatedProgram.addClass(fileName).setPublic(true); - - MethodDeclaration info = new MethodDeclaration(); - - info.setModifiers(Modifier.Keyword.PUBLIC, Modifier.Keyword.STATIC); - info.setType(new VoidType()); - info.setName("main"); - - Parameter parameter = new Parameter( - new ArrayType(JavaParser.parseClassOrInterfaceType("String")), - "args" - ); - info.setParameters(new NodeList<>(parameter)); - - MethodDeclaration generated = generateMethod(info, graph); - - clazz.addMember(generated); - - PrintWriter printWriter = new PrintWriter(new File(String.format("out/%s.java", fileName))); - - printWriter.print(clazz.toString()); - - printWriter.close(); - } -} diff --git a/src/main/java/tfm/validation/ProgramComparator.java b/src/main/java/tfm/validation/ProgramComparator.java deleted file mode 100644 index 2f6c263..0000000 --- a/src/main/java/tfm/validation/ProgramComparator.java +++ /dev/null @@ -1,24 +0,0 @@ -package tfm.validation; - -import com.github.javaparser.JavaParser; -import com.github.javaparser.ast.CompilationUnit; -import com.github.javaparser.ast.Node; - -import java.io.File; -import java.io.FileNotFoundException; - -public class ProgramComparator { - - public static boolean areEqual(File one, File two) throws FileNotFoundException { - JavaParser.getStaticConfiguration().setAttributeComments(false); - - CompilationUnit cu1 = JavaParser.parse(one); - CompilationUnit cu2 = JavaParser.parse(two); - - return areEqual(cu1, cu2); - } - - public static boolean areEqual(Node one, Node two) { - return one.equals(two); - } -} diff --git a/src/main/java/tfm/visitors/sdg/MethodDeclarationReplacer.java b/src/main/java/tfm/visitors/sdg/MethodDeclarationReplacer.java deleted file mode 100644 index 30542f1..0000000 --- a/src/main/java/tfm/visitors/sdg/MethodDeclarationReplacer.java +++ /dev/null @@ -1,4 +0,0 @@ -package tfm.visitors.sdg; - -public class MethodDeclarationReplacer { -} diff --git a/src/test/java/tfm/HandCraftedGraphs.java b/src/test/java/tfm/HandCraftedGraphs.java index 72ec352..945606e 100644 --- a/src/test/java/tfm/HandCraftedGraphs.java +++ b/src/test/java/tfm/HandCraftedGraphs.java @@ -12,7 +12,7 @@ import tfm.graphs.augmented.ACFG; import tfm.graphs.augmented.APDG; import tfm.graphs.augmented.PPDG; import tfm.nodes.GraphNode; -import tfm.visitors.pdg.ControlDependencyBuilder; +import tfm.graphs.pdg.ControlDependencyBuilder; public class HandCraftedGraphs { public static APDG problem1WithGotos() { diff --git a/src/test/java/tfm/PDGTests.java b/src/test/java/tfm/PDGTests.java index e68aff8..bbba0ab 100644 --- a/src/test/java/tfm/PDGTests.java +++ b/src/test/java/tfm/PDGTests.java @@ -11,8 +11,8 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import tfm.exec.GraphLog; import tfm.exec.PDGLog; -import tfm.graphs.CFG; -import tfm.graphs.PDG; +import tfm.graphs.cfg.CFG; +import tfm.graphs.pdg.PDG; import tfm.graphs.augmented.ACFG; import tfm.graphs.augmented.APDG; import tfm.graphs.augmented.PPDG; @@ -21,7 +21,7 @@ import tfm.slicing.GraphNodeCriterion; import tfm.slicing.Slice; import tfm.slicing.SlicingCriterion; import tfm.utils.Logger; -import tfm.visitors.pdg.ControlDependencyBuilder; +import tfm.graphs.pdg.ControlDependencyBuilder; import java.io.File; import java.io.IOException; -- GitLab From 75ee373a44e189734861c05d5549094a620d9d8b Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Fri, 24 Jan 2020 10:40:37 +0100 Subject: [PATCH 23/27] ControlDependencyBuilder is now package-private --- .../tfm/graphs/pdg/ControlDependencyBuilder.java | 5 ++--- .../tfm/{ => graphs/pdg}/HandCraftedGraphs.java | 3 +-- src/test/java/tfm/{ => graphs/pdg}/PDGTests.java | 16 +++++++--------- src/test/java/tfm/{ => utils}/FileFinder.java | 2 +- 4 files changed, 11 insertions(+), 15 deletions(-) rename src/test/java/tfm/{ => graphs/pdg}/HandCraftedGraphs.java (98%) rename src/test/java/tfm/{ => graphs/pdg}/PDGTests.java (94%) rename src/test/java/tfm/{ => utils}/FileFinder.java (98%) diff --git a/src/main/java/tfm/graphs/pdg/ControlDependencyBuilder.java b/src/main/java/tfm/graphs/pdg/ControlDependencyBuilder.java index 18eb56b..29fbe20 100644 --- a/src/main/java/tfm/graphs/pdg/ControlDependencyBuilder.java +++ b/src/main/java/tfm/graphs/pdg/ControlDependencyBuilder.java @@ -1,9 +1,8 @@ package tfm.graphs.pdg; import tfm.arcs.Arc; -import tfm.graphs.cfg.CFG; -import tfm.graphs.pdg.PDG; import tfm.graphs.augmented.PPDG; +import tfm.graphs.cfg.CFG; import tfm.nodes.GraphNode; import tfm.nodes.NodeFactory; @@ -29,7 +28,7 @@ import java.util.stream.Collectors; * Usage: pass an empty {@link PDG} and a filled {@link CFG} and then run {@link #analyze()}. * This builder should only be used once, and then discarded. */ -public class ControlDependencyBuilder { +class ControlDependencyBuilder { private final PDG pdg; private final CFG cfg; diff --git a/src/test/java/tfm/HandCraftedGraphs.java b/src/test/java/tfm/graphs/pdg/HandCraftedGraphs.java similarity index 98% rename from src/test/java/tfm/HandCraftedGraphs.java rename to src/test/java/tfm/graphs/pdg/HandCraftedGraphs.java index 945606e..698bcc5 100644 --- a/src/test/java/tfm/HandCraftedGraphs.java +++ b/src/test/java/tfm/graphs/pdg/HandCraftedGraphs.java @@ -1,4 +1,4 @@ -package tfm; +package tfm.graphs.pdg; import com.github.javaparser.ast.NodeList; import com.github.javaparser.ast.body.MethodDeclaration; @@ -12,7 +12,6 @@ import tfm.graphs.augmented.ACFG; import tfm.graphs.augmented.APDG; import tfm.graphs.augmented.PPDG; import tfm.nodes.GraphNode; -import tfm.graphs.pdg.ControlDependencyBuilder; public class HandCraftedGraphs { public static APDG problem1WithGotos() { diff --git a/src/test/java/tfm/PDGTests.java b/src/test/java/tfm/graphs/pdg/PDGTests.java similarity index 94% rename from src/test/java/tfm/PDGTests.java rename to src/test/java/tfm/graphs/pdg/PDGTests.java index bbba0ab..607c173 100644 --- a/src/test/java/tfm/PDGTests.java +++ b/src/test/java/tfm/graphs/pdg/PDGTests.java @@ -1,4 +1,4 @@ -package tfm; +package tfm.graphs.pdg; import com.github.javaparser.JavaParser; import com.github.javaparser.ast.Modifier; @@ -11,17 +11,15 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import tfm.exec.GraphLog; import tfm.exec.PDGLog; -import tfm.graphs.cfg.CFG; -import tfm.graphs.pdg.PDG; import tfm.graphs.augmented.ACFG; import tfm.graphs.augmented.APDG; import tfm.graphs.augmented.PPDG; +import tfm.graphs.cfg.CFG; import tfm.nodes.GraphNode; import tfm.slicing.GraphNodeCriterion; import tfm.slicing.Slice; import tfm.slicing.SlicingCriterion; import tfm.utils.Logger; -import tfm.graphs.pdg.ControlDependencyBuilder; import java.io.File; import java.io.IOException; @@ -40,19 +38,19 @@ public class PDGTests { private boolean error = false; @ParameterizedTest(name = "[{index}] {0} ({1})") - @MethodSource("tfm.FileFinder#findAllMethodDeclarations") + @MethodSource("tfm.utils.FileFinder#findAllMethodDeclarations") public void ppdgTest(File file, String methodName, MethodDeclaration root) throws IOException { runPdg(file, methodName, root, new PPDG()); } @ParameterizedTest(name = "[{index}] {0} ({1})") - @MethodSource("tfm.FileFinder#findAllMethodDeclarations") + @MethodSource("tfm.utils.FileFinder#findAllMethodDeclarations") public void apdgTest(File file, String methodName, MethodDeclaration root) throws IOException { runPdg(file, methodName, root, new APDG()); } @ParameterizedTest(name = "[{index}] {0} ({1})") - @MethodSource("tfm.FileFinder#findAllMethodDeclarations") + @MethodSource("tfm.utils.FileFinder#findAllMethodDeclarations") public void pdgTest(File file, String methodName, MethodDeclaration root) throws IOException { runPdg(file, methodName, root, new PDG()); } @@ -70,8 +68,8 @@ public class PDGTests { } @ParameterizedTest(name = "[{index}] {0} ({1})") - @MethodSource("tfm.FileFinder#findAllMethodDeclarations") - public void pdgCompare(File file, String methodName, MethodDeclaration root) throws IOException { + @MethodSource("tfm.utils.FileFinder#findAllMethodDeclarations") + public void pdgCompare(File file, String methodName, MethodDeclaration root) { ControlDependencyBuilder ctrlDepBuilder; if (containsUnsupportedStatements(root)) { diff --git a/src/test/java/tfm/FileFinder.java b/src/test/java/tfm/utils/FileFinder.java similarity index 98% rename from src/test/java/tfm/FileFinder.java rename to src/test/java/tfm/utils/FileFinder.java index 30399ea..b123405 100644 --- a/src/test/java/tfm/FileFinder.java +++ b/src/test/java/tfm/utils/FileFinder.java @@ -1,4 +1,4 @@ -package tfm; +package tfm.utils; import com.github.javaparser.JavaParser; import com.github.javaparser.ast.body.MethodDeclaration; -- GitLab From 441e12a2498bcafda3f0575ab4498ca114f466a2 Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Fri, 24 Jan 2020 11:16:58 +0100 Subject: [PATCH 24/27] Moved program test suite --- src/test/res/programs | 1 - src/{main/java/tfm => test/res}/programs/WhileLoop.java | 0 src/{main/java/tfm => test/res}/programs/cfg/CFG_Test1.java | 0 src/{main/java/tfm => test/res}/programs/cfg/CFG_Test2.java | 0 src/{main/java/tfm => test/res}/programs/cfg/CFG_Test3.java | 0 src/{main/java/tfm => test/res}/programs/cfg/CFG_Test4.java | 0 src/{main/java/tfm => test/res}/programs/cfg/CFG_Test5.java | 0 src/{main/java/tfm => test/res}/programs/cfg/Eval_1.java | 0 src/{main/java/tfm => test/res}/programs/cfg/Eval_2.java | 0 src/{main/java/tfm => test/res}/programs/cfg/Eval_3.java | 0 src/{main/java/tfm => test/res}/programs/cfg/Eval_4.java | 0 src/{main/java/tfm => test/res}/programs/pdg/Example1.java | 0 src/{main/java/tfm => test/res}/programs/pdg/Example2.java | 0 src/{main/java/tfm => test/res}/programs/pdg/Example3.java | 0 src/{main/java/tfm => test/res}/programs/pdg/Test.java | 0 src/{main/java/tfm => test/res}/programs/sdg/Example1.java | 0 16 files changed, 1 deletion(-) delete mode 120000 src/test/res/programs rename src/{main/java/tfm => test/res}/programs/WhileLoop.java (100%) rename src/{main/java/tfm => test/res}/programs/cfg/CFG_Test1.java (100%) rename src/{main/java/tfm => test/res}/programs/cfg/CFG_Test2.java (100%) rename src/{main/java/tfm => test/res}/programs/cfg/CFG_Test3.java (100%) rename src/{main/java/tfm => test/res}/programs/cfg/CFG_Test4.java (100%) rename src/{main/java/tfm => test/res}/programs/cfg/CFG_Test5.java (100%) rename src/{main/java/tfm => test/res}/programs/cfg/Eval_1.java (100%) rename src/{main/java/tfm => test/res}/programs/cfg/Eval_2.java (100%) rename src/{main/java/tfm => test/res}/programs/cfg/Eval_3.java (100%) rename src/{main/java/tfm => test/res}/programs/cfg/Eval_4.java (100%) rename src/{main/java/tfm => test/res}/programs/pdg/Example1.java (100%) rename src/{main/java/tfm => test/res}/programs/pdg/Example2.java (100%) rename src/{main/java/tfm => test/res}/programs/pdg/Example3.java (100%) rename src/{main/java/tfm => test/res}/programs/pdg/Test.java (100%) rename src/{main/java/tfm => test/res}/programs/sdg/Example1.java (100%) diff --git a/src/test/res/programs b/src/test/res/programs deleted file mode 120000 index 2fb351c..0000000 --- a/src/test/res/programs +++ /dev/null @@ -1 +0,0 @@ -../../main/java/tfm/programs \ No newline at end of file diff --git a/src/main/java/tfm/programs/WhileLoop.java b/src/test/res/programs/WhileLoop.java similarity index 100% rename from src/main/java/tfm/programs/WhileLoop.java rename to src/test/res/programs/WhileLoop.java diff --git a/src/main/java/tfm/programs/cfg/CFG_Test1.java b/src/test/res/programs/cfg/CFG_Test1.java similarity index 100% rename from src/main/java/tfm/programs/cfg/CFG_Test1.java rename to src/test/res/programs/cfg/CFG_Test1.java diff --git a/src/main/java/tfm/programs/cfg/CFG_Test2.java b/src/test/res/programs/cfg/CFG_Test2.java similarity index 100% rename from src/main/java/tfm/programs/cfg/CFG_Test2.java rename to src/test/res/programs/cfg/CFG_Test2.java diff --git a/src/main/java/tfm/programs/cfg/CFG_Test3.java b/src/test/res/programs/cfg/CFG_Test3.java similarity index 100% rename from src/main/java/tfm/programs/cfg/CFG_Test3.java rename to src/test/res/programs/cfg/CFG_Test3.java diff --git a/src/main/java/tfm/programs/cfg/CFG_Test4.java b/src/test/res/programs/cfg/CFG_Test4.java similarity index 100% rename from src/main/java/tfm/programs/cfg/CFG_Test4.java rename to src/test/res/programs/cfg/CFG_Test4.java diff --git a/src/main/java/tfm/programs/cfg/CFG_Test5.java b/src/test/res/programs/cfg/CFG_Test5.java similarity index 100% rename from src/main/java/tfm/programs/cfg/CFG_Test5.java rename to src/test/res/programs/cfg/CFG_Test5.java diff --git a/src/main/java/tfm/programs/cfg/Eval_1.java b/src/test/res/programs/cfg/Eval_1.java similarity index 100% rename from src/main/java/tfm/programs/cfg/Eval_1.java rename to src/test/res/programs/cfg/Eval_1.java diff --git a/src/main/java/tfm/programs/cfg/Eval_2.java b/src/test/res/programs/cfg/Eval_2.java similarity index 100% rename from src/main/java/tfm/programs/cfg/Eval_2.java rename to src/test/res/programs/cfg/Eval_2.java diff --git a/src/main/java/tfm/programs/cfg/Eval_3.java b/src/test/res/programs/cfg/Eval_3.java similarity index 100% rename from src/main/java/tfm/programs/cfg/Eval_3.java rename to src/test/res/programs/cfg/Eval_3.java diff --git a/src/main/java/tfm/programs/cfg/Eval_4.java b/src/test/res/programs/cfg/Eval_4.java similarity index 100% rename from src/main/java/tfm/programs/cfg/Eval_4.java rename to src/test/res/programs/cfg/Eval_4.java diff --git a/src/main/java/tfm/programs/pdg/Example1.java b/src/test/res/programs/pdg/Example1.java similarity index 100% rename from src/main/java/tfm/programs/pdg/Example1.java rename to src/test/res/programs/pdg/Example1.java diff --git a/src/main/java/tfm/programs/pdg/Example2.java b/src/test/res/programs/pdg/Example2.java similarity index 100% rename from src/main/java/tfm/programs/pdg/Example2.java rename to src/test/res/programs/pdg/Example2.java diff --git a/src/main/java/tfm/programs/pdg/Example3.java b/src/test/res/programs/pdg/Example3.java similarity index 100% rename from src/main/java/tfm/programs/pdg/Example3.java rename to src/test/res/programs/pdg/Example3.java diff --git a/src/main/java/tfm/programs/pdg/Test.java b/src/test/res/programs/pdg/Test.java similarity index 100% rename from src/main/java/tfm/programs/pdg/Test.java rename to src/test/res/programs/pdg/Test.java diff --git a/src/main/java/tfm/programs/sdg/Example1.java b/src/test/res/programs/sdg/Example1.java similarity index 100% rename from src/main/java/tfm/programs/sdg/Example1.java rename to src/test/res/programs/sdg/Example1.java -- GitLab From 23e9d713963a31ac55113dfa345f32f099e25616 Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Fri, 24 Jan 2020 12:11:06 +0100 Subject: [PATCH 25/27] DataDependencyArc: simplified #hashCode() and #equals(Object) --- .../java/tfm/arcs/pdg/DataDependencyArc.java | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/main/java/tfm/arcs/pdg/DataDependencyArc.java b/src/main/java/tfm/arcs/pdg/DataDependencyArc.java index 6c006b6..22a7bd5 100644 --- a/src/main/java/tfm/arcs/pdg/DataDependencyArc.java +++ b/src/main/java/tfm/arcs/pdg/DataDependencyArc.java @@ -39,24 +39,12 @@ public class DataDependencyArc extends Arc { @Override public boolean equals(Object o) { - if (this == o) { - return true; - } - - if (!(o instanceof DataDependencyArc)) { - return false; - } - - DataDependencyArc other = (DataDependencyArc) o; - - return Objects.equals(variable, other.variable) - && Objects.equals(getSource(), other.getSource()) - && Objects.equals(getTarget(), other.getTarget()); + return super.equals(o) && Objects.equals(variable, ((DataDependencyArc) o).variable); } @Override public int hashCode() { - return Objects.hash(variable, getSource(), getTarget()); + return Objects.hash(variable, super.hashCode()); } } -- GitLab From 2450625454a4545d4ec1c8c1b661bffd0ee775bd Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Fri, 24 Jan 2020 12:46:21 +0100 Subject: [PATCH 26/27] Fix: don't rebuild CFG if it is already built. --- src/main/java/tfm/graphs/pdg/PDGBuilder.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/tfm/graphs/pdg/PDGBuilder.java b/src/main/java/tfm/graphs/pdg/PDGBuilder.java index 1aee653..d699bc5 100644 --- a/src/main/java/tfm/graphs/pdg/PDGBuilder.java +++ b/src/main/java/tfm/graphs/pdg/PDGBuilder.java @@ -42,7 +42,8 @@ public class PDGBuilder { BlockStmt methodBody = methodDeclaration.getBody().get(); // build CFG - cfg.build(methodDeclaration); + if (!cfg.isBuilt()) + cfg.build(methodDeclaration); // Build control dependency ControlDependencyBuilder controlDependencyBuilder = new ControlDependencyBuilder(pdg, cfg); -- GitLab From 70348bc69094e5976788f40c7fd2d7252e0f0aff Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Fri, 24 Jan 2020 15:54:40 +0100 Subject: [PATCH 27/27] Fix: updated path for programs (Main and Utils) --- src/main/java/tfm/utils/Utils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/tfm/utils/Utils.java b/src/main/java/tfm/utils/Utils.java index 968b994..de41fe3 100644 --- a/src/main/java/tfm/utils/Utils.java +++ b/src/main/java/tfm/utils/Utils.java @@ -7,7 +7,7 @@ import java.util.Set; public class Utils { - public static final String PROGRAMS_FOLDER = "src/main/java/tfm/programs/"; + public static final String PROGRAMS_FOLDER = "src/test/res/programs/"; public static List emptyList() { return new ArrayList<>(0); -- GitLab