diff options
16 files changed, 2535 insertions, 3 deletions
diff --git a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/AddVariableToDerivedDataTypeRefactoring.java b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/AddVariableToDerivedDataTypeRefactoring.java new file mode 100644 index 00000000..b36088cd --- /dev/null +++ b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/AddVariableToDerivedDataTypeRefactoring.java @@ -0,0 +1,325 @@ +/******************************************************************************* + * 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 java.util.Set; + +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.parser.ASTDerivedTypeDefNode; +import org.eclipse.photran.internal.core.parser.ASTEntityDeclNode; +import org.eclipse.photran.internal.core.parser.ASTObjectNameNode; +import org.eclipse.photran.internal.core.parser.ASTTypeDeclarationStmtNode; +import org.eclipse.photran.internal.core.parser.IASTListNode; +import org.eclipse.photran.internal.core.parser.IASTNode; +import org.eclipse.photran.internal.core.parser.IBodyConstruct; +import org.eclipse.photran.internal.core.refactoring.infrastructure.FortranEditorRefactoring; +import org.eclipse.photran.internal.core.vpg.PhotranTokenRef; + +/** + * Refactoring that adds a variable to a derived data type. + * + * @author Gustavo Risetti + */ +@SuppressWarnings("nls") // TODO: Externalize strings +public class AddVariableToDerivedDataTypeRefactoring extends FortranEditorRefactoring { + + private static final String OPS = "ops"; //$NON-NLS-1$ + + private LinkedList<IBodyConstruct> statements_nodes = new LinkedList<IBodyConstruct>(); + private LinkedList<PhotranTokenRef> references = new LinkedList<PhotranTokenRef>(); + private String derivedTypeName; + private String derivedTypeVariableName; + private PhotranTokenRef derived_data_type_ref = null; + + @Override + public String getName() { + return "Add Variable To Derived Data Type"; + } + + public void setDerivedTypeVariableName(String name){ + assert name != null; + derivedTypeVariableName = name; + } + + public void setDerivedTypeName(String name){ + assert name != null; + derivedTypeName = name; + } + + // Search the beginning of variable declarations in each selected row, and checks + // if are used attributes that are not allowed in derived types. + private String findStatements(String s){ + final String[] attributes_not_allowed = {"parameter", "intent", "target", "optional", "save", "external", "intrinsic"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ + final String[] types_allowed = {"integer", "real", "complex", "character", "logical"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ + String statement_line = new String(); + boolean has_type_in_line = false; + boolean init = false; + int j=0; + if(s.length() == 0){ + return OPS; + }else{ + for(int i = 0; i < s.length(); i++){ + if(s.charAt(i) == ' ' || s.charAt(i) == '\t' && init == false){ + j++; + }else{ + init = true; + break; + } + } + if(s.charAt(j) == '!'){ + return OPS; + }else{ + statement_line = s.substring(j); + } + } + for(String type : types_allowed){ + if(statement_line.toLowerCase().contains(type)){ + has_type_in_line = true; + } + } + for(String attribute : attributes_not_allowed){ + if(statement_line.toLowerCase().contains(attribute)){ + has_type_in_line = false; + } + } + if(has_type_in_line){ + return statement_line; + }else{ + return OPS; + } + } + + @Override + protected void doCheckInitialConditions(RefactoringStatus status, IProgressMonitor pm) throws PreconditionFailure { + final String SELECT_DECLARATION_WARNING = "Please select a variable declaration (or a list of variable declarations)."; + final String USE_IN_DERIVED_TYPE_WARNING = "You can not use this refactoring within a Derived Data Type that already exists."; + ensureProjectHasRefactoringEnabled(status); + // Checks if variables were selected in a derived type that already exists. + IASTNode derived_type_node = findEnclosingNode(astOfFileInEditor, selectedRegionInEditor); + ScopingNode derived_type_scope = ScopingNode.getEnclosingScope(derived_type_node); + if(derived_type_scope instanceof ASTDerivedTypeDefNode){ + fail(USE_IN_DERIVED_TYPE_WARNING); + } + String selected_text = selectedRegionInEditor.getText(); + if (selected_text.isEmpty()){ + fail(SELECT_DECLARATION_WARNING); + }else{ + String selected_lines[] = selected_text.split("\n"); + for(String s : selected_lines){ + s = findStatements(s); + if(!s.equalsIgnoreCase(OPS)){ + statements_nodes.add(parseLiteralStatement(s)); + } + } + LinkedList<IBodyConstruct> nodes_to_remove = new LinkedList<IBodyConstruct>(); + for( IBodyConstruct node : statements_nodes){ + if(!(node instanceof ASTTypeDeclarationStmtNode)){ + nodes_to_remove.add(node); + } + } + // List of variables to be included in the derived type. + statements_nodes.removeAll(nodes_to_remove); + } + if(statements_nodes.isEmpty()){ + fail(SELECT_DECLARATION_WARNING); + } + } + + @SuppressWarnings("unchecked") + @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 name of the Derived Data Type can not contain spaces and exclamation points."; + final String SPACE_VTD_WARNING = "The name of the Derived Data Type instance can not contain spaces and exclamation points."; + final String NUMERIC_DIGITS_WARNING = "The names can not start with numeric digits."; + final String DERIVED_DATA_TYPE_REF_WARNING = "The Derived Data Type name entered was not found. Make sure you typed correctly."; + final String DERIVED_DATA_TYPE_INSTANCE_WARNING = "The Derived Data Type instance entered was not found. Make sure you typed correctly."; + final Character[] numeric_digits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + boolean match_name = false; + if(derivedTypeName.length() < 1 || derivedTypeVariableName.length() < 1){ + fail(VALID_NAMES_WARNING); + } + for(int i = 0; i< derivedTypeName.length(); i++){ + if(derivedTypeName.charAt(i) == ' ' || derivedTypeName.charAt(i) == '!' || derivedTypeName.charAt(i) == '\t'){ + fail(SPACE_TD_WARNING); + } + } + for(int i = 0; i< derivedTypeVariableName.length(); i++){ + if(derivedTypeVariableName.charAt(i) == ' ' || derivedTypeVariableName.charAt(i) == '!' || derivedTypeVariableName.charAt(i) == '\t'){ + fail(SPACE_VTD_WARNING); + } + } + for(int i=0; i<numeric_digits.length; i++){ + if(derivedTypeName.charAt(0) == numeric_digits[i] || derivedTypeVariableName.charAt(0) == numeric_digits[i]){ + fail(NUMERIC_DIGITS_WARNING); + } + } + // Checks if the derived type is spelled correctly. + IASTNode node = findEnclosingNode(astOfFileInEditor, selectedRegionInEditor); + ScopingNode scope = ScopingNode.getEnclosingScope(node); + List<ScopingNode> contained_scopes = scope.getAllContainedScopes(); + for(ScopingNode s : contained_scopes){ + if(s instanceof ASTDerivedTypeDefNode){ + if(((ASTDerivedTypeDefNode)s).getDerivedTypeStmt().getTypeName().getText().equalsIgnoreCase(derivedTypeName)){ + derived_data_type_ref = ((ASTDerivedTypeDefNode)s).getRepresentativeToken(); + } + } + } + if(derived_data_type_ref == null){ + fail(DERIVED_DATA_TYPE_REF_WARNING); + } + // Checks if the instance name of the derived type is spelled correctly. + IASTListNode<IASTNode> body = (IASTListNode<IASTNode>)scope.getBody(); + for(IASTNode n : body){ + if(n instanceof ASTTypeDeclarationStmtNode){ + if(((ASTTypeDeclarationStmtNode)n).getTypeSpec().isDerivedType()){ + IASTListNode<ASTEntityDeclNode> entityDeclList = ((ASTTypeDeclarationStmtNode)n).getEntityDeclList(); + for(ASTEntityDeclNode entity : entityDeclList){ + if(entity.getObjectName().getObjectName().getText().equals(derivedTypeVariableName)){ + match_name = true; + } + } + } + } + } + if(!match_name){ + fail(DERIVED_DATA_TYPE_INSTANCE_WARNING); + } + } + + @SuppressWarnings("static-access") + @Override + protected void doCreateChange(IProgressMonitor progressMonitor) throws CoreException, OperationCanceledException { + List<Character> blank_characters = new LinkedList<Character>(); + IASTNode node = findEnclosingNode(astOfFileInEditor, selectedRegionInEditor); + ScopingNode scope = astOfFileInEditor.getRoot().getEnclosingScope(node); + String tab = ""; //$NON-NLS-1$ + String headerStmt = scope.getHeaderStmt().toString(); + String[] headerStmtWithoutComments = headerStmt.split("\n"); + headerStmt = headerStmtWithoutComments[headerStmtWithoutComments.length - 1]; + tab = getBlankCharacters(blank_characters, tab, headerStmt); + tab+="\t\t"; //$NON-NLS-1$ + if(derived_data_type_ref != null){ + String new_statements = derived_data_type_ref.findToken().getText()+"\n"; + for(int i=0; i<statements_nodes.size(); i++){ + IBodyConstruct stmt = statements_nodes.get(i); + new_statements += tab + ((ASTTypeDeclarationStmtNode)stmt).toString().trim(); + if(i<statements_nodes.size()-1){ + new_statements += "\n"; //$NON-NLS-1$ + } + } + derived_data_type_ref.findToken().setText(new_statements); + } + // Search references of variables added to the derived type and replace the references by the derived type instance. + findReferences(scope); + if(statements_nodes.size() > 0){ + addChangeFromModifiedAST(fileInEditor, progressMonitor); + } + vpg.releaseAST(fileInEditor); + } + + void findReferences(ScopingNode scope){ + List<Definition> used_definitions = new LinkedList<Definition>(); + List<Definition> all_definitions = scope.getAllDefinitions(); + LinkedList<String> node_names = new LinkedList<String>(); + // Gets the names of the derived type variables. + for(IBodyConstruct t : statements_nodes){ + IASTListNode<ASTEntityDeclNode> statements = ((ASTTypeDeclarationStmtNode)t).getEntityDeclList(); + for(ASTEntityDeclNode d : statements){ + node_names.add(d.getObjectName().toString().trim()); + } + } + // Stores the definitions of variables actually used. + for(Definition def : all_definitions){ + for(String n : node_names){ + if(def.getDeclaredName().toString().trim().equals(n)){ + used_definitions.add(def); + } + } + } + // Stores references to each definition actually used. + for(Definition d : used_definitions){ + Set<PhotranTokenRef> references_to_definition = d.findAllReferences(false); + for(PhotranTokenRef t : references_to_definition){ + references.add(t); + } + } + // Replaces references with the new type, with the access modifier %. + for(PhotranTokenRef t : references){ + t.findToken().setText(derivedTypeVariableName+"%"+t.findToken().getText()); + } + // Remove the declarations of variables that were included in the derived type. + for(Definition def : used_definitions){ + try { + removeVariableDeclFor(def); + } catch (PreconditionFailure e) { + e.printStackTrace(); + } + } + } + + 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()); + } + } + + // Get indentation. + private String getBlankCharacters(List<Character> blank_characters, String tab, String headerStmt) { + boolean start = false; + for(int i=0; i<headerStmt.length(); i++){ + char c = headerStmt.charAt(i); + if((c != '\t') && (c != ' ')){ + start = true; + } + if((c == '\t' || c == ' ') && !start){ + blank_characters.add(headerStmt.charAt(i)); + } + } + for(int i=0; i<blank_characters.size();i++){ + tab+=blank_characters.get(i); + } + return tab; + } +} diff --git a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/ExtractSubprogramToModuleRefactoring.java b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/ExtractSubprogramToModuleRefactoring.java new file mode 100644 index 00000000..9af70464 --- /dev/null +++ b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/ExtractSubprogramToModuleRefactoring.java @@ -0,0 +1,339 @@ +/******************************************************************************* + * 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.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.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 extracts a subprogram to a module. + * + * @author Gustavo Risetti + */ +@SuppressWarnings("nls") // TODO: Externalize strings +public class ExtractSubprogramToModuleRefactoring extends FortranEditorRefactoring { + + IASTNode selectedFunctionOrSubroutine = null; + List<ASTModuleNode> fileModules = new LinkedList<ASTModuleNode>(); + private String moduleName; + ScopingNode originalScope = null; + List<Definition> parameters = new LinkedList<Definition>(); + + @Override + public String getName() { + return "Extract 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 extracted. + 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); + } + } + ASTModuleNode module = moduleExists(moduleName); + if(module != null){ + fail("The module " + moduleName.toUpperCase() + " already exists. Choose another name for the module to be created."); + } + } + + @Override + protected void doCreateChange(IProgressMonitor progressMonitor) throws CoreException, OperationCanceledException { + List<ScopingNode> scopes = new LinkedList<ScopingNode>(); + // Located where the module will be added in the AST. + Token insertModule = astOfFileInEditor.getRoot().findFirstToken(); + // 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){ + // If there is a parameter used only in the subroutine or function, it is stored + // in a list to be added in the module created. + parameters.add(def); + try{ + // The original statement is removed from original scope. + removeVariableDeclFor(def); + }catch (PreconditionFailure e){ + e.printStackTrace(); + } + } + } + } + } + + // Construction of the module. + String newModuleNode = "MODULE " + moduleName + "\n"; //$NON-NLS-1$ //$NON-NLS-2$ + // Adds parameters. + for(Definition def : parameters){ + ASTTypeDeclarationStmtNode declarationNode = getTypeDeclarationStmtNode(def.getTokenRef().findToken().getParent()); + newModuleNode += "\t" + declarationNode.toString(); //$NON-NLS-1$ + } + newModuleNode+="CONTAINS\n"; //$NON-NLS-1$ + // Adds the subroutine or function in the module body. + newModuleNode+=selectedFunctionOrSubroutine.toString(); + newModuleNode+="END MODULE " + moduleName + "\n\n"; //$NON-NLS-1$ //$NON-NLS-2$ + insertModule.setText(newModuleNode + insertModule.getText()); + // Adds the USE statement in scopes where the extracted 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$ + } + } + } +} diff --git a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/IntroduceCallTreeRefactoring.java b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/IntroduceCallTreeRefactoring.java new file mode 100644 index 00000000..c50979cd --- /dev/null +++ b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/IntroduceCallTreeRefactoring.java @@ -0,0 +1,196 @@ +/******************************************************************************* + * 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.resources.IFile; +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.core.IFortranAST; +import org.eclipse.photran.internal.core.analysis.binding.ScopingNode; +import org.eclipse.photran.internal.core.lexer.Token; +import org.eclipse.photran.internal.core.parser.ASTCallStmtNode; +import org.eclipse.photran.internal.core.parser.ASTDerivedTypeDefNode; +import org.eclipse.photran.internal.core.parser.ASTExecutableProgramNode; +import org.eclipse.photran.internal.core.parser.ASTMainProgramNode; +import org.eclipse.photran.internal.core.parser.IASTListNode; +import org.eclipse.photran.internal.core.parser.IASTNode; +import org.eclipse.photran.internal.core.refactoring.infrastructure.FortranResourceRefactoring; + +/** + * Refactoring that adds a call tree in a comment preceding each subprogram. + * + * @author Gustavo Risetti + */ +//@SuppressWarnings("nls") // TODO: Externalize strings +public class IntroduceCallTreeRefactoring extends FortranResourceRefactoring { + @Override + protected void doCheckFinalConditions(RefactoringStatus status, IProgressMonitor pm) throws PreconditionFailure { + try { + for (IFile file : selectedFiles) { + IFortranAST ast = vpg.acquirePermanentAST(file); + if (ast == null) { + status.addError("One of the selected files (" + file.getName() +") cannot be parsed."); + } else { + makeChangesTo(file, ast, status, pm); + vpg.releaseAST(file); + } + } + } finally { + vpg.releaseAllASTs(); + } + } + + @SuppressWarnings("unchecked") + private void makeChangesTo(IFile file, IFortranAST ast, RefactoringStatus status, IProgressMonitor pm) { + List<ScopingNode> scopes = ast.getRoot().getAllContainedScopes(); + List<Character> blank_characters = new LinkedList<Character>(); + List<String> callStmtsOfScope = new LinkedList<String>(); + Integer line_int = new Integer(0); + ScopingNode scopeChanged = null; + boolean hasCall = false; + // Get the number of calls within the main program + int mainProgramCalls = getMainProgramCalls(scopes); + int scopeCalls = 0; + for (ScopingNode scope : scopes){ + // Updates number of calls in scope. + scopeCalls = getScopeCalls(scopeCalls, scope); + callStmtsOfScope.clear(); + blank_characters.clear(); + scopeChanged = null; + hasCall = false; + if (!(scope instanceof ASTExecutableProgramNode) && !(scope instanceof ASTDerivedTypeDefNode)){ + IASTListNode<IASTNode> body = (IASTListNode<IASTNode>)scope.getBody(); + for (IASTNode node : body){ + if (node instanceof ASTCallStmtNode){ + hasCall = true; + scopeChanged = scope; + // Information of the line number where are the call. + if(scope instanceof ASTMainProgramNode){ + line_int = node.findFirstToken().getLine() + mainProgramCalls; + }else{ + line_int = node.findFirstToken().getLine() + scopeCalls + mainProgramCalls; + } + String line = line_int.toString(); + // Adds entry to the calls buffer of the scope. + callStmtsOfScope.add(((ASTCallStmtNode)node).getSubroutineName().getText() + " (on line <" +line+">)"); + } + } + if((hasCall== true) && (scopeChanged != null)){ + // Get the declaration of the subprogram. + Token firstToken = scopeChanged.findFirstToken(); + String firstTokenText = firstToken.getText(); + // Get indentation + String tab = ""; //$NON-NLS-1$ + String headerStmt = scopeChanged.getHeaderStmt().toString(); + String[] headerStmtWithoutComments = headerStmt.split("\n"); //$NON-NLS-1$ + headerStmt = headerStmtWithoutComments[headerStmtWithoutComments.length - 1]; + tab = getBlankCharacters(blank_characters, tab, headerStmt); + String name = ""; //$NON-NLS-1$ + if(scopeChanged.isMainProgram()){ + name = " in program "; + }if(scopeChanged.isModule()){ + name = " in module "; + }if(scopeChanged.isSubprogram()){ + name = " in subroutine "; + } + // Prints the call tree of each subroutine. + firstToken.setText("! " + "Calls" + name + scopeChanged.getName().toUpperCase()+": \n"); //$NON-NLS-1$ + for(int i=0; i<callStmtsOfScope.size(); i++){ + String arrow = "="; //$NON-NLS-1$ + for(int j=0; j<i; j++){ + arrow += "="; //$NON-NLS-1$ + } + arrow += ">"; //$NON-NLS-1$ + firstToken.setText(firstToken.getText()+ tab + "! " + arrow + " " + callStmtsOfScope.get(i).toString() + "\n"); //$NON-NLS-1$ //$NON-NLS-2$ + } + firstToken.setText(firstToken.getText()+tab + firstTokenText.trim()); + } + } + } + addChangeFromModifiedAST(file, pm); + } + + // Get correct indentation. + private String getBlankCharacters(List<Character> blank_characters, String tab, String headerStmt) { + boolean start = false; + for(int i=0; i<headerStmt.length(); i++){ + char c = headerStmt.charAt(i); + if((c != '\t') && (c != ' ')){ + start = true; + } + if((c == '\t' || c == ' ') && !start){ + blank_characters.add(headerStmt.charAt(i)); + } + } + for(int i=0; i<blank_characters.size();i++){ + tab+=blank_characters.get(i); + } + return tab; + } + + // Get the calls of the scope. + @SuppressWarnings("unchecked") + private int getScopeCalls(int scopeCalls, ScopingNode scope) { + if (!(scope instanceof ASTExecutableProgramNode) && !(scope instanceof ASTDerivedTypeDefNode)){ + IASTListNode<IASTNode> body = (IASTListNode<IASTNode>)scope.getBody(); + int n = 0; + for (IASTNode node : body){ + if (node instanceof ASTCallStmtNode){ + n++; + } + } + if(n > 0){ + n++; + } + scopeCalls+=n; + } + return scopeCalls; + } + + // Get the calls of the main program. + @SuppressWarnings("unchecked") + private int getMainProgramCalls(List<ScopingNode> scopes){ + int mainProgramCalls = 0; + for (ScopingNode scope : scopes){ + if(scope instanceof ASTMainProgramNode){ + IASTListNode<IASTNode> body = (IASTListNode<IASTNode>)scope.getBody(); + for (IASTNode node : body){ + if (node instanceof ASTCallStmtNode){ + mainProgramCalls ++; + } + } + if(mainProgramCalls > 0){ + mainProgramCalls ++; + } + } + } + return mainProgramCalls; + } + + @Override + protected void doCheckInitialConditions(RefactoringStatus status, IProgressMonitor pm) throws PreconditionFailure { + ensureProjectHasRefactoringEnabled(status); + removeFixedFormFilesFrom(this.selectedFiles, status); + removeCpreprocessedFilesFrom(this.selectedFiles, status); + } + + @Override + protected void doCreateChange(IProgressMonitor pm) throws CoreException, OperationCanceledException { + // The change is made in method makeChangesTo(...). + } + + @Override + public String getName() { + return "Introduce Call Tree"; + } +} 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$ + } + } + } +} diff --git a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/NestedIfThenElseToSelectCaseRefactoring.java b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/NestedIfThenElseToSelectCaseRefactoring.java new file mode 100644 index 00000000..4aaf1304 --- /dev/null +++ b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/NestedIfThenElseToSelectCaseRefactoring.java @@ -0,0 +1,248 @@ +/******************************************************************************* + * 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.resources.IFile; +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.core.IFortranAST; +import org.eclipse.photran.internal.core.analysis.binding.ScopingNode; +import org.eclipse.photran.internal.core.parser.ASTDerivedTypeDefNode; +import org.eclipse.photran.internal.core.parser.ASTElseConstructNode; +import org.eclipse.photran.internal.core.parser.ASTElseIfConstructNode; +import org.eclipse.photran.internal.core.parser.ASTExecutableProgramNode; +import org.eclipse.photran.internal.core.parser.ASTIfConstructNode; +import org.eclipse.photran.internal.core.parser.IASTListNode; +import org.eclipse.photran.internal.core.parser.IASTNode; +import org.eclipse.photran.internal.core.refactoring.infrastructure.FortranResourceRefactoring; + +/** + * Refactoring that converts nested if/then/else constructs into a SELECT CASE construct. + * + * @author Gustavo Risetti + */ +@SuppressWarnings("nls") // TODO: Externalize strings +public class NestedIfThenElseToSelectCaseRefactoring extends FortranResourceRefactoring{ + + List<ASTIfConstructNode> ifNodes = new LinkedList<ASTIfConstructNode>(); + List<ASTIfConstructNode> removeIfNodes = new LinkedList<ASTIfConstructNode>(); + List<String> varNames = new LinkedList<String>(); + List<String> cases = new LinkedList<String>(); + List<String> bodyCases = new LinkedList<String>(); + + @Override + public String getName() { + return "Nested If-Then-Else To Select Case"; + } + + @Override + protected void doCheckInitialConditions(RefactoringStatus status, IProgressMonitor pm) throws PreconditionFailure { + ensureProjectHasRefactoringEnabled(status); + removeFixedFormFilesFrom(this.selectedFiles, status); + removeCpreprocessedFilesFrom(this.selectedFiles, status); + } + + @Override + protected void doCheckFinalConditions(RefactoringStatus status, IProgressMonitor pm) throws PreconditionFailure{ + try { + for (IFile file : selectedFiles) { + IFortranAST ast = vpg.acquirePermanentAST(file); + if(ast == null) { + status.addError("One of the selected files (" + file.getName() +") cannot be parsed."); + }else { + makeChangesTo(file, ast, status, pm); + vpg.releaseAST(file); + } + } + }finally { + vpg.releaseAllASTs(); + } + } + + @SuppressWarnings("unchecked") + private void makeChangesTo(IFile file, IFortranAST ast, RefactoringStatus status, IProgressMonitor pm) throws PreconditionFailure { + boolean hasChanged = false; + List<ScopingNode> scopes = ast.getRoot().getAllContainedScopes(); + for(ScopingNode scope : scopes){ + if (!(scope instanceof ASTExecutableProgramNode) && !(scope instanceof ASTDerivedTypeDefNode)){ + IASTListNode<IASTNode> body = (IASTListNode<IASTNode>)scope.getBody(); + // Find nodes which contains nested if-then-else and add in a node list. + for(IASTNode node : body){ + if(node instanceof ASTIfConstructNode){ + ASTIfConstructNode ifNode = ((ASTIfConstructNode)node); + if(ifNode.getElseIfConstruct() != null){ + ifNodes.add((ASTIfConstructNode)node); + } + } + } + } + } + // Checks that appear only allowed comparisons (==, .eq., or) + for(ASTIfConstructNode ifNode : ifNodes){ + parserStmts(ifNode, null); + } + // Remove the nodes that do not satisfy the condition to be a case of a SELECT CASE + ifNodes.removeAll(removeIfNodes); + for(ASTIfConstructNode ifNode : ifNodes){ + // Gets the list of values and cases for the new node to be built. + getPairs(ifNode, null); + // Checks if the same variable is evaluated in expressions. + if(hasSameVars()){ + hasChanged = true; + String[] tabWithComments = ifNode.findFirstToken().getWhiteBefore().toString().split("\n"); //$NON-NLS-1$ + String tab = tabWithComments[tabWithComments.length-1]; + for(int i = 0; i < tab.length(); i ++){ + if(tab.charAt(i) == ' ' || tab.charAt(i) == '\t'){ + continue; + }else{ + tab = ""; //$NON-NLS-1$ + break; + } + } + // The new node is constructed. + String selectCaseNode = "SELECT CASE (" + varNames.get(0).trim() + ")\n"; //$NON-NLS-1$ //$NON-NLS-2$ + for(int i = 0; i< cases.size(); i++){ + String casesUnits = tab + "\tCASE " + cases.get(i).trim() + "\n"; //$NON-NLS-1$ //$NON-NLS-2$ + String[] body = bodyCases.get(i).split("\n"); //$NON-NLS-1$ + for(String bodyLine : body){ + casesUnits += tab + "\t\t" + bodyLine.trim()+"\n"; //$NON-NLS-1$ //$NON-NLS-2$ + } + selectCaseNode += casesUnits; + } + selectCaseNode += tab + "END SELECT\n"; //$NON-NLS-1$ + // Replaces the old node with the new node in AST. + ifNode.replaceWith(selectCaseNode); + varNames.clear(); + cases.clear(); + bodyCases.clear(); + }else{ + varNames.clear(); + cases.clear(); + bodyCases.clear(); + } + } + if (hasChanged){ + addChangeFromModifiedAST(file, pm); + } + } + + // Checks if the same variable is evaluated in expressions. + private boolean hasSameVars(){ + for(int i=0; i<varNames.size()-1; i++){ + if(!(varNames.get(i).equalsIgnoreCase(varNames.get(i+1)))){ + return false; + } + } + return true; + } + + // Gets the list of values ​​and cases. + private void getPairs(ASTIfConstructNode ifNode, ASTElseIfConstructNode elseIfNode) { + if(elseIfNode == null){ + String ifExpression = ifNode.getIfThenStmt().getGuardingExpression().toString().trim(); + ifExpression = ifExpression.replaceAll(".OR.", ".or."); //$NON-NLS-1$ //$NON-NLS-2$ + ifExpression = ifExpression.replaceAll(".Or.", ".or."); //$NON-NLS-1$ //$NON-NLS-2$ + ifExpression = ifExpression.replaceAll(".oR.", ".or."); //$NON-NLS-1$ //$NON-NLS-2$ + ifExpression = ifExpression.replaceAll(".EQ.", "=="); //$NON-NLS-1$ //$NON-NLS-2$ + ifExpression = ifExpression.replaceAll(".Eq.", "=="); //$NON-NLS-1$ //$NON-NLS-2$ + ifExpression = ifExpression.replaceAll(".eQ.", "=="); //$NON-NLS-1$ //$NON-NLS-2$ + ifExpression = ifExpression.replaceAll(".eq.", "=="); //$NON-NLS-1$ //$NON-NLS-2$ + String[] orSplit = ifExpression.split(".or."); //$NON-NLS-1$ + for(String s : orSplit){ + s = s.trim(); + String[] eqSplit = s.split("=="); //$NON-NLS-1$ + for(String seq : eqSplit){ + seq = seq.trim(); + } + for(int i=0; i<eqSplit.length; i+=2){ + varNames.add(eqSplit[i]); + cases.add("("+eqSplit[i+1].trim()+")"); //$NON-NLS-1$ //$NON-NLS-2$ + bodyCases.add(ifNode.getConditionalBody().toString()); + } + } + ASTElseIfConstructNode elseIf = ifNode.getElseIfConstruct(); + if(elseIf != null){ + getPairs(ifNode, elseIf); + } + }else{ + String elseIfExpression = elseIfNode.getElseIfStmt().getGuardingExpression().toString().trim(); + elseIfExpression = elseIfExpression.replaceAll(".OR.", ".or."); //$NON-NLS-1$ //$NON-NLS-2$ + elseIfExpression = elseIfExpression.replaceAll(".Or.", ".or."); //$NON-NLS-1$ //$NON-NLS-2$ + elseIfExpression = elseIfExpression.replaceAll(".oR.", ".or."); //$NON-NLS-1$ //$NON-NLS-2$ + elseIfExpression = elseIfExpression.replaceAll(".EQ.", "=="); //$NON-NLS-1$ //$NON-NLS-2$ + elseIfExpression = elseIfExpression.replaceAll(".Eq.", "=="); //$NON-NLS-1$ //$NON-NLS-2$ + elseIfExpression = elseIfExpression.replaceAll(".eQ.", "=="); //$NON-NLS-1$ //$NON-NLS-2$ + elseIfExpression = elseIfExpression.replaceAll(".eq.", "=="); //$NON-NLS-1$ //$NON-NLS-2$ + String[] orSplit = elseIfExpression.split(".or."); //$NON-NLS-1$ + for(String s : orSplit){ + s = s.trim(); + String[] eqSplit = s.split("=="); //$NON-NLS-1$ + for(String seq : eqSplit){ + seq = seq.trim(); + } + for(int i=0; i<eqSplit.length; i+=2){ + varNames.add(eqSplit[i]); + cases.add("("+eqSplit[i+1].trim()+")"); //$NON-NLS-1$ //$NON-NLS-2$ + bodyCases.add(elseIfNode.getConditionalBody().toString()); + } + } + ASTElseIfConstructNode elseIf = elseIfNode.getElseIfConstruct(); + if(elseIf != null){ + getPairs(ifNode, elseIf); + }else{ + ASTElseConstructNode elseDefault = elseIfNode.getElseConstruct(); + if(elseDefault != null){ + String elseDefaultExpression = elseDefault.getConditionalBody().toString(); + cases.add("DEFAULT"); //$NON-NLS-1$ + bodyCases.add(elseDefaultExpression); + } + } + } + } + + // Checks that appear only allowed comparisons (==, .eq., or) + private void parserStmts(ASTIfConstructNode ifNode, ASTElseIfConstructNode elseIfNode) { + String not_aloowed[] = {">", ".GT.", "<", ".LT.", ">=", ".GE.", "<=", ".LE.", "/=", ".NE.", ".AND.", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$ + ".EQV.", ".NEQV.", ".gt.", ".lt.", ".ge.", ".le.", ".ne.", ".and.", ".eqv.", ".neqv."}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ + if(elseIfNode == null){ + String ifExpression = ifNode.getIfThenStmt().getGuardingExpression().toString().trim(); + for(String s : not_aloowed){ + if(ifExpression.contains(s)){ + removeIfNodes.add(ifNode); + return; + } + } + ASTElseIfConstructNode elseIf = ifNode.getElseIfConstruct(); + if(elseIf != null){ + parserStmts(ifNode, elseIf); + } + }else{ + String elseIfExpression = elseIfNode.getElseIfStmt().getGuardingExpression().toString().trim(); + for(String s : not_aloowed){ + if(elseIfExpression.contains(s)){ + removeIfNodes.add(ifNode); + return; + } + } + ASTElseIfConstructNode elseIf = elseIfNode.getElseIfConstruct(); + if(elseIf != null){ + parserStmts(ifNode, elseIf); + } + } + } + + @Override + protected void doCreateChange(IProgressMonitor pm) throws CoreException, OperationCanceledException { + // The change is made in method makeChangesTo(...). + } +} diff --git a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/ReplaceDoLoopWithForallRefactoring.java b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/ReplaceDoLoopWithForallRefactoring.java new file mode 100644 index 00000000..4753ad56 --- /dev/null +++ b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/ReplaceDoLoopWithForallRefactoring.java @@ -0,0 +1,147 @@ +/******************************************************************************* + * 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 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.loops.ASTProperLoopConstructNode; +import org.eclipse.photran.internal.core.analysis.loops.LoopReplacer; +import org.eclipse.photran.internal.core.parser.ASTAssignmentStmtNode; +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; + +/** + * Refactoring that replaces a DO loop with a FORALL loop. + * + * @author Gustavo Risetti + */ +@SuppressWarnings("nls") // TODO: Externalize strings +public class ReplaceDoLoopWithForallRefactoring extends FortranEditorRefactoring { + + ASTProperLoopConstructNode selected_do_loop = null; + LinkedList<ASTProperLoopConstructNode> nested_selected_do_loop = new LinkedList<ASTProperLoopConstructNode>(); + + @Override + public String getName() { + return "Replace Do Loop By Forall"; + } + + @Override + protected void doCheckInitialConditions(RefactoringStatus status, IProgressMonitor pm) throws PreconditionFailure { + ensureProjectHasRefactoringEnabled(status); + LoopReplacer.replaceAllLoopsIn(this.astOfFileInEditor.getRoot()); + IASTNode do_loop_node = findEnclosingNode(astOfFileInEditor, selectedRegionInEditor); + if(!(do_loop_node instanceof ASTProperLoopConstructNode)){ + fail("Please, select a Do Loop."); + } + // Find the selected loop. + selected_do_loop = findSelectedDoLoop(); + // Checks if in the loops are made only assignments. + if(selected_do_loop != null){ + IASTListNode<IExecutionPartConstruct> body_selected_loop = selected_do_loop.getBody(); + for(IExecutionPartConstruct i : body_selected_loop){ + if(!getBody(i)){ + fail("Sorry, this refactoring can be applied only in Do Loops that contains just variable assignments."); + } + } + } + findNestedSelectedDoLoop(); + } + + private boolean getBody(IExecutionPartConstruct node){ + if(node instanceof ASTProperLoopConstructNode){ + IASTListNode<IExecutionPartConstruct> body = ((ASTProperLoopConstructNode)node).getBody(); + for(IExecutionPartConstruct i : body){ + if(i instanceof ASTProperLoopConstructNode){ + return getBody(i); + }else{ + if(!(i instanceof ASTAssignmentStmtNode)){ + return false; + } + } + } + }else if(!(node instanceof ASTAssignmentStmtNode)){ + return false; + } + return true; + } + + private ASTProperLoopConstructNode findSelectedDoLoop() { + return getLoopNode(this.astOfFileInEditor, this.selectedRegionInEditor); + } + + private void findNestedSelectedDoLoop(){ + if(selected_do_loop != null){ + IASTListNode<IExecutionPartConstruct> body_selected_loop = selected_do_loop.getBody(); + for(IExecutionPartConstruct i : body_selected_loop){ + addNestedSelectedDoLoop(i); + } + } + } + + private void addNestedSelectedDoLoop(IExecutionPartConstruct node){ + if(node instanceof ASTProperLoopConstructNode){ + nested_selected_do_loop.add((ASTProperLoopConstructNode)node); + IASTListNode<IExecutionPartConstruct> body = ((ASTProperLoopConstructNode)node).getBody(); + for(IExecutionPartConstruct i : body){ + if(i instanceof ASTProperLoopConstructNode){ + addNestedSelectedDoLoop(i); + } + } + } + } + + @Override + protected void doCheckFinalConditions(RefactoringStatus status, IProgressMonitor pm) throws PreconditionFailure { + // There is no final conditions to check... + } + + @Override + protected void doCreateChange(IProgressMonitor progressMonitor) throws CoreException, OperationCanceledException { + for(int i=nested_selected_do_loop.size()-1; i>=0; i--){ + ASTProperLoopConstructNode node = nested_selected_do_loop.get(i); + // Constructs a new FORALL node with the contents of the DO node and replaces in the AST. + String forall = constructForallNode(node); + node.replaceWith(parseLiteralStatementSequence(forall)); + } + String forall = constructForallNode(selected_do_loop); + selected_do_loop.replaceWith(parseLiteralStatementSequence(forall)); + addChangeFromModifiedAST(fileInEditor, progressMonitor); + vpg.releaseAST(fileInEditor); + } + + // Constructs a new FORALL node. + private String constructForallNode(ASTProperLoopConstructNode node){ + String variable = node.getLoopHeader().getLoopControl().getVariableName().getText(); + String initial_value = node.getLoopHeader().getLoopControl().getLb().toString().trim(); + String final_value = node.getLoopHeader().getLoopControl().getUb().toString().trim(); + String tab_init = node.findFirstToken().getWhiteBefore(); + String tab_end = node.getEndDoStmt().findFirstToken().getWhiteBefore(); + String step = null; + IExpr step_expr = node.getLoopHeader().getLoopControl().getStep(); + if(step_expr != null){ + step = step_expr.toString(); + } + String forall = tab_init + "FORALL (" + variable + "=" + initial_value + ":" + final_value; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + if(step != null){ + forall += ":" + step + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + }else{ + forall += ")"; //$NON-NLS-1$ + } + String body = node.getBody().toString(); + forall += "\n" + body + tab_end + "END FORALL"; //$NON-NLS-1$ //$NON-NLS-2$ + return forall; + } +} diff --git a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/TransformToDerivedDataTypeRefactoring.java b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/TransformToDerivedDataTypeRefactoring.java new file mode 100644 index 00000000..09bae7bb --- /dev/null +++ b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/refactoring/TransformToDerivedDataTypeRefactoring.java @@ -0,0 +1,304 @@ +/******************************************************************************* + * 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 java.util.Set; + +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.ASTDerivedTypeDefNode; +import org.eclipse.photran.internal.core.parser.ASTEntityDeclNode; +import org.eclipse.photran.internal.core.parser.ASTImplicitStmtNode; +import org.eclipse.photran.internal.core.parser.ASTObjectNameNode; +import org.eclipse.photran.internal.core.parser.ASTTypeDeclarationStmtNode; +import org.eclipse.photran.internal.core.parser.IASTListNode; +import org.eclipse.photran.internal.core.parser.IASTNode; +import org.eclipse.photran.internal.core.parser.IBodyConstruct; +import org.eclipse.photran.internal.core.vpg.PhotranTokenRef; +import org.eclipse.photran.internal.core.refactoring.infrastructure.FortranEditorRefactoring; + +/** + * Refactoring that converts local variable declarations into a derived type. + * + * @author Gustavo Risetti + */ +@SuppressWarnings("nls") // TODO: Externalize strings +public class TransformToDerivedDataTypeRefactoring extends FortranEditorRefactoring { + + private static final String OPS = "ops"; //$NON-NLS-1$ + + private LinkedList<IBodyConstruct> statements_nodes = new LinkedList<IBodyConstruct>(); + private LinkedList<PhotranTokenRef> references = new LinkedList<PhotranTokenRef>(); + private String derivedTypeVariableName; + private String derivedTypeName; + + @Override + public String getName() { + return "Transform To Derived Data Type"; + } + + public void setDerivedTypeName(String name) { + assert name != null; + derivedTypeName = name; + } + + public void setDerivedTypeVariableName(String name) { + assert name != null; + derivedTypeVariableName = name; + } + + // Search the beginning of variable declarations in each selected row, and checks + // if are used attributes that are not allowed in derived types. + private String findStatements(String s){ + final String[] attributes_not_allowed = {"parameter", "intent", "target", "optional", "save", "external", "intrinsic"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ + final String[] types_allowed = {"integer", "real", "complex", "character", "logical"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ + String statement_line = new String(); + boolean has_type_in_line = false; + boolean init = false; + int j=0; + if(s.length() == 0){ + return OPS; + }else{ + for(int i = 0; i < s.length(); i++){ + if(s.charAt(i) == ' ' || s.charAt(i) == '\t' && init == false){ + j++; + }else{ + init = true; + break; + } + } + if(s.charAt(j) == '!'){ + return OPS; + }else{ + statement_line = s.substring(j); + } + } + for(String type : types_allowed){ + if(statement_line.toLowerCase().contains(type)){ + has_type_in_line = true; + } + } + for(String attribute : attributes_not_allowed){ + if(statement_line.toLowerCase().contains(attribute)){ + has_type_in_line = false; + } + } + if(has_type_in_line){ + return statement_line; + }else{ + return OPS; + } + } + + @Override + protected void doCheckInitialConditions(RefactoringStatus status, IProgressMonitor pm) throws PreconditionFailure { + final String SELECT_DECLARATION_WARNING = "Please select a variable declaration (or a list of variable declarations)."; + final String USE_IN_DERIVED_TYPE_WARNING = "You can not use this refactoring within a Derived Data Type that already exists."; + ensureProjectHasRefactoringEnabled(status); + // Checks if variables were selected in a derived type that already exists. + IASTNode derived_type_node = findEnclosingNode(astOfFileInEditor, selectedRegionInEditor); + ScopingNode derived_type_scope = ScopingNode.getEnclosingScope(derived_type_node); + if(derived_type_scope instanceof ASTDerivedTypeDefNode){ + fail(USE_IN_DERIVED_TYPE_WARNING); + } + String selected_text = selectedRegionInEditor.getText(); + if (selected_text.isEmpty()){ + fail(SELECT_DECLARATION_WARNING); + }else{ + String selected_lines[] = selected_text.split("\n"); //$NON-NLS-1$ + for(String s : selected_lines){ + s = findStatements(s); + if(!s.equalsIgnoreCase(OPS)){ + statements_nodes.add(parseLiteralStatement(s)); + } + } + LinkedList<IBodyConstruct> nodes_to_remove = new LinkedList<IBodyConstruct>(); + for( IBodyConstruct node : statements_nodes){ + if(!(node instanceof ASTTypeDeclarationStmtNode)){ + nodes_to_remove.add(node); + } + } + // List of variables to be included in the new derived type. + statements_nodes.removeAll(nodes_to_remove); + } + if(statements_nodes.isEmpty()){ + fail(SELECT_DECLARATION_WARNING); + } + } + + @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 name of the Derived Data Type can not contain spaces and exclamation points."; + final String SPACE_VTD_WARNING = "The name of the new variable can not contain spaces and exclamation points."; + final String NUMERIC_DIGITS_WARNING = "The names created can not start with numeric digits."; + final Character[] numeric_digits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + if(derivedTypeName.length() < 1 || derivedTypeVariableName.length() < 1){ + fail(VALID_NAMES_WARNING); + } + for(int i = 0; i< derivedTypeName.length(); i++){ + if(derivedTypeName.charAt(i) == ' ' || derivedTypeName.charAt(i) == '!' || derivedTypeName.charAt(i) == '\t'){ + fail(SPACE_TD_WARNING); + } + } + for(int i = 0; i< derivedTypeVariableName.length(); i++){ + if(derivedTypeVariableName.charAt(i) == ' ' || derivedTypeVariableName.charAt(i) == '!' || derivedTypeVariableName.charAt(i) == '\t'){ + fail(SPACE_VTD_WARNING); + } + } + for(int i=0; i<numeric_digits.length; i++){ + if(derivedTypeName.charAt(0) == numeric_digits[i] || derivedTypeVariableName.charAt(0) == numeric_digits[i]){ + fail(NUMERIC_DIGITS_WARNING); + } + } + } + + @SuppressWarnings("static-access") + @Override + protected void doCreateChange(IProgressMonitor progressMonitor) throws CoreException, OperationCanceledException { + List<Character> blank_characters = new LinkedList<Character>(); + IASTNode node = findEnclosingNode(astOfFileInEditor, selectedRegionInEditor); + ScopingNode scope = astOfFileInEditor.getRoot().getEnclosingScope(node); + // Find where to add the declaration of the new derived type. + Token tokenToInsertDerivedDataType; + String tokenText; + tokenToInsertDerivedDataType = scope.getHeaderStmt().findLastToken(); + IASTListNode< ? extends IASTNode> scopebody = scope.getBody(); + for(IASTNode scopenode : scopebody){ + if(scopenode instanceof ASTImplicitStmtNode){ + ASTImplicitStmtNode implicitnode = (ASTImplicitStmtNode)scopenode; + tokenToInsertDerivedDataType = implicitnode.findLastToken(); + break; + } + } + tokenText = tokenToInsertDerivedDataType.getText(); + // Get indentation. + String tab = ""; //$NON-NLS-1$ + String headerStmt = scope.getHeaderStmt().toString(); + String[] headerStmtWithoutComments = headerStmt.split("\n"); + headerStmt = headerStmtWithoutComments[headerStmtWithoutComments.length - 1]; + tab = getBlankCharacters(blank_characters, tab, headerStmt); + tab+="\t"; //$NON-NLS-1$ + // Construct the new node. + String new_derived_type = new String(); + new_derived_type = tab + "TYPE " + derivedTypeName + "\n"; //$NON-NLS-1$ //$NON-NLS-2$ + for(IBodyConstruct s : statements_nodes){ + new_derived_type += tab + "\t" + ((ASTTypeDeclarationStmtNode)s).toString(); //$NON-NLS-1$ + } + new_derived_type += tab + "END TYPE " + derivedTypeName; //$NON-NLS-1$ + // Declaration of a derived type variable. + new_derived_type += "\n\n" + tab + "TYPE("+derivedTypeName+") :: "+ derivedTypeVariableName + "\n"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + tokenToInsertDerivedDataType.setText(tokenText.trim() + "\n" + new_derived_type + "\n"); //$NON-NLS-1$ //$NON-NLS-2$ + // Search references of variables added to the new type and replace the references by the new type. + findReferences(scope); + if(statements_nodes.size() > 0){ + addChangeFromModifiedAST(fileInEditor, progressMonitor); + } + vpg.releaseAST(fileInEditor); + } + + void findReferences(ScopingNode scope){ + List<Definition> used_definitions = new LinkedList<Definition>(); + List<Definition> all_definitions = scope.getAllDefinitions(); + LinkedList<String> node_names = new LinkedList<String>(); + // Gets the names of the derived type variables. + for(IBodyConstruct t : statements_nodes){ + IASTListNode<ASTEntityDeclNode> statements = ((ASTTypeDeclarationStmtNode)t).getEntityDeclList(); + for(ASTEntityDeclNode d : statements){ + node_names.add(d.getObjectName().toString().trim()); + } + } + // Stores the definitions of variables actually used. + for(Definition def : all_definitions){ + for(String n : node_names){ + if(def.getDeclaredName().toString().trim().equals(n)){ + used_definitions.add(def); + } + } + } + // Stores references to each definition actually used. + for(Definition d : used_definitions){ + Set<PhotranTokenRef> references_to_definition = d.findAllReferences(false); + for(PhotranTokenRef t : references_to_definition){ + references.add(t); + } + } + // Replaces references with the new type, with the access modifier %. + for(PhotranTokenRef t : references){ + t.findToken().setText(derivedTypeVariableName+"%"+t.findToken().getText()); //$NON-NLS-1$ + } + // Remove the declarations of variables that were included in the new derived type. + for(Definition def : used_definitions){ + try { + removeVariableDeclFor(def); + } catch (PreconditionFailure e) { + e.printStackTrace(); + } + } + + } + + 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 String getBlankCharacters(List<Character> blank_characters, String tab, String headerStmt) { + boolean start = false; + for(int i=0; i<headerStmt.length(); i++){ + char c = headerStmt.charAt(i); + if((c != '\t') && (c != ' ')){ + start = true; + } + if((c == '\t' || c == ' ') && !start){ + blank_characters.add(headerStmt.charAt(i)); + } + } + for(int i=0; i<blank_characters.size();i++){ + tab+=blank_characters.get(i); + } + return tab; + } +} 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 3de7224c..b494cb5d 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 @@ -183,7 +183,7 @@ RemoveRealAndDoublePrecisionLoopCountersRefactoring_PleaseSelectACountedDoLoop=P RemoveRealAndDoublePrecisionLoopCountersRefactoring_PleaseSelectADoLoop=Please select a DO loop. RemoveUnreferencedLabelsRefactoring_Name=Remove Unreferenced Labels RemoveUnreferencedLabelsRefactoring_ThereMustBeAtLeastOneLabeledStatement=To perform this refactoring, there MUST be at least one labeled statement. -RemoveUnusedVariablesRefactoring_CouldNotCompleteOperation=Sorry, could not complete the operation. +RemoveUnusedVariablesRefactoring_CouldNotCompleteOperation=The operation could not be completed. RemoveUnusedVariablesRefactoring_DoesNotRemovedUnusedVarsWithDefsOnAnotherLine=This refactoring does not remove unused variables when their dimentions are specified on another line. I.e. real a /n/n dimention a(10) will not be removed. RemoveUnusedVariablesRefactoring_Name=Remove Unused Local Variables RemoveUnusedVariablesRefactoring_RefactorAgainToRemoveAllUnusedVars=After clicking 'Continue', do the same refactoring again to make sure that all unused variables are removed from file {0}! diff --git a/org.eclipse.photran.ui.vpg/plugin.xml b/org.eclipse.photran.ui.vpg/plugin.xml index c34a91f2..5724ffbd 100644 --- a/org.eclipse.photran.ui.vpg/plugin.xml +++ b/org.eclipse.photran.ui.vpg/plugin.xml @@ -31,7 +31,16 @@ inputPage="org.eclipse.photran.internal.ui.refactoring.PermuteSubroutineArgsInputPage" /> <editorRefactoring - class = "org.eclipse.photran.internal.core.refactoring.SafeDeleteInternalSubprogramRefactoring" + class="org.eclipse.photran.internal.core.refactoring.SafeDeleteInternalSubprogramRefactoring" + /> + <editorRefactoring + command="org.eclipse.photran.ui.ExtractSubprogramToModuleRefactoringCommand" + /> + <editorRefactoring + command="org.eclipse.photran.ui.MoveSubprogramToModuleRefactoringCommand" + /> + <resourceRefactoring + class="org.eclipse.photran.internal.core.refactoring.IntroduceCallTreeRefactoring" /> </submenu> </group> @@ -69,6 +78,16 @@ </submenu> </group> <group> + <submenu name="Derived Type"><!-- Refactorings for derived types --> + <editorRefactoring + command="org.eclipse.photran.ui.AddVariableToDerivedDataTypeRefactoringCommand" + /> + <editorRefactoring + command="org.eclipse.photran.ui.TransformToDerivedDataTypeRefactoringCommand" + /> + </submenu> + </group> + <group> <submenu name="Do Loop"><!-- Loop transformations (for performance improvement) --> <editorRefactoring class="org.eclipse.photran.internal.core.refactoring.InterchangeLoopsRefactoring" @@ -85,6 +104,9 @@ <editorRefactoring class="org.eclipse.photran.internal.core.refactoring.UnrollLoopRefactoring" /> + <editorRefactoring + command="org.eclipse.photran.ui.ReplaceDoLoopWithForallRefactoringCommand" + /> </submenu> </group> <group> @@ -132,6 +154,9 @@ command="org.eclipse.photran.ui.IfConstructStatementConversionRefactoringCommand" /> <resourceRefactoring + class="org.eclipse.photran.internal.core.refactoring.NestedIfThenElseToSelectCaseRefactoring" + /> + <resourceRefactoring class="org.eclipse.photran.internal.core.refactoring.DataToParameterRefactoring" /> <resourceRefactoring @@ -198,6 +223,31 @@ categoryId="org.eclipse.photran.ui.RefactoringCategory" id="org.eclipse.photran.ui.AddSubroutineParameterRefactoringCommand"> </command> + <command + name="Add Variable to Derived Data Type..." + categoryId="org.eclipse.photran.ui.RefactoringCategory" + id="org.eclipse.photran.ui.AddVariableToDerivedDataTypeRefactoringCommand"> + </command> + <command + name="Extract Subprogram to Module..." + categoryId="org.eclipse.photran.ui.RefactoringCategory" + id="org.eclipse.photran.ui.ExtractSubprogramToModuleRefactoringCommand"> + </command> + <command + name="Move Subprogram to Module..." + categoryId="org.eclipse.photran.ui.RefactoringCategory" + id="org.eclipse.photran.ui.MoveSubprogramToModuleRefactoringCommand"> + </command> + <command + name="Replace Do Loop with Forall..." + categoryId="org.eclipse.photran.ui.RefactoringCategory" + id="org.eclipse.photran.ui.ReplaceDoLoopWithForallRefactoringCommand"> + </command> + <command + name="Transform to Derived Data Type..." + categoryId="org.eclipse.photran.ui.RefactoringCategory" + id="org.eclipse.photran.ui.TransformToDerivedDataTypeRefactoringCommand"> + </command> </extension> <!-- 2. Optionally associate the command with an accelerator key --> @@ -273,6 +323,31 @@ definitionId="org.eclipse.photran.ui.AddSubroutineParameterRefactoringCommand" class="org.eclipse.photran.internal.ui.refactoring.AddSubroutineParameterAction" id="org.eclipse.photran.ui.AddSubroutineParameterRefactoringAction"/> + <action + label="Add Variable to Derived Data Type" + definitionId="org.eclipse.photran.ui.AddVariableToDerivedDataTypeRefactoringCommand" + class="org.eclipse.photran.internal.ui.refactoring.AddVariableToDerivedDataTypeAction" + id="org.eclipse.photran.ui.AddVariableToDerivedDataTypeRefactoringAction"/> + <action + label="Extract Subprogram to Module" + definitionId="org.eclipse.photran.ui.ExtractSubprogramToModuleRefactoringCommand" + class="org.eclipse.photran.internal.ui.refactoring.ExtractSubprogramToModuleAction" + id="org.eclipse.photran.ui.ExtractSubprogramToModuleRefactoringAction"/> + <action + label="Move Subprogram to Module" + definitionId="org.eclipse.photran.ui.MoveSubprogramToModuleRefactoringCommand" + class="org.eclipse.photran.internal.ui.refactoring.MoveSubprogramToModuleAction" + id="org.eclipse.photran.ui.MoveSubprogramToModuleRefactoringAction"/> + <action + label="Replace Do Loop with Forall" + definitionId="org.eclipse.photran.ui.ReplaceDoLoopWithForallRefactoringCommand" + class="org.eclipse.photran.internal.ui.refactoring.ReplaceDoLoopWithForallAction" + id="org.eclipse.photran.ui.ReplaceDoLoopWithForallRefactoringAction"/> + <action + label="Transform to Derived Data Type" + definitionId="org.eclipse.photran.ui.TransformToDerivedDataTypeRefactoringCommand" + class="org.eclipse.photran.internal.ui.refactoring.TransformToDerivedDataTypeAction" + id="org.eclipse.photran.ui.TransformToDerivedDataTypeRefactoringAction"/> </actionSet> </extension> diff --git a/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/refactoring/AddVariableToDerivedDataTypeAction.java b/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/refactoring/AddVariableToDerivedDataTypeAction.java new file mode 100644 index 00000000..e83893e0 --- /dev/null +++ b/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/refactoring/AddVariableToDerivedDataTypeAction.java @@ -0,0 +1,120 @@ +/******************************************************************************* + * 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.ui.refactoring; + +import java.util.List; + +import org.eclipse.core.resources.IFile; +import org.eclipse.ltk.ui.refactoring.UserInputWizardPage; +import org.eclipse.photran.core.IFortranAST; +import org.eclipse.photran.internal.core.lexer.Token; +import org.eclipse.photran.internal.core.refactoring.AddVariableToDerivedDataTypeRefactoring; +import org.eclipse.photran.internal.core.vpg.PhotranVPG; +import org.eclipse.rephraserengine.core.vpg.refactoring.VPGRefactoring; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IEditorActionDelegate; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; + +/** + * User interface/action handler for {@link AddVariableToDerivedDataTypeRefactoring}. + * + * @author Gustavo Risetti + */ +public class AddVariableToDerivedDataTypeAction + extends AbstractFortranRefactoringActionDelegate + implements IWorkbenchWindowActionDelegate, IEditorActionDelegate +{ + public AddVariableToDerivedDataTypeAction() + { + super(AddVariableToDerivedDataTypeRefactoring.class, FortranAddVariableToDerivedDataTypeRefactoringWizard.class); + } + + @Override + protected VPGRefactoring<IFortranAST, Token, PhotranVPG> getRefactoring(List<IFile> files) + { + AddVariableToDerivedDataTypeRefactoring r = new AddVariableToDerivedDataTypeRefactoring(); + r.initialize( + getFortranEditor().getIFile(), + getFortranEditor().getSelection()); + return r; + } + + public static class FortranAddVariableToDerivedDataTypeRefactoringWizard extends AbstractFortranRefactoringWizard + { + protected AddVariableToDerivedDataTypeRefactoring addVariableToDerivedDataTypeRefactoring; + + public FortranAddVariableToDerivedDataTypeRefactoringWizard(AddVariableToDerivedDataTypeRefactoring r) + { + super(r); + this.addVariableToDerivedDataTypeRefactoring = r; + } + + @Override + protected void doAddUserInputPages() + { + addPage(new UserInputWizardPage(addVariableToDerivedDataTypeRefactoring.getName()) + { + protected Text derivedDataTypeName; + protected Text variableName; + + public void createControl(Composite parent) + { + Composite top = new Composite(parent, SWT.NONE); + initializeDialogUnits(top); + setControl(top); + + top.setLayout(new GridLayout(2, false)); + + Composite group = top; + Label lbl = new Label(group, SWT.NONE); + lbl.setText(Messages.AddVariableToDerivedDataTypeAction_label1Text); + + derivedDataTypeName = new Text(group, SWT.BORDER); + derivedDataTypeName.setText(""); //$NON-NLS-1$ + derivedDataTypeName.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + derivedDataTypeName.selectAll(); + derivedDataTypeName.addModifyListener(new ModifyListener() + { + public void modifyText(ModifyEvent e) + { + addVariableToDerivedDataTypeRefactoring.setDerivedTypeName(derivedDataTypeName.getText()); + } + }); + + Label lbl2 = new Label(group, SWT.NONE); + lbl2.setText(Messages.AddVariableToDerivedDataTypeAction_label2Text); + + variableName = new Text(group, SWT.BORDER); + variableName.setText(""); //$NON-NLS-1$ + variableName.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + variableName.selectAll(); + variableName.addModifyListener(new ModifyListener() + { + public void modifyText(ModifyEvent e) + { + addVariableToDerivedDataTypeRefactoring.setDerivedTypeVariableName(variableName.getText()); + } + }); + + // Call once for sure, just in case the user doesn't modify the text + addVariableToDerivedDataTypeRefactoring.setDerivedTypeName(derivedDataTypeName.getText()); + addVariableToDerivedDataTypeRefactoring.setDerivedTypeVariableName(derivedDataTypeName.getText()); + + derivedDataTypeName.setFocus(); + } + }); + } + } +} diff --git a/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/refactoring/ExtractSubprogramToModuleAction.java b/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/refactoring/ExtractSubprogramToModuleAction.java new file mode 100644 index 00000000..852a87d9 --- /dev/null +++ b/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/refactoring/ExtractSubprogramToModuleAction.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * 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.ui.refactoring; + +import java.util.List; + +import org.eclipse.core.resources.IFile; +import org.eclipse.ltk.ui.refactoring.UserInputWizardPage; +import org.eclipse.photran.core.IFortranAST; +import org.eclipse.photran.internal.core.lexer.Token; +import org.eclipse.photran.internal.core.refactoring.ExtractSubprogramToModuleRefactoring; +import org.eclipse.photran.internal.core.vpg.PhotranVPG; +import org.eclipse.rephraserengine.core.vpg.refactoring.VPGRefactoring; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IEditorActionDelegate; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; + +/** + * User interface/action handler for {@link ExtractSubprogramToModuleRefactoring}. + * + * @author Gustavo Risetti + */ +public class ExtractSubprogramToModuleAction + extends AbstractFortranRefactoringActionDelegate + implements IWorkbenchWindowActionDelegate, IEditorActionDelegate +{ + public ExtractSubprogramToModuleAction() + { + super(ExtractSubprogramToModuleRefactoring.class, FortranInsertFunctionOrSubroutineInModuleRefactoringWizard.class); + } + + @Override + protected VPGRefactoring<IFortranAST, Token, PhotranVPG> getRefactoring(List<IFile> files) + { + ExtractSubprogramToModuleRefactoring r = new ExtractSubprogramToModuleRefactoring(); + r.initialize( + getFortranEditor().getIFile(), + getFortranEditor().getSelection()); + return r; + } + + public static class FortranInsertFunctionOrSubroutineInModuleRefactoringWizard extends AbstractFortranRefactoringWizard + { + protected ExtractSubprogramToModuleRefactoring extractSubroutineOrFunctionToModuleRefactoring; + + public FortranInsertFunctionOrSubroutineInModuleRefactoringWizard(ExtractSubprogramToModuleRefactoring r) + { + super(r); + this.extractSubroutineOrFunctionToModuleRefactoring = r; + } + + @Override + protected void doAddUserInputPages() + { + addPage(new UserInputWizardPage(extractSubroutineOrFunctionToModuleRefactoring.getName()) + { + protected Text newNameField; + public void createControl(Composite parent) + { + Composite top = new Composite(parent, SWT.NONE); + initializeDialogUnits(top); + setControl(top); + + top.setLayout(new GridLayout(1, false)); + + Composite group = top; + Label lbl = new Label(group, SWT.NONE); + lbl.setText(Messages.ExtractSubprogramToModuleAction_labelText); + + newNameField = new Text(group, SWT.BORDER); + newNameField.setText(""); //$NON-NLS-1$ + newNameField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + newNameField.selectAll(); + newNameField.addModifyListener(new ModifyListener() + { + public void modifyText(ModifyEvent e) + { + extractSubroutineOrFunctionToModuleRefactoring.setModuleName(newNameField.getText()); + } + }); + + extractSubroutineOrFunctionToModuleRefactoring.setModuleName(newNameField.getText()); + newNameField.setFocus(); + } + }); + } + } +}
\ No newline at end of file diff --git a/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/refactoring/Messages.java b/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/refactoring/Messages.java index e85cb8ad..861d4134 100644 --- a/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/refactoring/Messages.java +++ b/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/refactoring/Messages.java @@ -78,6 +78,8 @@ public class Messages extends NLS public static String ExtractProcedureAction_SubroutineNameLabel; + public static String ExtractSubprogramToModuleAction_labelText; + public static String KeywordCaseInputPage_ChangeKeywordsToLabel; public static String KeywordCaseInputPage_ClickOKMessage; @@ -94,6 +96,8 @@ public class Messages extends NLS public static String MoveFromModuleInputPage_selectDataMessage; + public static String MoveSubprogramToModuleAction_labelText; + public static String RenameAction_MatchExternalSubprograms; public static String RenameAction_RenameAtoB; @@ -112,11 +116,21 @@ public class Messages extends NLS public static String RemoveRealAndDoublePrecisionLoopCountersInputPage_ClickPreviewMessage; + public static String ReplaceDoLoopWithForallAction_messageText; + public static String AddSubroutineParameterAction_DefaultLabel; public static String AddSubroutineParameterAction_DeclarationLabel; public static String AddSubroutineParameterAction_LocationLabel; + + public static String AddVariableToDerivedDataTypeAction_label1Text; + + public static String AddVariableToDerivedDataTypeAction_label2Text; + + public static String TransformToDerivedDataTypeAction_label1Text; + + public static String TransformToDerivedDataTypeAction_label2Text; static { diff --git a/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/refactoring/MoveSubprogramToModuleAction.java b/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/refactoring/MoveSubprogramToModuleAction.java new file mode 100644 index 00000000..25f9bbdf --- /dev/null +++ b/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/refactoring/MoveSubprogramToModuleAction.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * 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.ui.refactoring; + +import java.util.List; + +import org.eclipse.core.resources.IFile; +import org.eclipse.ltk.ui.refactoring.UserInputWizardPage; +import org.eclipse.photran.core.IFortranAST; +import org.eclipse.photran.internal.core.lexer.Token; +import org.eclipse.photran.internal.core.refactoring.AddVariableToDerivedDataTypeRefactoring; +import org.eclipse.photran.internal.core.refactoring.MoveSubprogramToModuleRefactoring; +import org.eclipse.photran.internal.core.vpg.PhotranVPG; +import org.eclipse.rephraserengine.core.vpg.refactoring.VPGRefactoring; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IEditorActionDelegate; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; + +/** + * User interface/action handler for {@link AddVariableToDerivedDataTypeRefactoring}. + * + * @author Gustavo Risetti + */ +public class MoveSubprogramToModuleAction + extends AbstractFortranRefactoringActionDelegate + implements IWorkbenchWindowActionDelegate, IEditorActionDelegate +{ + public MoveSubprogramToModuleAction() + { + super(MoveSubprogramToModuleRefactoring.class, FortranMoveSubroutineOrFunctionToModuleRefactoringWizard.class); + } + + @Override + protected VPGRefactoring<IFortranAST, Token, PhotranVPG> getRefactoring(List<IFile> files) + { + MoveSubprogramToModuleRefactoring r = new MoveSubprogramToModuleRefactoring(); + r.initialize( + getFortranEditor().getIFile(), + getFortranEditor().getSelection()); + return r; + } + + public static class FortranMoveSubroutineOrFunctionToModuleRefactoringWizard extends AbstractFortranRefactoringWizard + { + protected MoveSubprogramToModuleRefactoring moveSubroutineOrFunctionToModuleRefactoring; + + public FortranMoveSubroutineOrFunctionToModuleRefactoringWizard(MoveSubprogramToModuleRefactoring r) + { + super(r); + this.moveSubroutineOrFunctionToModuleRefactoring = r; + } + + @Override + protected void doAddUserInputPages() + { + addPage(new UserInputWizardPage(moveSubroutineOrFunctionToModuleRefactoring.getName()) + { + protected Text newNameField; + public void createControl(Composite parent) + { + Composite top = new Composite(parent, SWT.NONE); + initializeDialogUnits(top); + setControl(top); + + top.setLayout(new GridLayout(1, false)); + + Composite group = top; + Label lbl = new Label(group, SWT.NONE); + lbl.setText(Messages.MoveSubprogramToModuleAction_labelText); + + newNameField = new Text(group, SWT.BORDER); + newNameField.setText(""); //$NON-NLS-1$ + newNameField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + newNameField.selectAll(); + newNameField.addModifyListener(new ModifyListener() + { + public void modifyText(ModifyEvent e) + { + moveSubroutineOrFunctionToModuleRefactoring.setModuleName(newNameField.getText()); + } + }); + + moveSubroutineOrFunctionToModuleRefactoring.setModuleName(newNameField.getText()); + newNameField.setFocus(); + } + }); + } + } +}
\ No newline at end of file diff --git a/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/refactoring/ReplaceDoLoopWithForallAction.java b/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/refactoring/ReplaceDoLoopWithForallAction.java new file mode 100644 index 00000000..0008f291 --- /dev/null +++ b/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/refactoring/ReplaceDoLoopWithForallAction.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * 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.ui.refactoring; + +import java.util.List; + +import org.eclipse.core.resources.IFile; +import org.eclipse.ltk.ui.refactoring.UserInputWizardPage; +import org.eclipse.photran.core.IFortranAST; +import org.eclipse.photran.internal.core.lexer.Token; +import org.eclipse.photran.internal.core.refactoring.ReplaceDoLoopWithForallRefactoring; +import org.eclipse.photran.internal.core.vpg.PhotranVPG; +import org.eclipse.rephraserengine.core.vpg.refactoring.VPGRefactoring; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.ui.IEditorActionDelegate; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; + +/** + * User interface/action handler for {@link ReplaceDoLoopWithForallRefactoring}. + * + * @author Gustavo Risetti + */ +public class ReplaceDoLoopWithForallAction + extends AbstractFortranRefactoringActionDelegate + implements IWorkbenchWindowActionDelegate, IEditorActionDelegate +{ + public ReplaceDoLoopWithForallAction() + { + super(ReplaceDoLoopWithForallRefactoring.class, FortranReplaceDoLoopByForallRefactoringWizard.class); + } + + @Override + protected VPGRefactoring<IFortranAST, Token, PhotranVPG> getRefactoring(List<IFile> files) + { + ReplaceDoLoopWithForallRefactoring r = new ReplaceDoLoopWithForallRefactoring(); + r.initialize( + getFortranEditor().getIFile(), + getFortranEditor().getSelection()); + return r; + } + + public static class FortranReplaceDoLoopByForallRefactoringWizard extends AbstractFortranRefactoringWizard + { + protected ReplaceDoLoopWithForallRefactoring replaceDoLoopByForallRefactoring; + + public FortranReplaceDoLoopByForallRefactoringWizard(ReplaceDoLoopWithForallRefactoring r) + { + super(r); + this.replaceDoLoopByForallRefactoring = r; + } + + @Override + protected void doAddUserInputPages() + { + addPage(new UserInputWizardPage(replaceDoLoopByForallRefactoring.getName()) + { + public void createControl(Composite parent) + { + Composite top = new Composite(parent, SWT.NONE); + initializeDialogUnits(top); + setControl(top); + + top.setLayout(new GridLayout(1, false)); + + Composite group = top; + Label lbl = new Label(group, SWT.NONE); + lbl.setText(Messages.ReplaceDoLoopWithForallAction_messageText); + } + }); + } + } +} diff --git a/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/refactoring/TransformToDerivedDataTypeAction.java b/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/refactoring/TransformToDerivedDataTypeAction.java new file mode 100644 index 00000000..489948dd --- /dev/null +++ b/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/refactoring/TransformToDerivedDataTypeAction.java @@ -0,0 +1,121 @@ +/******************************************************************************* + * 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.ui.refactoring; + +import java.util.List; + +import org.eclipse.core.resources.IFile; +import org.eclipse.ltk.ui.refactoring.UserInputWizardPage; +import org.eclipse.photran.core.IFortranAST; +import org.eclipse.photran.internal.core.lexer.Token; +import org.eclipse.photran.internal.core.refactoring.TransformToDerivedDataTypeRefactoring; +import org.eclipse.photran.internal.core.vpg.PhotranVPG; +import org.eclipse.rephraserengine.core.vpg.refactoring.VPGRefactoring; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IEditorActionDelegate; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; + +/** + * User interface/action handler for {@link TransformToDerivedDataTypeRefactoring}. + * + * @author Gustavo Risetti + */ +public class TransformToDerivedDataTypeAction + extends AbstractFortranRefactoringActionDelegate + implements IWorkbenchWindowActionDelegate, IEditorActionDelegate +{ + public TransformToDerivedDataTypeAction() + { + super(TransformToDerivedDataTypeRefactoring.class, FortranTransformToDerivedDataTypeRefactoringWizard.class); + } + + @Override + protected VPGRefactoring<IFortranAST, Token, PhotranVPG> getRefactoring(List<IFile> files) + { + TransformToDerivedDataTypeRefactoring r = new TransformToDerivedDataTypeRefactoring(); + r.initialize( + getFortranEditor().getIFile(), + getFortranEditor().getSelection()); + return r; + } + + public static class FortranTransformToDerivedDataTypeRefactoringWizard extends AbstractFortranRefactoringWizard + { + protected TransformToDerivedDataTypeRefactoring transformToDerivedDataTypeRefactoring; + + public FortranTransformToDerivedDataTypeRefactoringWizard(TransformToDerivedDataTypeRefactoring r) + { + super(r); + this.transformToDerivedDataTypeRefactoring = r; + } + + @Override + protected void doAddUserInputPages() + { + addPage(new UserInputWizardPage(transformToDerivedDataTypeRefactoring.getName()) + { + protected Text newNameField; + protected Text newVariableName; + + public void createControl(Composite parent) + { + Composite top = new Composite(parent, SWT.NONE); + initializeDialogUnits(top); + setControl(top); + + top.setLayout(new GridLayout(2, false)); + + Composite group = top; + Label lbl = new Label(group, SWT.NONE); + lbl.setText(Messages.TransformToDerivedDataTypeAction_label1Text); + + newNameField = new Text(group, SWT.BORDER); + newNameField.setText(""); //$NON-NLS-1$ + newNameField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + newNameField.selectAll(); + newNameField.addModifyListener(new ModifyListener() + { + public void modifyText(ModifyEvent e) + { + transformToDerivedDataTypeRefactoring.setDerivedTypeName(newNameField.getText()); + } + }); + + Label lbl2 = new Label(group, SWT.NONE); + lbl2.setText(Messages.TransformToDerivedDataTypeAction_label2Text); + + newVariableName = new Text(group, SWT.BORDER); + newVariableName.setText(""); //$NON-NLS-1$ + newVariableName.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + newVariableName.selectAll(); + newVariableName.addModifyListener(new ModifyListener() + { + public void modifyText(ModifyEvent e) + { + transformToDerivedDataTypeRefactoring.setDerivedTypeVariableName(newVariableName.getText()); + } + }); + + // Call once for sure, just in case the user doesn't modify the text + transformToDerivedDataTypeRefactoring.setDerivedTypeName(newNameField.getText()); + transformToDerivedDataTypeRefactoring.setDerivedTypeVariableName(newNameField.getText()); + + newNameField.setFocus(); + } + }); + } + } +} + diff --git a/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/refactoring/messages.properties b/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/refactoring/messages.properties index d8b1cc00..926e52a9 100644 --- a/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/refactoring/messages.properties +++ b/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/refactoring/messages.properties @@ -21,6 +21,7 @@ CommonVarNamesInputPage_NewNameLabel=New Name CommonVarNamesInputPage_OriginalNameLabel=Original Name ExtractLocalVariableAction_DeclarationLabel=Declaration: ExtractProcedureAction_SubroutineNameLabel=Extract selected code to a subroutine named +ExtractSubprogramToModuleAction_labelText=Extract Subroutine or Function to Module: KeywordCaseInputPage_ChangeKeywordsToLabel=Change keywords to: KeywordCaseInputPage_ClickOKMessage=Click OK to change the case of all keywords in the selected files. To see what changes will be made, click Preview. KeywordCaseInputPage_LowerCaseLabel=Lower Case @@ -29,6 +30,7 @@ MoveFromModuleInputPage_leftPanelMessage=Members to Move MoveFromModuleInputPage_Name=Move From Module Refactoring MoveFromModuleInputPage_rightPanelMessage=Destination Module MoveFromModuleInputPage_selectDataMessage=Please select member data to move from module +MoveSubprogramToModuleAction_labelText=Move Subroutine or Function to Module: RenameAction_MatchExternalSubprograms=Match external subprograms with interfaces and external declarations RenameAction_RenameAtoB=Rename {0} to RemoveAssignGotoInputPage_Prompt=Add Default Case? @@ -41,7 +43,12 @@ RemoveRealAndDoublePrecisionLoopCountersInputPage_ReplaceWithDoLoop=DO Loop RemoveRealAndDoublePrecisionLoopCountersInputPage_ReplaceWithDoWhileLoop=DO WHILE Loop RemoveRealAndDoublePrecisionLoopCountersInputPage_ClickOKMessage=Click OK to replace the real/double precision loop counter. RemoveRealAndDoublePrecisionLoopCountersInputPage_ClickPreviewMessage=To see what the changes will be made, click Preview. +ReplaceDoLoopWithForallAction_messageText=Click OK to replace the selected Do Loop by Forall. To see what changes will be made, click Preview. AddSubroutineParameterAction_DeclarationLabel=Declaration: AddSubroutineParameterAction_LocationLabel=Position: AddSubroutineParameterAction_DefaultLabel=Default Value: -IfConstructStatementConversionAction_AddEmptyElseBlock=Add Empty ELSE Block
\ No newline at end of file +AddVariableToDerivedDataTypeAction_label1Text=Derived Data Type to introduce the selected variable: +AddVariableToDerivedDataTypeAction_label2Text=Derived Data Type instance to be used: +IfConstructStatementConversionAction_AddEmptyElseBlock=Add Empty ELSE Block +TransformToDerivedDataTypeAction_label1Text=Name the new Derived Data Type with the name: +TransformToDerivedDataTypeAction_label2Text=Name the new variable with the name: |