protected EObject findCorrectContainer( org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ExpectedTerminal expectedTerminal) { EObject container = expectedTerminal.getContainer(); EClass ruleMetaclass = expectedTerminal.getTerminal().getRuleMetaclass(); if (ruleMetaclass.isInstance(container)) { // container is correct for expected terminal return container; } // the container is wrong EObject parent = null; EObject previousParent = null; EObject correctContainer = null; EObject hookableParent = null; org.emftext.language.xpath3.resource.xpath3.grammar.Xpath3ContainmentTrace containmentTrace = expectedTerminal.getContainmentTrace(); EClass startClass = containmentTrace.getStartClass(); org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ContainedFeature currentLink = null; org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ContainedFeature previousLink = null; org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ContainedFeature[] containedFeatures = containmentTrace.getPath(); for (int i = 0; i < containedFeatures.length; i++) { currentLink = containedFeatures[i]; if (i > 0) { previousLink = containedFeatures[i - 1]; } EClass containerClass = currentLink.getContainerClass(); hookableParent = findHookParent(container, startClass, currentLink, parent); if (hookableParent != null) { // we found the correct parent break; } else { previousParent = parent; parent = containerClass.getEPackage().getEFactoryInstance().create(containerClass); if (parent != null) { if (previousParent == null) { // replace container for expectedTerminal with correctContainer correctContainer = parent; } else { // This assignment is only performed to get rid of a warning about a potential // null pointer access. Variable 'previousLink' cannot be null here, because it is // initialized for all loop iterations where 'i' is greather than 0 and for the // case where 'i' equals zero, this path is never executed, because // 'previousParent' is null in this case. org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ContainedFeature link = previousLink; org.emftext.language.xpath3.resource.xpath3.util.Xpath3EObjectUtil.setFeature( parent, link.getFeature(), previousParent, false); } } } } if (correctContainer == null) { correctContainer = container; } if (currentLink == null) { return correctContainer; } hookableParent = findHookParent(container, startClass, currentLink, parent); final EObject finalHookableParent = hookableParent; final EStructuralFeature finalFeature = currentLink.getFeature(); final EObject finalParent = parent; if (parent != null && hookableParent != null) { expectedTerminal.setAttachmentCode( new Runnable() { public void run() { org.emftext.language.xpath3.resource.xpath3.util.Xpath3EObjectUtil.setFeature( finalHookableParent, finalFeature, finalParent, false); } }); } return correctContainer; }
protected Collection<org.emftext.language.xpath3.resource.xpath3.ui.Xpath3CompletionProposal> deriveProposals( final org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ExpectedTerminal expectedTerminal, String content, org.emftext.language.xpath3.resource.xpath3.IXpath3TextResource resource, int cursorOffset) { org.emftext.language.xpath3.resource.xpath3.IXpath3ExpectedElement expectedElement = (org.emftext.language.xpath3.resource.xpath3.IXpath3ExpectedElement) expectedTerminal.getTerminal(); if (expectedElement instanceof org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ExpectedCsString) { org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ExpectedCsString csString = (org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ExpectedCsString) expectedElement; return handleKeyword( expectedTerminal, csString, expectedTerminal.getPrefix(), expectedTerminal.getContainer()); } else if (expectedElement instanceof org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ExpectedBooleanTerminal) { org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ExpectedBooleanTerminal expectedBooleanTerminal = (org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ExpectedBooleanTerminal) expectedElement; return handleBooleanTerminal( expectedTerminal, expectedBooleanTerminal, expectedTerminal.getPrefix()); } else if (expectedElement instanceof org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ExpectedEnumerationTerminal) { org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ExpectedEnumerationTerminal expectedEnumerationTerminal = (org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ExpectedEnumerationTerminal) expectedElement; return handleEnumerationTerminal( expectedTerminal, expectedEnumerationTerminal, expectedTerminal.getPrefix()); } else if (expectedElement instanceof org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ExpectedStructuralFeature) { final org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ExpectedStructuralFeature expectedFeature = (org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ExpectedStructuralFeature) expectedElement; final EStructuralFeature feature = expectedFeature.getFeature(); final EClassifier featureType = feature.getEType(); final EObject container = findCorrectContainer(expectedTerminal); // Here it gets really crazy. We need to modify the model in a way that reflects // the state the model would be in, if the expected terminal were present. After // computing the corresponding completion proposals, the original state of the // model is restored. This procedure is required, because different models can be // required for different completion situations. This can be particularly observed // when the user has not yet typed a character that starts an element to be // completed. final Collection<org.emftext.language.xpath3.resource.xpath3.ui.Xpath3CompletionProposal> proposals = new ArrayList< org.emftext.language.xpath3.resource.xpath3.ui.Xpath3CompletionProposal>(); expectedTerminal.materialize( new Runnable() { public void run() { if (feature instanceof EReference) { EReference reference = (EReference) feature; if (featureType instanceof EClass) { if (reference.isContainment()) { // the FOLLOW set should contain only non-containment references assert false; } else { proposals.addAll( handleNCReference( expectedTerminal, container, reference, expectedTerminal.getPrefix(), expectedFeature.getTokenName())); } } } else if (feature instanceof EAttribute) { EAttribute attribute = (EAttribute) feature; if (featureType instanceof EEnum) { EEnum enumType = (EEnum) featureType; proposals.addAll( handleEnumAttribute( expectedTerminal, expectedFeature, enumType, expectedTerminal.getPrefix(), container)); } else { // handle EAttributes (derive default value depending on the type of the // attribute, figure out token resolver, and call deResolve()) proposals.addAll( handleAttribute( expectedTerminal, expectedFeature, container, attribute, expectedTerminal.getPrefix())); } } else { // there should be no other subclass of EStructuralFeature assert false; } } }); // Return the proposals that were computed in the closure call. return proposals; } else { // there should be no other class implementing IExpectedElement assert false; } return Collections.emptyList(); }