Friday, November 27, 2009

New cross-language refactoring support for Groovy-Eclipse plugin

Thanks to the work of Michael Klenk and his students at the Institute for Software in Switzerland, the Groovy-Eclipse plugin now has cross-language refactoring support for renaming. Its use is seamless. Let me give you an example.

Let's start with a simple Java file and a simple Groovy file:

before

You can rename the field in the Java class:

during1

This will perform the standard Java refactoring on all Java classes in your projects. Additionally, the refactoring will be performed on your groovy classes. If there are any ambiguous references to the Java field, the following dialog will open up allowing you to choose which references should be refactored:

choose

And the result is what you would expect:

after

The refactoring can be initiated from the Groovy side as well:

groovyrefactor_menu

As you can see, extract method an inline method are two other refactorings supported in Groovy code.

This functionality is currently available in the latest snapshot build of Groovy-Eclipse for Eclipse 3.5, available from the following update site:
   http://dist.codehaus.org/groovy/distributions/greclipse/snapshot/e3.5/


Please send any questions or problems to the mailing list. We're happy to help. Enjoy!

Thursday, November 19, 2009

Getting AspectJ Pointcut matching timer information in AJDT

Andy Clement has just added pointcut match timing information to AspectJ. A number of people have been asking to have this included in AJDT, and so I did a little work and made it available in the latest dev builds of AJDT for 3.4 and 3.5.

Here's how to display timing information:


  1. Select Verbose and Pointcut matching timers from the AspectJ compiler preferences page (this can be either globally from Eclipse preferences or for a specific project from the project properties page):

    compiler prefs

  2. In the AJDT Event Trace View, ensure that you have Compiler / Task list messages selected:

    event trace



And now on every project build (incremental or full), you will see pointcut matching times spit out to the event trace:

output

Enjoy! Questions can be sent to the AJDT developer's mailing list.

Monday, November 16, 2009

How type inferencing for Groovy in Eclipse is leading to all sorts of Groovy goodness

Of all of the recent improvements of Groovy-Eclipse since M1 has been released, the groovy type inferencing engine is the most pervasive and powerful. This inferencing engine is able to take a groovy file or code snippet and infer the type of any or all of its expressions. It now forms the core of several of the most prominent features of Groovy-Eclipse. Everything that I describe here is currently available in the latest snapshot release of Groovy-Eclipse for Eclipse 3.5 and the update site is here:
http://dist.codehaus.org/groovy/distributions/greclipse/snapshot/e3.5


In this post, I am going to describe how the inferencing engine is currently used in Groovy-Eclipse and then I will dive a deep and describe how it is implemented. I'll end the post by describing our plans for immediate the future.

What type inferencing is used for



Underlining statically indeterminate references


The Groovy editor now underlines all references that cannot be determined while editing. This happens in a background thread while you type. So, the following code (notice the mispelling of asImmutable):


def aList = []
def otherList = aList.asImmutabl()
otherList.asImmutable()



...will appear in the editor like this...

underline

...and when the typo is fixed, the underlines go away...

nounderline

Code is re-analyzed after every keystroke (well, actually, it is after every keystroke that is followed by 500ms of no keystrokes). The type of every reference in the file is looked up using the inferencing engine. Every reference that cannot be found is considered to be unknown and will be underlined.

Of course, Groovy being a dynamic language, not all references can be statically linked to a type (other than Object). This is especially the case when working with DSLs (such as Grails) that use metaprogramming to add new methods and fields to existing types. Later, I'll describe our plans for extensibility.

Search



Inferencing is used for Java Search as well. Using the search short cut (CTRL-Shift-G or CMD-Shift-G on Mac) or running search from the Java Search dialog, references from and to Groovy code snippets can be located. However, there are some difficulties here. Compared to Java, Groovy is quite a bit more flexible in the ways that fields and methods can be referenced. For example, this field is assigned a closure and referenced as if it were a method:

class Foo {
def x = { print it }
}

x("Hello!")


And this method is referenced in a way that is statically indistinguishable from a field:


class Foo {
def x() { print "Hello!" }
}

x


Furthermore, the spread operator and the use of default parameters makes the Java way of determining which method or field is referenced impossible. So, Groovy search is significantly more liberal than Java search in what it considers a search match. If a reference corresponds to any field, method, or property in the declaring type (regardless of parameter count and whether it is accessed as a field or method), then the match is considered successful. This leads to the following scenarios.

1. Performing search on the field declaration finds field references here:
searchForField

2. Performing search on the method declaration finds exactly the same references:
searchForMethod

And, notice that references attached to the wrong type are not considered a match.
searchNoResults

Content Assist



Most of the internals of Groovy-Eclipse has been rewritten since the previous 1.5.7 release. The most recent rewrite is of content assist. Although the previous version worked (usually), there was always a noticeable lag while waiting for the content assist window to appear. This previous implementation of content assist used a combination of Java classloading and Groovy AST matching in order to find all completion proposals available at a given location, which was both messy and slow. Now, we have hooked into the inferencing engine and have completely rewritten proposal generation with extensibility in mind. And we have made some remarkable improvements in performance.

