Committed Unroll Loop (Bug 317314)
diff --git a/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/before-and-after/beforeAndAfter.f90 b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/before-and-after/beforeAndAfter.f90
new file mode 100644
index 0000000..55df1a2
--- /dev/null
+++ b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/before-and-after/beforeAndAfter.f90
@@ -0,0 +1,15 @@
+program test

+

+    implicit none

+

+    integer :: i, j

+

+    j=1

+    !<<<<<8,1,13,1,1,true,pass

+    do i=1,5

+        print *, i

+        j = i

+    end do

+    j = 1

+

+end program test

diff --git a/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/before-and-after/beforeAndAfter.f90.result b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/before-and-after/beforeAndAfter.f90.result
new file mode 100644
index 0000000..ba5999e
--- /dev/null
+++ b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/before-and-after/beforeAndAfter.f90.result
@@ -0,0 +1,20 @@
+program test

+

+    implicit none

+

+    integer :: i, j

+

+    j=1

+    print *, 1

+    j = 1

+    print *, 2

+    j = 2

+    print *, 3

+    j = 3

+    print *, 4

+    j = 4

+    print *, 5

+    j = 5

+    j = 1

+

+end program test

diff --git a/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/complete-unroll-with-step/completeUnrollWithStep.f90 b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/complete-unroll-with-step/completeUnrollWithStep.f90
new file mode 100644
index 0000000..62ee0e5
--- /dev/null
+++ b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/complete-unroll-with-step/completeUnrollWithStep.f90
@@ -0,0 +1,11 @@
+program test

+

+    implicit none

+

+    integer :: i

+    !<<<<<6,1,10,1,1,true,pass

+    do i=1,9,2

+        print *, i

+    end do

+

+end program test

diff --git a/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/complete-unroll-with-step/completeUnrollWithStep.f90.result b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/complete-unroll-with-step/completeUnrollWithStep.f90.result
new file mode 100644
index 0000000..db37fd7
--- /dev/null
+++ b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/complete-unroll-with-step/completeUnrollWithStep.f90.result
@@ -0,0 +1,12 @@
+program test

+

+    implicit none

+

+    integer :: i

+    print *, 1

+    print *, 3

+    print *, 5

+    print *, 7

+    print *, 9

+

+end program test

diff --git a/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/complex-body-unroll2/ComplexBodyCompleteUnroll.f90 b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/complex-body-unroll2/ComplexBodyCompleteUnroll.f90
new file mode 100644
index 0000000..6d01b83
--- /dev/null
+++ b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/complex-body-unroll2/ComplexBodyCompleteUnroll.f90
@@ -0,0 +1,14 @@
+program test

+

+    implicit none

+

+    integer :: i, j=-1

+    !<<<<<6,1,13,1,1,true,pass

+    do i=1,5,2

+        j = j**i

+        j = j+j

+        print *, i

+        print *, j

+    end do

+

+end program test

diff --git a/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/complex-body-unroll2/ComplexBodyCompleteUnroll.f90.result b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/complex-body-unroll2/ComplexBodyCompleteUnroll.f90.result
new file mode 100644
index 0000000..a04d951
--- /dev/null
+++ b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/complex-body-unroll2/ComplexBodyCompleteUnroll.f90.result
@@ -0,0 +1,19 @@
+program test

+

+    implicit none

+

+    integer :: i, j=-1

+    j = j**1

+    j = j+j

+    print *, 1

+    print *, j

+    j = j**3

+    j = j+j

+    print *, 3

+    print *, j

+    j = j**5

+    j = j+j

+    print *, 5

+    print *, j

+

+end program test

diff --git a/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/complexLoopBodyUnroll/complexLoopBodyUnroll.f90 b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/complexLoopBodyUnroll/complexLoopBodyUnroll.f90
new file mode 100644
index 0000000..a44bab8
--- /dev/null
+++ b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/complexLoopBodyUnroll/complexLoopBodyUnroll.f90
@@ -0,0 +1,15 @@
+!Fix this text case after reindenter update

+program test

+

+    implicit none

+

+    integer :: i, j=-1

+    !<<<<<7,1,14,1,4,false,pass

+    do i=1,5

+        j = j**i

+        j = j+j

+        print *, i

+        print *, j

+    end do

+

+end program test

