blob: 7a18d20ebe98cc051c3d67e373ea0f236565fa7d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007-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 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.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.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.FortranResourceRefactoring;
import org.eclipse.photran.internal.core.reindenter.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
* @author Ashley Kasza - externalized strings
*/
public class IntroImplicitNoneRefactoring extends FortranResourceRefactoring
{
@Override
public String getName()
{
return Messages.IntroImplicitNoneRefactoring_Name;
}
/*
* 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);
removeCpreprocessedFilesFrom(this.selectedFiles, status);
}
// /////////////////////////////////////////////////////////////////////////
// Final Preconditions & Change Creation
// /////////////////////////////////////////////////////////////////////////
@Override
protected void doCheckFinalConditions(RefactoringStatus status, IProgressMonitor pm)
throws PreconditionFailure
{
logVPGErrors(status, this.selectedFiles);
try
{
for (IFile f : this.selectedFiles)
{
IFortranAST tempAST = this.vpg.acquirePermanentAST(f);
if (tempAST == null)
{
status.addError(
Messages.bind(Messages.IntroImplicitNoneRefactoring_SelectedFileCannotBeParsed, f.getName()));
}
else
{
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(findIndexOfLastUseStmtIn(body)+1, newDeclarations);
Reindenter.reindent(newDeclarations, ast);
}
}
this.addChangeFromModifiedAST(file, progressMonitor);
}
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); //$NON-NLS-1$
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 = findInsertionIndexForSorting(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 findInsertionIndexForSorting(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 //$NON-NLS-1$
return typeString + " :: " + def.getCanonicalizedName() + EOL; //$NON-NLS-1$
}
@Override
protected void doCreateChange(IProgressMonitor progressMonitor) throws CoreException,
OperationCanceledException
{
// Change creation done in #doCheckFinalConditions
}
}