diff options
author | Jeffrey Overbey | 2014-05-20 05:22:33 +0000 |
---|---|---|
committer | Jeffrey Overbey | 2014-05-20 05:22:33 +0000 |
commit | fd74bd2044bc4748c8eff6c778cb06f63feb2ef5 (patch) | |
tree | 87162bb1de8e87ea46805a4dd27031eccd957449 | |
parent | a6687fd87076031307c6fb6487ce86e6f1824203 (diff) | |
download | org.eclipse.photran-fd74bd2044bc4748c8eff6c778cb06f63feb2ef5.tar.gz org.eclipse.photran-fd74bd2044bc4748c8eff6c778cb06f63feb2ef5.tar.xz org.eclipse.photran-fd74bd2044bc4748c8eff6c778cb06f63feb2ef5.zip |
Bug 414906 - Class/Derived type and context aware autocompletion
10 files changed, 687 insertions, 28 deletions
diff --git a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/analysis/binding/Binder.java b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/analysis/binding/Binder.java index a1a726bc..d97474aa 100644 --- a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/analysis/binding/Binder.java +++ b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/analysis/binding/Binder.java @@ -1,3 +1,14 @@ +/******************************************************************************* + * Copyright (c) 2007, 2014 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 + * Chris Hansen (U Washington) - Auto-complete improvements (Bug 414906) + *******************************************************************************/ package org.eclipse.photran.internal.core.analysis.binding; import java.io.PrintStream; @@ -17,6 +28,7 @@ import org.eclipse.photran.internal.core.vpg.PhotranVPGWriter; * {@link Token#resolveBinding()} and related methods to look up binding information. * * @author Jeff Overbey + * @author Chris Hansen */ public class Binder { @@ -49,6 +61,9 @@ public class Binder start = System.currentTimeMillis(); ast.accept(new SubprogramTypeCollector()); logTime(start, SubprogramTypeCollector.class, filename); + + start = System.currentTimeMillis(); + ast.accept(new DerivedTypeCollector()); logTime(start, DerivedTypeCollector.class, filename); start = System.currentTimeMillis(); ast.accept(new ModuleLoader(file)); logTime(start, ModuleLoader.class, filename); diff --git a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/analysis/binding/Definition.java b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/analysis/binding/Definition.java index 1707b55e..0e4fc228 100644 --- a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/analysis/binding/Definition.java +++ b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/analysis/binding/Definition.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 University of Illinois at Urbana-Champaign and others. + * Copyright (c) 2007, 2014 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 @@ -7,6 +7,7 @@ * * Contributors: * UIUC - Initial API and implementation + * Chris Hansen (U Washington) - Auto-complete improvements (Bug 414906) *******************************************************************************/ package org.eclipse.photran.internal.core.analysis.binding; @@ -63,6 +64,7 @@ import org.eclipse.rephraserengine.core.vpg.IVPGNode; * <b>array spec</b> may give an array specification (e.g., one-dimensional, indexed from 3 to 5). * * @author Jeff Overbey + * @author Chris Hansen */ public class Definition implements IPhotranSerializable, Comparable<Definition> { @@ -126,7 +128,7 @@ public class Definition implements IPhotranSerializable, Comparable<Definition> protected Classification classification; protected PhotranTokenRef tokenRef; - protected String declaredName, canonicalizedName; + protected String declaredName, canonicalizedName, completionText; //protected Visibility visibility; protected Type type; protected ArraySpec arraySpec; @@ -157,6 +159,7 @@ public class Definition implements IPhotranSerializable, Comparable<Definition> //this.visibility = visibility; //Visibility.INHERIT_FROM_SCOPE; this.type = type; this.arraySpec = null; + this.completionText = declaredName; } protected String canonicalize(String identifier) @@ -222,6 +225,11 @@ public class Definition implements IPhotranSerializable, Comparable<Definition> { return classification == Classification.DERIVED_TYPE; } + + public boolean isDerivedTypeComponent() + { + return classification == Classification.DERIVED_TYPE_COMPONENT; + } public boolean isSubprogram() { @@ -325,6 +333,19 @@ public class Definition implements IPhotranSerializable, Comparable<Definition> { return canonicalizedName; } + + /** Sets the auto-completion text to be used for this definition. This is usually the name of the defined entity, + * however for procedures/functions this text contains the argument list as well. */ + public void setCompletionText(String completionText) + { + this.completionText = completionText; + } + + /** @return the auto-completion text for this definition, canonicalized by <code>PhotranVPG.canonicalizeIdentifier</code> */ + public String getCompletionText() + { + return completionText; + } /** @return a description of the type of entity being defined */ public String describeClassification() @@ -1139,6 +1160,7 @@ public class Definition implements IPhotranSerializable, Comparable<Definition> result.intent_out = PhotranVPGSerializer.deserialize(in); result.optional = PhotranVPGSerializer.deserialize(in); result.save = PhotranVPGSerializer.deserialize(in); + result.completionText = PhotranVPGSerializer.deserialize(in); return result; } @@ -1160,6 +1182,7 @@ public class Definition implements IPhotranSerializable, Comparable<Definition> PhotranVPGSerializer.serialize(intent_out, out); PhotranVPGSerializer.serialize(optional, out); PhotranVPGSerializer.serialize(save, out); + PhotranVPGSerializer.serialize(completionText, out); } public char getSerializationCode() diff --git a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/analysis/binding/DefinitionCollector.java b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/analysis/binding/DefinitionCollector.java index 36b2a6de..7fd1b304 100644 --- a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/analysis/binding/DefinitionCollector.java +++ b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/analysis/binding/DefinitionCollector.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 University of Illinois at Urbana-Champaign and others. + * Copyright (c) 2007, 2014 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 @@ -7,6 +7,7 @@ * * Contributors: * UIUC - Initial API and implementation + * Chris Hansen (U Washington) - Auto-complete improvements (Bug 414906) *******************************************************************************/ package org.eclipse.photran.internal.core.analysis.binding; @@ -41,9 +42,12 @@ import org.eclipse.photran.internal.core.parser.ASTLabelDoStmtNode; import org.eclipse.photran.internal.core.parser.ASTModuleStmtNode; import org.eclipse.photran.internal.core.parser.ASTNamelistGroupsNode; import org.eclipse.photran.internal.core.parser.ASTNamelistStmtNode; +import org.eclipse.photran.internal.core.parser.ASTProcComponentDefStmtNode; +import org.eclipse.photran.internal.core.parser.ASTProcDeclNode; import org.eclipse.photran.internal.core.parser.ASTProgramStmtNode; import org.eclipse.photran.internal.core.parser.ASTSelectCaseStmtNode; import org.eclipse.photran.internal.core.parser.ASTSelectTypeStmtNode; +import org.eclipse.photran.internal.core.parser.ASTSpecificBindingNode; import org.eclipse.photran.internal.core.parser.ASTStmtFunctionStmtNode; import org.eclipse.photran.internal.core.parser.ASTSubroutineStmtNode; import org.eclipse.photran.internal.core.parser.ASTSubroutineSubprogramNode; @@ -51,6 +55,7 @@ import org.eclipse.photran.internal.core.parser.ASTTypeAttrSpecNode; import org.eclipse.photran.internal.core.parser.ASTTypeDeclarationStmtNode; import org.eclipse.photran.internal.core.parser.ASTTypeParamDeclNode; import org.eclipse.photran.internal.core.parser.ASTTypeParamDefStmtNode; +import org.eclipse.photran.internal.core.parser.ASTTypeSpecNode; import org.eclipse.photran.internal.core.parser.ASTWhereConstructStmtNode; import org.eclipse.photran.internal.core.parser.IASTListNode; import org.eclipse.photran.internal.core.parser.IInterfaceSpecification; @@ -66,6 +71,7 @@ import org.eclipse.photran.internal.core.vpg.PhotranVPG; * Operators are NOT included in the symbol table. * * @author Jeff Overbey + * @author Chris Hansen * @see Binder */ class DefinitionCollector extends BindingCollector @@ -93,7 +99,8 @@ class DefinitionCollector extends BindingCollector Definition d = addDefinition(node.getTypeName(), Definition.Classification.DERIVED_TYPE, Type.VOID); - ScopingNode enclosingScope = node.findNearestAncestor(ScopingNode.class); + ScopingNode parentScope = node.findNearestAncestor(ScopingNode.class); + ScopingNode enclosingScope = parentScope.getEnclosingScope(); // if (node.getAccessSpec() != null) // d.setVisibility(node.getAccessSpec()); @@ -137,6 +144,32 @@ class DefinitionCollector extends BindingCollector Definition.Classification.DERIVED_TYPE_COMPONENT, Type.parse(node.getTypeSpec())); } + + @Override public void visitASTProcComponentDefStmtNode(ASTProcComponentDefStmtNode node) + { + super.traverseChildren(node); + + IASTListNode<ASTProcDeclNode> decls = node.getProcDeclList(); + for (int i = 0; i < decls.size(); i++) { + ASTTypeSpecNode typeAttr = node.getProcInterface().getTypeSpec(); + Type procType = Type.VOID; + if (typeAttr != null) + procType = Type.parse(typeAttr); + + addDefinition(decls.get(i).getProcedureEntityName(), + Definition.Classification.DERIVED_TYPE_COMPONENT, + procType); + } + } + + @Override public void visitASTSpecificBindingNode(ASTSpecificBindingNode node) + { + super.traverseChildren(node); + + addDefinition(node.getBindingName(), + Definition.Classification.SUBROUTINE, + Type.VOID); + } // # R501 // <TypeDeclarationStmt> ::= diff --git a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/analysis/binding/DerivedTypeCollector.java b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/analysis/binding/DerivedTypeCollector.java new file mode 100644 index 00000000..7ab01b32 --- /dev/null +++ b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/analysis/binding/DerivedTypeCollector.java @@ -0,0 +1,122 @@ +/******************************************************************************* + * Copyright (c) 2014 Chris Hansen 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: + * Chris Hansen (U Washington) - Initial API and implementation + *******************************************************************************/ +package org.eclipse.photran.internal.core.analysis.binding; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.photran.internal.core.lexer.Token; +import org.eclipse.photran.internal.core.parser.ASTBindingAttrNode; +import org.eclipse.photran.internal.core.parser.ASTProcComponentDefStmtNode; +import org.eclipse.photran.internal.core.parser.ASTProcDeclNode; +import org.eclipse.photran.internal.core.parser.ASTSpecificBindingNode; +import org.eclipse.photran.internal.core.parser.IASTListNode; +import org.eclipse.photran.internal.core.vpg.AnnotationType; +import org.eclipse.photran.internal.core.vpg.PhotranTokenRef; + +/** + * Phase 6 of name-binding analysis. + * <p> + * Visits derived type declarations, setting children in the VPG. + * + * @author Chris Hansen + * @see Binder + */ +class DerivedTypeCollector extends BindingCollector +{ + @Override public void visitASTProcComponentDefStmtNode(ASTProcComponentDefStmtNode node) + { + super.traverseChildren(node); + IASTListNode<ASTProcDeclNode> decls = node.getProcDeclList(); + PhotranTokenRef procRef = decls.get(0).getProcedureEntityName().getTokenRef(); + + Token bindingInterface = node.getProcInterface().getInterfaceName(); + String compText = null; + // + ArrayList<Definition> intDefs = vpg.findAllDeclarationsInInterfacesForExternalSubprogram(bindingInterface.getText()); + if (intDefs != null) { + Definition subDef = intDefs.get(0); + compText = subDef.getCompletionText(); + } + // + if (compText!=null) { + int argStart = compText.indexOf('('); + if (argStart>=0) { + compText = compText.substring(argStart); + } else { + compText = "()"; //$NON-NLS-1$ + } + } else { + compText = "()"; //$NON-NLS-1$ + } + + Definition def = vpg.getDefinitionFor(procRef); + compText = def.getDeclaredName() + compText; + def.setCompletionText(compText.toString()); + vpgProvider.setDefinitionFor(procRef, def); + } + + @Override public void visitASTSpecificBindingNode(ASTSpecificBindingNode node) + { + super.traverseChildren(node); + + boolean skipFirst = true; + PhotranTokenRef procRef = node.getBindingName().getTokenRef(); + IASTListNode<ASTBindingAttrNode> bindAttrs = node.getBindingAttrList(); + if (bindAttrs != null) { + for (ASTBindingAttrNode bindAttr: bindAttrs) { + if (bindAttr.isNoPass()) + skipFirst = false; + } + } + Token bindingInterface = node.getInterfaceName(); + PhotranTokenRef tokenRef = null; + if (bindingInterface != null) { + ScopingNode enclosingScope = bindingInterface.getEnclosingScope().getGlobalScope(); + List<PhotranTokenRef> possParents = enclosingScope.manuallyResolve(bindingInterface); + tokenRef = possParents.get(0); + } else { + Token proToken = node.getProcedureName(); + if (proToken == null) + return; + ScopingNode enclosingScope = proToken.getEnclosingScope(); + List<PhotranTokenRef> possParents = enclosingScope.manuallyResolve(proToken); + tokenRef = possParents.get(0); + } + Definition subDef = tokenRef.getAnnotation(AnnotationType.DEFINITION_ANNOTATION_TYPE); + String compText = subDef.getCompletionText(); + if (compText!=null) { + int argStart = compText.indexOf('('); + if (argStart>=0) { + compText = compText.substring(argStart); + } else { + compText = "()"; //$NON-NLS-1$ + } + if (skipFirst) { + argStart = compText.indexOf(','); + if (argStart>=0) { + compText = compText.substring(argStart+1); + } else { + compText = ")"; //$NON-NLS-1$ + } + compText = "(" + compText; //$NON-NLS-1$ + } + } else { + compText = "()"; //$NON-NLS-1$ + } + + Definition def = vpg.getDefinitionFor(procRef); + compText = def.getDeclaredName() + compText; + def.setCompletionText(compText.toString()); + vpgProvider.setDefinitionFor(procRef, def); + + } +} diff --git a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/analysis/binding/SubprogramTypeCollector.java b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/analysis/binding/SubprogramTypeCollector.java index 24c9062a..20297241 100644 --- a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/analysis/binding/SubprogramTypeCollector.java +++ b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/analysis/binding/SubprogramTypeCollector.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010 University of Illinois at Urbana-Champaign and others. + * Copyright (c) 2010, 2014 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 @@ -7,6 +7,7 @@ * * Contributors: * UIUC - Initial API and implementation + * Chris Hansen (U Washington) - Auto-complete improvements (Bug 414906) *******************************************************************************/ package org.eclipse.photran.internal.core.analysis.binding; @@ -20,6 +21,7 @@ import org.eclipse.photran.internal.core.parser.ASTFunctionStmtNode; import org.eclipse.photran.internal.core.parser.ASTSubroutineParNode; import org.eclipse.photran.internal.core.parser.ASTSubroutineStmtNode; import org.eclipse.photran.internal.core.parser.ASTTypeSpecNode; +import org.eclipse.photran.internal.core.parser.IASTListNode; import org.eclipse.photran.internal.core.vpg.AnnotationType; import org.eclipse.photran.internal.core.vpg.PhotranTokenRef; @@ -29,6 +31,7 @@ import org.eclipse.photran.internal.core.vpg.PhotranTokenRef; * Visits subprogram declarations, setting their types in the VPG. * * @author Jeff Overbey + * @author Chris Hansen * @see Binder */ class SubprogramTypeCollector extends BindingCollector @@ -38,7 +41,9 @@ class SubprogramTypeCollector extends BindingCollector super.traverseChildren(node); PhotranTokenRef tokenRef = node.getSubroutineName().getSubroutineName().getTokenRef(); + IASTListNode<ASTSubroutineParNode> subParams = node.getSubroutinePars(); updateDefinitionWithTypeInfo(tokenRef, typeOf(node)); + updateDefinitionWithSubParameters(tokenRef, typeOf(node), subParams); } @Override public void visitASTFunctionStmtNode(ASTFunctionStmtNode node) @@ -46,7 +51,9 @@ class SubprogramTypeCollector extends BindingCollector super.traverseChildren(node); PhotranTokenRef tokenRef = node.getFunctionName().getFunctionName().getTokenRef(); + IASTListNode<ASTFunctionParNode> funParams = node.getFunctionPars(); updateDefinitionWithTypeInfo(tokenRef, typeOf(node)); + updateDefinitionWithFunParameters(tokenRef, typeOf(node), funParams); } private void updateDefinitionWithTypeInfo(PhotranTokenRef tokenRef, FunctionType type) @@ -55,6 +62,68 @@ class SubprogramTypeCollector extends BindingCollector def.setType(type); vpgProvider.setDefinitionFor(tokenRef, def); } + + private void updateDefinitionWithSubParameters(PhotranTokenRef tokenRef, FunctionType type, IASTListNode<ASTSubroutineParNode> subParams) + { + Definition def = vpg.getDefinitionFor(tokenRef); + // Populate subroutines auto-completion with parameters + StringBuilder fullId = new StringBuilder(40); + fullId.append(def.getDeclaredName()); + fullId.append('('); + if (subParams != null) { + int paramCount = 0; + for (ASTSubroutineParNode param: subParams) { + Token tmpToken = param.getVariableName(); + String paramText = tmpToken.getText(); + if (paramCount>0) + fullId.append(','); + fullId.append(paramText); + // + Definition varDef = bindUniquely(tmpToken); + if (varDef != null) { + if (varDef.isOptional()) { + fullId.append('='); + fullId.append(paramText); + } + } + paramCount=paramCount+1; + } + } + fullId.append(')'); + def.setCompletionText(fullId.toString()); + vpgProvider.setDefinitionFor(tokenRef, def); + } + + private void updateDefinitionWithFunParameters(PhotranTokenRef tokenRef, FunctionType type, IASTListNode<ASTFunctionParNode> funParams) + { + Definition def = vpg.getDefinitionFor(tokenRef); + // Populate function auto-completion with parameters + StringBuilder fullId = new StringBuilder(40); + fullId.append(def.getDeclaredName()); + fullId.append('('); + if (funParams != null) { + int paramCount = 0; + for (ASTFunctionParNode param: funParams) { + Token tmpToken = param.getVariableName(); + String paramText = tmpToken.getText(); + if (paramCount>0) + fullId.append(','); + fullId.append(paramText); + // + Definition varDef = bindUniquely(tmpToken); + if (varDef != null) { + if (varDef.isOptional()) { + fullId.append('='); + fullId.append(paramText); + } + } + paramCount=paramCount+1; + } + } + fullId.append(')'); + def.setCompletionText(fullId.toString()); + vpgProvider.setDefinitionFor(tokenRef, def); + } private FunctionType typeOf(ASTSubroutineStmtNode node) { diff --git a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/analysis/types/DerivedType.java b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/analysis/types/DerivedType.java index 93b239e0..fa23d971 100644 --- a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/analysis/types/DerivedType.java +++ b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/analysis/types/DerivedType.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 University of Illinois at Urbana-Champaign and others. + * Copyright (c) 2007, 2014 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 @@ -7,6 +7,7 @@ * * Contributors: * UIUC - Initial API and implementation + * Chris Hansen (U Washington) - Auto-complete improvements (Bug 414906) *******************************************************************************/ package org.eclipse.photran.internal.core.analysis.types; @@ -20,6 +21,7 @@ import org.eclipse.photran.internal.core.vpg.PhotranVPGSerializer; * A {@link Type} representing a Fortran derived type with a particular name. * * @author Jeff Overbey + * @author Chris Hansen */ public class DerivedType extends Type { @@ -33,6 +35,11 @@ public class DerivedType extends Type this.name = name.toLowerCase(); } + public String getName() + { + return this.name; + } + @Override public String toString() { return "type(" + name + ")"; //$NON-NLS-1$ //$NON-NLS-2$ diff --git a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/vpg/PhotranVPGComponentFactory.java b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/vpg/PhotranVPGComponentFactory.java index e4f62799..fc4f1bce 100644 --- a/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/vpg/PhotranVPGComponentFactory.java +++ b/org.eclipse.photran.core.vpg/src/org/eclipse/photran/internal/core/vpg/PhotranVPGComponentFactory.java @@ -36,7 +36,7 @@ public class PhotranVPGComponentFactory { File logFile = new File( Activator.getDefault().getStateLocation().addTrailingSeparator().toOSString() + - "photran70vpg-log.txt"); //$NON-NLS-1$ + "photran83vpg-log.txt"); //$NON-NLS-1$ return new VPGLog<Token, PhotranTokenRef>(logFile, this); } @@ -71,7 +71,7 @@ public class PhotranVPGComponentFactory private static File getFileInPluginStateLocation() { - return new File(Activator.getDefault().getStateLocation().addTrailingSeparator().toOSString() + "photran70vpg.new"); //$NON-NLS-1$ + return new File(Activator.getDefault().getStateLocation().addTrailingSeparator().toOSString() + "photran83vpg.new"); //$NON-NLS-1$ } public PhotranVPGWriter createVPGWriter(VPGDB<IFortranAST, Token, PhotranTokenRef> db, VPGLog<Token,PhotranTokenRef> log) diff --git a/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/editor_vpg/contentassist/FortranCompletionProcessor.java b/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/editor_vpg/contentassist/FortranCompletionProcessor.java index fac1c747..f8a5dad4 100755 --- a/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/editor_vpg/contentassist/FortranCompletionProcessor.java +++ b/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/editor_vpg/contentassist/FortranCompletionProcessor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009 University of Illinois at Urbana-Champaign and others. + * Copyright (c) 2009, 2014 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 @@ -7,13 +7,17 @@ * * Contributors: * UIUC - Initial API and implementation + * Chris Hansen (U Washington) - Auto-complete improvements (Bug 414906) *******************************************************************************/ package org.eclipse.photran.internal.ui.editor_vpg.contentassist; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.TreeSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; @@ -25,11 +29,23 @@ import org.eclipse.jface.text.contentassist.IContentAssistant; import org.eclipse.jface.text.contentassist.IContextInformation; import org.eclipse.jface.text.contentassist.IContextInformationValidator; import org.eclipse.photran.internal.core.analysis.binding.Definition; +import org.eclipse.photran.internal.core.analysis.binding.Definition.Classification; +import org.eclipse.photran.internal.core.analysis.binding.ScopingNode; +import org.eclipse.photran.internal.core.analysis.types.DerivedType; +import org.eclipse.photran.internal.core.analysis.types.Type; +import org.eclipse.photran.internal.core.lexer.Token; +import org.eclipse.photran.internal.core.parser.ASTDerivedTypeDefNode; +import org.eclipse.photran.internal.core.parser.ASTDerivedTypeStmtNode; +import org.eclipse.photran.internal.core.parser.ASTTypeAttrSpecNode; +import org.eclipse.photran.internal.core.parser.IASTListNode; import org.eclipse.photran.internal.core.properties.SearchPathProperties; +import org.eclipse.photran.internal.core.vpg.PhotranTokenRef; +import org.eclipse.photran.internal.core.vpg.PhotranVPG; import org.eclipse.photran.internal.ui.editor.FortranEditor; -import org.eclipse.photran.internal.ui.editor.FortranTemplateCompletionProcessor; import org.eclipse.photran.internal.ui.editor.FortranStmtPartitionScanner; +import org.eclipse.photran.internal.ui.editor.FortranTemplateCompletionProcessor; import org.eclipse.photran.internal.ui.editor_vpg.FortranEditorTasks; +import org.eclipse.photran.internal.ui.editor_vpg.contentassist.FortranCompletionProposalComputer.Context; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.RGB; @@ -37,6 +53,7 @@ import org.eclipse.swt.graphics.RGB; * Fortran content assist processor which uses the VPG to determine which identifiers are in scope. * * @author Jeff Overbey + * @author Chris Hansen */ public class FortranCompletionProcessor implements IContentAssistProcessor { @@ -95,21 +112,38 @@ public class FortranCompletionProcessor implements IContentAssistProcessor int line = determineLineNumberForOffset(offset, document); String scopeName = determineScopeNameForLine(line); + Context contextType = determineContext(offset,line,document); + List<Definition> classDefs = null; + if (contextType == Context.USE) { + classDefs = determineModuleNames(); + if (classDefs.isEmpty()) + classDefs = null; + } else if (contextType == Context.USE_ONLY) { + classDefs = determineModuleDefs(offset,line,document,scopeName); + if (classDefs.isEmpty()) + classDefs = null; + } else { + classDefs = determineDefsForClass(offset,line,document,scopeName); + } if (scopeName != null) - computer = new FortranCompletionProposalComputer(defs, scopeName, document, offset); + computer = new FortranCompletionProposalComputer(defs, scopeName, document, offset,contextType); // Include proposals in this order: + if (classDefs != null && computer != null) { + // If we are working on a type look for internal fields only + proposals.addAll(computer.proposalsFromTheseDefs(classDefs)); + } else { + // 1. Local variables, functions, etc. + if (computer != null) proposals.addAll(computer.proposalsFromDefs()); - // 1. Local variables, functions, etc. - if (computer != null) proposals.addAll(computer.proposalsFromDefs()); - - // 2. Code templates - for (ICompletionProposal proposal : new FortranTemplateCompletionProcessor().computeCompletionProposals(viewer, offset)) - proposals.add(proposal); + // 2. Code templates + for (ICompletionProposal proposal : new FortranTemplateCompletionProcessor().computeCompletionProposals(viewer, offset)) + proposals.add(proposal); - // 3. Intrinsic procedures - if (computer != null) proposals.addAll(computer.proposalsFromIntrinsics()); + // 3. Intrinsic procedures + if (computer != null) proposals.addAll(computer.proposalsFromIntrinsics()); + } } catch (Exception e) { @@ -119,6 +153,310 @@ public class FortranCompletionProcessor implements IContentAssistProcessor return proposals.toArray(new ICompletionProposal[proposals.size()]); } + + private final Context determineContext(int offset, int line, IDocument document) throws BadLocationException + { + Context contextType = Context.GENERIC; + // Get line to analyze + int line_offset = document.getLineOffset(line); + int cur_length = offset-line_offset; + String current_line = document.get(line_offset, cur_length); + current_line = current_line.toLowerCase(); + // Check for beginning keyword + String keywordList = "[ ]*(class|type|use|allocate|deallocate|nullify)"; //$NON-NLS-1$ + Pattern var_pattern = Pattern.compile(keywordList); + Matcher matchedKeyword = var_pattern.matcher(current_line); + String keyword = null; + if (matchedKeyword.find()) + keyword = matchedKeyword.group(); + if (keyword != null) { + keyword = keyword.replaceAll(" ",""); //$NON-NLS-1$ //$NON-NLS-2$ + // Determine type of statement + if (keyword.matches("class|type")) { //$NON-NLS-1$ + if (current_line.contains("(") && !current_line.contains(")")) //$NON-NLS-1$ //$NON-NLS-2$ + contextType=Context.TYPE_VARIABLE_DEF; + } else if (keyword.matches("allocate")) { //$NON-NLS-1$ + if (current_line.contains("(") && !current_line.contains(")")) //$NON-NLS-1$ //$NON-NLS-2$ + contextType=Context.ALLOCATE; + } else if (keyword.matches("deallocate|nullify")) { //$NON-NLS-1$ + if (current_line.contains("(") && !current_line.contains(")")) //$NON-NLS-1$ //$NON-NLS-2$ + contextType=Context.DEALLOCATE; + } else if (keyword.matches("use")) { //$NON-NLS-1$ + if (!current_line.contains(":")) //$NON-NLS-1$ + contextType=Context.USE; + else + contextType=Context.USE_ONLY; + } + } + // Unknown context + return contextType; + } + + private final List<Definition> determineDefsForClass(int offset, int line, IDocument document, String scopeName) throws BadLocationException + { + String scopeTemp = scopeName; + ScopingNode parentScope = null; + List<Definition> classDefs = null; + ScopingNode classScope = null; + // Get line to analyze + int line_offset = document.getLineOffset(line); + int cur_length = offset-line_offset; + String current_line = document.get(line_offset, cur_length); + String prevChar = document.get(offset-1,1); + // Compute base variable for current class chain + String current_variable = null; + Pattern var_pattern = Pattern.compile("[a-zA-Z0-9_%(,)]*"); //$NON-NLS-1$ + Matcher matched_vars = var_pattern.matcher(current_line); + while (matched_vars.find()) { + String var_temp = matched_vars.group(); + if (!var_temp.equals("")) //$NON-NLS-1$ + current_variable = matched_vars.group(); + } + if (current_variable == null) + return classDefs; + if (!(current_variable.contains("%") && current_variable.endsWith(prevChar))) //$NON-NLS-1$ + return classDefs; + // Handle arrays usage + current_variable = current_variable.replaceAll("\\(([^\\)]+)\\)", ""); //$NON-NLS-1$ //$NON-NLS-2$ + // Remove leading characters if setting an array index + int parenLoc = current_variable.lastIndexOf('('); + if (parenLoc>=0) + { + current_variable = current_variable.substring(parenLoc+1); + } + // Handle nested classes + String[] sub_fields = current_variable.split("%"); //$NON-NLS-1$ + String base_variable = sub_fields[0].toLowerCase(); + // Search for base variable in currently available scopes + String type_name = null; + Iterable<Definition> proposalsToConsider = null; + while (true) + { + proposalsToConsider = defs.get(scopeTemp); + if (proposalsToConsider != null) + { + for (Definition def : proposalsToConsider) + { + if (!def.isLocalVariable()) + continue; + String identifier = def.getCanonicalizedName(); + if (!identifier.equals(base_variable)) + continue; + // Base variable definition found + Type var_type = def.getType(); + if (var_type instanceof DerivedType ) { + DerivedType typeNode = (DerivedType) var_type; + type_name = typeNode.getName(); + break; + } + } + } + // Exit if type name was determined + if (type_name != null) + break; + // Step to next outer scope if declaration has not been found + int colon = scopeTemp.indexOf(':'); + if (colon < 0) + break; + else + scopeTemp = scopeTemp.substring(colon+1); + } + // Step up remaining scopes looking for type definition + outerloop: + while (true) + { + proposalsToConsider = defs.get(scopeTemp); + if (proposalsToConsider != null) + { + for (Definition def : proposalsToConsider) + { + if (!def.isDerivedType()) + continue; + String identifier = def.getCanonicalizedName(); + // Type definition found + if (identifier.equals(type_name)) { + PhotranTokenRef mytoken = def.getTokenRef(); + Token mydef = mytoken.getASTNode(); + parentScope = mydef.getEnclosingScope(); + classScope = mydef.getLocalScope(); + // Get known definitions + classDefs = classScope.getAllDefinitions(); + // If class chain wait till top level + if (sub_fields.length > 1) { + break; + } else { + break outerloop; + } + } + } + } + // + if (classDefs != null) + break; + // Step to next outer scope if declaration has not been found + int colon = scopeTemp.indexOf(':'); + if (colon < 0) + break; + else + scopeTemp = scopeTemp.substring(colon+1); + } + // Step up class chain to current type + if (sub_fields.length > 1) { + for (int i = 1; i<sub_fields.length; i=i+1) + { + if (sub_fields[i]=="") //$NON-NLS-1$ + break; + // Find variable in current type + proposalsToConsider = classDefs; + if (proposalsToConsider != null) + { + for (Definition def : proposalsToConsider) + { + if (!def.isDerivedTypeComponent()) + continue; + // + String identifier = def.getCanonicalizedName(); + if (!identifier.equals(sub_fields[i].toLowerCase())) + continue; + // Get type name + Type var_type = def.getType(); + if (var_type instanceof DerivedType ) { + DerivedType typeNode = (DerivedType) var_type; + type_name = typeNode.getName(); + break; + } + } + } + // Find new type in parent scope + proposalsToConsider = parentScope.getAllDefinitions(); + if (proposalsToConsider != null) + { + for (Definition def : proposalsToConsider) + { + if (!def.isDerivedType()) + continue; + // + String identifier = def.getCanonicalizedName(); + if (!identifier.equals(type_name)) + continue; + // + PhotranTokenRef mytoken = def.getTokenRef(); + // Look in parent scope + Token mydef = mytoken.getASTNode(); + List<PhotranTokenRef> possParents = parentScope.manuallyResolve(mydef); + mytoken = possParents.get(0); + mydef = mytoken.getASTNode(); + classScope = mydef.getLocalScope(); + parentScope = mydef.getEnclosingScope(); + // Get known definitions + classDefs = classScope.getAllDefinitions(); + break; + } + } + } + } + // If we have located the scope get definitions + if (classScope != null) { + // Definitions for this scope + classDefs = classScope.getAllDefinitions(); + // Process inherited elements + PhotranTokenRef mytoken = null; + while (true) { + if (classScope instanceof ASTDerivedTypeDefNode ) { + Token parentClass = null; + ASTDerivedTypeDefNode typeNode = (ASTDerivedTypeDefNode) classScope; + // Look for inheritance node + ASTDerivedTypeStmtNode typeDef = typeNode.getDerivedTypeStmt(); + IASTListNode<ASTTypeAttrSpecNode> defList = typeDef.getTypeAttrSpecList(); + if (defList != null) { + for (ASTTypeAttrSpecNode currDef: defList) { + if (!currDef.isExtends()) + continue; + parentClass = currDef.getParentTypeName(); + List<PhotranTokenRef> possParents = parentScope.manuallyResolve(parentClass); + mytoken = possParents.get(0); + parentClass = mytoken.getASTNode(); + } + } + // Scan parent class for new methods/variables + if (parentClass==null) { + break; + } else { + ScopingNode tempScope = parentClass.getLocalScope(); + // Get known definitions + List<Definition> tempDefs = tempScope.getAllDefinitions(); + for (Definition newDef: tempDefs) { + boolean overridden = false; + for (Definition currDef: classDefs){ + String currIden = currDef.getCanonicalizedName(); + if (currIden.equals(newDef.getCanonicalizedName())) + overridden = true; + } + if (!overridden) + classDefs.add(newDef); + } + // Update scope to move up inheritance ladder + classScope = tempScope; + } + } + } + } + return classDefs; + } + + private final List<Definition> determineModuleNames() + { + List<Definition> moduleDefs = new LinkedList<Definition>(); + PhotranVPG vpg = PhotranVPG.getInstance(); + Iterable<String> moduleNames = vpg.listAllModules(); + for (String module: moduleNames) { + Definition dummyDef = new Definition(module,null,Classification.MODULE,Type.VOID); + moduleDefs.add(dummyDef); + } + return moduleDefs; + } + + private final List<Definition> determineModuleDefs(int offset, int line, IDocument document, String scopeName) throws BadLocationException + { + List<Definition> moduleDefs = new LinkedList<Definition>(); + // Get line to analyze + int line_offset = document.getLineOffset(line); + int cur_length = offset-line_offset; + String current_line = document.get(line_offset, cur_length); + current_line = current_line.toLowerCase(); + // Check for beginning keyword + String varChars = "[a-z0-9_]*"; //$NON-NLS-1$ + Pattern var_pattern = Pattern.compile(varChars); + Matcher matchedKeyword = var_pattern.matcher(current_line); + String moduleName = null; + while (matchedKeyword.find()) { + moduleName = matchedKeyword.group(); + if (!(moduleName.matches("use") || moduleName.isEmpty())) //$NON-NLS-1$ + break; + } + if (moduleName == null) + return moduleDefs; + // Find module and get defs + PhotranVPG vpg = PhotranVPG.getInstance(); + ArrayList<Definition> modules = vpg.findAllModulesNamed(moduleName); + if (modules != null) { + if ((modules.isEmpty() || modules.size()>1)) + return moduleDefs; + // + Definition module = modules.get(0); + PhotranTokenRef moduleTokenRef = module.getTokenRef(); + Token moduleToken = moduleTokenRef.getASTNode(); + ScopingNode moduleScope = moduleToken.getLocalScope(); + List<Definition> tempDefs = moduleScope.getAllPublicDefinitions(); + String moduleFile = moduleTokenRef.getFilename(); + for (Definition def: tempDefs) { + PhotranTokenRef defTokenRef = def.getTokenRef(); + if (moduleFile.equals(defTokenRef.getFilename())) + moduleDefs.add(def); + } + } + return moduleDefs; + } private int determineLineNumberForOffset(int offset, IDocument document) throws BadLocationException { diff --git a/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/editor_vpg/contentassist/FortranCompletionProcessorVPGTask.java b/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/editor_vpg/contentassist/FortranCompletionProcessorVPGTask.java index 6fa8265c..799afce4 100755 --- a/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/editor_vpg/contentassist/FortranCompletionProcessorVPGTask.java +++ b/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/editor_vpg/contentassist/FortranCompletionProcessorVPGTask.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009 University of Illinois at Urbana-Champaign and others. + * Copyright (c) 2009, 2014 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 @@ -7,6 +7,7 @@ * * Contributors: * UIUC - Initial API and implementation + * Chris Hansen (U Washington) - Auto-complete improvements (Bug 414906) *******************************************************************************/ package org.eclipse.photran.internal.ui.editor_vpg.contentassist; @@ -53,9 +54,10 @@ final class FortranCompletionProcessorVPGTask implements IFortranEditorVPGTask TreeSet<Definition> set = defs.get(qualifier); if (set == null) set = new TreeSet<Definition>(); - for (Definition def : allDefs) - if (def != null) + for (Definition def : allDefs) + if (def != null) { set.add(def); + } defs.put(qualifier, set); } diff --git a/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/editor_vpg/contentassist/FortranCompletionProposalComputer.java b/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/editor_vpg/contentassist/FortranCompletionProposalComputer.java index e616ae76..8d87ef7b 100755 --- a/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/editor_vpg/contentassist/FortranCompletionProposalComputer.java +++ b/org.eclipse.photran.ui.vpg/src/org/eclipse/photran/internal/ui/editor_vpg/contentassist/FortranCompletionProposalComputer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009 University of Illinois at Urbana-Champaign and others. + * Copyright (c) 2009, 2014 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 @@ -7,6 +7,7 @@ * * Contributors: * UIUC - Initial API and implementation + * Chris Hansen (U Washington) - Auto-complete improvements (Bug 414906) *******************************************************************************/ package org.eclipse.photran.internal.ui.editor_vpg.contentassist; @@ -39,19 +40,39 @@ import org.eclipse.swt.graphics.Image; * Computes the list of items be shown in the content assist list. * * @author Jeff Overbey + * @author Chris Hansen * * @see FortranCompletionProcessor#computeCompletionProposals(org.eclipse.jface.text.ITextViewer, int) */ class FortranCompletionProposalComputer extends CompletionComputer { + public static enum Context + { + GENERIC, + TYPE_VARIABLE_DEF, + ALLOCATE, + DEALLOCATE, + USE, + USE_ONLY; + } + private HashMap<String, TreeSet<Definition>> defs; private String scope; - - FortranCompletionProposalComputer(HashMap<String, TreeSet<Definition>> defs, String scope, IDocument document, int offset) throws BadLocationException + protected Context context; + + FortranCompletionProposalComputer(HashMap<String, TreeSet<Definition>> defs, String scope, IDocument document, int offset, Context contextType) throws BadLocationException { super(document, offset); this.defs = defs; this.scope = scope; + this.context = contextType; + } + + public List<ICompletionProposal> proposalsFromTheseDefs(Iterable<Definition> defsIn) throws BadLocationException + { + TreeSet<FortranCompletionProposal> proposals = new TreeSet<FortranCompletionProposal>(); + addProposals(defsIn, proposals); + return toProposalArray(proposals); } public List<ICompletionProposal> proposalsFromDefs() throws BadLocationException @@ -88,9 +109,29 @@ class FortranCompletionProposalComputer extends CompletionComputer { if (def.getClassification().equals(Classification.MAIN_PROGRAM)) continue; - - String identifier = def.getDeclaredName(); + //Filter by context + if (this.context == Context.TYPE_VARIABLE_DEF) { + if (!(def.getClassification().equals(Classification.DERIVED_TYPE))) + continue; + } else if (this.context == Context.ALLOCATE) { + if (!(def.getClassification().equals(Classification.DERIVED_TYPE) || + def.getClassification().equals(Classification.VARIABLE_DECLARATION) || + def.getClassification().equals(Classification.FUNCTION))) + continue; + } else if (this.context == Context.DEALLOCATE) { + if (!def.getClassification().equals(Classification.VARIABLE_DECLARATION)) + continue; + } else if (this.context == Context.USE) { + if (!def.getClassification().equals(Classification.MODULE)) + continue; + } + // + String identifier = def.getCompletionText(); String canonicalizedId = def.getCanonicalizedName(); + // + if (this.context == Context.USE_ONLY) + identifier = def.getDeclaredName(); + // if (canonicalizedId.startsWith(prefix) && canonicalizedId.endsWith(suffix)) proposals.add(createProposal(identifier, def.describeClassification(), @@ -221,8 +262,17 @@ class FortranCompletionProposalComputer extends CompletionComputer for (int i = 0; i < args.length; i++) { if (i > 0) sb.append(", "); //$NON-NLS-1$ + // + String argTemp = args[i]; + if (argTemp.indexOf('=')>=0) { + String[] argSplit = argTemp.split("="); //$NON-NLS-1$ + sb.append(argSplit[0].trim().replace(' ', '_')); + sb.append('='); + argTemp=argSplit[1]; + } + // sb.append("${"); //$NON-NLS-1$ - sb.append(args[i].trim().replace(' ', '_')); + sb.append(argTemp.trim().replace(' ', '_')); sb.append('}'); } sb.append(')'); |