diff --git a/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/complexLoopBodyUnroll/complexLoopBodyUnroll.f90.result b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/complexLoopBodyUnroll/complexLoopBodyUnroll.f90.result
new file mode 100644
index 0000000..1382cc6
--- /dev/null
+++ b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/complexLoopBodyUnroll/complexLoopBodyUnroll.f90.result
@@ -0,0 +1,28 @@
+!Fix this text case after reindenter update

+program test

+

+    implicit none

+

+    integer :: i, j=-1

+    !<<<<<7,1,14,1,4,false,pass

+    do i=1,5,4

+        j = j**i

+        j = j+j

+        print *, i

+        print *, j

+        if(i+1>5) exit

+        j = j**(i+1)

+        j = j+j

+        print *, (i+1)

+        print *, j

+        j = j**(i+2)

+        j = j+j

+        print *, (i+2)

+        print *, j

+        j = j**(i+3)

+        j = j+j

+        print *, (i+3)

+        print *, j

+    end do

+

+end program test

diff --git a/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/decrement-loop-partial/decrementLoopPartial.f90 b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/decrement-loop-partial/decrementLoopPartial.f90
new file mode 100644
index 0000000..007e91b
--- /dev/null
+++ b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/decrement-loop-partial/decrementLoopPartial.f90
@@ -0,0 +1,12 @@
+program test

+

+    implicit none

+

+    integer :: k

+    !<<<<<6,1,9,1,2,false,pass

+    do k=9,1,-2

+        print *, k

+    end do

+

+

+end program test

diff --git a/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/decrement-loop-partial/decrementLoopPartial.f90.result b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/decrement-loop-partial/decrementLoopPartial.f90.result
new file mode 100644
index 0000000..1a2d429
--- /dev/null
+++ b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/decrement-loop-partial/decrementLoopPartial.f90.result
@@ -0,0 +1,13 @@
+program test

+

+    implicit none

+

+    integer :: k

+    !<<<<<6,1,9,1,2,false,pass

+    do k=9,1,-4

+        print *, k

+        print *, (k+-2)

+    end do

+

+

+end program test

diff --git a/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/decrement-loop/decrementLoopComplete.f90 b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/decrement-loop/decrementLoopComplete.f90
new file mode 100644
index 0000000..da9c3a9
--- /dev/null
+++ b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/decrement-loop/decrementLoopComplete.f90
@@ -0,0 +1,12 @@
+program test

+

+    implicit none

+

+    integer :: k

+    !<<<<<6,1,9,1,1,true,pass

+    do k=5,1,-1

+        print *, k

+    end do

+

+

+end program test

diff --git a/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/decrement-loop/decrementLoopComplete.f90.result b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/decrement-loop/decrementLoopComplete.f90.result
new file mode 100644
index 0000000..5d60747
--- /dev/null
+++ b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/decrement-loop/decrementLoopComplete.f90.result
@@ -0,0 +1,13 @@
+program test

+

+    implicit none

+

+    integer :: k

+    print *, 5

+    print *, 4

+    print *, 3

+    print *, 2

+    print *, 1

+

+

+end program test

diff --git a/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/nested-loop-unroll/nestedLoopUnroll.f90 b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/nested-loop-unroll/nestedLoopUnroll.f90
new file mode 100644
index 0000000..3de1d55
--- /dev/null
+++ b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/nested-loop-unroll/nestedLoopUnroll.f90
@@ -0,0 +1,14 @@
+program test

+

+    implicit none

+

+    integer :: i, j

+    !<<<<<6,1,8,1,2,false,pass

+    do i=1,5

+

+        do j=1,5

+            print *, i+j

+        end do

+    end do

+

+end program test

diff --git a/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/nested-loop-unroll/nestedLoopUnroll.f90.result b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/nested-loop-unroll/nestedLoopUnroll.f90.result
new file mode 100644
index 0000000..625d332
--- /dev/null
+++ b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/nested-loop-unroll/nestedLoopUnroll.f90.result
@@ -0,0 +1,19 @@
+program test

+

+    implicit none

+

+    integer :: i, j

+    !<<<<<6,1,8,1,2,false,pass

+    do i=1,5,2

+

+        do j=1,5

+            print *, i+j

+        end do

+        if(i+1>5) exit

+

+        do j=1,5

+            print *, (i+1)+j

+        end do

+    end do

+

+end program test

