blob: 5756b3984069e977dae20517a9be4412fbd4ef28 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007 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 java.util.ArrayList;
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.core.vpg.util.Notification;
import org.eclipse.photran.internal.core.analysis.binding.Definition;
import org.eclipse.photran.internal.core.analysis.binding.ScopingNode;
import org.eclipse.photran.internal.core.analysis.types.Type;
import org.eclipse.photran.internal.core.parser.ASTDerivedTypeDefNode;
import org.eclipse.photran.internal.core.parser.ASTExecutableProgramNode;
import org.eclipse.photran.internal.core.parser.ASTImplicitStmtNode;
import org.eclipse.photran.internal.core.parser.IBodyConstruct;
import org.eclipse.photran.internal.core.parser.Parser.GenericASTVisitor;
import org.eclipse.photran.internal.core.parser.Parser.IASTListNode;
import org.eclipse.photran.internal.core.parser.Parser.IASTNode;
import org.eclipse.photran.internal.core.refactoring.infrastructure.MultipleFileFortranRefactoring;
import org.eclipse.photran.internal.core.refactoring.infrastructure.Reindenter;
/**
* Refactoring to add an IMPLICIT NONE statement and explicit declarations for all implicitly-declared variables
* into a scope and all nested scopes (where needed).
*
* @author Jeff Overbey, Timofey Yuvashev
*/
public class IntroImplicitNoneRefactoring extends MultipleFileFortranRefactoring
{
public IntroImplicitNoneRefactoring(ArrayList<IFile> myFiles)
{
super(myFiles);
}
@Override
public String getName()
{
return "Introduce Implicit None";
}
/*public String getScopeDescription()
{
return selectedScope == null || selectedScope.getHeaderStmt() == null
? "the selected scope..."
: "\n" + SourcePrinter.getSourceCodeFromASTNode(selectedScope.getHeaderStmt());
}*/
///////////////////////////////////////////////////////////////////////////
// Initial Preconditions
///////////////////////////////////////////////////////////////////////////
@Override
protected void doCheckInitialConditions(RefactoringStatus status, IProgressMonitor pm) throws PreconditionFailure
{
ensureProjectHasRefactoringEnabled(status);
removeFixedFormFilesFrom(this.selectedFiles, status);
}
///////////////////////////////////////////////////////////////////////////
// Final Preconditions & Change Creation
///////////////////////////////////////////////////////////////////////////
@Override
protected void doCheckFinalConditions(RefactoringStatus status, IProgressMonitor pm) throws PreconditionFailure
{
logVPGErrors(status);
try
{
for(IFile f : this.selectedFiles)
{
IFortranAST tempAST = this.vpg.acquirePermanentAST(f);
if (tempAST == null)
status.addError("One of the selected files (" + f.getName() +") cannot be parsed.");
introduceImplicitNoneInFile(pm, tempAST.getRoot(), tempAST, f);
vpg.releaseAST(f);
}
}
finally
{
vpg.releaseAllASTs();
}
}
@SuppressWarnings("unchecked")
private void introduceImplicitNoneInFile(IProgressMonitor progressMonitor,
ScopingNode scopeNode,
IFortranAST ast,
IFile file)
{
assert scopeNode != null;
//Get all scopes contained in the file
List<ScopingNode> nodeList = scopeNode.getAllContainedScopes();
for (ScopingNode scope : nodeList)
{
if (!(scope instanceof ASTExecutableProgramNode)
&& !(scope instanceof ASTDerivedTypeDefNode)
&& !scope.isImplicitNone())
{
ASTImplicitStmtNode implicitStmt = findExistingImplicitStatement(scope);
if (implicitStmt != null) implicitStmt.removeFromTree();
IASTListNode<IBodyConstruct> newDeclarations = constructDeclarations(scope);
IASTListNode<IASTNode> body = (IASTListNode<IASTNode>)scope.getOrCreateBody();
body.addAll(0, newDeclarations);
Reindenter.reindent(newDeclarations, ast);
}
}
this.addChangeFromModifiedAST(file, progressMonitor);
}
private ASTImplicitStmtNode findExistingImplicitStatement(final ScopingNode scope)
{
try
{
scope.accept(new GenericASTVisitor()
{
@Override
public void visitASTImplicitStmtNode(ASTImplicitStmtNode node)
{
if (node.getImplicitToken().getEnclosingScope() == scope)
throw new Notification(node);
}
});
}
catch (Notification n)
{
return (ASTImplicitStmtNode)n.getResult();
}
return null;
}
private IASTListNode<IBodyConstruct> constructDeclarations(final ScopingNode scope)
{
final ArrayList<Definition> definitions = new ArrayList<Definition>(16);
for (Definition def : scope.getAllDefinitions())
if (def != null && def.isImplicit())
definitions.add(def);
StringBuilder newStmts = new StringBuilder();
newStmts.append("implicit none" + EOL);
for (Definition def : sort(definitions))
newStmts.append(constructDeclaration(def));
return parseLiteralStatementSequence(newStmts.toString());
}
private ArrayList<Definition> sort(ArrayList<Definition> array)
{
for (int indexOfElementToInsert = 1; indexOfElementToInsert < array.size(); indexOfElementToInsert++)
{
Definition def = array.get(indexOfElementToInsert);
int targetIndex = findIndexToInsertAt(array, indexOfElementToInsert);
for (int i = indexOfElementToInsert - 1; i >= targetIndex; i--)
array.set(i+1, array.get(i));
array.set(targetIndex, def);
}
return array;
}
private int findIndexToInsertAt(ArrayList<Definition> array, int indexOfElementToInsert)
{
for (int beforeIndex = 0; beforeIndex < indexOfElementToInsert; beforeIndex++)
if (array.get(indexOfElementToInsert).getCanonicalizedName().compareTo(array.get(beforeIndex).getCanonicalizedName()) < 0)
return beforeIndex;
return indexOfElementToInsert;
}
private String constructDeclaration(final Definition def)
{
Type type = def.getType();
String typeString = type == null ? "type(unknown)" : type.toString(); // TODO
return typeString + " :: " + def.getCanonicalizedName() + EOL;
}
@Override
protected void doCreateChange(IProgressMonitor progressMonitor) throws CoreException, OperationCanceledException
{
// Change creation done in #doCheckFinalConditions
}
}