Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeffrey Overbey2011-03-16 07:38:34 +0000
committerJeffrey Overbey2011-03-16 07:38:34 +0000
commitf614e3b3943992a9146f4a4efa9d47c56150ca1b (patch)
treeab43d95e385a22b3978cd8c27fa445c017f11d02 /org.eclipse.photran.core.vpg
parent614eee08f350091f6f61db216cc77ccc57b9d536 (diff)
downloadorg.eclipse.photran-f614e3b3943992a9146f4a4efa9d47c56150ca1b.tar.gz
org.eclipse.photran-f614e3b3943992a9146f4a4efa9d47c56150ca1b.tar.xz
org.eclipse.photran-f614e3b3943992a9146f4a4efa9d47c56150ca1b.zip
Bug 331880 - Refactoring [427]: IF Statement/Construct Refactoring
Diffstat (limited to 'org.eclipse.photran.core.vpg')
-rw-r--r--org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/IfConstructStatementConversionRefactoring.java224
-rw-r--r--org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/Messages.java12
-rw-r--r--org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/infrastructure/FortranResourceRefactoring.java10
-rw-r--r--org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/messages.properties6
4 files changed, 247 insertions, 5 deletions
diff --git a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/IfConstructStatementConversionRefactoring.java b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/IfConstructStatementConversionRefactoring.java
new file mode 100644
index 00000000..6413cb5b
--- /dev/null
+++ b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/IfConstructStatementConversionRefactoring.java
@@ -0,0 +1,224 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Zeeshan Ansari, Mark Chen, Burim Isai, Waseem Sheikh, Mumtaz Vauhkonen.
+ * 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:
+ * Zeeshan Ansari
+ * Mark Chen
+ * Mumtaz Vauhkonen
+ * Burim Isai
+ * Waseem Sheikh
+ *******************************************************************************/
+package org.eclipse.photran.internal.core.refactoring;
+
+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.parser.ASTIfConstructNode;
+import org.eclipse.photran.internal.core.parser.ASTIfStmtNode;
+import org.eclipse.photran.internal.core.parser.ASTNode;
+import org.eclipse.photran.internal.core.parser.IExecutionPartConstruct;
+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;
+
+/**
+ * Converts an IF construct to an IF statement and vice versa. User must select the entire IF
+ * statement or IF construct block, and select the refactoring option in the menu.
+ *
+ * @author Zeeshan Ansari
+ * @author Mark Chen
+ * @author Mumtaz Vauhkonrn
+ * @author Burim Isai
+ * @author Waseem Sheikh
+ */
+public class IfConstructStatementConversionRefactoring extends FortranEditorRefactoring
+{
+ private ASTNode selectedNode = null;
+ private boolean shouldAddEmptyElseBlock = false;
+
+ /**
+ * Beyond the standard condition checks, this checks to ensure that a valid IF statement or IF
+ * construct is selected and is refactorable.
+ *
+ * @param ifConstructNode
+ * @throws PreconditionFailure
+ */
+ @Override
+ protected void doCheckInitialConditions(RefactoringStatus status, IProgressMonitor pm)
+ throws PreconditionFailure
+ {
+ ensureProjectHasRefactoringEnabled(status);
+
+ if (!fileInEditor.exists())
+ fail(Messages.FortranEditorRefactoring_CantPerformRefactoringOnFileThatDoesNotExist);
+
+ if (fileInEditor.isReadOnly())
+ fail(Messages.FortranEditorRefactoring_CantPerformRefactoringOnReadOnlyFile);
+
+ ASTIfStmtNode ifStmtNode = getNode(this.astOfFileInEditor, this.selectedRegionInEditor, ASTIfStmtNode.class);
+ ASTIfConstructNode ifConstructNode = getNode(this.astOfFileInEditor, this.selectedRegionInEditor, ASTIfConstructNode.class);
+
+ if (ifStmtNode != null)
+ selectedNode = ifStmtNode;
+ else if (ifConstructNode != null)
+ {
+ checkRefactorableConstruct(ifConstructNode);
+ selectedNode = ifConstructNode;
+ }
+ else
+ fail(Messages.IfConstructStatementConversionRefactoring_SelectAValidIfStatement);
+ }
+
+ /**
+ * Checks various conditions to see if the user-selected IF construct is refactorable to an IF
+ * statement. This includes making sure there is only one valid statement line in the construct
+ * and that the construct is not named.
+ *
+ * @param ifConstructNode
+ * @throws PreconditionFailure
+ */
+ private void checkRefactorableConstruct(ASTIfConstructNode ifConstructNode) throws PreconditionFailure
+ {
+ // Checks for named construct
+ if (ifConstructNode.getIfThenStmt().getName() != null)
+ fail(Messages.IfConstructStatementConversionRefactoring_InvalidNamedConstruct);
+
+ // Check for multiple statements within construct
+ if (ifConstructNode.getConditionalBody().size() > 1
+ || ifConstructNode.getElseIfConstruct() != null
+ || ifConstructNode.getElseConstruct() != null)
+ fail(Messages.IfConstructStatementConversionRefactoring_TooManyStatements);
+ }
+
+ public boolean isStmtNode()
+ {
+ return selectedNode != null && selectedNode instanceof ASTIfStmtNode;
+ }
+
+ public void setAddEmptyElseBlock()
+ {
+ shouldAddEmptyElseBlock = true;
+ }
+
+ @Override
+ protected void doCheckFinalConditions(RefactoringStatus status, IProgressMonitor pm)
+ throws PreconditionFailure
+ {
+ // No final preconditions
+ }
+
+ /**
+ * Determines whether an IF statement is selected or an IF construct is selected (done in
+ * pre-condition). Depending on which, it will execute the appropriate refactoring (statement to
+ * construct or vise versa). It will then reindent the entire section of refactored code based
+ * on the formating context of the code around it.
+ *
+ * @param pm
+ * @throws CoreException, OperationCanceledException
+ */
+ @Override
+ protected void doCreateChange(IProgressMonitor pm) throws CoreException,
+ OperationCanceledException
+ {
+ if (selectedNode instanceof ASTIfStmtNode)
+ refactorIfStmt();
+ else if (selectedNode instanceof ASTIfConstructNode)
+ refactorIfConstruct();
+ else
+ throw new IllegalStateException();
+
+ Reindenter.reindent(selectedNode, this.astOfFileInEditor, Strategy.REINDENT_EACH_LINE);
+ this.addChangeFromModifiedAST(this.fileInEditor, pm);
+
+ }
+
+ protected void refactorIfStmt()
+ {
+ ASTIfStmtNode ifStmtNode = (ASTIfStmtNode)selectedNode;
+ ifStmtNode.replaceWith(createNewIfConstruct(ifStmtNode));
+ }
+
+ protected void refactorIfConstruct()
+ {
+ ASTIfConstructNode ifConstructNode = (ASTIfConstructNode)selectedNode;
+ ifConstructNode.replaceWith(createNewIfStmt(ifConstructNode));
+ }
+
+ /**
+ * Creates a new IF statement from the selected IF construct
+ *
+ * @param ifConstructNode
+ */
+ private ASTIfStmtNode createNewIfStmt(ASTIfConstructNode ifConstructNode)
+ {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append(" if ("); //$NON-NLS-1$
+ sb.append(ifConstructNode.getIfThenStmt().getGuardingExpression().toString().trim());
+ sb.append(") "); //$NON-NLS-1$
+
+ if (!ifConstructNode.getConditionalBody().isEmpty())
+ {
+ IExecutionPartConstruct stmt = ifConstructNode.getConditionalBody().get(0);
+
+ String leadingComments = stmt.findFirstToken().getWhiteBefore().trim();
+ if (!leadingComments.equals("")) //$NON-NLS-1$
+ {
+ sb.append("&\n"); //$NON-NLS-1$
+ sb.append(stmt.toString());
+ }
+ else
+ {
+ sb.append(stmt.toString().trim() + "\n"); //$NON-NLS-1$
+ }
+ }
+
+ ASTIfStmtNode result = (ASTIfStmtNode)parseLiteralStatement(sb.toString());
+
+ String trailingComments = ifConstructNode.getEndIfStmt().findFirstToken().getWhiteBefore();
+ if (!trailingComments.trim().equals("")) //$NON-NLS-1$
+ result.findLastToken().setWhiteAfter(trailingComments + "\n"); //$NON-NLS-1$
+
+ return result;
+ }
+
+ /**
+ * Creates a new IF construct from the selected IF statement, with an option to add an empty
+ * ELSE construct
+ *
+ * @param ifConstructNode
+ */
+ private ASTIfConstructNode createNewIfConstruct(ASTIfStmtNode ifStmtNode)
+ {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append(" if ("); //$NON-NLS-1$
+ sb.append(ifStmtNode.getGuardingExpression().toString());
+ sb.append(") then"); //$NON-NLS-1$
+ sb.append("\n "); //$NON-NLS-1$
+ sb.append(ifStmtNode.getActionStmt().toString().trim());
+ sb.append("\n !can add more statements here"); //$NON-NLS-1$
+ if (shouldAddEmptyElseBlock)
+ {
+ sb.append("\n else"); //$NON-NLS-1$
+ sb.append("\n !can add more statements here"); //$NON-NLS-1$
+ }
+ sb.append("\n end if"); //$NON-NLS-1$
+
+ ASTIfConstructNode newIfConstructNode = (ASTIfConstructNode)parseLiteralStatement(sb
+ .toString());
+
+ return newIfConstructNode;
+ }
+
+ @Override
+ public String getName()
+ {
+ return Messages.IfConstructStatementConversionRefactoring_Name;
+ }
+}
diff --git a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/Messages.java b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/Messages.java
index 4ebb975f..e2e0072a 100644
--- a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/Messages.java
+++ b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/Messages.java
@@ -267,6 +267,18 @@ public class Messages extends NLS
public static String ExtractLocalVariableRefactoring_VarsOnlyExtractedFromStmtsIn;
public static String InterchangeLoopsRefactoring_Name;
+
+ public static String IfConstructStatementConversionRefactoring_Name;
+
+ public static String IfConstructStatementConversionRefactoring_SelectAValidIfStatement;
+
+ public static String IfConstructStatementConversionRefactoring_InvalidNamedConstruct;
+
+ public static String IfConstructStatementConversionRefactoring_TooManyStatements;
+
+ public static String FortranEditorRefactoring_CantPerformRefactoringOnReadOnlyFile;
+
+ public static String FortranEditorRefactoring_CantPerformRefactoringOnFileThatDoesNotExist;
public static String InterchangeLoopsRefactoring_SelectTwoPerfNextedLoops;
diff --git a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/infrastructure/FortranResourceRefactoring.java b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/infrastructure/FortranResourceRefactoring.java
index fa755f17..90d2e084 100644
--- a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/infrastructure/FortranResourceRefactoring.java
+++ b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/infrastructure/FortranResourceRefactoring.java
@@ -533,7 +533,7 @@ public abstract class FortranResourceRefactoring
return getNode(firstToken, lastToken, node);
}
/**end test code*/
- protected static ASTNode getNode(IFortranAST ast, ITextSelection selection, Class<? extends ASTNode> node)
+ protected static <T extends IASTNode> T getNode(IFortranAST ast, ITextSelection selection, Class<T> node)
{
Token firstToken = findFirstTokenAfter(ast, selection.getOffset());
Token lastToken = findLastTokenBefore(ast, selection.getOffset()+selection.getLength());
@@ -542,13 +542,13 @@ public abstract class FortranResourceRefactoring
return getNode(firstToken, lastToken, node);
}
- protected static ASTNode getNode(Token firstToken, Token lastToken, Class<? extends ASTNode> node)
+ protected static <T extends IASTNode> T getNode(Token firstToken, Token lastToken, Class<T> node)
{
assert(firstToken != null);
assert(lastToken != null);
- ASTNode firstTokenNode = firstToken.findNearestAncestor(node);
- ASTNode lastTokenNode = lastToken.findNearestAncestor(node);
- if(firstTokenNode == null || lastTokenNode == null || firstTokenNode != lastTokenNode)
+ T firstTokenNode = firstToken.findNearestAncestor(node);
+ T lastTokenNode = lastToken.findNearestAncestor(node);
+ if (firstTokenNode == null || lastTokenNode == null || firstTokenNode != lastTokenNode)
return null;
return firstTokenNode;
//return null;
diff --git a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/messages.properties b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/messages.properties
index 5c9c108b..c7c3d815 100644
--- a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/messages.properties
+++ b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/messages.properties
@@ -214,3 +214,9 @@ SafeDeleteInternalSubprogramRefactoring_NotAnInternalSubprogram=Not an internal
SafeDeleteInternalSubprogramRefactoring_SubroutineMustHaveOnlyInternalReferences=Subroutine must only have internal references.
StandardizeStatementsRefactoring_Name=Standardize Statements
StandardizeStatementsRefactoring_SelectedFileCannotBeParsed=One of the selected files ({0}) cannot be parsed.
+IfConstructStatementConversionRefactoring_Name= Convert Between If Statement and If Construct
+IfConstructStatementConversionRefactoring_SelectAValidIfStatement= Please select a valid IF statement or construct.
+IfConstructStatementConversionRefactoring_InvalidNamedConstruct= Cannot refactor a named IF construct. Please select an unnamed IF construct.
+IfConstructStatementConversionRefactoring_TooManyStatements= Selected IF construct contains too many statements and cannot be refactored to an IF statement.
+FortranEditorRefactoring_CantPerformRefactoringOnReadOnlyFile= Can't perform refactoring on a read-only file.
+FortranEditorRefactoring_CantPerformRefactoringOnFileThatDoesNotExist= Can't perform refactoring on a file that does not exist.

Back to the top