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;
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;
29 public class ParameterInfoTest extends LightCodeInsightFixtureTestCase {
31 protected String getBasePath() {
32 return JavaTestUtil.getRelativeJavaTestDataPath() + "/codeInsight/parameterInfo/";
35 public void testPrivateMethodOfEnclosingClass() { doTest(); }
36 public void testNotAccessible() { doTest(); }
40 protected LightProjectDescriptor getProjectDescriptor() {
44 private void doTest() {
45 myFixture.configureByFile(getTestName(false) + ".java");
47 MethodParameterInfoHandler handler = new MethodParameterInfoHandler();
48 CreateParameterInfoContext context = new MockCreateParameterInfoContext(getEditor(), getFile());
49 PsiExpressionList list = handler.findElementForParameterInfo(context);
51 Object[] itemsToShow = context.getItemsToShow();
52 assertNotNull(itemsToShow);
53 assertTrue(itemsToShow.length > 0);
56 public void testParameterInfoDoesNotShowInternalJetbrainsAnnotations() {
57 myFixture.configureByText("x.java", "class X { void f(@org.intellij.lang.annotations.Flow int i) { f(<caret>0); }}");
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);
69 public void testSelectionWithGenerics() {
70 doTest2CandidatesWithPreselection();
73 public void testOverloadWithVarargs() {
74 doTest2CandidatesWithPreselection();
77 public void testOverloadWithVarargsMultipleArgs() {
78 doTest2CandidatesWithPreselection();
81 public void testOverloadWithVarargsSingleArg() {
82 doTest2CandidatesWithPreselection();
85 public void testOverloadWithErrorOnTheTopLevel() {
86 doTest2CandidatesWithPreselection();
87 PsiElement elementAtCaret = myFixture.getFile().findElementAt(myFixture.getEditor().getCaretModel().getOffset());
88 PsiCall call = LambdaUtil.treeWalkUp(elementAtCaret);
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();
94 JavaResolveResult result = call.resolveMethodGenerics();
95 assertTrue(result instanceof MethodCandidateInfo);
96 assertTrue(((MethodCandidateInfo)result).isApplicable());
99 public void testOverloadWithVarargsArray() {
100 doTest2CandidatesWithPreselection();
103 public void testSuperConstructorCalls() {
104 EditorHintFixture hintFixture = new EditorHintFixture(getTestRootDisposable());
105 myFixture.configureByText("x.java",
107 " public A(String s, int... p) {}\n" +
109 " class B extends A {\n" +
111 " super(<caret>\"a\", 1);\n" +
114 myFixture.performEditorAction(IdeActions.ACTION_EDITOR_SHOW_PARAMETER_INFO);
115 UIUtil.dispatchAllInvocationEvents();
116 assertEquals("<html><b>String s</b>, int... p</html>", hintFixture.getCurrentHintText());
119 public void testPreselectionOfCandidatesInNestedMethod() {
120 myFixture.configureByFile(getTestName(false) + ".java");
122 MethodParameterInfoHandler handler = new MethodParameterInfoHandler();
123 CreateParameterInfoContext context = new MockCreateParameterInfoContext(getEditor(), getFile());
124 PsiExpressionList list = handler.findElementForParameterInfo(context);
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));
137 private void doTest2CandidatesWithPreselection() {
138 myFixture.configureByFile(getTestName(false) + ".java");
140 MethodParameterInfoHandler handler = new MethodParameterInfoHandler();
141 CreateParameterInfoContext context = new MockCreateParameterInfoContext(getEditor(), getFile());
142 PsiExpressionList list = handler.findElementForParameterInfo(context);
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));
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;
163 public void testStopAtAccessibleStaticCorrectCandidate() {
164 myFixture.configureByFile(getTestName(false) + ".java");
166 MethodParameterInfoHandler handler = new MethodParameterInfoHandler();
167 CreateParameterInfoContext context = new MockCreateParameterInfoContext(getEditor(), getFile());
168 PsiExpressionList list = handler.findElementForParameterInfo(context);
170 Object[] itemsToShow = context.getItemsToShow();
171 assertNotNull(itemsToShow);
172 assertEquals(1, itemsToShow.length);
173 assertEquals(0, ((MethodCandidateInfo)itemsToShow[0]).getElement().getParameterList().getParametersCount());
176 public void testAfterGenericsInsideCall() {
177 myFixture.configureByFile(getTestName(false) + ".java");
179 MethodParameterInfoHandler handler = new MethodParameterInfoHandler();
180 CreateParameterInfoContext context = new MockCreateParameterInfoContext(getEditor(), getFile());
181 PsiExpressionList list = handler.findElementForParameterInfo(context);
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<T> type, <b>boolean tags</b></html>", presentation);
195 public void testNoParams() { doTestPresentation("<html><no parameters></html>", -1); }
196 public void testGenericsInsideCall() { doTestPresentation("<html>List<String> param</html>", -1); }
197 public void testGenericsOutsideCall() { doTestPresentation("<html>List<String> param</html>", -1); }
198 public void testIgnoreVarargs() { doTestPresentation("<html>Class<T> a, <b>Class<? extends CharSequence>... stopAt</b></html>", 1); }
200 private void doTestPresentation(String expectedString, int parameterIndex) {
201 myFixture.configureByFile(getTestName(false) + ".java");
202 String presentation = parameterPresentation(parameterIndex);
203 assertEquals(expectedString, presentation);
206 private String parameterPresentation(int parameterIndex) {
207 return parameterPresentation(0, parameterIndex);
210 private String parameterPresentation(int lineIndex, int parameterIndex) {
211 MethodParameterInfoHandler handler = new MethodParameterInfoHandler();
212 CreateParameterInfoContext context = createContext();
213 PsiExpressionList list = handler.findElementForParameterInfo(context);
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);
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()) {
229 public int getParameterListStart() {
230 return argList == null ? caretOffset : argList.getTextRange().getStartOffset();
235 public void testAnnotationWithGenerics() {
236 myFixture.configureByFile(getTestName(false) + ".java");
237 String text = annoParameterPresentation();
238 assertEquals("<html>Class<List<String[]>> <b>value</b>()</html>", text);
241 private String annoParameterPresentation() {
242 AnnotationParameterInfoHandler handler = new AnnotationParameterInfoHandler();
243 CreateParameterInfoContext context = new MockCreateParameterInfoContext(getEditor(), getFile());
244 PsiAnnotationParameterList list = handler.findElementForParameterInfo(context);
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);
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));
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));
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));
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));
279 public void testHighlightMethodJustChosenInCompletion() {
280 myFixture.configureByText("a.java", "class Foo {" +
282 "void bar(boolean a);" +
283 "void bar(String a);" +
285 "void bar2(int a);" +
287 LookupElement[] elements = myFixture.completeBasic();
288 assertEquals("(String a)", LookupElementPresentation.renderElement(elements[1]).getTailText());
289 myFixture.getLookup().setCurrentItem(elements[1]);
290 myFixture.type('\n');
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));
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));
303 myFixture.addClass("class Bar {" +
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>) }}");
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));
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));
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<? super Object> collection, @NotNull Object... ts</html>", parameterPresentation(-1));
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());
342 public void testTypeInvalidationByCompletion() {
343 myFixture.configureByFile(getTestName(false) + ".java");
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);
353 myFixture.completeBasic();
354 myFixture.type('\n');
356 assertTrue(argList.isValid());
357 // items now contain references to invalid PSI
358 updateParameterInfo(handler, argList, items);
359 assertSize(2, context.getItemsToShow());
361 myFixture.checkResultByFile(getTestName(false) + "_after.java");
364 public void _testHighlightCurrentParameterAfterTypingFirstArgumentOfThree() {
365 myFixture.configureByFile(getTestName(false) + ".java");
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);
374 MockUpdateParameterInfoContext updateContext = updateParameterInfo(handler, argList, items);
375 assertTrue(updateContext.isUIComponentEnabled(0));
376 assertTrue(updateContext.isUIComponentEnabled(1));
377 assertEquals(0, updateContext.getCurrentParameter());
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());