[groovy] more precise ambiguous block check (IDEA-148160)

This commit is contained in:
Daniil Ovchinnikov
2015-11-18 22:19:49 +03:00
parent 2f3c5872c3
commit 6dd293f451
2 changed files with 173 additions and 13 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -92,6 +92,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.*;
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.types.*;
import org.jetbrains.plugins.groovy.lang.psi.api.util.GrStatementOwner;
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.types.TypeInferenceHelper;
import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.modifiers.GrAnnotationCollector;
@@ -393,12 +394,25 @@ public class GroovyAnnotator extends GroovyElementVisitor {
@Override
public void visitTypeDefinitionBody(GrTypeDefinitionBody typeDefinitionBody) {
final PsiElement parent = typeDefinitionBody.getParent();
if (parent instanceof GrAnonymousClassDefinition) {
final PsiElement prev = typeDefinitionBody.getPrevSibling();
if (PsiUtil.isLineFeed(prev)) {
myHolder.createErrorAnnotation(typeDefinitionBody, GroovyBundle.message("ambiguous.code.block"));
}
if (!(parent instanceof GrAnonymousClassDefinition)) return;
final PsiElement prev = typeDefinitionBody.getPrevSibling();
if (!PsiUtil.isLineFeed(prev)) return;
final PsiElement newExpression = parent.getParent();
if (!(newExpression instanceof GrNewExpression)) return;
final GrStatementOwner statementOwner = PsiTreeUtil.getParentOfType(newExpression, GrStatementOwner.class);
final GrParenthesizedExpression parenthesizedExpression = PsiTreeUtil.getParentOfType(newExpression, GrParenthesizedExpression.class);
if (parenthesizedExpression != null && PsiTreeUtil.isAncestor(statementOwner, parenthesizedExpression, true)) return;
final GrArgumentList argumentList = PsiTreeUtil.getParentOfType(newExpression, GrArgumentList.class);
if (argumentList != null && !(argumentList instanceof GrCommandArgumentList)) {
if (PsiTreeUtil.isAncestor(statementOwner, argumentList, true)) return;
}
myHolder.createErrorAnnotation(typeDefinitionBody, GroovyBundle.message("ambiguous.code.block"));
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -1002,14 +1002,160 @@ class Sub<W extends Window> extends Super<W> {
''')
}
void testAnonymousBodyOnNewLine() {
testHighlighting('''\
class Foo{}
print new Foo()
void 'test anonymous body on new line within parenthesized expression'() {
testHighlighting '''\
class Foo {
def i
}
def foo = new Foo()
<error descr="Ambiguous code block">{
String toString() {'abc'}
}</error>
''')
def bar = (new Foo()
{
})
def baz
baz = new Foo()
<error descr="Ambiguous code block">{
}</error>
baz = (new Foo()
{
})
(baz = new Foo()
{
})
new Foo()
<error descr="Ambiguous code block">{
}</error>
(new Foo()
{
})
new Foo()
<error descr="Ambiguous code block">{
}</error> + 666
(new Foo()
{
}) + 444
1 + (new Foo()
{
} + 555)
(1 + new Foo()
{
} + 112)
new Foo()
<error descr="Ambiguous code block">{
}</error>.getI()
(new Foo()
{
}).getI()
(new Foo()
{
}.getI())
def mm() {
new Foo()
<error descr="Ambiguous code block">{
}</error>
}
def mm2() {
(new Foo()
{
})
}
def mm3() {
return new Foo()
<error descr="Ambiguous code block">{
}</error>
}
def mm4() {
return (new Foo()
{
})
}
(new Foo()
{
def foo() {
// still error
new Foo()
<error descr="Ambiguous code block">{
}</error>
}
})
'''
}
void 'test anonymous body on new line within argument list'() {
testHighlighting '''\
class Foo {}
def foo(param) {}
foo(new Foo()
{
})
def baz
foo(baz = new Foo()
{
})
foo(new Foo()
{
} + 666)
foo(1 + new Foo()
{
})
foo(1 + new Foo()
{
} + 666)
foo(new Foo()
{
}.getI())
foo(new Foo()
{
}.identity { it })
foo new Foo()
<error descr="Ambiguous code block">{
}</error>
foo 1 + (new Foo()
{
}) + 22
foo(new Foo() {
def a() {
// still error
new Foo()
<error descr="Ambiguous code block">{
}</error>
}
})
'''
}
void testGenerics() {