revert parameter info fix, as it breaks completion hints behavior
[idea/community.git] / java / java-tests / testSrc / com / intellij / java / codeInsight / ParameterInfoTest.java
1 // Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package com.intellij.java.codeInsight;
3
4 import com.intellij.JavaTestUtil;
5 import com.intellij.codeInsight.AnnotationUtil;
6 import com.intellij.codeInsight.hint.ParameterInfoComponent;
7 import com.intellij.codeInsight.hint.api.impls.AnnotationParameterInfoHandler;
8 import com.intellij.codeInsight.hint.api.impls.MethodParameterInfoHandler;
9 import com.intellij.codeInsight.lookup.LookupElement;
10 import com.intellij.codeInsight.lookup.LookupElementPresentation;
11 import com.intellij.ide.highlighter.JavaFileType;
12 import com.intellij.lang.parameterInfo.CreateParameterInfoContext;
13 import com.intellij.lang.parameterInfo.ParameterInfoUIContextEx;
14 import com.intellij.openapi.actionSystem.IdeActions;
15 import com.intellij.openapi.util.Disposer;
16 import com.intellij.openapi.util.registry.Registry;
17 import com.intellij.psi.*;
18 import com.intellij.psi.infos.MethodCandidateInfo;
19 import com.intellij.psi.util.PsiTreeUtil;
20 import com.intellij.testFramework.LightProjectDescriptor;
21 import com.intellij.testFramework.fixtures.EditorHintFixture;
22 import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
23 import com.intellij.testFramework.utils.parameterInfo.MockCreateParameterInfoContext;
24 import com.intellij.testFramework.utils.parameterInfo.MockParameterInfoUIContext;
25 import com.intellij.testFramework.utils.parameterInfo.MockUpdateParameterInfoContext;
26 import com.intellij.util.ui.UIUtil;
27 import org.jetbrains.annotations.NotNull;
28
29 public class ParameterInfoTest extends LightCodeInsightFixtureTestCase {
30   @Override
31   protected String getBasePath() {
32     return JavaTestUtil.getRelativeJavaTestDataPath() + "/codeInsight/parameterInfo/";
33   }
34
35   public void testPrivateMethodOfEnclosingClass() { doTest(); }
36   public void testNotAccessible() { doTest(); }
37
38   @NotNull
39   @Override
40   protected LightProjectDescriptor getProjectDescriptor() {
41     return JAVA_8;
42   }
43
44   private void doTest() {
45     myFixture.configureByFile(getTestName(false) + ".java");
46
47     MethodParameterInfoHandler handler = new MethodParameterInfoHandler();
48     CreateParameterInfoContext context = new MockCreateParameterInfoContext(getEditor(), getFile());
49     PsiExpressionList list = handler.findElementForParameterInfo(context);
50     assertNotNull(list);
51     Object[] itemsToShow = context.getItemsToShow();
52     assertNotNull(itemsToShow);
53     assertTrue(itemsToShow.length > 0);
54   }
55
56   public void testParameterInfoDoesNotShowInternalJetbrainsAnnotations() {
57     myFixture.configureByText("x.java", "class X { void f(@org.intellij.lang.annotations.Flow int i) { f(<caret>0); }}");
58
59     CreateParameterInfoContext context = new MockCreateParameterInfoContext(getEditor(), getFile());
60     PsiMethod method = PsiTreeUtil.getParentOfType(getFile().findElementAt(context.getOffset()), PsiMethod.class);
61     assertNotNull(method);
62     MockParameterInfoUIContext<PsiMethod> uiContext = new MockParameterInfoUIContext<>(method);
63     String list = MethodParameterInfoHandler.updateMethodPresentation(method, PsiSubstitutor.EMPTY, uiContext);
64     assertEquals("int i", list);
65     PsiAnnotation[] annotations = AnnotationUtil.getAllAnnotations(method.getParameterList().getParameters()[0], false, null);
66     assertEquals(1, annotations.length);
67   }
68
69   public void testSelectionWithGenerics() {
70     doTest2CandidatesWithPreselection();
71   }
72
73   public void testOverloadWithVarargs() {
74     doTest2CandidatesWithPreselection();
75   }
76
77   public void testOverloadWithVarargsMultipleArgs() {
78     doTest2CandidatesWithPreselection();
79   }
80
81   public void testOverloadWithVarargsSingleArg() {
82     doTest2CandidatesWithPreselection();
83   }
84
85   public void testOverloadWithErrorOnTheTopLevel() {
86     doTest2CandidatesWithPreselection();
87     PsiElement elementAtCaret = myFixture.getFile().findElementAt(myFixture.getEditor().getCaretModel().getOffset());
88     PsiCall call = LambdaUtil.treeWalkUp(elementAtCaret);
89     assertNotNull(call);
90     //cache the type of first argument: if type is calculated by cached session of first (wrong) overload, then applicability check would fail
91     //applicability check itself takes into account only child constraints and thus won't see cached elements on top level, thus explicit type calculation
92     PsiType type = call.getArgumentList().getExpressions()[1].getType();
93     assertNotNull(type);
94     JavaResolveResult result = call.resolveMethodGenerics();
95     assertTrue(result instanceof MethodCandidateInfo);
96     assertTrue(((MethodCandidateInfo)result).isApplicable());
97   }
98
99   public void testOverloadWithVarargsArray() {
100     doTest2CandidatesWithPreselection();
101   }
102
103   public void testSuperConstructorCalls() {
104     EditorHintFixture hintFixture = new EditorHintFixture(getTestRootDisposable());
105     myFixture.configureByText("x.java",
106                               "class A {\n" +
107                               "       public A(String s, int... p) {}\n" +
108                               "   }\n" +
109                               "   class B extends A {\n" +
110                               "       public B() {\n" +
111                               "           super(<caret>\"a\", 1);\n" +
112                               "       }\n" +
113                               "   }");
114     myFixture.performEditorAction(IdeActions.ACTION_EDITOR_SHOW_PARAMETER_INFO);
115     UIUtil.dispatchAllInvocationEvents();
116     assertEquals("<html><b>String s</b>, int... p</html>", hintFixture.getCurrentHintText());
117   }
118
119   public void testPreselectionOfCandidatesInNestedMethod() {
120     myFixture.configureByFile(getTestName(false) + ".java");
121
122     MethodParameterInfoHandler handler = new MethodParameterInfoHandler();
123     CreateParameterInfoContext context = new MockCreateParameterInfoContext(getEditor(), getFile());
124     PsiExpressionList list = handler.findElementForParameterInfo(context);
125     assertNotNull(list);
126     Object[] itemsToShow = context.getItemsToShow();
127     assertNotNull(itemsToShow);
128     assertEquals(3, itemsToShow.length);
129     assertTrue(itemsToShow[0] instanceof MethodCandidateInfo);
130     ParameterInfoComponent.createContext(itemsToShow, getEditor(), handler, -1);
131     MockUpdateParameterInfoContext updateParameterInfoContext = updateParameterInfo(handler, list, itemsToShow);
132     assertTrue(updateParameterInfoContext.isUIComponentEnabled(0) ||
133                 updateParameterInfoContext.isUIComponentEnabled(1) ||
134                 updateParameterInfoContext.isUIComponentEnabled(2));
135   }
136
137   private void doTest2CandidatesWithPreselection() {
138     myFixture.configureByFile(getTestName(false) + ".java");
139
140     MethodParameterInfoHandler handler = new MethodParameterInfoHandler();
141     CreateParameterInfoContext context = new MockCreateParameterInfoContext(getEditor(), getFile());
142     PsiExpressionList list = handler.findElementForParameterInfo(context);
143     assertNotNull(list);
144     Object[] itemsToShow = context.getItemsToShow();
145     assertNotNull(itemsToShow);
146     assertEquals(2, itemsToShow.length);
147     assertTrue(itemsToShow[0] instanceof MethodCandidateInfo);
148     ParameterInfoComponent.createContext(itemsToShow, getEditor(), handler, -1);
149     MockUpdateParameterInfoContext updateParameterInfoContext = updateParameterInfo(handler, list, itemsToShow);
150     assertTrue(updateParameterInfoContext.isUIComponentEnabled(0) || updateParameterInfoContext.isUIComponentEnabled(1));
151   }
152
153   @NotNull
154   private MockUpdateParameterInfoContext updateParameterInfo(MethodParameterInfoHandler handler,
155                                                              PsiExpressionList list,
156                                                              Object[] itemsToShow) {
157     MockUpdateParameterInfoContext updateParameterInfoContext = new MockUpdateParameterInfoContext(getEditor(), getFile(), itemsToShow);
158     updateParameterInfoContext.setParameterOwner(list);
159     handler.updateParameterInfo(list, updateParameterInfoContext);
160     return updateParameterInfoContext;
161   }
162
163   public void testStopAtAccessibleStaticCorrectCandidate() {
164     myFixture.configureByFile(getTestName(false) + ".java");
165
166     MethodParameterInfoHandler handler = new MethodParameterInfoHandler();
167     CreateParameterInfoContext context = new MockCreateParameterInfoContext(getEditor(), getFile());
168     PsiExpressionList list = handler.findElementForParameterInfo(context);
169     assertNotNull(list);
170     Object[] itemsToShow = context.getItemsToShow();
171     assertNotNull(itemsToShow);
172     assertEquals(1, itemsToShow.length);
173     assertEquals(0, ((MethodCandidateInfo)itemsToShow[0]).getElement().getParameterList().getParametersCount());
174   }
175
176   public void testAfterGenericsInsideCall() {
177     myFixture.configureByFile(getTestName(false) + ".java");
178
179     MethodParameterInfoHandler handler = new MethodParameterInfoHandler();
180     CreateParameterInfoContext context = new MockCreateParameterInfoContext(getEditor(), getFile());
181     PsiExpressionList list = handler.findElementForParameterInfo(context);
182     assertNotNull(list);
183     Object[] itemsToShow = context.getItemsToShow();
184     assertNotNull(itemsToShow);
185     assertEquals(2, itemsToShow.length);
186     assertTrue(itemsToShow[0] instanceof MethodCandidateInfo);
187     PsiMethod method = ((MethodCandidateInfo)itemsToShow[0]).getElement();
188     ParameterInfoUIContextEx parameterContext = ParameterInfoComponent.createContext(itemsToShow, getEditor(), handler, 1);
189     parameterContext.setUIComponentEnabled(true);
190     PsiSubstitutor substitutor = ((MethodCandidateInfo)itemsToShow[0]).getSubstitutor();
191     String presentation = MethodParameterInfoHandler.updateMethodPresentation(method, substitutor, parameterContext);
192     assertEquals("<html>Class&lt;T&gt; type, <b>boolean tags</b></html>", presentation);
193   }
194
195   public void testNoParams() { doTestPresentation("<html>&lt;no parameters&gt;</html>", -1); }
196   public void testGenericsInsideCall() { doTestPresentation("<html>List&lt;String&gt; param</html>", -1); }
197   public void testGenericsOutsideCall() { doTestPresentation("<html>List&lt;String&gt; param</html>", -1); }
198   public void testIgnoreVarargs() { doTestPresentation("<html>Class&lt;T&gt; a, <b>Class&lt;? extends CharSequence&gt;... stopAt</b></html>", 1); }
199
200   private void doTestPresentation(String expectedString, int parameterIndex) {
201     myFixture.configureByFile(getTestName(false) + ".java");
202     String presentation = parameterPresentation(parameterIndex);
203     assertEquals(expectedString, presentation);
204   }
205
206   private String parameterPresentation(int parameterIndex) {
207     return parameterPresentation(0, parameterIndex);
208   }
209
210   private String parameterPresentation(int lineIndex, int parameterIndex) {
211     MethodParameterInfoHandler handler = new MethodParameterInfoHandler();
212     CreateParameterInfoContext context = createContext();
213     PsiExpressionList list = handler.findElementForParameterInfo(context);
214     assertNotNull(list);
215     Object[] itemsToShow = context.getItemsToShow();
216     assertNotNull(itemsToShow);
217     assertTrue(itemsToShow[lineIndex] instanceof MethodCandidateInfo);
218     PsiMethod method = ((MethodCandidateInfo)itemsToShow[lineIndex]).getElement();
219     ParameterInfoUIContextEx parameterContext = ParameterInfoComponent.createContext(itemsToShow, getEditor(), handler, parameterIndex);
220     PsiSubstitutor substitutor = ((MethodCandidateInfo)itemsToShow[lineIndex]).getSubstitutor();
221     return MethodParameterInfoHandler.updateMethodPresentation(method, substitutor, parameterContext);
222   }
223
224   private CreateParameterInfoContext createContext() {
225     int caretOffset = getEditor().getCaretModel().getOffset();
226     PsiExpressionList argList = PsiTreeUtil.findElementOfClassAtOffset(getFile(), caretOffset, PsiExpressionList.class, false);
227     return new MockCreateParameterInfoContext(getEditor(), getFile()) {
228       @Override
229       public int getParameterListStart() {
230         return argList == null ? caretOffset : argList.getTextRange().getStartOffset();
231       }
232     };
233   }
234
235   public void testAnnotationWithGenerics() {
236     myFixture.configureByFile(getTestName(false) + ".java");
237     String text = annoParameterPresentation();
238     assertEquals("<html>Class&lt;List&lt;String[]&gt;&gt; <b>value</b>()</html>", text);
239   }
240
241   private String annoParameterPresentation() {
242     AnnotationParameterInfoHandler handler = new AnnotationParameterInfoHandler();
243     CreateParameterInfoContext context = new MockCreateParameterInfoContext(getEditor(), getFile());
244     PsiAnnotationParameterList list = handler.findElementForParameterInfo(context);
245     assertNotNull(list);
246     Object[] itemsToShow = context.getItemsToShow();
247     assertNotNull(itemsToShow);
248     assertEquals(1, itemsToShow.length);
249     assertTrue(itemsToShow[0] instanceof PsiAnnotationMethod);
250     PsiAnnotationMethod method = (PsiAnnotationMethod)itemsToShow[0];
251     ParameterInfoUIContextEx parameterContext = ParameterInfoComponent.createContext(itemsToShow, getEditor(), handler, -1);
252     return AnnotationParameterInfoHandler.updateUIText(method, parameterContext);
253   }
254
255   public void testParameterAnnotation() {
256     myFixture.addClass("import java.lang.annotation.*;\n@Documented @Target({ElementType.PARAMETER}) @interface TA { }");
257     myFixture.configureByText("a.java", "class C {\n void m(@TA String s) { }\n void t() { m(<caret>\"test\"); }\n}");
258     assertEquals("<html>@TA String s</html>", parameterPresentation(-1));
259   }
260
261   public void testParameterUndocumentedAnnotation() {
262     myFixture.addClass("import java.lang.annotation.*;\n@Target({ElementType.PARAMETER}) @interface TA { }");
263     myFixture.configureByText("a.java", "class C {\n void m(@TA String s) { }\n void t() { m(<caret>\"test\"); }\n}");
264     assertEquals("<html>String s</html>", parameterPresentation(-1));
265   }
266
267   public void testParameterTypeAnnotation() {
268     myFixture.addClass("import java.lang.annotation.*;\n@Documented @Target({ElementType.PARAMETER, ElementType.TYPE_USE}) @interface TA { }");
269     myFixture.configureByText("a.java", "class C {\n void m(@TA String s) { }\n void t() { m(<caret>\"test\"); }\n}");
270     assertEquals("<html>@TA String s</html>", parameterPresentation(-1));
271   }
272
273   public void testParameterUndocumentedTypeAnnotation() {
274     myFixture.addClass("import java.lang.annotation.*;\n@Target({ElementType.PARAMETER, ElementType.TYPE_USE}) @interface TA { }");
275     myFixture.configureByText("a.java", "class C {\n void m(@TA String s) { }\n void t() { m(<caret>\"test\"); }\n}");
276     assertEquals("<html>@TA String s</html>", parameterPresentation(-1));
277   }
278
279   public void testHighlightMethodJustChosenInCompletion() {
280     myFixture.configureByText("a.java", "class Foo {" +
281                                         "{ bar<caret> }" +
282                                         "void bar(boolean a);" +
283                                         "void bar(String a);" +
284                                         "void bar(int a);" +
285                                         "void bar2(int a);" +
286                                         "}");
287     LookupElement[] elements = myFixture.completeBasic();
288     assertEquals("(String a)", LookupElementPresentation.renderElement(elements[1]).getTailText());
289     myFixture.getLookup().setCurrentItem(elements[1]);
290     myFixture.type('\n');
291
292     assertEquals("<html>boolean a</html>", parameterPresentation(0, -1));
293     assertEquals("<html>String a</html>", parameterPresentation(1, -1));
294     assertEquals("<html>int a</html>", parameterPresentation(2, -1));
295
296     checkHighlighted(1);
297   }
298
299   public void testHighlightConstructorJustChosenInCompletion() {
300     Registry.get("java.completion.show.constructors").setValue(true);
301     Disposer.register(myFixture.getTestRootDisposable(), () -> Registry.get("java.completion.show.constructors").setValue(false));
302
303     myFixture.addClass("class Bar {" +
304                        "Bar(boolean a);" +
305                        "Bar(String a);" +
306                        "Bar(int a);" +
307                        "} " +
308                        "class Bar2 {}");
309     myFixture.configureByText("a.java", "class Foo {{ new Bar<caret> }}");
310     LookupElement[] elements = myFixture.completeBasic();
311     assertEquals("(boolean a) (default package)", LookupElementPresentation.renderElement(elements[2]).getTailText());
312     myFixture.getLookup().setCurrentItem(elements[2]);
313     myFixture.type('\n');
314     myFixture.checkResult("class Foo {{ new Bar(<caret>) }}");
315
316     assertEquals("<html>boolean a</html>", parameterPresentation(0, -1));
317     assertEquals("<html>String a</html>", parameterPresentation(1, -1));
318     assertEquals("<html>int a</html>", parameterPresentation(2, -1));
319
320     checkHighlighted(0);
321   }
322
323   public void testNoStrikeoutForSingleDeprecatedMethod() {
324     myFixture.configureByText(JavaFileType.INSTANCE, "class C { void m() { System.runFinalizersOnExit(true<caret>); } }");
325     assertEquals("<html>boolean b</html>", parameterPresentation(-1));
326   }
327
328   public void testInferredWithVarargs() {
329     myFixture.configureByText(JavaFileType.INSTANCE, 
330                               "import java.util.*; class C { void m(Object objects[], List<Object> list) { Collections.addAll(<caret>list, objects);} }");
331     assertEquals("<html>Collection&lt;? super Object&gt; collection, @NotNull Object... ts</html>", parameterPresentation(-1));
332   }
333
334   private void checkHighlighted(int lineIndex) {
335     MethodParameterInfoHandler handler = new MethodParameterInfoHandler();
336     CreateParameterInfoContext context = createContext();
337     PsiExpressionList list = handler.findElementForParameterInfo(context);
338     Object[] itemsToShow = context.getItemsToShow();
339     assertEquals(itemsToShow[lineIndex], updateParameterInfo(handler, list, itemsToShow).getHighlightedParameter());
340   }
341
342   public void testTypeInvalidationByCompletion() {
343     myFixture.configureByFile(getTestName(false) + ".java");
344
345     MethodParameterInfoHandler handler = new MethodParameterInfoHandler();
346     CreateParameterInfoContext context = new MockCreateParameterInfoContext(getEditor(), getFile());
347     PsiExpressionList argList = handler.findElementForParameterInfo(context);
348     assertNotNull(argList);
349     Object[] items = context.getItemsToShow();
350     assertSize(2, items);
351     updateParameterInfo(handler, argList, items);
352     
353     myFixture.completeBasic();
354     myFixture.type('\n');
355
356     assertTrue(argList.isValid());
357     // items now contain references to invalid PSI
358     updateParameterInfo(handler, argList, items);
359     assertSize(2, context.getItemsToShow());
360     
361     myFixture.checkResultByFile(getTestName(false) + "_after.java");
362   }
363
364   public void _testHighlightCurrentParameterAfterTypingFirstArgumentOfThree() {
365     myFixture.configureByFile(getTestName(false) + ".java");
366
367     MethodParameterInfoHandler handler = new MethodParameterInfoHandler();
368     CreateParameterInfoContext context = new MockCreateParameterInfoContext(getEditor(), getFile());
369     PsiExpressionList argList = handler.findElementForParameterInfo(context);
370     assertNotNull(argList);
371     Object[] items = context.getItemsToShow();
372     assertSize(2, items);
373
374     MockUpdateParameterInfoContext updateContext = updateParameterInfo(handler, argList, items);
375     assertTrue(updateContext.isUIComponentEnabled(0));
376     assertTrue(updateContext.isUIComponentEnabled(1));
377     assertEquals(0, updateContext.getCurrentParameter());
378
379     myFixture.type("1, ");
380     PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
381     handler.updateParameterInfo(argList, updateContext);
382     assertFalse(updateContext.isUIComponentEnabled(0));
383     assertTrue(updateContext.isUIComponentEnabled(1));
384     assertEquals(1, updateContext.getCurrentParameter());
385   }
386
387 }