Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/MoveSubprogramToModuleRefactoring.java')
-rw-r--r--org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/MoveSubprogramToModuleRefactoring.java355
1 files changed, 355 insertions, 0 deletions
diff --git a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/MoveSubprogramToModuleRefactoring.java b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/MoveSubprogramToModuleRefactoring.java
new file mode 100644
index 00000000..14354807
--- /dev/null
+++ b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/MoveSubprogramToModuleRefactoring.java
@@ -0,0 +1,355 @@
+/*******************************************************************************
+ * Copyright (c) 2011 UFSM - Universidade Federal de Santa Maria (www.ufsm.br).
+ * 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
+ *******************************************************************************/
+package org.eclipse.photran.internal.core.refactoring;
+
+import java.util.LinkedList;
+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.lexer.Token;
+import org.eclipse.photran.internal.core.parser.ASTAssignmentStmtNode;
+import org.eclipse.photran.internal.core.parser.ASTCallStmtNode;
+import org.eclipse.photran.internal.core.parser.ASTContainsStmtNode;
+import org.eclipse.photran.internal.core.parser.ASTDerivedTypeDefNode;
+import org.eclipse.photran.internal.core.parser.ASTEntityDeclNode;
+import org.eclipse.photran.internal.core.parser.ASTExecutableProgramNode;
+import org.eclipse.photran.internal.core.parser.ASTFunctionSubprogramNode;
+import org.eclipse.photran.internal.core.parser.ASTImplicitStmtNode;
+import org.eclipse.photran.internal.core.parser.ASTModuleNode;
+import org.eclipse.photran.internal.core.parser.ASTNameNode;
+import org.eclipse.photran.internal.core.parser.ASTObjectNameNode;
+import org.eclipse.photran.internal.core.parser.ASTSubroutineSubprogramNode;
+import org.eclipse.photran.internal.core.parser.ASTTypeDeclarationStmtNode;
+import org.eclipse.photran.internal.core.parser.ASTUseStmtNode;
+import org.eclipse.photran.internal.core.parser.ASTVarOrFnRefNode;
+import org.eclipse.photran.internal.core.parser.IASTListNode;
+import org.eclipse.photran.internal.core.parser.IASTNode;
+import org.eclipse.photran.internal.core.parser.IInternalSubprogram;
+import org.eclipse.photran.internal.core.refactoring.infrastructure.FortranEditorRefactoring;
+
+/**
+ * Refactoring that moves a subprogram into a module.
+ *
+ * @author Gustavo Risetti
+ */
+@SuppressWarnings("nls") // TODO: Externalize strings
+public class MoveSubprogramToModuleRefactoring extends FortranEditorRefactoring {
+
+ IASTNode selectedFunctionOrSubroutine = null;
+ List<ASTModuleNode> fileModules = new LinkedList<ASTModuleNode>();
+ private String moduleName;
+ ScopingNode originalScope = null;
+ ASTModuleNode module = null;
+ List<Definition> parameters = new LinkedList<Definition>();
+
+ @Override
+ public String getName() {
+ return "Move Subroutine Or Function To Module";
+ }
+
+ public void setModuleName(String name){
+ this.moduleName = name;
+ }
+
+ @Override
+ protected void doCheckInitialConditions(RefactoringStatus status, IProgressMonitor pm) throws PreconditionFailure {
+ ensureProjectHasRefactoringEnabled(status);
+ // Finds the selected node and checks if it is a subroutine or a function.
+ IASTNode selectedNode = findEnclosingNode(astOfFileInEditor, selectedRegionInEditor);
+ if(selectedNode instanceof ASTSubroutineSubprogramNode || selectedNode instanceof ASTFunctionSubprogramNode){
+ selectedFunctionOrSubroutine = selectedNode;
+ }else{
+ fail("Please, select a Subroutine or a Function statement.");
+ }
+ // Stores all the modules of the file, to verify if the user will
+ // enter a name of an existing module.
+ for (ScopingNode scope : astOfFileInEditor.getRoot().getAllContainedScopes()){
+ if(scope instanceof ASTModuleNode){
+ fileModules.add((ASTModuleNode)scope);
+ }
+ }
+ // Stores a reference to the scope of where the subroutine or function will be moved.
+ originalScope = ((ScopingNode)selectedFunctionOrSubroutine).getEnclosingScope();
+ }
+
+ ASTModuleNode moduleExists(String moduleName){
+ for(ASTModuleNode module : fileModules){
+ if(module.getName().equalsIgnoreCase(moduleName)){
+ return module;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected void doCheckFinalConditions(RefactoringStatus status, IProgressMonitor pm) throws PreconditionFailure {
+ final String VALID_NAMES_WARNING = "Fill in the fields with valid values.";
+ final String SPACE_TD_WARNING = "The module name can not contain spaces and exclamation points.";
+ final String NUMERIC_DIGITS_WARNING = "The module name can not start with numeric digits.";
+ final Character[] numeric_digits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
+
+ if(moduleName.length() < 1){
+ fail(VALID_NAMES_WARNING);
+ }
+ for(int i = 0; i< moduleName.length(); i++){
+ if(moduleName.charAt(i) == ' ' || moduleName.charAt(i) == '!' || moduleName.charAt(i) == '\t'){
+ fail(SPACE_TD_WARNING);
+ }
+ }
+ for(int i=0; i<numeric_digits.length; i++){
+ if(moduleName.charAt(0) == numeric_digits[i]){
+ fail(NUMERIC_DIGITS_WARNING);
+ }
+ }
+ module = moduleExists(moduleName);
+ if(module == null){
+ fail("The module " + moduleName.toUpperCase() + " does not exist. Make sure you typed the name correctly.");
+ }
+ }
+
+ @Override
+ protected void doCreateChange(IProgressMonitor progressMonitor) throws CoreException, OperationCanceledException {
+ List<ScopingNode> scopes = new LinkedList<ScopingNode>();
+ // Checks for a PARAMETER variable used only in the selected code.
+ boolean moveParameter;
+ for(Definition def : originalScope.getAllDefinitions()){
+ if(def.isParameter()){
+ if(!(hasReference(def.getDeclaredName(), originalScope)) && hasReference(def.getDeclaredName(), selectedFunctionOrSubroutine)){
+ moveParameter = true;
+ for(IInternalSubprogram internal : originalScope.getInternalSubprograms()){
+ if(internal instanceof ASTSubroutineSubprogramNode){
+ if(selectedFunctionOrSubroutine instanceof ASTSubroutineSubprogramNode){
+ if(((ASTSubroutineSubprogramNode)internal) != ((ASTSubroutineSubprogramNode)selectedFunctionOrSubroutine)){
+ if(hasReference(def.getDeclaredName(), ((ASTSubroutineSubprogramNode)internal))){
+ moveParameter = false;
+ }
+ }
+ }else{
+ if(hasReference(def.getDeclaredName(), ((ASTSubroutineSubprogramNode)internal))){
+ moveParameter = false;
+ }
+ }
+ }
+ if(internal instanceof ASTFunctionSubprogramNode){
+ if(selectedFunctionOrSubroutine instanceof ASTFunctionSubprogramNode){
+ if(((ASTFunctionSubprogramNode)internal) != ((ASTFunctionSubprogramNode)selectedFunctionOrSubroutine)){
+ if(hasReference(def.getDeclaredName(), ((ASTFunctionSubprogramNode)internal))){
+ moveParameter = false;
+ }
+ }
+ }else{
+ if(hasReference(def.getDeclaredName(), ((ASTFunctionSubprogramNode)internal))){
+ moveParameter = false;
+ }
+ }
+ }
+ }
+ if(moveParameter){
+ parameters.add(def);
+ try{
+ removeVariableDeclFor(def);
+ }catch (PreconditionFailure e){
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ }
+
+ Token insertParameters = null;
+ for(IASTNode node : module.getModuleBody()){
+ if(node instanceof ASTImplicitStmtNode){
+ insertParameters = ((ASTImplicitStmtNode)node).findLastToken();
+ break;
+ }
+ }
+ String parametersString = ""; //$NON-NLS-1$
+ for(Definition def : parameters){
+ ASTTypeDeclarationStmtNode declarationNode = getTypeDeclarationStmtNode(def.getTokenRef().findToken().getParent());
+ parametersString += "\t" + declarationNode.toString(); //$NON-NLS-1$
+ }
+ if(!parameters.isEmpty()){
+ if(insertParameters != null){
+ insertParameters.setText(insertParameters.getText() +"\n"+ parametersString); //$NON-NLS-1$
+ }else{
+ insertParameters = module.getNameToken();
+ insertParameters.setText(insertParameters.getText() +"\n"+ parametersString); //$NON-NLS-1$
+ }
+ }
+
+ ASTContainsStmtNode contains = module.getContainsStmt();
+ // Checks if the module has the CONTAINS command.
+ if(contains != null){
+ String tokenText = contains.findLastToken().getText();
+ contains.findLastToken().setText(tokenText + selectedFunctionOrSubroutine.toString());
+ }else{
+ String tokenText = module.getEndModuleStmt().findFirstToken().getText();
+ module.getEndModuleStmt().findFirstToken().setText("CONTAINS\n"+selectedFunctionOrSubroutine.toString()+tokenText); //$NON-NLS-1$
+ }
+ // Adds the USE statement in scopes where the moved subroutine or function is used.
+ addUseInScope(scopes);
+ selectedFunctionOrSubroutine.removeFromTree();
+ if(originalScope.getInternalSubprograms().size() == 1){
+ originalScope.getContainsStmt().removeFromTree();
+ }
+ addChangeFromModifiedAST(fileInEditor, progressMonitor);
+ vpg.releaseAST(fileInEditor);
+ }
+
+ private void removeVariableDeclFor(Definition def) throws PreconditionFailure {
+ ASTTypeDeclarationStmtNode declarationNode = getTypeDeclarationStmtNode(def.getTokenRef().findToken().getParent());
+ IASTListNode<ASTEntityDeclNode> entityDeclList = declarationNode.getEntityDeclList();
+ if (entityDeclList.size() == 1) {
+ declarationNode.findFirstToken().setWhiteBefore(""); //$NON-NLS-1$
+ declarationNode.replaceWith(""); //$NON-NLS-1$
+ }else {
+ removeVariableDeclFromList(def, entityDeclList);
+ }
+ }
+
+ private void removeVariableDeclFromList(Definition def, IASTListNode<ASTEntityDeclNode> entityDeclList) throws PreconditionFailure {
+ for (ASTEntityDeclNode decl : entityDeclList) {
+ ASTObjectNameNode objectName = decl.getObjectName();
+ String declName = objectName.getObjectName().getText();
+ if (declName.equals(def.getDeclaredName())) {
+ if (!entityDeclList.remove(decl)) {
+ fail("The operation could not be completed.");
+ }
+ break;
+ }
+ }
+ entityDeclList.findFirstToken().setWhiteBefore(" "); //$NON-NLS-1$
+ }
+
+ private ASTTypeDeclarationStmtNode getTypeDeclarationStmtNode(IASTNode node) {
+ if (node == null){
+ return null;
+ }else if (node instanceof ASTTypeDeclarationStmtNode){
+ return (ASTTypeDeclarationStmtNode)node;
+ }else{
+ return getTypeDeclarationStmtNode(node.getParent());
+ }
+ }
+
+ private boolean hasReference(String name, IASTNode scope){
+ boolean r = false;
+ if(scope instanceof ASTSubroutineSubprogramNode){
+ for (int i=0; i<((ASTSubroutineSubprogramNode)scope).getBody().size(); i++){
+ r = isReferenced(((ASTSubroutineSubprogramNode)scope).getBody().get(i), name);
+ if (r) break;
+ }
+ }
+ if(scope instanceof ASTFunctionSubprogramNode){
+ for (int i=0; i<((ASTFunctionSubprogramNode)scope).getBody().size(); i++){
+ r = isReferenced(((ASTFunctionSubprogramNode)scope).getBody().get(i), name);
+ if (r) break;
+ }
+ }
+ return r;
+ }
+
+ private boolean hasReference(String name, ScopingNode scope){
+ boolean r = false;
+ for (int i=0; i<scope.getBody().size(); i++){
+ r = isReferenced(scope.getBody().get(i), name);
+ if (r) break;
+ }
+ return r;
+ }
+
+ private boolean isReferenced(IASTNode node, String name){
+ boolean r = false;
+ if (node instanceof ASTVarOrFnRefNode) {
+ r = existsReferenceForVariable(node, name);
+ } else {
+ for (IASTNode child : node.getChildren()) {
+ if (! r ) {
+ r = isReferenced(child, name);
+ } else {
+ break;
+ }
+ }
+ }
+ return r;
+ }
+
+ private boolean existsReferenceForVariable(IASTNode node, String name){
+ boolean r = false;
+ if (node instanceof ASTNameNode) {
+ if ( ((ASTNameNode)node).getName().getText().equalsIgnoreCase(name) ) {
+ r = true;
+ }
+ } else {
+ for (IASTNode child : node.getChildren()) {
+ if (! r ) {
+ r = existsReferenceForVariable(child, name);
+ } else {
+ break;
+ }
+ }
+ }
+ return r;
+ }
+
+ private void addUseInScope(List<ScopingNode> scopes) {
+ String name = null;
+ for (ScopingNode scope : astOfFileInEditor.getRoot().getAllContainedScopes()){
+ if (!(scope instanceof ASTExecutableProgramNode) && !(scope instanceof ASTDerivedTypeDefNode)){
+ for(IASTNode node : scope.getBody()){
+ if(node instanceof ASTCallStmtNode){
+ if(selectedFunctionOrSubroutine instanceof ASTSubroutineSubprogramNode){
+ name = ((ASTSubroutineSubprogramNode)selectedFunctionOrSubroutine).getName();
+ }else{
+ name = ((ASTFunctionSubprogramNode)selectedFunctionOrSubroutine).getName();
+ }
+ if(((ASTCallStmtNode)node).getSubroutineName().getText().equalsIgnoreCase(name)){
+ if(!scopes.contains(scope)){
+ scopes.add(scope);
+ }
+ }
+ }if(node instanceof ASTAssignmentStmtNode){
+ if(selectedFunctionOrSubroutine instanceof ASTFunctionSubprogramNode){
+ name = ((ASTFunctionSubprogramNode)selectedFunctionOrSubroutine).getName();
+ String funcName = null;
+ if(((ASTAssignmentStmtNode)node).getRhs() instanceof ASTVarOrFnRefNode){
+ funcName = ((ASTVarOrFnRefNode)((ASTAssignmentStmtNode)node).getRhs()).getName().getName().getText();
+ if(name.equalsIgnoreCase(funcName)){
+ if(!scopes.contains(scope)){
+ scopes.add(scope);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ boolean hasUse = false;
+ for(ScopingNode scope : scopes){
+ hasUse = false;
+ for(IASTNode node : scope.getBody()){
+ if(node instanceof ASTUseStmtNode){
+ if(((ASTUseStmtNode)node).getName().getText().equalsIgnoreCase(moduleName)){
+ hasUse = true;
+ break;
+ }
+ }
+ }
+ if(!hasUse){
+ String lastToken = scope.getHeaderStmt().findLastToken().getText();
+ scope.getHeaderStmt().findLastToken().setText(lastToken+"\tUSE " + moduleName + "\n"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+ }
+}

Back to the top