diff options
author | Jeffrey Overbey | 2011-03-16 07:38:34 +0000 |
---|---|---|
committer | Jeffrey Overbey | 2011-03-16 07:38:34 +0000 |
commit | f614e3b3943992a9146f4a4efa9d47c56150ca1b (patch) | |
tree | ab43d95e385a22b3978cd8c27fa445c017f11d02 /org.eclipse.photran.core.vpg | |
parent | 614eee08f350091f6f61db216cc77ccc57b9d536 (diff) | |
download | org.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')
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. |