REPL code review
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Mon Sep 14 15:58:46 UTC 2015
The changes look good; I like how you handled the diamond case by
reusing the target-type machinery to find a suitable target-type.
The smart filter simplification is also welcome.
Thanks
Maurizio
On 14/09/15 16:06, Jan Lahoda wrote:
> Hi Maurizio,
>
> I've tried to tweak the code according to the comments below. Links
> inline.
>
> On 11.9.2015 19:01, Jan Lahoda wrote:
>> Hi Maurizio,
>>
>> Thanks for the review and comments!
>>
>> On 11.9.2015 17:25, Maurizio Cimadamore wrote:
>> [snip]
>>
>>> -SourceCodeAnalysisImpl - generally looks good, and the tab completion
>>> logic is quite clever:
>>>
>>> - in scopeContent() what is the difference between the
>>> 'scopeIterable' and a call to Scope.getLocalElements (which is routed
>>> via Scope.getSymbols)?
>>
>> The general intent of scopeContent is to gather all elements that are
>> defined at the given place (for which the Scope was created).
>> Scope.getLocalElements only returns elements that are local to the scope
>> - for example for a Scope that was created for a location inside a
>> method, the getLocalElements won't include the imported elements.
>>
>> So, generally, it is necessary to recursively use
>> Scope.getEnclosingScope() and use getLocalElements on all the Scopes
>> from the given Scope up. The scopeIterable is used to do that - it
>> iterates up the Scope hierarchy - on each item of the iterable the
>> getLocalElements is called and the results are concatenated (using
>> Stream.flatMap).
>>
>> I'll work on the other comments for SourceCodeAnalysisImpl.
>>
>> Thanks,
>> Jan
>>
>>>
>>> - the logic for filtering based on target type is cool - but could
>>> use some cleanup - for instance there are two smart filters, and it's
>>> not clear why those are needed; it seems like smartTypeFilter is only
>>> used in imports, and the main difference is that it is allowed to
>>> operate on type elements, while the smartFilter can't; but the typing
>>> logic is the same (except for isAssignable vs. isSubtype - which
>>> shouldn't be important in the smartTypeFilter case anyway). I suggest
>>> just using smartFilter (without the class filtering logic), and the add
>>> the proper extra filtering logic
>>> (i.e. must be a class, must be a non-class) as a separate 'kind'
>>> filter.
>
> http://hg.openjdk.java.net/kulla/dev/langtools/rev/1fdd34dd23bc
>
> I kept smartTypeFilter and smartFilter, but the only the first one is
> doing the actual type check now - the second one adds the kind check
> (to get a full filter).
>
>>>
>>> -found a bug with varargs (varargs expansion does not take place):
>>>
>>> -> class Foo { static void m(int... i) { } }
>>> | Replaced class Foo
>>> | Update overwrote class Foo
>>> -> Foo.m(Display all 395 possibilities? (y or n)
>
> http://hg.openjdk.java.net/kulla/dev/langtools/rev/946ca38ccc49
>
>>>
>>> -found bugs around constructors; asMemberOf doesn't get called, and
>>> that leads to useless smart filters:
>>>
>>> -> class Baz<X> {
>>> >> Baz(X x) { }
>>> >> }
>>> | Added class Baz
>>>
>>> -> String s = "";
>>> | Added variable s of type String with initial value ""
>>>
>>> -> new Baz(Display all 391 possibilities? (y or n)
>>>
>>> -> new Baz<String>(Display all 391 possibilities? (y or n)
>>>
>>> -> Baz<String> bz = new Baz<>(Display all 391 possibilities? (y
>>> or n)
>>>
>>> The problem is that the type of the constructor is Baz(X) and no
>>> variable in scope can possibly have type X, so all elements in the
>>> scope
>>> are cleared out. In the first two cases should be fixable by simply
>>> adding a call to asMemberOf() on the constructor element. The third
>>> case
>>> is more difficult - perhaps some heuristics could be attempted, but the
>>> general case is hard.
>
> http://hg.openjdk.java.net/kulla/dev/langtools/rev/ea1fd645628d
>
> It first tries to find the type in the AST, and if there is no usable
> type, it resorts to the targetType machinery that already exists. I
> hope this will work reasonably, I think.
>
>>>
>>> -smart completion doesn't always work as expected - in particular,
>>> target-type-based suggestions seem to occur only once:
>>>
>>> -> fs.m(
>>> ls <press tab to see more>
>>>
>>> -> fs.m
>>> | Error:
>>> | cannot find symbol
>>> | symbol: variable m
>>> | fs.m
>>> | ^--^
>>>
>>> -> fs.m(Display all 389 possibilities? (y or n)
>>>
>>> After first time, all members will be displayed (unless you start
>>> working on a different instance...)
>
> http://hg.openjdk.java.net/kulla/dev/langtools/rev/214544e27c9a
>
> Pressing <tab> should now cycle between the "smart" and ordinary
> completion. (I was looking if I could improve typing detection - so
> that the completion state would reset when the user would e.g. type
> and then delete something, but so far, I didn't find a reasonable way
> to do that.)
>
>
> How do these look?
>
> Thanks!
> Jan
>
>>>
>>> * TaskFactory:
>>> - I see that cntResolve counts the recoverable errors - javac does
>>> have a notion of recoverable errors that is used in annotation
>>> processing - all recoverable diagnostics are marked with a special flag
>>> (DiagnosticFlag.RECOVERABLE). I wonder if it would be more robust to
>>> rely on that, rather than using raw diagnostic text (as the latter
>>> might
>>> change over time).
>>>
>>> - I like the hierarchy of tasks - it is very easy to see which
>>> tasks
>>> are meant to operate on source code and which on synthetic wraps.
>>>
>>>
>>> Maurizio
>>>
More information about the kulla-dev
mailing list