Question

I am using Xtend to write custom QuickFixes for the Eclipse UI plugin of my Xtext language. The idea is to extend org.eclipse.xtext.ui.editor.quickfix.DefaultQuickfixProvider and use call the accept method of an org.eclipse.xtext.ui.editor.quickfix.IssueResolutionAcceptor.

accept has several overloaded signatures, including:

  • void accept(Issue issue, String label, String description, String image, IModification modification)
  • void accept(Issue issue, String label, String description, String image, ISemanticModification semanticModification)

Using the first of those signatures is easy using Xtend's lambda expression syntax:

@Fix(MyDSLValidator::INVALID_TYPE_NAME)
def removeInitialUnderscore(Issue issue, IssueResolutionAcceptor acceptor) {
    acceptor.accept(issue,
    "Remove initial underscore",
    "Remove initial underscore",
    'upcase.png')
    [
        context |
        context.xtextDocument.replace(issue.offset, 1, "")
    ]
}

The Xtend compiler produces the following Java code:

public void removeInitialUnderscore(final Issue issue, final IssueResolutionAcceptor acceptor) {
  final IModification _function = new IModification() {
    public void apply(final IModificationContext context) throws Exception {
      IXtextDocument _xtextDocument = context.getXtextDocument();
      Integer _offset = issue.getOffset();
      _xtextDocument.replace((_offset).intValue(), 1, "");
    }
  };
  acceptor.accept(issue, 
    "Remove initial underscore", 
    "Remove initial underscore", 
    "upcase.png", _function);
}

Now I want to write a second QuickFix that uses ISemanticModification instead of IModification so that I can get access to the underlying EMF model, not just the strings. However, I'm struggling to tell the Xtend compiler which overloading of the method I'd like to use:

@Fix(MyDSLValidator::MISSING_USAGE)
def addMissingUseStatement(Issue issue, IssueResolutionAcceptor acceptor) {
    acceptor.accept(issue,
    "Add missing use statement",
    "Add missing use statement",
    "upcase.png",
    [
        EObject element |
        (element.eContainer as MyContainer).usages.add(
                    (element as MyElement).myattr.eContainer as MyOtherContainer
                )
    ])
}

Xtend always thinks I want to pass an IModification instead of an ISemanticModification and produces an error in the compiled java code because the two apply methods have different signatures, IModification takes an IModificationContext while ISemanticModification takes an EObject.

@Fix(MyDSLValidator.MISSING_USAGE)
public void addMissingUseStatement(final Issue issue, final IssueResolutionAcceptor acceptor) {
  final IModification _function = new IModification() {
    public void apply(final IModificationContext element) throws Exception {
      EObject _eContainer = element.eContainer(); // COMPILE ERROR
      EList<Circuit> _usages = ((MyContainer) _eContainer).getUsages();
      MyAttr _myattr = ((MyAttr ) element).getMyattr();
      EObject _eContainer_1 = _myattr.eContainer();
      _usages.add(
        ((MyOtherContainer) _eContainer_1));
    }
  };
  acceptor.accept(issue, 
    "Add missing use statement", 
    "Add missing use statement", 
    "upcase.png", _function);
}

How do I tell Xtend which overloading to use? As far as I know, it's not possible to create an anonymous object in Xtend, so there needs to be another way to call IssueResolutionAcceptor.accept passing an ISemanticModification.

Was it helpful?

Solution

The ISemanticModification accepts two arguments where the IModification only uses one argument. To implement a semantic modification, you should use a lambda with two parameters respectively:

acceptor.accept(issue,
    "Add missing use statement",
    "Add missing use statement",
    "upcase.png") [ element, context |
      ..
    ]
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top