Content assist when model is incomplete [message #1724265] |
Mon, 22 February 2016 11:11  |
Eclipse User |
|
|
|
Hi,
I have a problem when wanting to create a proposal based on an incomplete model: If having the code as below (example 1) and invoking Ctrl-space as indicated -- as I have overidden the method
completeModelQuery_Methods(ModelQuery model, Assignment assignment, ContentAssistContext context, ICompletionProposalAcceptor acceptor)
in a AbstractQuickSvtProposalProvider subclass, it gets called as expected. The "model" parameter has a rootObject named "point" and one entry in the methods list named "Rectangle" -- makes sense, the parser is doing it's best to resolve the incomplete model. As the "point" variable is defined in the topmost statement (RootVarDefinition), and I want the definition type (varType -- i.e. "Point") - I expected that the rootObject (a VarDefinition cross-reference), would be resolved to the VarDefinition in the RootVarDefinition statement.
BUT for some reason the rootObject of the model parameter is contained in an instance of a GenericVarDefinition with varType value = "rect" , varValue = null - and I can see no reliable way of getting the correct VarDefinition.
What would be the best solution to make the parser less confused in case of example 1 below ..?
BTW: Example 2 below works as expected, as the parser is helped by the statement not including a "point" ..
Example 1: Not working ...
Root: Point point {
if (point.[Ctrl-space]
Rectangle rect = point.bounds;
}
Example 2: Working ...
Root: Point point {
if (point.[Ctrl-space]
int i = 0;
Rectangle rect = point.bounds;
}
Grammar (simplified and abbreviated ..):
ModelRoot:
rootVarDefinition=RootVarDefinition '{'
(contents+=Content)*
'}'
;
RootVarDefinition:
'Root:' varType=ID varDefinition=VarDefinition
;
Content:
GenericVarDefinition | DefIfElseStatement
;
DefIfElseStatement:
'if' '(' booleanStatement=BooleanStatement ')' '{'
(ifValues+=Content)*
'}'
('else' '{'
(elseValues+=Content)*
'}')?
;
GenericVarDefinition:
varType=ID varDefinition=VarDefinition '=' varValue=Operand ';'
;
Operand:
(opAlt1=ModelQuery | opAlt2=SimpleValue) (arithOp=ArithOp nextOp=Operand)?
;
SimpleValue:
valueInt=INT | valueNull='null' | valueString=STRING
;
ModelQuery:
rootObject=[VarDefinition] ('.' methods+=Method)*
;
Method:
methodName=ID ( '(' methodParameter=Operand ')')?
;
VarDefinition:
name=ID
;
|
|
|
|
Re: Content assist when model is incomplete [message #1725141 is a reply to message #1724417] |
Tue, 01 March 2016 04:00  |
Eclipse User |
|
|
|
Found the issue. For other reasons the custom implementation of the scope provider collected the VarDefinitions into a Map with the name of the definition as key - so the first correct definition was overwritten by a second bad one. If instead allowing all VarDefinitions to be added to the scope, it worked as expected.
So the only IMO odd thing is why the "bad" VarDefinition is constructed at all .. Again; having the code below ..
Root: Point point {
if (point.
int x = point.routes.size;
}
and adding collection and logging in a scope provider ..
@Override
public IScope getScope(EObject context, EReference reference) {
Class<?> refC = reference.getContainerClass();
if (refC.equals(ModelQuery.class)) {
return Scopes.scopeFor(getDefinitions(context));
}
return super.getScope(context, reference);
}
private List<VarDefinition> getDefinitions(EObject context) {
List<VarDefinition> defs = new ArrayList<>();
ModelRoot root = getModelRoot(context);
RootVarDefinition rootVarDef = root.getRootVarDefinition();
System.out.println("Found def named: " + rootVarDef.getVarDefinition().getName() + " type: "
+ rootVarDef.getVarType());
defs.add(rootVarDef.getVarDefinition());
for (Content content : root.getContents()) {
if (content instanceof GenericVarDefinition) {
GenericVarDefinition genDef = (GenericVarDefinition) content;
System.out.println("Found def named: " + genDef.getVarDefinition().getName() + " type: "
+ genDef.getVarType());
defs.add(genDef.getVarDefinition());
}
}
return defs;
}
private ModelRoot getModelRoot(EObject context) {
if (context instanceof ModelRoot) {
return (ModelRoot) context;
} else {
return getModelRoot(context.eContainer());
}
}
gives this result:
Found def named: point type: Point
Found def named: point type: x
Found def named: size type: routes
The bold def is "bad" .. I guess my question is; is this expected? And if so, is there any way of telling that this is not a valid def?
Debugged a bit and found that the Xtext code handles duplicate names by just picking the first one. In org.eclipse.xtext.scoping.impl.AbstractScope:
protected IEObjectDescription getSingleLocalElementByName(QualifiedName name) {
Iterable<IEObjectDescription> result = getLocalElementsByName(name);
Iterator<IEObjectDescription> iterator = result.iterator();
if (iterator.hasNext())
return iterator.next();
return null;
}
Might be just good enough I guess ..
Rgs,
/N
|
|
|
Powered by
FUDForum. Page generated in 0.27617 seconds