blob: b718365c098f8d90b83035dce9155f8a51ed7114 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009 University of Illinois at Urbana-Champaign and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* UIUC - Initial API and implementation
*******************************************************************************/
package org.eclipse.photran.internal.core.refactoring;
import 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.ScopingNode;
import org.eclipse.photran.internal.core.parser.ASTContainsStmtNode;
import org.eclipse.photran.internal.core.parser.ASTMainProgramNode;
import org.eclipse.photran.internal.core.parser.ASTSubroutineSubprogramNode;
import org.eclipse.photran.internal.core.parser.IInternalSubprogram;
import org.eclipse.photran.internal.core.parser.Parser.ASTListNode;
import org.eclipse.photran.internal.core.parser.Parser.IASTNode;
import org.eclipse.photran.internal.core.refactoring.infrastructure.SingleFileFortranRefactoring;
import org.eclipse.photran.internal.core.vpg.PhotranVPG;
import org.eclipse.rephraserengine.core.preservation.PreservationAnalysis;
import org.eclipse.rephraserengine.core.preservation.Preserve;
import org.eclipse.rephraserengine.core.refactorings.UserInputString;
/**
* Refactoring to add an empty subroutine to a Fortran program.
*
* @author Jeff Overbey
*/
public class AddEmptySubprogramRefactoring extends SingleFileFortranRefactoring
{
///////////////////////////////////////////////////////////////////////////
// Fields
///////////////////////////////////////////////////////////////////////////
private PreservationAnalysis preservation = null;
private ScopingNode enclosingScope;
private String newName = null;
@Override
public String getName()
{
return "Add Empty Subprogram";
}
///////////////////////////////////////////////////////////////////////////
// User-Specified Parameters
///////////////////////////////////////////////////////////////////////////
@UserInputString(label="Name:")
public void setName(String name)
{
assert name != null;
this.newName = name;
}
///////////////////////////////////////////////////////////////////////////
// Initial Preconditions
///////////////////////////////////////////////////////////////////////////
@Override
protected void doCheckInitialConditions(RefactoringStatus status, IProgressMonitor pm) throws PreconditionFailure
{
ensureProjectHasRefactoringEnabled(status);
IASTNode selection = this.findEnclosingNode(this.astOfFileInEditor, this.selectedRegionInEditor);
if (selection == null)
fail("Please place the cursor inside a scope.");
enclosingScope = selection.findNearestAncestor(ScopingNode.class);
if (enclosingScope == null) // Should never happen since <ActionStmt> only under <Body>
fail("Please place the cursor inside a scope.");
if (!(enclosingScope instanceof ASTMainProgramNode))
fail("Please place the cursor inside a main program.");
}
///////////////////////////////////////////////////////////////////////////
// Final Preconditions
///////////////////////////////////////////////////////////////////////////
@Override
protected void doCheckFinalConditions(RefactoringStatus status, IProgressMonitor pm) throws PreconditionFailure
{
assert newName != null;
assert enclosingScope != null;
try
{
preservation = new PreservationAnalysis(PhotranVPG.getInstance(), pm,
Preserve.all(PhotranVPG.BINDING_EDGE_TYPE));
preservation.monitor(fileInEditor);
createNewSubprogram();
vpg.commitChangesFromAST(fileInEditor);
preservation.checkForPreservation(status);
this.addChangeFromModifiedAST(this.fileInEditor, pm);
}
finally
{
vpg.releaseAllASTs();
}
}
///////////////////////////////////////////////////////////////////////////
// Change
///////////////////////////////////////////////////////////////////////////
@Override
protected void doCreateChange(IProgressMonitor pm) throws CoreException, OperationCanceledException
{
}
// from ExtractProcedureRefactoring
private ASTSubroutineSubprogramNode createNewSubprogram()
{
StringBuilder sb = new StringBuilder();
sb.append("\n");
sb.append("subroutine ");
sb.append(newName);
sb.append("()\n");
sb.append(" implicit none\n");
sb.append("end subroutine\n");
ASTSubroutineSubprogramNode newSubroutine = (ASTSubroutineSubprogramNode)parseLiteralProgramUnit(sb.toString());
return insertNewSubprogram(newSubroutine);
}
/* The new subprogram must be an internal subprogram if the statements are being extracted
* from a main program or subprogram that contains other internal subprograms. Otherwise,
* references to existing internal subprograms will not carry over to the extracted subprogram.
*/
private ASTSubroutineSubprogramNode insertNewSubprogram(ASTSubroutineSubprogramNode newSubroutine)
{
// if (selection.enclosingScope.isSubprogram())
// return insertAfterEnclosingSubprogram(newSubroutine);
// else if (selection.enclosingScope.isMainProgram())
// return insertAsInternalSubprogramOf((ASTMainProgramNode)selection.enclosingScope, newSubroutine);
// else
// throw new IllegalStateException();
return insertAsInternalSubprogramOf((ASTMainProgramNode)enclosingScope, newSubroutine);
}
private ASTSubroutineSubprogramNode insertAsInternalSubprogramOf(
ASTMainProgramNode program,
ASTSubroutineSubprogramNode subprogram)
{
assert preservation != null;
if (program.getContainsStmt() == null)
{
ASTContainsStmtNode containsStmt = createContainsStmt();
program.setContainsStmt(containsStmt);
containsStmt.setParent(program);
preservation.markAlpha(fileInEditor, program.getContainsStmt());
}
if (program.getInternalSubprograms() == null)
{
ASTListNode<IInternalSubprogram> internals = new ASTListNode<IInternalSubprogram>();
program.setInternalSubprograms(internals);
internals.setParent(program);
}
program.getInternalSubprograms().add(subprogram);
subprogram.setParent(program.getInternalSubprograms());
preservation.markAlpha(fileInEditor, subprogram);
//Reindenter.reindent(subprogram, this.astOfFileInEditor);
return subprogram;
}
}