diff --git a/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/simple-complete-unroll/simpleCompleteUnroll.f90 b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/simple-complete-unroll/simpleCompleteUnroll.f90
new file mode 100644
index 0000000..d3c8429
--- /dev/null
+++ b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/simple-complete-unroll/simpleCompleteUnroll.f90
@@ -0,0 +1,13 @@
+program test

+

+    integer :: i

+

+    !<<<<<6,1,10,1,1,true,pass

+

+    do i=1,9

+        print *, i

+    end do

+

+

+

+end program test

diff --git a/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/simple-complete-unroll/simpleCompleteUnroll.f90.result b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/simple-complete-unroll/simpleCompleteUnroll.f90.result
new file mode 100644
index 0000000..c2adcc9
--- /dev/null
+++ b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/simple-complete-unroll/simpleCompleteUnroll.f90.result
@@ -0,0 +1,16 @@
+program test

+

+    integer :: i

+    print *, 1

+    print *, 2

+    print *, 3

+    print *, 4

+    print *, 5

+    print *, 6

+    print *, 7

+    print *, 8

+    print *, 9

+

+

+

+end program test

diff --git a/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/test-simple-loop/testSimpleLoop.f90 b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/test-simple-loop/testSimpleLoop.f90
new file mode 100644
index 0000000..1173ec1
--- /dev/null
+++ b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/test-simple-loop/testSimpleLoop.f90
@@ -0,0 +1,9 @@
+program test

+

+    implicit none

+    !<<<<<4,1,8,1,2,false,pass

+    DO i=1,9

+        print *, i

+    END DO

+

+end program test

diff --git a/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/test-simple-loop/testSimpleLoop.f90.result b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/test-simple-loop/testSimpleLoop.f90.result
new file mode 100644
index 0000000..723509e
--- /dev/null
+++ b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/test-simple-loop/testSimpleLoop.f90.result
@@ -0,0 +1,11 @@
+program test

+

+    implicit none

+    !<<<<<4,1,8,1,2,false,pass

+    DO i=1,9,2

+        print *, i

+        if(i+1>9) exit

+        print *, (i+1)

+    END DO

+

+end program test

diff --git a/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/testUnrollWithStep/unrollWithStep.f90 b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/testUnrollWithStep/unrollWithStep.f90
new file mode 100644
index 0000000..4f5d98a
--- /dev/null
+++ b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/testUnrollWithStep/unrollWithStep.f90
@@ -0,0 +1,13 @@
+program test

+

+    implicit none

+

+    integer :: i

+

+    !<<<<<7,1,11,1,2,false,pass

+    do i=1,9,2

+        print *, i

+    end do

+

+

+end program

diff --git a/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/testUnrollWithStep/unrollWithStep.f90.result b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/testUnrollWithStep/unrollWithStep.f90.result
new file mode 100644
index 0000000..2979242
--- /dev/null
+++ b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/testUnrollWithStep/unrollWithStep.f90.result
@@ -0,0 +1,15 @@
+program test

+

+    implicit none

+

+    integer :: i

+

+    !<<<<<7,1,11,1,2,false,pass

+    do i=1,9,4

+        print *, i

+        if(i+2>9) exit

+        print *, (i+2)

+    end do

+

+

+end program

diff --git a/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/unroll-with-expr-arg/unrollWithExpr.f90 b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/unroll-with-expr-arg/unrollWithExpr.f90
new file mode 100644
index 0000000..a60f842
--- /dev/null
+++ b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/unroll-with-expr-arg/unrollWithExpr.f90
@@ -0,0 +1,11 @@
+program test

+

+    implicit none

+

+    integer :: i, n=4

+    !<<<<<6,1,8,1,2,false,pass

+    do i=1,n*n

+        print *, i

+    end do

+

+end program test

diff --git a/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/unroll-with-expr-arg/unrollWithExpr.f90.result b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/unroll-with-expr-arg/unrollWithExpr.f90.result
new file mode 100644
index 0000000..16854f9
--- /dev/null
+++ b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/unroll-with-expr-arg/unrollWithExpr.f90.result
@@ -0,0 +1,15 @@
+program test

+

+    implicit none

+    integer :: loopUpperBound

+

+    integer :: i, n=4

+    loopUpperBound = n*n

+    !<<<<<6,1,8,1,2,false,pass

+    do i=1, loopUpperBound,2

+        print *, i

+        if(i+1>loopUpperBound) exit

