unresolved 'name' replaced by 'foo' in test to ensure that it won't appear as 'dynami...
[idea/community.git] / plugins / groovy / test / org / jetbrains / plugins / groovy / lang / resolve / TypeInferenceTest.groovy
1 /*
2  * Copyright 2000-2014 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.jetbrains.plugins.groovy.lang.resolve
17
18 import com.intellij.psi.PsiIntersectionType
19 import com.intellij.psi.PsiReference
20 import com.intellij.psi.PsiType
21 import org.jetbrains.plugins.groovy.lang.psi.GroovyFile
22 import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap
23 import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration
24 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrAssignmentExpression
25 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression
26 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression
27 import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType
28
29 import static com.intellij.psi.CommonClassNames.*
30
31 /**
32  * @author ven
33  */
34 public class TypeInferenceTest extends TypeInferenceTestBase {
35
36   public void testTryFinallyFlow() {
37     GrReferenceExpression ref = (GrReferenceExpression)configureByFile("tryFinallyFlow/A.groovy").element;
38     final PsiType type = ref.type;
39     assertTrue(type instanceof PsiIntersectionType);
40     final PsiType[] conjuncts = ((PsiIntersectionType)type).conjuncts;
41     assertEquals(conjuncts.length, 2);
42   }
43
44   public void testTryFinallyFlow1() {
45     GrReferenceExpression ref = (GrReferenceExpression)configureByFile("tryFinallyFlow1/A.groovy").element;
46     final PsiType type = ref.type;
47     assertNotNull(type);
48     assertTrue(type.equalsToText("java.lang.Integer"));
49   }
50
51   public void testTryFinallyFlow2() {
52     GrReferenceExpression ref = (GrReferenceExpression)configureByFile("tryFinallyFlow2/A.groovy").element;
53     final PsiType type = ref.type;
54     assertNotNull(type);
55     assertTrue(type.equalsToText("java.lang.Integer"));
56   }
57
58   public void testThrowVariable() {
59     GrReferenceExpression ref = (GrReferenceExpression)configureByFile("throwVariable/A.groovy").element;
60     final PsiType type = ref.type;
61     assertNotNull(type);
62     assertEquals("java.lang.Exception", type.canonicalText);
63   }
64
65   public void testGrvy852() {
66     GrReferenceExpression ref = (GrReferenceExpression)configureByFile("grvy852/A.groovy").element;
67     final PsiType type = ref.type;
68     assertNotNull(type);
69     assertEquals("java.lang.Object", type.canonicalText);
70   }
71
72   public void testGenericMethod() {
73     GrReferenceExpression ref = (GrReferenceExpression)configureByFile("genericMethod/A.groovy").element;
74     final PsiType type = ref.type;
75     assertNotNull(type);
76     assertEquals("java.util.List<java.lang.String>", type.canonicalText);
77   }
78
79   public void testCircular() {
80     GrReferenceExpression ref = (GrReferenceExpression)configureByFile("circular/A.groovy").element;
81     assertNull(ref.type);
82   }
83
84   public void testCircular1() {
85     GrReferenceExpression ref = (GrReferenceExpression)configureByFile("circular1/A.groovy").element;
86     assertNull(ref.type);
87   }
88
89   public void testClosure() {
90     GrReferenceExpression ref = (GrReferenceExpression)configureByFile("closure/A.groovy").element;
91     assertNotNull(ref.type);
92   }
93
94   public void testClosure1() {
95     GrReferenceExpression ref = (GrReferenceExpression)configureByFile("closure1/A.groovy").element;
96     assertTrue(ref.type.equalsToText("java.lang.Integer"));
97   }
98
99   public void testClosure2() {
100     GrReferenceExpression ref = (GrReferenceExpression)configureByFile("closure2/A.groovy").element;
101     assertTrue(ref.type.equalsToText("java.lang.Integer"));
102   }
103
104   public void testGrvy1209() {
105     GrReferenceExpression ref = (GrReferenceExpression)configureByFile("grvy1209/A.groovy").element;
106     assertTrue(ref.type.equalsToText("java.lang.String"));
107   }
108
109   public void testLeastUpperBoundClosureType() {
110     GrReferenceExpression ref = (GrReferenceExpression)configureByFile("leastUpperBoundClosureType/A.groovy").element;
111     assertInstanceOf(ref.type, GrClosureType.class);
112   }
113
114   public void testJavaLangClassType() {
115     final GrReferenceExpression ref = (GrReferenceExpression)configureByFile("javaLangClassType/A.groovy").element;
116     assertEquals("java.lang.String", ref.type.canonicalText);
117   }
118
119   public void testGenericWildcard() {
120     final GrReferenceExpression ref = (GrReferenceExpression)configureByFile("genericWildcard/A.groovy").element;
121     assertEquals("A<Base>", ref.type.canonicalText);
122   }
123
124   public void testArrayLikeAccessWithIntSequence() {
125     final GrReferenceExpression ref = (GrReferenceExpression)configureByFile("arrayLikeAccessWithIntSequence/A.groovy").element;
126     assertEquals("java.util.List<java.lang.Integer>", ref.type.canonicalText);
127   }
128
129   public void testArrayAccess() {
130     final GrReferenceExpression ref = (GrReferenceExpression)configureByFile("arrayAccess/A.groovy");
131     assertEquals(JAVA_LANG_STRING, ref.type.canonicalText);
132   }
133
134   public void testReturnTypeByTailExpression() {
135     final GrReferenceExpression ref = (GrReferenceExpression)configureByFile("returnTypeByTailExpression/A.groovy");
136     assertEquals(JAVA_LANG_STRING, ref.type.canonicalText);
137   }
138
139   public void testParameterWithBuiltinType() {
140     GrReferenceExpression refExpr = (GrReferenceExpression)configureByFile("parameterWithBuiltinType/A.groovy");
141     assertEquals("java.lang.Integer", refExpr.type.canonicalText);
142   }
143
144   public void testRawTypeInReturnExpression() {
145     assertNotNull(resolve("A.groovy"));
146   }
147
148   public void testMethodCallInvokedOnArrayAccess() {
149     final GrReferenceExpression reference = (GrReferenceExpression)configureByFile("A.groovy");
150     assertNotNull(reference)
151     assertNotNull(reference.type)
152     assertEquals("java.lang.Integer", reference.type.canonicalText);
153   }
154
155   private void assertTypeEquals(String expected, String fileName) {
156     final PsiReference ref = configureByFile(getTestName(true) + "/" + fileName);
157     assertInstanceOf(ref, GrReferenceExpression.class);
158     final PsiType type = ((GrReferenceExpression)ref).type;
159     assertNotNull(type);
160     assertEquals(expected, type.canonicalText);
161   }
162
163   public void testTypeOfGroupBy() {
164     assertTypeEquals("java.util.Map<java.lang.Integer,java.util.List<java.lang.Integer>>", "A.groovy");
165   }
166
167   public void testConditionalExpressionWithNumericTypes() {
168     assertTypeEquals("java.lang.Number", "A.groovy");
169   }
170
171   public void testImplicitCallMethod() {
172     assertEquals("java.lang.String", ((GrExpression)configureByFile("A.groovy")).type.canonicalText);
173   }
174
175   public void testTupleWithNullInIt() {
176     assertTypeEquals("java.util.ArrayList", "A.groovy");
177   }
178
179   public void testImplicitlyReturnedMethodCall() {
180     assertTypeEquals("java.util.Map<BasicRange,java.util.Map<BasicRange,java.lang.Double>>", "A.groovy");
181   }
182
183   public void testInferWithClosureType() {
184     assertTypeEquals("java.util.Date", "A.groovy");
185   }
186
187   public void testPlusEquals1() {
188     assertTypeEquals("Test", "A.groovy");
189   }
190
191   public void testPlusEquals2() {
192     assertTypeEquals("java.lang.String", "A.groovy");
193   }
194
195   public void testPlusEquals3() {
196     assertTypeEquals("java.lang.String", "A.groovy");
197   }
198
199   public void testPlusEqualsClosure() {
200     assertTypeEquals("java.lang.String", "A.groovy");
201   }
202
203   public void testGetAtClosure() {
204     assertTypeEquals("java.lang.String", "A.groovy");
205   }
206
207   public void testPreferMethodOverloader() {
208     assertTypeEquals("java.lang.String", "A.groovy");
209   }
210
211   public void testSafeInvocationInClassQualifier() {
212     assertTypeEquals("java.lang.Class", "SafeInvocationInClassQualifier.groovy");
213   }
214
215   public void testReturnTypeFromMethodClosure() {
216     assertTypeEquals("java.lang.String", "A.groovy");
217   }
218
219   public void testNoSOF() {
220     final PsiReference ref = configureByFile(getTestName(true) + "/A.groovy");
221     assertInstanceOf(ref, GrReferenceExpression.class);
222     final PsiType type = ((GrReferenceExpression)ref).type;
223     assertTrue(true); //test just should not fail with SOF exception
224   }
225
226   public void testTraditionalForVar() {
227     assertTypeEquals(JAVA_LANG_INTEGER, "A.groovy");
228   }
229
230   public void testIncMethod() {
231     assertTypeEquals(JAVA_LANG_INTEGER, "A.groovy");
232   }
233
234   public void testDGMFind() {
235     assertTypeEquals("java.io.File", "a.groovy");
236   }
237
238   public void testMultiTypeParameter() {
239     assertTypeEquals("X | Y", "a.groovy");
240   }
241
242   public void testTypeArgsInAccessor() {
243     assertTypeEquals("Foo<java.lang.String>", "a.groovy");
244   }
245
246   public void testSingleParameterInStringInjection() {
247     assertTypeEquals("java.io.StringWriter", "a.groovy");
248   }
249
250   void testIndexPropertyPlusAssigned() {
251     GroovyFile file = myFixture.configureByText('a.groovy', '''
252 class X {
253     def putAt(String s, X x){new Date()}
254
255     def getAt(String s) {new X()}
256
257     def plus(int i) {this}
258 }
259
260 map = new X()
261
262 map['i'] += 2
263 ''') as GroovyFile
264     GrAssignmentExpression assignment = file.topStatements[2] as GrAssignmentExpression
265     assertType("X", assignment.type)
266   }
267
268   void testAllTypeParamsAreSubstituted() {
269     assertTypeEquals('java.util.Map', 'a.groovy')
270   }
271
272   void testDiamond() {
273     GroovyFile file = myFixture.configureByText('a.groovy', '''
274 List<String> list = new ArrayList<>()
275 List<Integer> l2
276
277 (list, l2) = [new ArrayList<>(), new ArrayList<>()]
278 ''') as GroovyFile
279
280     def statements = file.topStatements
281
282     assertEquals('java.util.ArrayList<java.lang.String>', (statements[0] as GrVariableDeclaration).variables[0].initializerGroovy.type.canonicalText)
283     assertEquals('java.util.ArrayList<java.lang.String>', ((statements[2] as GrAssignmentExpression).RValue as GrListOrMap).initializers[0].type.canonicalText)
284     assertEquals('java.util.ArrayList<java.lang.Integer>', ((statements[2] as GrAssignmentExpression).RValue as GrListOrMap).initializers[1].type.canonicalText)
285   }
286
287   void testWildCardsNormalized() {
288     assertTypeEquals(Object.canonicalName, 'a.groovy')
289   }
290
291   void testIndexPropertyInLHS() {
292     assertTypeEquals("java.util.Map", 'a.groovy')
293   }
294
295   void testEmptyMapTypeArgs() {
296     myFixture.configureByText('a.groovy', '''
297 class X<A, B> implements Map<A, B> {}
298
299 X<String, Integer> x = [:]
300 ''')
301
302     def type = ((myFixture.file as GroovyFile).statements[0] as GrVariableDeclaration).variables[0].initializerGroovy.type
303     assertEquals("java.util.Map<java.lang.String,java.lang.Integer>", type.canonicalText)
304   }
305
306   void testRawCollectionsInCasts() {
307     doTest('''\
308 String[] a = ["a"]
309 def b = a as ArrayList
310 def cc = b[0]
311 print c<caret>c''', String.canonicalName)
312   }
313
314   void testFind() {
315     doTest('''\
316 def arr =  ['1', '2', '3'] as String[]
317 def found = arr.find({it=='1'})
318 print fou<caret>nd''', String.canonicalName)
319   }
320
321   void testFindAll() {
322     doTest('''\
323 def arr =  ['1', '2', '3']
324 def found = arr.findAll({it==1})
325 print fou<caret>nd''', 'java.util.ArrayList<java.lang.String>')
326   }
327
328   void testFindAllForArray() {
329     doTest('''\
330 def arr =  ['1', '2', '3'] as String[]
331 def found = arr.findAll({it==1})
332 print fou<caret>nd''', 'java.util.ArrayList<java.lang.String>')
333   }
334
335   void testFindAllForSet() {
336     myFixture.addClass('''\
337 package java.util;
338 class HashSet<T> implements Set<T> {} ''')
339     doTest('''\
340 def arr =  ['1', '2', '3'] as Set<String>
341 def found = arr.findAll({it==1})
342 print fou<caret>nd''', 'java.util.HashSet<java.lang.String>')
343   }
344
345   void testInferArgumentTypeFromMethod1() {
346     doTest('''\
347 def bar(String s) {}
348
349 def foo(Integer a) {
350   while(true) {
351     bar(a)
352     <caret>a.substring(2)
353   }
354 }
355 ''', '[java.lang.Integer,java.lang.String]')
356   }
357
358   void testInferArgumentTypeFromMethod2() {
359     doTest('''\
360 def bar(String s) {}
361
362 def foo(Integer a) {
363     bar(a)
364     <caret>a.substring(2)
365 }
366 ''', '[java.lang.Integer,java.lang.String]')
367   }
368
369   void testInferArgumentTypeFromMethod3() {
370     doTest('''\
371 def bar(String s) {}
372
373 def foo(Integer a) {
374     bar(a)
375     print a
376     <caret>a.substring(2)
377 }
378 ''', '[java.lang.Integer,java.lang.String]')
379   }
380
381   void testInferArgumentTypeFromMethod4() {
382     doTest('''\
383 def bar(String s) {}
384
385 def foo(Integer a) {
386   while(true) {
387     bar(a)
388     print a
389     <caret>a.substring(2)
390   }
391 }
392 ''', '[java.lang.Integer,java.lang.String]')
393   }
394
395   void testEmptyListOrListWithGenerics() {
396     doTest('''\
397 def list = cond ? [1, 2, 3] : []
398 print lis<caret>t
399 ''', "$JAVA_UTIL_LIST<$JAVA_LANG_INTEGER>")
400   }
401
402   void testEmptyListOrListWithGenerics2() {
403     doTest('''\
404 def List<Integer> foo(){}
405 def list = cond ? foo() : []
406 print lis<caret>t
407 ''', "$JAVA_UTIL_LIST<$JAVA_LANG_INTEGER>")
408   }
409
410   void testEmptyMapOrMapWithGenerics() {
411     doTest('''\
412 def map = cond ? [1:'a', 2:'a', 3:'a'] : [:]
413 print ma<caret>p
414 ''', "$JAVA_UTIL_MAP<$JAVA_LANG_STRING, $JAVA_LANG_STRING>")
415   }
416
417   void testEmptyMapOrMapWithGenerics2() {
418     doTest('''\
419 def Map<String, String> foo(){}
420 def map = cond ? foo() : [:]
421 print ma<caret>p
422 ''', "$JAVA_UTIL_MAP<$JAVA_LANG_STRING,$JAVA_LANG_STRING>")
423   }
424
425   void testSpread1() {
426     myFixture.addClass('''\
427 class A {
428   String getString() {return "a";}
429 }''')
430     doTest('''\
431 [new A()].stri<caret>ng
432 ''', "$JAVA_UTIL_ARRAY_LIST<$JAVA_LANG_STRING>")
433   }
434
435   void testSpread2() {
436
437     myFixture.addClass('''\
438 class A {
439   String getString() {return "a";}
440 }''')
441     doTest('''\
442 class Cat {
443   static getFoo(String b) {2}
444 }
445 use(Cat) {
446   [new A()].string.fo<caret>o
447 }
448 ''', "$JAVA_UTIL_ARRAY_LIST<$JAVA_LANG_INTEGER>")
449   }
450
451   void testSpread3() {
452     myFixture.addClass('''\
453 class A {
454   String getString() {return "a";}
455 }''')
456     doTest('''\
457 [[new A()]].stri<caret>ng
458 ''', "$JAVA_UTIL_ARRAY_LIST<$JAVA_UTIL_ARRAY_LIST<$JAVA_LANG_STRING>>")
459   }
460
461   void testSpread4() {
462     myFixture.addClass('''\
463 class A {
464   String getString() {return "a";}
465 }''')
466     doTest('''\
467 class Cat {
468   static getFoo(String b) {2}
469 }
470
471 use(Cat){
472   [[new A()]].string.fo<caret>o
473 }
474 ''', "$JAVA_UTIL_ARRAY_LIST<$JAVA_UTIL_ARRAY_LIST<$JAVA_LANG_INTEGER>>")
475   }
476
477   void testInstanceOfInferring1() {
478     doTest('''\
479 def bar(oo) {
480   boolean b = oo instanceof String || oo != null
481   o<caret>o
482 }
483 ''', null)
484   }
485
486   void testInstanceOfInferring2() {
487     doTest('''\
488 def bar(oo) {
489   boolean b = oo instanceof String || o<caret>o != null
490   oo
491 }
492 ''', null)
493   }
494
495   void testInstanceOfInferring3() {
496     doTest('''\
497 def bar(oo) {
498   boolean b = oo instanceof String && o<caret>o != null
499   oo
500 }
501 ''', String.canonicalName)
502   }
503
504   void testInstanceOfInferring4() {
505     doTest('''\
506 def bar(oo) {
507   boolean b = oo instanceof String && oo != null
508   o<caret>o
509 }
510 ''', null)
511   }
512
513   void testInstanceOfInferring5() {
514     doTest('''\
515 def foo(def oo) {
516   if (oo instanceof String && oo instanceof CharSequence) {
517     oo
518   }
519   else {
520     o<caret>o
521   }
522
523 }
524 ''', null)
525   }
526
527   void testInstanceOfInferring6() {
528     doTest('''\
529 def foo(bar) {
530   if (!(bar instanceof String) && bar instanceof Runnable) {
531     ba<caret>r
532   }
533 }''', 'java.lang.Runnable')
534   }
535
536   void testInString() {
537     doTest '''\
538 def foo(ii) {
539   if (ii in String)
540     print i<caret>i
541 }''', 'java.lang.String'
542   }
543
544   void testIndexProperty() {
545     doTest('''\
546 private void getCommonAncestor() {
547     def c1 = [new File('a')]
548     for (int i = 0; i < 2; i++) {
549         if (c1[i] != null) break
550         def cur = c1[i]
551         print cu<caret>r
552     }
553 }
554 ''', 'java.io.File')
555
556   }
557
558   void testWildcardClosureParam() {
559     doTest('''\
560 class Tx {
561     def methodOfT() {}
562 }
563
564 def method(List<? extends Tx> t) {
565     t.collect { print i<caret>t }
566 }
567 ''', 'Tx')
568   }
569
570   void testAssert() {
571     doTest('''\
572 def foo(def var) {
573   assert var instanceof String
574   va<caret>r.isEmpty()
575 }
576 ''', 'java.lang.String')
577   }
578
579   void testUnresolvedSpread() {
580     doTest('''\
581 def xxx = abc*.foo
582 print xx<caret>x''', 'java.util.List')
583   }
584
585   void testThisInCategoryClass() {
586     doTest('''\
587 class Cat {}
588
589 @groovy.lang.Category(Cat)
590 class Any {
591   void foo() {
592     print th<caret>is
593   }
594 }
595 ''', 'Cat')
596   }
597
598   void testNormalizeTypeFromMap() {
599     doTest('''\
600         def pp = new HashMap<?, ?>().a
601         print p<caret>p
602 ''', 'java.lang.Object')
603   }
604
605   void testUnary() {
606     doExprTest('~/abc/', 'java.util.regex.Pattern')
607   }
608
609   void testUnary2() {
610     doExprTest('-/abc/', null)
611   }
612
613   void testUnary3() {
614     doExprTest('''
615       class A {
616         def bitwiseNegate() {'abc'}
617       }
618       ~new A()
619 ''', 'java.lang.String')
620   }
621
622   void testPlus1() {
623     doExprTest('2+2', 'java.lang.Integer')
624   }
625
626   void testPlus2() {
627     doExprTest('2f+2', 'java.lang.Double')
628   }
629
630   void testPlus3() {
631     doExprTest('2f+2f', 'java.lang.Double')
632   }
633
634   void testPlus4() {
635     doExprTest('2.5+2', 'java.math.BigDecimal')
636   }
637
638   void testMultiply1() {
639     doExprTest('2*2', 'java.lang.Integer')
640   }
641
642   void testMultiply2() {
643     doExprTest('2f*2f', 'java.lang.Double')
644   }
645
646   void testMultiply3() {
647     doExprTest('2d*2d', 'java.lang.Double')
648   }
649
650   void testMultiply4() {
651     doExprTest('2.4*2', 'java.math.BigDecimal')
652   }
653
654   void testMultiply5() {
655     doExprTest('((byte)2)*((byte)2)', 'java.lang.Integer')
656   }
657
658   void testMultiply6() {
659     doExprTest('"abc"*"cde"', 'java.lang.String') //expected number as a right operand
660   }
661
662   void testMultiply7() {
663     doExprTest('''
664       class A {
665         def multiply(A a) {new B()}
666       }
667       class B{}
668       new A()*new A()
669 ''', 'B')
670   }
671
672   void testMultiply8() {
673     doExprTest('''
674       class A { }
675       new A()*new A()
676 ''', null)
677   }
678
679   void testDiv1() {
680     doExprTest('1/2', 'java.math.BigDecimal')
681   }
682
683   void testDiv2() {
684     doExprTest('1/2.4', 'java.math.BigDecimal')
685   }
686
687   void testDiv3() {
688     doExprTest('1d/2', 'java.lang.Double')
689   }
690
691   void testDiv4() {
692     doExprTest('1f/2', 'java.lang.Double')
693   }
694
695   void testDiv5() {
696     doExprTest('1f/2.4', 'java.lang.Double')
697   }
698
699   void testRecursionWithMaps() {
700     doTest('''
701 def foo(Map map) {
702   while(true)
703     ma<caret>p = [a:map]
704 }
705 ''', 'java.util.Map<java.lang.String, java.util.Map>')
706   }
707
708   void testRecursionWithLists() {
709     doTest('''
710 def foo(List list) {
711   while(true)
712     lis<caret>t = [list]
713 }
714 ''', 'java.util.ArrayList<java.util.List>')
715   }
716
717 }