Using the following code snippet I performed content assist 5 times under the old implementation and the new and took the average of the last 3 of each:


def x
x.hasProperty("foo").





Old implementation2315 milliseconds
New implementation8 milliseconds


That's right...there is a 3 orders of magnitude speed up under the new implementation, making content assist a much more pleasant feature to use. But please note that this is just the time for calculation of the proposals and it does not include the time required to actually pop up the window.

Open declaration


The implementation of open declaration (or code select as it is called in JDT because it is a general mechanism to determine what the current selection refers to and is also used for things like calculating hovers) also uses inferencing. Pressing F3 whenever the selection is any form of "navigateToMe" in the following code, the expected declaration will open:

navigateBefore ---> navigateAfter

Although Groovy-Eclipse M1 used type inferencing for code select, it was using the inferencing from content assist and was subject to the same mistakes, duplicate answers, and slowness that content assist had.

How it works


The inferencing engine has unified the implementation of several of Groovy-Eclipse's most widely used features. With this unification, we have been able to significantly reduce the amount of duplicated code, improve performance, and plan for extensibility.

There are four interacting components of the inferencing engine:


  1. The Abstract Syntax Tree (or AST): this is an abstract representation of the syntax of a groovy file expressed hierarchically. The code to work on can be obtained either from the disk, or it can be the latest in memory. The AST is generated by the Groovy compiler based on the current state of the editor whenever Eclipse is otherwise idle.

  2. The type inferencing visitor: this visitor walks the AST (i.e., uses a visitor pattern to visit every AST node) and delegates to the type lookups and the requestor described below. A new visitor is created for each call to the inferencing engine.

  3. The type lookups: these objects lookup the type information of a particular expression using whatever mechanism they require. They can store and retrieve information about types in a way that all other lookups can use. In this way, each lookup can do what it can and coordinate with other lookups where required. Several default lookups are provided including a simple lookup, an inferencing lookup (that stores information about types via assignment expressions), and a category lookup (that looks up types in Groovy categories). Type lookups are created from a registry on each call to the inferencing engine.

  4. The requestor: this is the object that collects the type information determined by the lookups. The requestor is general and can be used as a way to store the types of all expressions, lookup the type of a particular expression, or look for expressions with unknown types (just to name a few uses). The requestor is created by client code and past to the visitor to start the inferencing process.



The following diagram shows process and how the different pieces work together:

arch


  1. The visitor visits an AST expression node

  2. The visitor sends this expression to the type lookups.

    • each lookup responds with a type and its confidence in that type (ie, exact, potential, inferred...), or null, if it cannot find a type

    • a lookup may additionally store information in a scope object that is passed around to other lookups so that information can be shared between them


  3. The result of the lookup is sent to the requestor

  4. The requestor processes the result and may choose to end the visit or continue.

  5. If required, the visitor will continue to visit the rest of the abstract syntax of the Groovy file



What's next


One of the core design goals of the inferencing engine is extensibility. The inferencing engine must be extensible in two ways. First, it must be usable to help support new features such as quick fixes and refactoring. Also, DSLs, (most notably Grails) must be able to extend inferencing with their own type lookups. It should be apparent through the description of the variety of ways that the engine is currently used that it versatile and can become the core implementation of any number of new Groovy-Eclipse features. As for DSL extensibility, that has not yet been implemented, but the stubs are available. Other DSLs will need to implement their own type lookup, but there is currently no way for these new lookups to be plugged in. Fortunately, it will be possible to use Eclipse's plugin architecture here and this will be the subject of my next blog post (after it gets implemented).

Saturday, October 3, 2009

AJDT 2.0.1 is released!

Overview

In this service release of AJDT, we have included a number of performance enhancements, as well as a few new features. This is the last scheduled release of the AJDT stream targeting 3.4. The next release, in early 2010, will be targeting the 3.5 stream only. And our second 2010 release will target 3.5. At the same time, we will also release an early development version of AJDT targeting Eclipse 3.6 in time for EclipseCon 2010.

AJDT is available from the following update sites for Eclipse 3.5 and 3.4 respectively:
http://download.eclipse.org/tools/ajdt/35/update
http://download.eclipse.org/tools/ajdt/34/update

Export Feature With AspectJ

A new wizard is available to export features with AspectJ support. This wizard can be initiated from the File -> Export... command:



This wizard supports all of the options that the standard export feature supports. The only difference is that the AspectJ compiler is used to compile the projects instead of the Java compiler:


AJDT support for passing aop.xml file

AJDT now provides UI support to pass aop.xml files to the compiler. AspectJ bug 124460 describes how the AspectJ compiler can use aop.xml files for compile time weaving. And now AJDT provides UI support in the following way.

In project properties of your AspectJ project, select aop.xml management. Here you add and remove aop.xml files that will be sent to the compiler. Note that these files are highlighted using a special icon. Also, note that the name aop.xml is optional. Any xml file can be sent to the compiler in this way. See the following screenshot for an example


