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;
+ }
+
+}