+        print *, (i+1)

+    end do

+

+end program test

diff --git a/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/upper-bound-int-expr/unrollWithUpperIntExpr.f90 b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/upper-bound-int-expr/unrollWithUpperIntExpr.f90
new file mode 100644
index 0000000..c24313a
--- /dev/null
+++ b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/upper-bound-int-expr/unrollWithUpperIntExpr.f90
@@ -0,0 +1,12 @@
+program test

+

+    implicit none

+

+    integer :: i

+    !<<<<<6,1,10,1,4,false,pass

+    do i=1,3+5,1

+        print *, i

+    end do

+

+

+end program test

diff --git a/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/upper-bound-int-expr/unrollWithUpperIntExpr.f90.result b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/upper-bound-int-expr/unrollWithUpperIntExpr.f90.result
new file mode 100644
index 0000000..841ce68
--- /dev/null
+++ b/org.eclipse.photran.core.vpg.tests/refactoring-test-code/unroll-loop/upper-bound-int-expr/unrollWithUpperIntExpr.f90.result
@@ -0,0 +1,20 @@
+program test

+

+    implicit none

+    integer :: loopUpperBound

+

+    integer :: i

+    loopUpperBound = 3+5

+    !<<<<<6,1,10,1,4,false,pass

+    do i=1, loopUpperBound,4

+        print *, i

+        if(i+1>loopUpperBound) exit

+        print *, (i+1)

+        if(i+2>loopUpperBound) exit

+        print *, (i+2)

+        if(i+3>loopUpperBound) exit

+        print *, (i+3)

+    end do

+

+

+end program test

diff --git a/org.eclipse.photran.core.vpg.tests/src/org/eclipse/photran/internal/tests/refactoring/UnrollLoopRefactoringTestSuite.java b/org.eclipse.photran.core.vpg.tests/src/org/eclipse/photran/internal/tests/refactoring/UnrollLoopRefactoringTestSuite.java
new file mode 100644
index 0000000..be244af
--- /dev/null
+++ b/org.eclipse.photran.core.vpg.tests/src/org/eclipse/photran/internal/tests/refactoring/UnrollLoopRefactoringTestSuite.java
@@ -0,0 +1,65 @@
+/*******************************************************************************

+ * Copyright (c) 2010 University of Illinois at Urbana-Champaign and others.

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * which accompanies this distribution, and is available at

+ * http://www.eclipse.org/legal/epl-v10.html

+ *

+ * Contributors:

+ *    UIUC - Initial API and implementation

+ *******************************************************************************/

+package org.eclipse.photran.internal.tests.refactoring;

+

+import junit.framework.Test;

+

+import org.eclipse.core.resources.IFile;

+import org.eclipse.jface.text.TextSelection;

+import org.eclipse.photran.internal.core.refactoring.UnrollLoopRefactoring;

+import org.eclipse.photran.internal.tests.Activator;

+import org.eclipse.photran.internal.tests.PhotranRefactoringTestSuiteFromMarkers;

+

+/**

+ * Test suite for loop unrolling refactoring

+ * 

+ * @author Ashley Kasza

+ */

+public class UnrollLoopRefactoringTestSuite extends PhotranRefactoringTestSuiteFromMarkers<UnrollLoopRefactoring>

+{

+    private static final String DIR = "refactoring-test-code/unroll-loop";

+

+    public static Test suite() throws Exception

+    {

+        return new UnrollLoopRefactoringTestSuite();

+    }

+

+    public UnrollLoopRefactoringTestSuite() throws Exception

+    {

+        super(Activator.getDefault(),

+            "Running Loop Unrolling refactoring in",

+            DIR,

+            UnrollLoopRefactoring.class);

+    }

+

+    @Override

+    protected boolean initializeRefactoring(UnrollLoopRefactoring refactoring, IFile file,

+        TextSelection selection, String[] markerText)

+    {

+        boolean result = super.initializeRefactoring(refactoring, file, selection, markerText);

+

+        String s = markerText[4]; // file field(s) are just before result

+        String s2 = markerText[5];

+        refactoring.setLoopUnrollNumber(s);

+        refactoring.setComplete(s2.equals("true"));

+        // }

+

+        return result;

+    }

+

+    /** Prevents the compilation and running of tests we know don't compile or run */

+    @Override protected boolean shouldCompile(IFile fileContainingMarker)

+    {

+        String filename = fileContainingMarker.getName();

+        return !filename.equalsIgnoreCase("decrementLoopPartial.f90")

+            && !filename.equalsIgnoreCase("testSimpleLoop.f90");

+    }

+}

