blob: e0e878d54de7f0896be55d79ce5ae904a0702dfe [file] [log] [blame]
/*
* Copyright 2000-2014 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.lang.highlighting
import com.intellij.codeInspection.InspectionProfileEntry
import com.intellij.testFramework.LightProjectDescriptor
import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor
import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection
import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GrUnresolvedAccessInspection
/**
* Created by Max Medvedev on 27/02/14
*/
class Gr2_3HighlightingTest extends GrHighlightingTestBase {
@Override
protected LightProjectDescriptor getProjectDescriptor() {
return GroovyLightProjectDescriptor.GROOVY_2_3
}
@Override
InspectionProfileEntry[] getCustomInspections() {
[new GroovyAssignabilityCheckInspection(), new GrUnresolvedAccessInspection()]
}
void assertScript(String text) {
testHighlighting("import groovy.transform.CompileStatic\nimport groovy.transform.stc.ClosureParams\n" + text)
}
void shouldFailWithMessages(String text) {
assertScript(text)
}
void testInferenceOnNonExtensionMethod() {
assertScript '''
import groovy.transform.stc.FirstParam
public <T> T foo(T arg, @ClosureParams(FirstParam) Closure c) { c.call(arg) }
@CompileStatic
def test() {
assert foo('a') { it.toUpperCase() } == 'A'
}
'''
}
void testFromStringWithSimpleType() {
assertScript '''
import groovy.transform.stc.FromString
void foo(@ClosureParams(value=FromString,options="java.lang.String") Closure cl) { cl.call('foo') }
@CompileStatic
def test() {
foo { String str -> println str.toUpperCase()}
}
'''
shouldFailWithMessages '''
import groovy.transform.stc.FromString
void foo(@ClosureParams(value=FromString,options="java.lang.String") Closure cl) { cl.call('foo') }
@CompileStatic
def test() {
foo { <error descr="Expected String">Date</error> str -> println str}
}
'''
}
void testFromStringWithGenericType() {
assertScript '''
import groovy.transform.stc.FromString
void foo(@ClosureParams(value=FromString,options="java.util.List<java.lang.String>") Closure cl) { cl.call(['foo']) }
@CompileStatic
def test() {
foo { List<String> str -> str.each { println it.toUpperCase() } }
}
'''
shouldFailWithMessages '''
import groovy.transform.stc.FromString
void foo(@ClosureParams(value=FromString,options="java.util.List<java.lang.String>") Closure cl) { cl.call(['foo']) }
@CompileStatic
def test() {
foo { <error descr="Expected List<String>">List<Date></error> d -> d.each { println it } }
}
'''
}
void testFromStringWithDirectGenericPlaceholder() {
assertScript '''
import groovy.transform.stc.FromString
public <T> void foo(T t, @ClosureParams(value=FromString,options="T") Closure cl) { cl.call(t) }
@CompileStatic
def test() {
foo('hey') { println it.toUpperCase() }
}
'''
}
void testFromStringWithGenericPlaceholder() {
assertScript '''
import groovy.transform.stc.FromString
public <T> void foo(T t, @ClosureParams(value=FromString,options="java.util.List<T>") Closure cl) { cl.call([t,t]) }
@CompileStatic
def test() {
foo('hey') { List<String> str -> str.each { println it.toUpperCase() } }
}
'''
}
void testFromStringWithGenericPlaceholderFromClass() {
assertScript '''
import groovy.transform.stc.FromString
class Foo<T> {
public void foo(@ClosureParams(value=FromString,options="java.util.List<T>") Closure cl) { cl.call(['hey','ya']) }
}
@CompileStatic
def test() {
def foo = new Foo<String>()
foo.foo { List<String> str -> str.each { println it.toUpperCase() } }
}'''
}
void testFromStringWithGenericPlaceholderFromClassWithTwoGenerics() {
assertScript '''
import groovy.transform.stc.FromString
class Foo<T,U> {
public void foo(@ClosureParams(value=FromString,options="java.util.List<U>") Closure cl) { cl.call(['hey','ya']) }
}
@CompileStatic
def test() {
def foo = new Foo<Integer,String>()
foo.foo { List<String> str -> str.each { println it.toUpperCase() } }
}'''
}
void testFromStringWithGenericPlaceholderFromClassWithTwoGenericsAndNoExplicitSignature() {
assertScript '''
import groovy.transform.stc.FromString
class Foo<T,U> {
public void foo(@ClosureParams(value=FromString,options="java.util.List<U>") Closure cl) { cl.call(['hey','ya']) }
}
@CompileStatic
def test() {
def foo = new Foo<Integer,String>()
foo.foo { it.each { println it.toUpperCase() } }
}'''
}
void testFromStringWithGenericPlaceholderFromClassWithTwoGenericsAndNoExplicitSignatureAndNoFQN() {
assertScript '''
import groovy.transform.stc.FromString
class Foo<T,U> {
public void foo(@ClosureParams(value=FromString,options="List<U>") Closure cl) { cl.call(['hey','ya']) }
}
@CompileStatic
def test() {
def foo = new Foo<Integer,String>()
foo.foo { it.each { println it.toUpperCase() } }
}'''
}
void testFromStringWithGenericPlaceholderFromClassWithTwoGenericsAndNoExplicitSignatureAndNoFQNAndReferenceToSameUnitClass() {
assertScript '''
import groovy.transform.stc.FromString
class Foo {
void bar() {
println 'Haha!'
}
}
class Tor<D,U> {
public void foo(@ClosureParams(value=FromString,options="List<U>") Closure cl) { cl.call([new Foo(), new Foo()]) }
}
@CompileStatic
def test() {
def tor = new Tor<Integer,Foo>()
tor.foo { it.each { it.bar() } }
}'''
}
void testFromStringWithGenericPlaceholderFromClassWithTwoGenericsAndNoExplicitSignatureAndNoFQNAndReferenceToSameUnitClassAndTwoArgs() {
assertScript '''
import groovy.transform.stc.FromString
class Foo {
void bar() {
println 'Haha!'
}
}
class Tor<D,U> {
public void foo(@ClosureParams(value=FromString,options=["D,List<U>"]) Closure cl) { cl.call(3, [new Foo(), new Foo()]) }
}
@CompileStatic
def test() {
def tor = new Tor<Integer,Foo>()
tor.foo { r, e -> r.times { e.each { it.bar() } } }
}
'''
}
void testFromStringWithGenericPlaceholderFromClassWithTwoGenericsAndPolymorphicSignature() {
assertScript '''
import groovy.transform.stc.FromString
class Foo {
void bar() {
println 'Haha!'
}
}
class Tor<D,U> {
public void foo(@ClosureParams(value=FromString,options=["D,List<U>", "D"]) Closure cl) {
if (cl.maximumNumberOfParameters==2) {
cl.call(3, [new Foo(), new Foo()])
} else {
cl.call(3)
}
}
}
@CompileStatic
def test() {
def tor = new Tor<Integer,Foo>()
tor.foo { r, e -> r.times { e.each { it.bar() } } }
tor.foo { it.times { println 'polymorphic' } }
}
'''
}
void testTrait1() {
testHighlighting('''
trait X {
void foo() {}
}
''')
}
void testTrait2() {
testHighlighting('''
interface A {}
trait X implements A {
void foo() {}
}
''')
}
void testTrait3() {
testHighlighting('''
class A {}
trait X extends <error descr="Only traits are expected here">A</error> {
void foo() {}
}
''')
}
void testTrait4() {
testHighlighting('''
trait A {}
trait X extends A {
void foo() {}
}
''')
}
void testTraitExtendsList() {
testHighlighting('''
trait B extends <error descr="Only traits are expected here">HashMap</error> {}''')
}
void testIncIsNotAllowedInTraits() {
testHighlighting('''
trait C {
def x = 5
def foo() {
<error descr="++ expressions on trait fields/properties are not supported in traits">x++</error>
}
}
''')
}
void testTraitAsAnonymous() {
testHighlighting('''
trait T {}
new <error descr="Anonymous classes cannot be created from traits">T</error>(){}
''')
}
void testAbstractMethodsInTrait() {
testHighlighting('''
trait T {
def foo() {}
def <error descr="Not abstract method should have body">bar</error>()
abstract baz()
abstract xyz() <error descr="Abstract methods must not have body">{}</error>
}
''')
}
void testTraitImplementsInterfaceMethod() {
testHighlighting('''
interface A {def foo()}
trait B implements A { def foo() {}}
class C implements B {}
''')
}
void 'test not implemented trait method'() {
testHighlighting('''
trait T {abstract def foo()}
<error descr="Method 'foo' is not implemented">class C implements T</error> {}
''')
}
void 'test not implemented interface method with trait in hierarchy'() {
testHighlighting('''
interface T {def foo()}
trait X implements T {}
<error descr="Method 'foo' is not implemented">class C implements X</error> {}
''')
}
void 'test trait methods cannot be protected'(){
testHighlighting('trait T {<error descr="Trait methods are not allowed to be protected">protected</error> foo(){}}')
}
void 'test trait can implement numerous traits'() {
testHighlighting('''
trait A{}
trait B{}
trait D extends A {}
trait E implements A {}
trait F extends A implements B {}
trait G implements A, B {}
''')
}
}