Bug 552561 - Expressions view: provide API for other languages (like groovy)
Summary: Expressions view: provide API for other languages (like groovy)
Status: NEW
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Debug (show other bugs)
Version: 4.14   Edit
Hardware: All All
: P3 enhancement (vote)
Target Milestone: ---   Edit
Assignee: JDT-Debug-Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords: api, helpwanted, needinfo
Depends on:
Blocks:
 
Reported: 2019-10-30 08:45 EDT by Matthias Fuchs CLA
Modified: 2019-11-02 12:26 EDT (History)
3 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Matthias Fuchs CLA 2019-10-30 08:45:20 EDT
Hi guys,

I have been playing around with groovy the last days and so far I really like it (imho, it's underestimated!). Anyways, So far it works great with the groovy eclipse plugin, even debugging almost works.
What doesn't work is the expressions view. It can handle Java code, but not groovy code, like the safe-navigator/elvis operator `foo?.test?.value`.

Also the Debug/display view doesn't support groovy,

I've already file a bug at the plugins github issues: https://github.com/groovy/groovy-eclipse/issues/569

But I was told, that this is an issue with Eclipse JDT and to file a bug here :-)

In case there is no good and fast-forward way to implement this feature for a new language, it would be nice to implement such an API in eclipse.

If this does already exist somewhere, please guide me to the right place, so I can try to implement this myself


Thanks for your help.

Best regards,
Matthias
Comment 1 Andrey Loskutov CLA 2019-10-30 09:51:49 EDT
(In reply to Matthias Fuchs from comment #0)
> I've already file a bug at the plugins github issues:
> https://github.com/groovy/groovy-eclipse/issues/569
> 
> But I was told, that this is an issue with Eclipse JDT and to file a bug
> here :-)

From original bug Groovy-eclipse wants this:

"an extension mechanism to provide support to use any JVM language for expression evaluation".

I doubt the JDT debug maintainers have time/interest to work on this, but this does not mean it is not a valid request. 

Someone who needs that must identify places that need to be extended and provide a plan how to fix that and a Gerrit patch following https://wiki.eclipse.org/Platform/How_to_Contribute
Comment 2 Eric Milles CLA 2019-11-01 15:23:42 EDT
One step in the right direction would be to find all the places in JDT that create a CompilationUnit from source using ASTParser.  There are several instances of this where the unit name is not set. making it difficult to determine within the parser if it is Java source being parsed or another JVM language.  I have had to fall back on regex matching against the source text to see if I can determine it is Groovy source.

One such example is in RunToLineAdapter:
    ASTParser parser = ASTParser.newParser(AST.JLS9);
    parser.setSource(document.get().toCharArray());
    // missing: parser.setUnitName(typeRoot.getElementName()); or maybe document has the comp unit name
    CompilationUnit compilationUnit= (CompilationUnit)parser.createAST(null);
Comment 3 Eric Milles CLA 2019-11-01 15:42:33 EDT
One clarification, the need for setUnitName(String) is only when using setSource(char[]).
Comment 4 Eric Milles CLA 2019-11-02 10:49:35 EDT
Specifically for the Expressions evaluation to support other languages, 4 changes are required:

1) In org.eclipse.jdt.internal.debug.eval.ast.engine.EvaluationSourceGenerator#createEvaluationSourceFromSource, parser.setUnitName() must be called (near parser.setSource(...);).  parser.setUnitName(type.getCompilationUnit().getPath().toString()); works for source units.  I did not have a chance to try binary units.

2) In org.eclipse.jdt.internal.debug.eval.ast.engine.EvaluationSourceGenerator#createEvaluationSourceFromSource or org.eclipse.jdt.internal.debug.eval.ast.engine.SourceBasedSourceGenerator#buildCompilationUnit, the unit name "Eval" needs the same file extension as the unit name that was parsed for context.

3) In org.eclipse.jdt.internal.debug.eval.ast.engine.SourceBasedSourceGenerator#buildRunMethod, the method return type "void " needs to be replaced with "Object " to avoid compilation error "Cannot use return statement with an expression on a method that returns void".

4) In org.eclipse.jdt.internal.debug.eval.ast.engine.ASTEvaluationEngine#createExpressionFromAST, some change is required to get the instructions for the generated method from the GroovyCompilationUnit.  If this change is not made, this method is returning "[no op]" and so all debug evaluations display "null".
Comment 5 Eric Milles CLA 2019-11-02 10:56:22 EDT
For (4) in previous comment, I have a hook in GroovyCompilationUnit that requires implementation:

  public class GroovyCompilationUnit extends CompilationUnit {
    /**
     * sneaky... required because we cannot get in the jdt.debug code and change it. Here the plan is that if the debug
     * MethodSearchVisitor is being used we don't find the method. If it was found the body would be empty and the debug code would
     * think the method has not changed across builds - when it may have. It is empty because we don't parse below the method level
     * for groovy.
     *
     */
    @Override
    protected void accept0(ASTVisitor visitor) {
        switch (visitor.getClass().getName()) {
        case "org.eclipse.jdt.internal.debug.core.hcr.MethodSearchVisitor":
            return;
        case "org.eclipse.jdt.internal.debug.eval.ast.engine.ASTInstructionCompiler":
            // TODO
        }
        super.accept0(visitor);
    }


Note: Special handling is required because Groovy Development Tools (GDT) only create enough JDT model data for joint compilation.  This is similar to creating Java stubs during groovyc (or what APT might do for Java).  Methods are defined with empty bodies and so there are no debug instructions available naturally for the eval engine to harvest and execute.
Comment 6 Eric Milles CLA 2019-11-02 12:26:12 EDT
Here are some additional uses of parser.setSource(char[]) that lack a call to setUnitName(...)

org.eclipse.jdt.internal.formatter.DefaultCodeFormatter.createParser(int)

org.eclipse.jdt.ui.wizards.NewTypeWizardPage.constructCUContent(ICompilationUnit, String, String)

org.eclipse.jdt.internal.core.CreateTypeMemberOperation.generateElementAST(ASTRewrite, ICompilationUnit)

org.eclipse.jdt.internal.core.CreateTypeMemberOperation.generateSyntaxIncorrectAST()

org.eclipse.jdt.internal.core.SortElementsOperation.processElement(ICompilationUnit, char[])