diff --git a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/UnrollLoopRefactoring.java b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/UnrollLoopRefactoring.java
new file mode 100644
index 0000000..e8c7194
--- /dev/null
+++ b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/UnrollLoopRefactoring.java
@@ -0,0 +1,437 @@
+/*******************************************************************************

+ * Copyright (c) 2010 University of Illinois at Urbana-Champaign and others.

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * which accompanies this distribution, and is available at

+ * http://www.eclipse.org/legal/epl-v10.html

+ *

+ * Contributors:

+ *    UIUC - Initial API and implementation

+ *******************************************************************************/

+package org.eclipse.photran.internal.core.refactoring;

+

+import java.util.List;

+

+import org.eclipse.core.runtime.CoreException;

+import org.eclipse.core.runtime.IProgressMonitor;

+import org.eclipse.core.runtime.OperationCanceledException;

+import org.eclipse.ltk.core.refactoring.RefactoringStatus;

+import org.eclipse.photran.internal.core.analysis.binding.Definition;

+import org.eclipse.photran.internal.core.analysis.binding.ScopingNode;

+import org.eclipse.photran.internal.core.analysis.binding.VariableAccess;

+import org.eclipse.photran.internal.core.analysis.loops.ASTProperLoopConstructNode;

+import org.eclipse.photran.internal.core.analysis.loops.ASTVisitorWithLoops;

+import org.eclipse.photran.internal.core.analysis.loops.LoopReplacer;

+import org.eclipse.photran.internal.core.lexer.Terminal;

+import org.eclipse.photran.internal.core.lexer.Token;

+import org.eclipse.photran.internal.core.parser.ASTIntConstNode;

+import org.eclipse.photran.internal.core.parser.ASTLoopControlNode;

+import org.eclipse.photran.internal.core.parser.IASTListNode;

+import org.eclipse.photran.internal.core.parser.IASTNode;

+import org.eclipse.photran.internal.core.parser.IExecutionPartConstruct;

+import org.eclipse.photran.internal.core.parser.IExpr;

+import org.eclipse.photran.internal.core.refactoring.infrastructure.FortranEditorRefactoring;

+import org.eclipse.photran.internal.core.reindenter.Reindenter;

+import org.eclipse.photran.internal.core.reindenter.Reindenter.Strategy;

+import org.eclipse.rephraserengine.core.refactorings.UserInputBoolean;

+import org.eclipse.rephraserengine.core.refactorings.UserInputString;

+

+/**

+ * Refactoring used to unroll a loop a certain number of times or completely.

+ * 

+ * @author Ashley Kasza

+ */

+public class UnrollLoopRefactoring extends FortranEditorRefactoring