In order to use aop.xml files for compile-time configuring of the weaver, you must add the -xmlConfigured option under Non-Standard Compiler Options in the project's AspectJ Compiler options. This work is described in bug 287459.

This work is still experimental. We hope to receive some feedback so that compile time XML configuration of the weaver can be improved. Please send all comments to theAspectJ mailing list, or to bugzilla.

AspectJ 1.6.6

AJDT 2.0.1 contains AspectJ 1.6.6 and this version is available for download separately. See the release notes here.

Bug Fixes

Thirty-four bugs have been addressed in this release. See Bugzilla for the full report.

Thanks!

Thanks to those of you who have submitted patches, bug reports, and contributed to the mailing list for this release. We appreciate your help. Specifically, in this release:

Previous Releases

See here for information on the new features in AJDT 2.0.0.

Tuesday, September 29, 2009

Groovy-Eclipse plugin now supports Eclipse 3.5.1

The Groovy-Eclipse plugin can now be installed into Eclipse 3.5.1. As always, the update site is here:

http://dist.codehaus.org/groovy/distributions/greclipse/snapshot/e3.5/

You can stop reading here if you don't care how I got this to work, or why I am a little bit surprised by this.

The Groovy-Eclipse plugin uses a feature patch on the JDT core bundle in order to achieve a high level of integration with JDT. Typically, feature patches can only apply to a specific version of a feature (e.g., 3.5.0.v20090527-2000-7r88FEeFJePyvYeA33DjZ_c1 or some ugliness). This means that Groovy-Eclipse, until recently could only install in a specific version of Eclipse, the one that ships the JDT feature version 3.5.0.v20090527-2000-7r88FEeFJePyvYeA33DjZ_c1. However, Andrew Niefer describes how to get around this by editing the content.xml file to widen the range that the patch applies to. Excellent stuff, and lucky for me, because I didn't want to branch the Groovy-Eclipse code base every time a new service release of Eclipse comes out.

Unfortunately, his instructions were not entirely accurate. Andrew mentions that the range attribute in the <patchscope> element needs to be widened in order allow the patch to be installable on multiple versions. I tried exactly what he suggested, but could not get my patch to install in both 3.5.0 and 3.5.1. After a little bit of exploration, I found that I also needed to change the range attribute in the <lifecycle> element.

All this meant was adding a single line to my ant script, to be executed after the p2 repository is generated:

    
<replace file="${updateSiteDir}/content.xml"
summary="yes" token="${orig.jdt.feature.version.range}"
value="${new.jdt.feature.version.range}"/>

And this turned out to be very simple. Thanks for the hint!

Thursday, June 25, 2009

AJDT 2.0.0 is released!

We have just released AJDT 2.0.0 for Eclipse 3.5 and 3.4.

Get it now from the update sites:
For Eclipse 3.5: http://download.eclipse.org/tools/ajdt/35/update
For Eclipse 3.4: http://download.eclipse.org/tools/ajdt/34/update

In addition to a new Push In refactoring and ITD-aware navigation and Javadocs, you can find out about what's included in this release at our New & Noteworthy page.

AJDT 2.0.0 will also be available in the upcoming SpringSource Tool Suite 2.1.0.

This release would not have been possible with out help from the AspectJ and AJDT community. So, thank you for your bug reports, patches, discussions and being warm and welcoming to newcomers.

Wednesday, June 3, 2009

Update on Greclipse 2.0 (Groovy support in Eclipse)

Today, I decided to run EclEmma on the Groovy-Eclipse plugin test suite. Shockingly, I found that JUnit support, content assist, and code navigation are completely test-fress. So, I took a stab at creating a solid and flexible test infrastructure that makes it easy to write plugin tests, especially ones that exercise the Java model.

How did I do this? I did it by hooking into existing JDT functionality, just like I have been doing for the rest of my work on Greclipse. I downloaded the JDT core tests from CVS and used what I needed. Now, I can write extremely concise tests that exercise the code I want it to. For example, I wrote the following test case that tests code selection on a closure in a groovy script (i.e., this is the code that is executed when you perform Open Declaration in an editor):


public void testCodeSelectClosure() throws Exception {
IPath projectPath = createGenericProject();
IPath root = projectPath.append("src");
String contents =
"def x = {\n"+
"t -> print t\n"+
"}\n"+
"x('hello')\n";
env.addGroovyClass(root, "Script", contents);
GroovyCompilationUnit unit = getGroovyCompilationUnit(root, "Script.groovy");
IJavaElement[] elts = unit.codeSelect(contents.lastIndexOf('x'), 1);
assertEquals("Should have found a selection", 1, elts.length);
assertEquals("Should have found local variable 'x'", "x", elts[0].getElementName());
}


I have written many tests for JUnit support (or is that GUnit?), and some for code selection. I still need to work on content assist. So, I can now be confident that as we make changes towards the 2.0 release, we are not sliding back in functionality. There is a lot of good work that has already been put into the plugin (including groovy-aware type inference for content assist) and we need to make sure that this does not regress as we go forward.