diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java index 9e6ea841a280..deeed49144b2 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -754,8 +754,13 @@ class ControlFlowAnalyzer extends JavaElementVisitor { @Override public void visitTryStatement(PsiTryStatement statement) { startElement(statement); - PsiCodeBlock finallyBlock = statement.getFinallyBlock(); + PsiResourceList resourceList = statement.getResourceList(); + if (resourceList != null) { + resourceList.accept(this); + } + + PsiCodeBlock finallyBlock = statement.getFinallyBlock(); if (finallyBlock != null) { myCatchStack.push(new CatchDescriptor(finallyBlock)); } @@ -817,6 +822,21 @@ class ControlFlowAnalyzer extends JavaElementVisitor { if (catchBlock != null) catchBlock.accept(this); } + @Override + public void visitResourceList(PsiResourceList resourceList) { + startElement(resourceList); + + List variables = resourceList.getResourceVariables(); + for (PsiResourceVariable variable : variables) { + PsiExpression initializer = variable.getInitializer(); + if (initializer != null) { + initializeVariable(variable, initializer); + } + } + + finishElement(resourceList); + } + @Override public void visitWhileStatement(PsiWhileStatement statement) { startElement(statement); diff --git a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java index 5b31aa91021b..27ed039a7b16 100644 --- a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java @@ -589,7 +589,10 @@ public class LambdaUtil { methodReferenceExpression.process(classRef, substRef); final MethodSignature signature1 = method.getSignature(resolveResult.getSubstitutor()); - final MethodSignature signature2 = ((PsiMethod)resolve).getSignature(substRef.get()); + PsiSubstitutor subst = PsiSubstitutor.EMPTY; + subst = subst.putAll(result.getSubstitutor()); + subst = subst.putAll(substRef.get()); + final MethodSignature signature2 = ((PsiMethod)resolve).getSignature(subst); if (areAcceptable(signature1, signature2, classRef.get(), substRef.get(), ((PsiMethod)resolve).isVarArgs())) return true; } } @@ -636,7 +639,7 @@ public class LambdaUtil { for (int i = 0; i < min; i++) { final PsiType type1 = signatureParameterTypes1[offset + i]; final PsiType type2 = isVarargs && i == min - 1 ? ((PsiArrayType)signatureParameterTypes2[i]).getComponentType() : signatureParameterTypes2[i]; - if (!GenericsUtil.eliminateWildcards(psiSubstitutor.substitute(type1)).equals(GenericsUtil.eliminateWildcards(type2))) { + if (!TypeConversionUtil.isAssignable(type2, psiSubstitutor.substitute(GenericsUtil.eliminateWildcards(type1)))) { return false; } } diff --git a/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java b/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java index 59e4665b235f..cf321a385570 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java @@ -797,6 +797,21 @@ public class TypeConversionUtil { } public static boolean boxingConversionApplicable(final PsiType left, final PsiType right) { + if (right instanceof PsiMethodReferenceType) { + final JavaResolveResult result = ((PsiMethodReferenceType)right).getExpression().advancedResolve(false); + PsiElement element = result.getElement(); + final PsiClassType.ClassResolveResult functionalInterfaceResult = PsiUtil.resolveGenericsClassInType(left); + final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceResult); + if (element instanceof PsiMethod && interfaceMethod != null) { + final PsiType[] parameterTypes = ((PsiMethod)element).getSignature(result.getSubstitutor()).getParameterTypes(); + final PsiType[] argTypes = interfaceMethod.getSignature(functionalInterfaceResult.getSubstitutor()).getParameterTypes(); + if (parameterTypes.length != argTypes.length) return false; + for (int i = 0; i < parameterTypes.length; i++) { + if (boxingConversionApplicable(parameterTypes[i], argTypes[i])) return true; + } + } + } + if (left instanceof PsiPrimitiveType && !PsiType.NULL.equals(left)) { return right instanceof PsiClassType && isAssignable(left, right); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java index 78f8598de730..c18de0281b8b 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java @@ -21,6 +21,7 @@ import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.impl.PsiManagerEx; +import com.intellij.psi.impl.source.resolve.ParameterTypeInferencePolicy; import com.intellij.psi.impl.source.resolve.ResolveCache; import com.intellij.psi.impl.source.tree.ChildRole; import com.intellij.psi.impl.source.tree.JavaElementType; @@ -30,6 +31,7 @@ import com.intellij.psi.scope.ElementClassFilter; import com.intellij.psi.scope.JavaScopeProcessorEvent; import com.intellij.psi.scope.PsiConflictResolver; import com.intellij.psi.scope.PsiScopeProcessor; +import com.intellij.psi.scope.conflictResolvers.JavaMethodsConflictResolver; import com.intellij.psi.scope.processor.FilterScopeProcessor; import com.intellij.psi.scope.processor.MethodCandidatesProcessor; import com.intellij.psi.scope.util.PsiScopesUtil; @@ -37,6 +39,7 @@ import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.MethodSignature; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; +import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.SmartList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -220,7 +223,7 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase public ResolveResult[] resolve(@NotNull PsiJavaReference reference, boolean incompleteCode) { final Ref classRef = new Ref(); final Ref substRef = new Ref(); - boolean checkStatic = process(classRef, substRef); + final boolean beginsWithReferenceType = process(classRef, substRef); final PsiClass containingClass = classRef.get(); final PsiSubstitutor substitutor = substRef.get(); @@ -242,15 +245,59 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType); final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult); final MethodSignature signature = interfaceMethod != null ? interfaceMethod.getSignature(resolveResult.getSubstitutor()) : null; - final MethodReferenceConflictResolver conflictResolver = new MethodReferenceConflictResolver(containingClass, substitutor, - signature); - final MethodCandidatesProcessor processor = new MethodCandidatesProcessor(PsiMethodReferenceExpressionImpl.this, - new PsiConflictResolver[]{conflictResolver}, - new SmartList()); + final MethodReferenceConflictResolver conflictResolver = + new MethodReferenceConflictResolver(containingClass, substitutor, signature, beginsWithReferenceType); + final PsiConflictResolver[] resolvers; + if (signature != null) { + final PsiType[] parameterTypes = signature.getParameterTypes(); + resolvers = new PsiConflictResolver[]{conflictResolver, + new JavaMethodsConflictResolver(PsiMethodReferenceExpressionImpl.this, parameterTypes) { + @Override + public CandidateInfo resolveConflict(List conflicts) { + boolean varargs = false; + for (CandidateInfo conflict : conflicts) { + final PsiElement psiElement = conflict.getElement(); + if (psiElement instanceof PsiMethod && ((PsiMethod)psiElement).isVarArgs()) { + varargs = true; + break; + } + } + checkSpecifics(conflicts, varargs ? MethodCandidateInfo.ApplicabilityLevel.VARARGS : MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY); + return conflicts.size() == 1 ? conflicts.get(0) : null; + } + }}; + } + else { + resolvers = new PsiConflictResolver[]{conflictResolver}; + } + final MethodCandidatesProcessor processor = + new MethodCandidatesProcessor(PsiMethodReferenceExpressionImpl.this, resolvers, new SmartList()) { + @Override + protected MethodCandidateInfo createCandidateInfo(final PsiMethod method, + PsiSubstitutor substitutor, + boolean staticProblem, + boolean accessible) { + final PsiExpressionList argumentList = getArgumentList(); + return new MethodCandidateInfo(method, substitutor, !accessible, staticProblem, argumentList, myCurrentFileContext, + argumentList != null ? argumentList.getExpressionTypes() : null, getTypeArguments(), + getLanguageLevel()) { + @Override + public PsiSubstitutor inferTypeArguments(ParameterTypeInferencePolicy policy) { + if (signature == null) return PsiSubstitutor.EMPTY; + final PsiType[] types = method.getSignature(PsiSubstitutor.EMPTY).getParameterTypes(); + final PsiType[] rightTypes = signature.getParameterTypes(); + if (types.length != rightTypes.length) return PsiSubstitutor.EMPTY; + return JavaPsiFacade.getInstance(getProject()).getResolveHelper() + .inferTypeArguments(method.getTypeParameters(), types, rightTypes, + PsiUtil.getLanguageLevel(PsiMethodReferenceExpressionImpl.this)); + } + }; + } + }; processor.setIsConstructor(isConstructor); processor.setName(isConstructor ? containingClass.getName() : element.getText()); - if (checkStatic) { + if (beginsWithReferenceType) { if (containingClass.getContainingClass() == null || !containingClass.hasModifierProperty(PsiModifier.STATIC)) { PsiClass aClass = null; if (PsiTreeUtil.isAncestor(containingClass, PsiMethodReferenceExpressionImpl.this, false)) { @@ -275,13 +322,15 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase private final PsiClass myContainingClass; private final PsiSubstitutor mySubstitutor; private final MethodSignature mySignature; + private final boolean myBeginsWithReferenceType; private MethodReferenceConflictResolver(PsiClass containingClass, PsiSubstitutor psiSubstitutor, - @Nullable MethodSignature signature) { + @Nullable MethodSignature signature, boolean beginsWithReferenceType) { myContainingClass = containingClass; mySubstitutor = psiSubstitutor; mySignature = signature; + myBeginsWithReferenceType = beginsWithReferenceType; } @Nullable @@ -293,7 +342,8 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase final PsiType[] parameterTypes = mySignature.getParameterTypes(); if (parameterTypes.length > 0) { final PsiClassType.ClassResolveResult classResolveResult = PsiUtil.resolveGenericsClassInType(parameterTypes[0]); - if (LambdaUtil.isReceiverType(parameterTypes[0], myContainingClass) && classResolveResult.getSubstitutor().equals(mySubstitutor)) { + if (LambdaUtil.isReceiverType(parameterTypes[0], myContainingClass) && + ((parameterTypes[0] instanceof PsiClassType && ((PsiClassType)parameterTypes[0]).isRaw()) || classResolveResult.getSubstitutor().equals(mySubstitutor))) { hasReceiver = true; } } @@ -305,33 +355,35 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase final PsiMethod psiMethod = ((MethodCandidateInfo)conflict).getElement(); if (psiMethod == null) continue; PsiSubstitutor subst = PsiSubstitutor.EMPTY; + subst = subst.putAll(conflict.getSubstitutor()); subst = subst.putAll(mySubstitutor); final PsiType[] signatureParameterTypes2 = psiMethod.getSignature(subst).getParameterTypes(); final boolean varArgs = psiMethod.isVarArgs(); - final boolean isStatic = psiMethod.hasModifierProperty(PsiModifier.STATIC); - + final boolean validConstructorRef = psiMethod.isConstructor() && (myContainingClass.getContainingClass() == null || myContainingClass.hasModifierProperty(PsiModifier.STATIC)); + final boolean staticOrValidConstructorRef = psiMethod.hasModifierProperty(PsiModifier.STATIC) || validConstructorRef; + if ((parameterTypes.length == signatureParameterTypes2.length || varArgs && parameterTypes.length >= signatureParameterTypes2.length) && - (isStatic || (psiMethod.isConstructor() && (conflict.isStaticsScopeCorrect() || myContainingClass.getContainingClass() == null) && !hasReceiver))) { + (!myBeginsWithReferenceType || staticOrValidConstructorRef)) { boolean correct = true; for (int i = 0; i < parameterTypes.length; i++) { final PsiType type1 = parameterTypes[i]; final PsiType type2 = varArgs && i >= signatureParameterTypes2.length - 1 ? ((PsiArrayType)signatureParameterTypes2[signatureParameterTypes2.length -1]).getComponentType() : signatureParameterTypes2[i]; - correct &= GenericsUtil.eliminateWildcards(subst.substitute(type1)).equals(GenericsUtil.eliminateWildcards(type2)); + correct &= TypeConversionUtil.isAssignable(type2, subst.substitute(GenericsUtil.eliminateWildcards(type1))); } if (correct) { firstCandidates.add(conflict); } } - if (hasReceiver && parameterTypes.length == signatureParameterTypes2.length + 1 && !isStatic && (!psiMethod.isConstructor() || myContainingClass.getContainingClass() != null)) { + if (hasReceiver && parameterTypes.length == signatureParameterTypes2.length + 1 && !staticOrValidConstructorRef) { boolean correct = true; for (int i = 0; i < signatureParameterTypes2.length; i++) { final PsiType type1 = parameterTypes[i + 1]; final PsiType type2 = signatureParameterTypes2[i]; - correct &= GenericsUtil.eliminateWildcards(subst.substitute(type1)).equals(GenericsUtil.eliminateWildcards(type2)); + correct &= TypeConversionUtil.isAssignable(type2, subst.substitute(GenericsUtil.eliminateWildcards(type1))); } if (correct) { secondCandidates.add(conflict); @@ -339,7 +391,15 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase } } - if (secondCandidates.size() + firstCandidates.size() != 1) return null; + final int acceptedCount = secondCandidates.size() + firstCandidates.size(); + if (acceptedCount != 1) { + if (acceptedCount == 0) { + conflicts.clear(); + } + firstCandidates.addAll(secondCandidates); + conflicts.retainAll(firstCandidates); + return null; + } return !firstCandidates.isEmpty() ? firstCandidates.get(0) : secondCandidates.get(0); } } diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java index a72cfe5027b7..2c93a6e8945b 100644 --- a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java +++ b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java @@ -128,7 +128,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ } } - private void checkSpecifics(List conflicts, @MethodCandidateInfo.ApplicabilityLevelConstant int applicabilityLevel) { + public void checkSpecifics(List conflicts, @MethodCandidateInfo.ApplicabilityLevelConstant int applicabilityLevel) { final boolean applicable = applicabilityLevel > MethodCandidateInfo.ApplicabilityLevel.NOT_APPLICABLE; int conflictsCount = conflicts.size(); @@ -450,7 +450,8 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ PsiType type1 = params1[Math.min(i, params1.length - 1)].getType(); PsiType type2 = params2[Math.min(i, params2.length - 1)].getType(); if (applicabilityLevel == MethodCandidateInfo.ApplicabilityLevel.VARARGS) { - if (type1 instanceof PsiEllipsisType && type2 instanceof PsiEllipsisType) { + if (type1 instanceof PsiEllipsisType && type2 instanceof PsiEllipsisType && + (((PsiArrayType)type1).getComponentType().equalsToText(CommonClassNames.JAVA_LANG_OBJECT) || ((PsiArrayType)type2).getComponentType().equalsToText(CommonClassNames.JAVA_LANG_OBJECT))) { type1 = ((PsiEllipsisType)type1).toArrayType(); type2 = ((PsiEllipsisType)type2).toArrayType(); } diff --git a/java/java-tests/testData/codeInsight/completion/normalSorting/PreselectLastChosen.java b/java/java-tests/testData/codeInsight/completion/normalSorting/PreselectLastChosen.java new file mode 100644 index 000000000000..1ba055805277 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normalSorting/PreselectLastChosen.java @@ -0,0 +1,7 @@ +import java.util.Set; + +public class Foo { + void foo(Set set) { + set.adx + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/TryWithResourcesWarn.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/TryWithResourcesWarn.java index c2adf2667a93..796de41f705c 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/TryWithResourcesWarn.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/TryWithResourcesWarn.java @@ -1,5 +1,3 @@ -import java.lang.Exception; - class C { static class MyResource implements AutoCloseable { @Override public void close() { } @@ -25,4 +23,21 @@ class C { System.out.println(r); } } + + interface MyResourceProvider { + MyResource getResource(); + } + + void m3() throws Exception { + MyResourceProvider provider = null; + try (MyResource r = provider.getResource()) { + System.out.println(r); + } + } + + void m4() { + try (MyResource r = null) { + System.out.println(r); + } + } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/ambiguousVarargs/pck/AmbiguousMethodCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/ambiguousVarargs/pck/AmbiguousMethodCall.java index 3ced31214dcf..d1b120225a79 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/ambiguousVarargs/pck/AmbiguousMethodCall.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/ambiguousVarargs/pck/AmbiguousMethodCall.java @@ -21,4 +21,12 @@ abstract class A { { foo(1); } -} \ No newline at end of file +} +abstract class A1 { + abstract void foo(double ... x); + abstract void foo(int... x); + + { + foo(1); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/ConstructorRefsInnerClasses.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/ConstructorRefsInnerClasses.java index fb13de303bae..127e57db4ef7 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/ConstructorRefsInnerClasses.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/ConstructorRefsInnerClasses.java @@ -73,4 +73,46 @@ class StaticInner1 { static { call3(StaticInner1.Inner :: new); } +} + +class StaticInner2 { + + static class Inner { + Inner() {} + } + + + interface I1 { + Inner m(StaticInner2 rec); + } + + + static { + I1 i1 = StaticInner2.Inner :: new; + } + + { + I1 i1 = StaticInner2.Inner :: new; + } +} + +class NonStaticInner2 { + + class Inner { + Inner() {} + } + + + interface I1 { + Inner m(NonStaticInner2 rec); + } + + + static { + I1 i1 = NonStaticInner2.Inner :: new; + } + + { + I1 i1 = NonStaticInner2.Inner :: new; + } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/MethodRefMisc1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/MethodRefMisc1.java index a3434a67a5c9..ece7a65b2eea 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/MethodRefMisc1.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/MethodRefMisc1.java @@ -54,7 +54,7 @@ class MyTest2 { static void call(Integer i, I s) { } static void test() { - call(1, MyTest2::m); //ambiguous + call(1, MyTest2::m); //ambiguous } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/MethodTypeParamsInference.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/MethodTypeParamsInference.java new file mode 100644 index 000000000000..d802dcbb33ab --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/MethodTypeParamsInference.java @@ -0,0 +1,52 @@ +class MyTest { + interface I1 { + void m(String s); + } + + interface I2 { + void m(Integer s); + } + + interface I3 { + void m(Object o); + } + + static void m(T p) {} + + static void m1(T1 fx) { } + + static void foo(I1 i) {} + static void foo(I2 i) {} //m + static void foo(I3 i) {} + + static { + foo(MyTest::m); + foo(MyTest::m1); + } +} + + +class MyTest1 { + interface I1 { + void m(Integer s); + } + + interface I2 { + void m(Integer s); + } + + static void m(T p) { } + static void m1(T p) { } + + static void foo1(I1 i) { } + static void foo2(I1 i) { } + static void foo2(I2 i) { } + + static { + foo1(MyTest1::m); + foo2(MyTest1::m); + + foo1(MyTest1::m1); + foo2(MyTest1::m1); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/Varargs.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/Varargs.java index 9c8931dd9cc4..ece7ace9adff 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/Varargs.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/methodRef/Varargs.java @@ -1,6 +1,5 @@ -class MethodReference27 { - - interface SAM { +class MyTest1 { + interface I { void m(int i1, int i2); } @@ -13,10 +12,63 @@ class MethodReference27 { static void m2(int... is) { } static void m2(double... ds) {} + static void m3(int... is) { } + static void m3(Object... ds) {} + public static void main(String[] args) { - SAM s1 = MethodReference27::m1; - s1.m(42,42); - SAM s2 = MethodReference27 :: m2; - s2.m(42,42); + I i1 = MyTest1::m1; + i1.m(42,42); + + I i2 = MyTest1 :: m2; + i2.m(42,42); + + I i3 = MyTest1 :: m3; } } + +class MyTest { + + interface I1 { + void m(int i); + } + + interface I2 { + void m(MyTest t, int i); + } + + static void static_1(Integer i) {} + static void static_2(Integer i1, Integer i2) {} + static void static_3(String s) {} + static void static_4(String... ss) {} + + void _1(Integer i) {} + void _2(Integer i1, Integer i2) {} + void _3(String s) {} + void _4(String... ss) {} + + static { + I1 i1 = MyTest::static_1; + I1 i2 = MyTest::static_2; + I1 i3 = MyTest::static_3; + I1 i4 = MyTest::static_4; + } + + + { + I1 i_1 = MyTest::_1; + I1 i_2 = MyTest::_2; + I1 i_3 = MyTest::_3; + I1 i_4 = MyTest::_4; + + I1 i1 = this::_1; + I1 i2 = this::_2; + I1 i3 = this::_3; + I1 i4 = this::_4; + + I2 i21 = MyTest::m1; + I2 i22 = MyTest::m2; + I2 i23 = MyTest::m3; + I2 i24 = MyTest::m4; + } +} + diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.groovy index 22e5a39ef44e..ed394a8e9cda 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.groovy @@ -453,4 +453,14 @@ import java.lang.annotation.Target; assert lookup.items[1].object instanceof PsiMethod } + public void testPreselectLastChosen() { + checkPreferredItems(0, 'add', 'addAll') + for (i in 0..10) { + incUseCount(lookup, 1) + } + assertPreferredItems 1, 'add', 'addAll' + incUseCount(lookup, 0) + assertPreferredItems 0, 'add', 'addAll' + } + } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java index ae05e2cb85f5..350deee39287 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java @@ -20,6 +20,7 @@ import com.intellij.codeInsight.daemon.impl.HighlightInfo; import com.intellij.codeInspection.InspectionProfileEntry; import com.intellij.codeInspection.LocalInspectionTool; import com.intellij.codeInspection.compiler.JavacQuirksInspection; +import com.intellij.codeInspection.dataFlow.DataFlowInspection; import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection; import com.intellij.codeInspection.defUse.DefUseInspection; import com.intellij.codeInspection.redundantCast.RedundantCastInspection; @@ -146,7 +147,7 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase { public void testNumericLiterals() throws Exception { doTest(false, false); } public void testMultiCatch() throws Exception { doTest(false, false); } public void testTryWithResources() throws Exception { doTest(false, false); } - public void testTryWithResourcesWarn() throws Exception { doTest(true, false, new DefUseInspection()); } + public void testTryWithResourcesWarn() throws Exception { doTest(true, false, new DefUseInspection(), new DataFlowInspection()); } public void testSafeVarargsApplicability() throws Exception { doTest(true, false); } public void testUncheckedGenericsArrayCreation() throws Exception { doTest(true, false); } public void testPreciseRethrow() throws Exception { doTest(false, false); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/MethodRefHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/MethodRefHighlightingTest.java index d02eeb4e362a..afa6f4ac1ba5 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/MethodRefHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/MethodRefHighlightingTest.java @@ -40,7 +40,11 @@ public class MethodRefHighlightingTest extends LightDaemonAnalyzerTestCase { public void testMethodRefMisc() throws Exception { doTest(); } - + + public void testMethodTypeParamsInference() throws Exception { + doTest(); + } + public void testMethodRefMisc1() throws Exception { doTest(); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/StatisticsWeigher.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/StatisticsWeigher.java index fe45af2e81e8..3958e67fb744 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/StatisticsWeigher.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/StatisticsWeigher.java @@ -51,15 +51,17 @@ public class StatisticsWeigher extends CompletionWeigher { @Override public Integer weigh(@NotNull LookupElement item) { - final StatisticsInfo info = getBaseStatisticsInfo(item, myLocation); - if (info == StatisticsInfo.EMPTY) { + final StatisticsInfo baseInfo = getBaseStatisticsInfo(item, myLocation); + if (baseInfo == StatisticsInfo.EMPTY) { return 0; } - int max = 0; - for (StatisticsInfo statisticsInfo : composeStatsWithPrefix(info, myLocation.getCompletionParameters().getLookup().itemPattern(item))) { - max = Math.max(max, ourStatManager.getUseCount(statisticsInfo)); + int maxUseCount = 0; + int minRecency = Integer.MAX_VALUE; + for (StatisticsInfo eachInfo : composeStatsWithPrefix(baseInfo, myLocation.getCompletionParameters().getLookup().itemPattern(item))) { + maxUseCount = Math.max(maxUseCount, ourStatManager.getUseCount(eachInfo)); + minRecency = Math.min(minRecency, ourStatManager.getLastUseRecency(eachInfo)); } - return max; + return minRecency == Integer.MAX_VALUE ? maxUseCount : 100 - minRecency; } } diff --git a/platform/platform-api/src/com/intellij/psi/statistics/StatisticsManager.java b/platform/platform-api/src/com/intellij/psi/statistics/StatisticsManager.java index ca0a203f6484..87361ef86aad 100644 --- a/platform/platform-api/src/com/intellij/psi/statistics/StatisticsManager.java +++ b/platform/platform-api/src/com/intellij/psi/statistics/StatisticsManager.java @@ -46,6 +46,7 @@ public abstract class StatisticsManager implements SettingsSavingComponent { } public abstract int getUseCount(@NotNull StatisticsInfo info); + public abstract int getLastUseRecency(@NotNull StatisticsInfo info); public abstract void incUseCount(@NotNull StatisticsInfo info); public int getUseCount(final Key> key, final T element, final Loc location) { diff --git a/platform/platform-impl/src/com/intellij/psi/statistics/impl/StatisticsManagerImpl.java b/platform/platform-impl/src/com/intellij/psi/statistics/impl/StatisticsManagerImpl.java index 16b6967f9e4f..71a3a7933c77 100644 --- a/platform/platform-impl/src/com/intellij/psi/statistics/impl/StatisticsManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/psi/statistics/impl/StatisticsManagerImpl.java @@ -58,6 +58,18 @@ public class StatisticsManagerImpl extends StatisticsManager { } } + @Override + public int getLastUseRecency(@NotNull StatisticsInfo info) { + if (info == StatisticsInfo.EMPTY) return 0; + + String key1 = info.getContext(); + int unitNumber = getUnitNumber(key1); + synchronized (LOCK) { + StatisticsUnit unit = getUnit(unitNumber); + return unit.getRecency(key1, info.getValue()); + } + } + public void incUseCount(@NotNull final StatisticsInfo info) { if (info == StatisticsInfo.EMPTY) return; if (ApplicationManager.getApplication().isUnitTestMode() && !myTestingStatistics) { diff --git a/platform/platform-impl/src/com/intellij/psi/statistics/impl/StatisticsUnit.java b/platform/platform-impl/src/com/intellij/psi/statistics/impl/StatisticsUnit.java index 5099260d1851..635a437946ff 100644 --- a/platform/platform-impl/src/com/intellij/psi/statistics/impl/StatisticsUnit.java +++ b/platform/platform-impl/src/com/intellij/psi/statistics/impl/StatisticsUnit.java @@ -33,6 +33,14 @@ class StatisticsUnit { myNumber = number; } + public int getRecency(String key1, String key2) { + final List list = myDataMap.get(key1); + if (list == null) return Integer.MAX_VALUE; + + int i = list.indexOf(key2); + return i >= 0 ? i : Integer.MAX_VALUE; + } + public int getData(String key1, String key2) { final List list = myDataMap.get(key1); if (list == null) return 0; diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/Configuration.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/Configuration.java index ad0b6cda2930..89f2ddad8444 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/Configuration.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/Configuration.java @@ -143,15 +143,16 @@ public class Configuration implements PersistentStateComponent, Modific return super.getModificationCount() + myParentConfiguration.getModificationCount(); } - public boolean replaceInjections(final List newInjections, - final List originalInjections) { - if (!originalInjections.isEmpty()) { - if (myParentConfiguration.replaceInjections(Collections.emptyList(), originalInjections)) { - myParentConfiguration.replaceInjections(newInjections, Collections.emptyList()); + public boolean replaceInjections(List newInjections, + List originalInjections, + boolean forceLevel) { + if (!forceLevel && !originalInjections.isEmpty()) { + if (myParentConfiguration.replaceInjections(Collections.emptyList(), originalInjections, forceLevel)) { + myParentConfiguration.replaceInjections(newInjections, Collections.emptyList(), forceLevel); return true; } } - return super.replaceInjections(newInjections, originalInjections); + return super.replaceInjections(newInjections, originalInjections, forceLevel); } } @@ -389,7 +390,7 @@ public class Configuration implements PersistentStateComponent, Modific importInjections(getInjections(supportId), importingInjections, originalInjections, newInjections); } if (!newInjections.isEmpty()) configurationModified(); - replaceInjections(newInjections, originalInjections); + replaceInjections(newInjections, originalInjections, true); return newInjections.size(); } @@ -505,7 +506,7 @@ public class Configuration implements PersistentStateComponent, Modific } protected void replaceInjectionsWithUndoInner(final List add, final List remove) { - replaceInjections(add, remove); + replaceInjections(add, remove, false); } public static void replaceInjectionsWithUndo(final Project project, final T add, final T remove, @@ -541,8 +542,9 @@ public class Configuration implements PersistentStateComponent, Modific }.execute(); } - public boolean replaceInjections(final List newInjections, - final List originalInjections) { + public boolean replaceInjections(List newInjections, + List originalInjections, + boolean forceLevel) { boolean changed = false; for (BaseInjection injection : originalInjections) { changed |= myInjections.get(injection.getSupportId()).remove(injection); diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/InjectionsSettingsUI.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/InjectionsSettingsUI.java index fa76551b37ac..864d7a93c19d 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/InjectionsSettingsUI.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/InjectionsSettingsUI.java @@ -882,7 +882,7 @@ public class InjectionsSettingsUI implements SearchableConfigurable.Parent, NonD public void apply() { final List injectionList = getInjectionList(injectionInfos); - cfg.replaceInjections(injectionList, originalInjections); + cfg.replaceInjections(injectionList, originalInjections, true); originalInjections.clear(); originalInjections.addAll(injectionList); sortInjections(originalInjections); diff --git a/plugins/spellchecker/src/com/intellij/spellchecker/english.dic b/plugins/spellchecker/src/com/intellij/spellchecker/english.dic index 969921ac609b..5753c8e2deaf 100644 --- a/plugins/spellchecker/src/com/intellij/spellchecker/english.dic +++ b/plugins/spellchecker/src/com/intellij/spellchecker/english.dic @@ -108015,6 +108015,7 @@ receivership receivership's receives receiving +recency recension recension's recent