+{

+    private String LOOP_UPPER_BOUND = "loopUpperBound"; //$NON-NLS-1$

+

+    private ASTProperLoopConstructNode doLoop = null;

+

+    // user inputs

+    private boolean isCompleteUnrolling = false;

+

+    private int iterationStep = 0;

+

+    private boolean check = true;

+

+    //protected boolean variableIsWritten;

+

+    @Override

+    protected void doCheckInitialConditions(RefactoringStatus status, IProgressMonitor pm)

+        throws PreconditionFailure

+    {

+        ensureProjectHasRefactoringEnabled(status);

+

+        LoopReplacer.replaceAllLoopsIn(this.astOfFileInEditor.getRoot());

+

+        // get loop node from the ast at the selected region

+        doLoop = getLoopNode(this.astOfFileInEditor, this.selectedRegionInEditor);

+        // fail if no do loop was selected

+        if (doLoop == null)

+        {

+            fail(Messages.ReverseLoopRefactoring_SelectDoLoop);

+        }

+

+        IASTListNode<IExecutionPartConstruct> body = doLoop.getBody();

+        if (checkForLabels(body))

+        {

+            fail(Messages.UnrollLoopRefactoring_cannotUnrollLoopWithLabel);

+        }

+        try

+        {

+            doLoop.getStepInt();

+        }

+        catch (NumberFormatException e)

+        {

+            fail(Messages.UnrollLoopRefactoring_InvalidStepError);

+        }

+        if (!(doLoop.getUpperBoundIExpr() instanceof ASTIntConstNode))

+        {

+            if(!checkLoopUpperBoundsNameAvailable())

+                fail(Messages.UnrollLoopRefactoring_unableToCreateUpperBound);

+        }

+        if(checkIndexVariableWrite(doLoop.getBody()))

+            fail(Messages.bind(Messages.UnrollLoopRefactoring_LoopWritesToIndexVariable, doLoop.getIndexVariable().getText()));

+    }

+    

+    private boolean checkIndexVariableWrite(IASTNode node)

+    {

+        FindNameVisitor findNameUse = new FindNameVisitor(doLoop.getIndexVariable().getText());

+        node.accept(findNameUse);

+        return findNameUse.getNameIsUsed();

+        

+    }

+    public class FindNameVisitor extends ASTVisitorWithLoops

+    {

+        private boolean indexIsWritten;

+        private String indexVariableName;

+        public FindNameVisitor(String name)

+        {

+            super();

+            indexIsWritten = false;

+            indexVariableName = name;

+        }

+        public boolean getNameIsUsed()

+        {

+            return indexIsWritten;

+        }

+        @Override

+        public void visitToken(Token token)

+        {

+            if (token.getTerminal() == Terminal.T_IDENT && token.getText().equals(indexVariableName))

+            {

+                if((token.getVariableAccessType()).equals(VariableAccess.WRITE))

+                {

+                    indexIsWritten = true;

+                }

+            }

+        }

+    }

+    

+    private boolean checkLoopUpperBoundsNameAvailable(){

+        boolean canUse;

+        for (int i = 1; i <= 10; i++)

+        {

+            canUse = true;

+            ScopingNode scope = ScopingNode.getLocalScope(doLoop);

+            List<Definition> defList = scope.getAllDefinitions();

+            for (Definition d : defList)

+            {

+                if (d.getCanonicalizedName().equals(LOOP_UPPER_BOUND.toLowerCase()))

+                {

+                    LOOP_UPPER_BOUND = "loopUpperBound" + Integer.toString(i); //$NON-NLS-1$

+                    canUse = false;

+                }

+            }

+            if (canUse == true)

+            {

+                //break;

+                return true;

+            }

+        }

+        return false;

+    }

+    @Override

+    protected void doCheckFinalConditions(RefactoringStatus status, IProgressMonitor pm)

+        throws PreconditionFailure

+    {

+

+        if ((!(doLoop.getLowerBoundIExpr() instanceof ASTIntConstNode) || !(doLoop

+            .getUpperBoundIExpr() instanceof ASTIntConstNode)) && isCompleteUnrolling)

+        {

+            fail(Messages.UnrollLoopRefactoring_SelectLoopWithExplicitBound);

+        }

+    }

+

+    @Override

+    protected void doCreateChange(IProgressMonitor pm) throws CoreException,

+        OperationCanceledException

+    {

+        ASTLoopControlNode doLoopControlNode = doLoop.getLoopHeader().getLoopControl();

+        IASTListNode<IExecutionPartConstruct> doLoopBody = doLoop.getBody();

+        // Must get the parent here before any changes are made.

+        IASTNode doLoopParent = doLoop.getParent();

+

+        if (isCompleteUnrolling)

+        {

+

+            completeLoopUnrolling(doLoopControlNode, doLoopBody); 

+

+        }

+        else

+        {

+            numberedLoopUnrolling(doLoopBody, doLoopControlNode);

+

+        }

+

+        Reindenter.reindent(doLoopParent, this.astOfFileInEditor, Strategy.REINDENT_EACH_LINE);

+

+        this.addChangeFromModifiedAST(this.fileInEditor, pm);

+

+        vpg.releaseAST(this.fileInEditor);

+

+    }

+

+    /**

+     * Checks for any labels in the body

+     * @param body - body of the loop to check

+     * @return true if there are labels, false if not

+     */

+    private boolean checkForLabels(IASTListNode<IExecutionPartConstruct> body)

+    {

+        for (int i = 0; i < body.size(); i++)

+        {

+

+            if ((body.get(i)).findFirstToken().getTerminal() == Terminal.T_ICON)

+            {// instanceof ASTLabelNode){

+                return true;

+            }

+        }

+        return false;

+    }

+

+    /***********************************************************

+     * Functions used for unrolling a certain number of times.

+     ***********************************************************/

+

+    /**

+     * Function copies the body of the loop n times, replacing "i" with 1-n every time it copies

+     * @param doLoopBody - the body of the loop that's being unrolled

+     * @param doLoopControlNode - the bounds and step of the loop

+     */

+    @SuppressWarnings({ "unchecked", "rawtypes" })

+    protected void numberedLoopUnrolling(IASTListNode<IExecutionPartConstruct> doLoopBody,

+        ASTLoopControlNode doLoopControlNode)

+    {

+        if (!(doLoop.getUpperBoundIExpr() instanceof ASTIntConstNode))

+        {

+            evalExpressionBeforeLoop();

+            // upper = parseLiteralExpression(LOOP_UPPER_BOUND);

+            doLoopControlNode.setUb(parseLiteralExpression(LOOP_UPPER_BOUND));

+        }

+        boolean checkAllStatements = false;

+        IASTListNode newBody = (IASTListNode<IExecutionPartConstruct>)(doLoopBody.clone());

+        IASTListNode dummyBody = null;

+        String iterationName = (doLoopControlNode.getVariableName()).getText();

+        // IExpr stepNode = doLoopControlNode.getStep();

+        int step = 1;

+        int checkBound = 0;

+        if (doLoop.getLowerBoundIExpr() instanceof ASTIntConstNode

+            && doLoop.getUpperBoundIExpr() instanceof ASTIntConstNode)

+        {

+            int high = doLoop.getUpperBoundInt();

+            int low = doLoop.getLowerBoundInt();

+            checkBound = (high - low + 1) % (step * iterationStep);

+        }else{

+            checkAllStatements = true;

+        }

+        

+        step = doLoop.getStepInt();

+        // System.out.println(step);

+        for (int i = 1; i < iterationStep; i++)

+        {

+            // replace "i" with 1-#, and add it to the AST

+            dummyBody = replaceIndexVariableNameInBody(doLoop.getBody(), iterationName, (i) * step);

+

+            if (check == true && (i == checkBound || checkAllStatements))

+            {

+                dummyBody.add(0, includeBoundsCheck(i * step, iterationName));

+            }

+            newBody.addAll(dummyBody);

+        }

+        doLoopBody.replaceWith(newBody);

+        doLoop.setStepInt(step * iterationStep);

+        // changeDoLoopStep(doLoopControlNode);

+    }

+

+    /**

+     * Adds an if statement before each loop body to check bounds

+     * @param step - by how much a loop steps

+     * @return

+     */

+    private IASTNode includeBoundsCheck(int indexPlus, String iterationName)

+    {

+        IASTNode checkNode = null;

+        IExpr upper = doLoop.getUpperBoundIExpr();

+        String checkBounds = "if(" + iterationName + "+" + indexPlus; //$NON-NLS-1$ //$NON-NLS-2$

+        if (doLoop.getStepInt() > 0)

+        { // loop increments

+            checkBounds += ">" + upper.findFirstToken().getText();//$NON-NLS-1$

+        }

+        else

+        { // loop decrements

+            checkBounds += "<" + upper.findFirstToken().getText(); //$NON-NLS-1$

+        }

+        checkBounds += ") exit"; //$NON-NLS-1$

+        checkNode = parseLiteralStatementSequence(checkBounds);

+        return checkNode;

+    }

+

+    /**

+     * take an expression out of the upper bound and evals it before the loop.

+     * @param ub - upper bound of a loop

+     */

+    @SuppressWarnings("unchecked")

+    private void evalExpressionBeforeLoop()

+    {

+

+        ScopingNode scope = ScopingNode.getLocalScope(doLoop);

+        IASTListNode<IASTNode> body = (IASTListNode<IASTNode>)scope.getOrCreateBody();

+        String upperBound = LOOP_UPPER_BOUND + " = " + doLoop.getUpperBoundIExpr().toString(); //$NON-NLS-1$

+        int upperBoundIndx = (body).indexOf(doLoop);

+        IASTNode upperBoundNode = parseLiteralStatement(upperBound);

+        body.add(upperBoundIndx, upperBoundNode);

+        String declarationString = "integer :: " + LOOP_UPPER_BOUND; //$NON-NLS-1$

+        int insertionIndex = findIndexToInsertTypeDeclaration(body);

+        body.add(insertionIndex, parseLiteralStatement(declarationString));

+    }

+

+    /**

+     * Function to visit all statements in node and replace instances of "i"

+     * @param node - node to search through

+     * @param name - instance name to look for (usually "i")

+     * @param iteration - number to replace "i" with

+     */

+

+    @SuppressWarnings("rawtypes")

+    private IASTListNode replaceIndexVariableNameInBody(IASTNode node, final String name,

+        final int iteration)

+    {

+        IASTListNode newBody = (IASTListNode)(node.clone());

+        newBody.accept(new ASTVisitorWithLoops()

+        {

+            @Override

+            public void visitToken(Token token)

+            {

+                if (token.getTerminal() == Terminal.T_IDENT && (token.getText()).equals(name))

+                {

+                    String s2 = token.getText();

+                    s2 = "(" + s2 + "+" + Integer.toString(iteration) + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$

+                    token.replaceWith(s2);

+                }

+            }

+

+        });

+        return newBody;

+    }

+

+

+    /********************************************************

+     * Functions for completely unrolling a loop

+     ********************************************************/

+

+    /**

+     * Determines the number of times to copy the body, then copies the body and replaces the

+     * iteration variable with 0-#

+     * @param doLoopControlNode is the bounds and step of the loop

+     * @param doLoopBody is all the statements contained in the do loop

+     */

+

+    private void completeLoopUnrolling(ASTLoopControlNode doLoopControlNode,

+        IASTListNode<IExecutionPartConstruct> doLoopBody)

+    {

+        Token varName = doLoopControlNode.getVariableName();

+        String iterationName = varName.getText(); // iterationName = i in do i=1,5

+        int l = doLoop.getLowerBoundInt();

+        int h = doLoop.getUpperBoundInt();

+

+        int step = 1;

+        step = doLoop.getStepInt();

+        IASTListNode<IExecutionPartConstruct> dummyBody = null;

+        IASTListNode<IExecutionPartConstruct> newBody = null;

+

+        newBody = replaceIndexVariableNameWithConst(doLoopBody, l, iterationName);

+        int counter = 1;

+        int bound = Math.abs(h - l);

+        int j = l;

+        while (counter <= bound)

+        {

+            j += step;

+            dummyBody = replaceIndexVariableNameWithConst(doLoopBody, j, iterationName);

+            newBody.addAll(dummyBody);

+            counter += Math.abs(step);

+        }

+        doLoop.replaceWith(newBody);

+    }

+

+    /**

+     * Function for finding all instances of "i" and changing them to a specific number

+     * @param node - the node to search through

+     * @param stepNum - the number used to replace "i"

+     */

+    @SuppressWarnings("unchecked")

+    private IASTListNode<IExecutionPartConstruct> replaceIndexVariableNameWithConst(IASTNode node,

+        final int stepNum, final String iterationName)

+    {

+        IASTListNode<IExecutionPartConstruct> newBody = (IASTListNode<IExecutionPartConstruct>)node.clone();

+        newBody.accept(new ASTVisitorWithLoops()

+        {

+            @Override

+            public void visitToken(Token token)

+            {

+                if (token.getTerminal() == Terminal.T_IDENT

+                    && token.getText().equalsIgnoreCase(iterationName))

+                {

+                    // replace i with iteration step

+                    String s = Integer.toString(stepNum);

+                    token.setText(s);

+                }

+            }

+        });

+        return newBody;

+    }

+

+    /****************************

+     * User Input functions

+     ***************************/

+

+    @UserInputString(label = "Enter unrolling count ", defaultValueMethod = "getSuggestedUnrollingCount")

+    public void setLoopUnrollNumber(String input)

+    {

+        iterationStep = Integer.parseInt(input);

+    }

+

+    public String getSuggestedUnrollingCount()

+    {

+        return "4"; //$NON-NLS-1$

+    }

+

+    @UserInputBoolean(label = "Complete unrolling")

+    public void setComplete(boolean isComplete)

+    {

+        isCompleteUnrolling = isComplete;

+    }

+

+    @UserInputBoolean(label = "Include bounds checking", defaultValue = true)

+    public void setBoundsChecking(boolean boundsCheck)

+    {

+        check = boundsCheck;

+    }

+

+    @Override

+    public String getName()

+    {

+        return Messages.UnrollLoopRefactoring_LoopUnrollingName;

+    }

+

+}