Affects Version/s: 2.0.1Release
Fix Version/s: 2.0.2Release
Number of attachments :
Starting from the discussion in
GRECLIPSE-610, this issue will describe the problem of how to handle ASTs that have transforms applied to them. The problem is that some IDE operations require the untransformed AST whereas others require the transformed AST. Groovy-Eclipse caches the transformed AST after each reconcile and uses that to perform most of its operations like inference, content assist, underlining, and code select. The problem is that if code blocks have been moved around, we are not always able to visit everything and know where to look for certain pieces of code.
Here are several possibilities for fixing this:
- Always visit all parts of the AST for every visit and rather than cut a visit short after an element is found, continue visiting other (synthetic) methods just in case a more appropriate AST node is found. This can be complicated because things like inferencing and code select require the existence of a containing IJavaElement (ie- a code element that is in the Java model and not something that is transformed). This will drastically complicate the Inferencing visitor (and other similar visitors) because we always need to map back to something in the Java model even if the Groovy element has been transformed and moved to a synthetic groovy method outside of the model. However, this possibility is nice because it would not add any extra processing to to reconciles and memory footprint would not go up.
- Instead of caching a single instance of the (transformed) AST, cache both the untransformed AST and the transformed AST. This is nice because depending on the operation, we can choose to walk the appropriate AST. However, there are 3 problems here. First, it will take extra time to create the copy. Second, the size of a GroovyCompilationUnit will essentially double. Third, some operations would require both the transformed and the untransformed AST at the same time. It will be tricky to start from one, translate an AST node from one tree to the other (ie- what does equality mean between these two trees?) and then use the information from one tree to populate results of the other.
- Only cache the untransformed tree. If Peter is right in
GRECLIPSE-610and transforms that add declarations to be called in user code are rare, then perhaps we don't need to cache the transformed tree at all. Again, some extra time would be spent to create the copy of the AST, but perhaps we can be smart about it and only do a copy on write. Also, the size of GroovyCompilationUnits would not need to increase. The downside is that some very common transforms would need special handling for inferencing and content assist. One that comes to mind immediately is @Singleton. The getInstance method needs to be in content assist and it should not be underlined. So, we would need to create a special ITypeLookup and ContentAssistProvider for this.
At this point, I am leaning towards #3, but I can also see the benefit of #1 where we do not need to special case AST Transforms that add user declarations.