mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 21:11:28 +07:00
[java] skip plain cannot infer diamond error (IDEA-283409); add ambiguous constructor call (IDEA-272115)
this unifies error messages with method calls and allows more specific tooltips and additional fixes GitOrigin-RevId: 5ab4340d822bba3d6563da12a16e4c41216a8627
This commit is contained in:
committed by
intellij-monorepo-bot
parent
10f7715893
commit
e6165048e8
@@ -109,11 +109,16 @@ public final class GenericsHighlightUtil {
|
||||
if (!(inferenceResult.failedToInfer() && expectedType instanceof PsiClassType && ((PsiClassType)expectedType).isRaw())) {
|
||||
HighlightInfo highlightInfo = HighlightInfo
|
||||
.newHighlightInfo(HighlightInfoType.ERROR).range(referenceParameterList).descriptionAndTooltip(errorMessage).create();
|
||||
if (inferenceResult == PsiDiamondType.DiamondInferenceResult.ANONYMOUS_INNER_RESULT &&
|
||||
!PsiUtil.isLanguageLevel9OrHigher(referenceParameterList)) {
|
||||
QuickFixAction.registerQuickFixAction(highlightInfo, QUICK_FIX_FACTORY.createIncreaseLanguageLevelFix(LanguageLevel.JDK_1_9));
|
||||
if (inferenceResult == PsiDiamondType.DiamondInferenceResult.ANONYMOUS_INNER_RESULT) {
|
||||
if (!PsiUtil.isLanguageLevel9OrHigher(referenceParameterList)) {
|
||||
QuickFixAction.registerQuickFixAction(highlightInfo,
|
||||
QUICK_FIX_FACTORY.createIncreaseLanguageLevelFix(LanguageLevel.JDK_1_9));
|
||||
}
|
||||
return highlightInfo;
|
||||
}
|
||||
if (inferenceResult == PsiDiamondType.DiamondInferenceResult.EXPLICIT_CONSTRUCTOR_TYPE_ARGS) {
|
||||
return highlightInfo;
|
||||
}
|
||||
return highlightInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1166,7 +1171,7 @@ public final class GenericsHighlightUtil {
|
||||
}
|
||||
PsiClassType type = JavaPsiFacade.getElementFactory(holder.getProject()).createType(containingClass);
|
||||
|
||||
HighlightMethodUtil.checkConstructorCall(type.resolveGenerics(), enumConstant, type, null, holder, javaSdkVersion);
|
||||
HighlightMethodUtil.checkConstructorCall(type.resolveGenerics(), enumConstant, type, null, holder, javaSdkVersion, enumConstant.getArgumentList());
|
||||
}
|
||||
|
||||
static HighlightInfo checkEnumSuperConstructorCall(@NotNull PsiMethodCallExpression expr) {
|
||||
|
||||
@@ -559,7 +559,7 @@ public final class HighlightMethodUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
static HighlightInfo createIncompatibleTypeHighlightInfo(@NotNull PsiCallExpression methodCall,
|
||||
static HighlightInfo createIncompatibleTypeHighlightInfo(@NotNull PsiCall methodCall,
|
||||
@NotNull PsiResolveHelper resolveHelper,
|
||||
@NotNull MethodCandidateInfo resolveResult,
|
||||
@NotNull PsiElement elementToHighlight) {
|
||||
@@ -1657,16 +1657,33 @@ public final class HighlightMethodUtil {
|
||||
}
|
||||
|
||||
PsiJavaCodeReferenceElement classReference = expression.getClassOrAnonymousClassReference();
|
||||
checkConstructorCall(typeResult, expression, type, classReference, holder, javaSdkVersion);
|
||||
checkConstructorCall(typeResult, expression, type, classReference, holder, javaSdkVersion, expression.getArgumentList());
|
||||
}
|
||||
|
||||
static void checkAmbiguousConstructorCall(PsiJavaCodeReferenceElement ref,
|
||||
PsiElement resolved,
|
||||
PsiElement parent,
|
||||
HighlightInfoHolder holder,
|
||||
JavaSdkVersion version) {
|
||||
if (resolved instanceof PsiClass && parent instanceof PsiNewExpression && ((PsiClass)resolved).getConstructors().length > 0) {
|
||||
PsiNewExpression newExpression = (PsiNewExpression)parent;
|
||||
if (newExpression.resolveMethod() == null && !PsiTreeUtil.findChildrenOfType(newExpression.getArgumentList(), PsiFunctionalExpression.class).isEmpty()) {
|
||||
PsiType type = newExpression.getType();
|
||||
if (type != null) {
|
||||
checkConstructorCall(((PsiClassType)type).resolveGenerics(), newExpression, type, newExpression.getClassReference(), holder, version, ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void checkConstructorCall(@NotNull PsiClassType.ClassResolveResult typeResolveResult,
|
||||
@NotNull PsiConstructorCall constructorCall,
|
||||
@NotNull PsiType type,
|
||||
@Nullable PsiJavaCodeReferenceElement classReference,
|
||||
@NotNull HighlightInfoHolder holder,
|
||||
@NotNull JavaSdkVersion javaSdkVersion) {
|
||||
@NotNull JavaSdkVersion javaSdkVersion,
|
||||
@Nullable PsiElement elementToHighlight) {
|
||||
if (elementToHighlight == null) return;
|
||||
PsiExpressionList list = constructorCall.getArgumentList();
|
||||
if (list == null) return;
|
||||
PsiClass aClass = typeResolveResult.getElement();
|
||||
@@ -1754,10 +1771,12 @@ public final class HighlightMethodUtil {
|
||||
String name = aClass.getName();
|
||||
name += buildArgTypesList(list);
|
||||
String description = JavaErrorBundle.message("cannot.resolve.constructor", name);
|
||||
HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(list).descriptionAndTooltip(description).navigationShift(+1).create();
|
||||
HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
|
||||
.range(elementToHighlight).descriptionAndTooltip(description).create();
|
||||
if (info != null) {
|
||||
WrapExpressionFix.registerWrapAction(results, list.getExpressions(), info, getFixRange(list));
|
||||
registerFixesOnInvalidConstructorCall(constructorCall, classReference, list, aClass, constructors, results, info);
|
||||
TextRange fixRange = getFixRange(elementToHighlight);
|
||||
WrapExpressionFix.registerWrapAction(results, list.getExpressions(), info, fixRange);
|
||||
registerFixesOnInvalidConstructorCall(constructorCall, classReference, list, aClass, constructors, results, info, fixRange);
|
||||
holder.add(info);
|
||||
}
|
||||
}
|
||||
@@ -1773,7 +1792,7 @@ public final class HighlightMethodUtil {
|
||||
if (constructorCall instanceof PsiNewExpression) {
|
||||
methodCandidates = resolveHelper.getReferencedMethodCandidates((PsiCallExpression)constructorCall, true);
|
||||
}
|
||||
registerFixesOnInvalidConstructorCall(constructorCall, classReference, list, aClass, constructors, methodCandidates, info);
|
||||
registerFixesOnInvalidConstructorCall(constructorCall, classReference, list, aClass, constructors, methodCandidates, info, getFixRange(list));
|
||||
registerMethodReturnFixAction(info, result, constructorCall);
|
||||
holder.add(info);
|
||||
}
|
||||
@@ -1789,6 +1808,9 @@ public final class HighlightMethodUtil {
|
||||
if (result != null && !holder.hasErrorResults()) {
|
||||
holder.add(checkVarargParameterErasureToBeAccessible(result, constructorCall));
|
||||
}
|
||||
if (result != null && !holder.hasErrorResults()) {
|
||||
holder.add(createIncompatibleTypeHighlightInfo(constructorCall, resolveHelper, result, constructorCall));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1822,8 +1844,8 @@ public final class HighlightMethodUtil {
|
||||
@NotNull PsiClass aClass,
|
||||
PsiMethod @NotNull [] constructors,
|
||||
JavaResolveResult @NotNull [] results,
|
||||
@NotNull final HighlightInfo info) {
|
||||
TextRange fixRange = getFixRange(list);
|
||||
@NotNull final HighlightInfo info,
|
||||
TextRange fixRange) {
|
||||
if (classReference != null) {
|
||||
ConstructorParametersFixer.registerFixActions(classReference, constructorCall, info, fixRange);
|
||||
ChangeTypeArgumentsFix.registerIntentions(results, list, info, aClass, fixRange);
|
||||
|
||||
@@ -1221,6 +1221,9 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
if (!myHolder.hasErrorResults() && resolved instanceof PsiModifierListOwner) {
|
||||
ref.accept(myPreviewFeatureVisitor);
|
||||
}
|
||||
if (!myHolder.hasErrorResults()) {
|
||||
HighlightMethodUtil.checkAmbiguousConstructorCall(ref, resolved, ref.getParent(), myHolder, myJavaSdkVersion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,6 @@ import java.util.List;
|
||||
class Test {
|
||||
|
||||
{
|
||||
List<List<String>> l = new ArrayList<List<error descr="Cannot infer arguments"><></error>>();
|
||||
<error descr="Incompatible types. Found: 'java.util.ArrayList<java.util.List>', required: 'java.util.List<java.util.List<java.lang.String>>'">List<List<String>> l = new ArrayList<List<>>();</error>
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
class Test {
|
||||
{
|
||||
D<String> ds = new D<error descr="Cannot infer arguments (unable to resolve constructor)"><></error>(9);
|
||||
D<String> ds = new D<><error descr="Cannot resolve constructor 'D(int)'">(9)</error>;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
class Test {
|
||||
{
|
||||
Holder h = null;
|
||||
Result<String> r1 = new Result<error descr="Cannot infer arguments"><></error>(h);
|
||||
Result<String> r1 = <error descr="Incompatible types. Found: 'Result<Holder>', required: 'Result<java.lang.String>'">new Result<>(h);</error>
|
||||
Result<String> r2 = <error descr="Incompatible types. Found: 'Result<Holder>', required: 'Result<java.lang.String>'">Result.create(h);</error>
|
||||
|
||||
Holder dataHolder = null;
|
||||
Result<String> r3 = new Result<error descr="Cannot infer arguments"><></error>(new Holder<>(dataHolder));
|
||||
Result<String> r3 = <error descr="Incompatible types. Found: 'Result<Holder>', required: 'Result<java.lang.String>'">new Result<>(new Holder<>(dataHolder));</error>
|
||||
Result<String> r4 = <error descr="Incompatible types. Found: 'Result<Holder>', required: 'Result<java.lang.String>'">Result.create(new Holder<>(dataHolder));</error>
|
||||
|
||||
Result<String> r5 = new Result<error descr="Cannot infer arguments"><></error>(Holder.create(dataHolder));
|
||||
Result<String> r5 = <error descr="Incompatible types. Found: 'Result<Holder>', required: 'Result<java.lang.String>'">new Result<>(Holder.create(dataHolder));</error>
|
||||
Result<String> r6 = <error descr="Incompatible types. Found: 'Result<Holder>', required: 'Result<java.lang.String>'">Result.create(Holder.create(dataHolder));</error>
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
class A<R>{
|
||||
A(R value) {}
|
||||
public static void main(String[] args) {
|
||||
A<Integer> a = new A<><error descr="'A(R)' in 'A' cannot be applied to '(java.lang.String, int)'" tooltip="Expected 1 arguments but found 2">("hi", 1)</error>;
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ public class ConcurrentCollectors {
|
||||
static <T, K, D, M1 extends Map<K, D>> C<T, M1> groupingBy(F<M1> f,
|
||||
C<T, D> c,
|
||||
BiConsumer<M1, T> consumer) {
|
||||
return new CImpl<error descr="Cannot infer arguments"><></error>(f, consumer, arg(c.getOp()));
|
||||
return new CImpl<><error descr="'CImpl(ConcurrentCollectors.F<R>, ConcurrentCollectors.BiConsumer<R,T>, ConcurrentCollectors.BiOp<R>)' in 'ConcurrentCollectors.CImpl' cannot be applied to '(ConcurrentCollectors.F<M1>, ConcurrentCollectors.BiConsumer<M1,T>, ConcurrentCollectors.BiOp<ConcurrentCollectors.ConcurrentMap<java.lang.Object,D>>)'">(f, consumer, arg(c.getOp()))</error>;
|
||||
}
|
||||
|
||||
static <K, V, M2 extends ConcurrentMap<K, V>> BiOp<M2> arg(BiOp<V> op) {
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
class OverloadCast {
|
||||
|
||||
public void runMe() {
|
||||
new <error descr="Cannot resolve constructor 'OverloadCast(<method reference>, <lambda expression>)'">OverloadCast</error>(WhitespaceTokenizer::<error descr="Cannot resolve constructor 'WhitespaceTokenizer'">new</error>, src -> new LowerCaseFilter<error descr="'LowerCaseFilter(OverloadCast.TokenStream)' in 'OverloadCast.LowerCaseFilter' cannot be applied to '(<lambda parameter>)'">(src)</error>);
|
||||
<error descr="Ambiguous method call: both 'OverloadCast.overloadCast(Supplier<Tokenizer>, Function<TokenStream, TokenFilter>)' and 'OverloadCast.overloadCast(Function<TokenStream, TokenFilter>, Function<String, String>)' match">overloadCast</error>(WhitespaceTokenizer::<error descr="Cannot resolve constructor 'WhitespaceTokenizer'">new</error>, src -> new LowerCaseFilter<error descr="'LowerCaseFilter(OverloadCast.TokenStream)' in 'OverloadCast.LowerCaseFilter' cannot be applied to '(<lambda parameter>)'">(src)</error>);
|
||||
}
|
||||
|
||||
private OverloadCast(Supplier<Tokenizer> tokenizerFactory, Function<TokenStream, TokenFilter> filterCreator) {
|
||||
}
|
||||
|
||||
private OverloadCast(Function<TokenStream, TokenFilter> filterCreator, Function<String, String> readerWrapper) {
|
||||
}
|
||||
|
||||
private void overloadCast(Supplier<Tokenizer> tokenizerFactory, Function<TokenStream, TokenFilter> filterCreator) {
|
||||
}
|
||||
|
||||
private void overloadCast(Function<TokenStream, TokenFilter> filterCreator, Function<String, String> readerWrapper) {
|
||||
}
|
||||
|
||||
private class Tokenizer {
|
||||
}
|
||||
|
||||
private class TokenStream {
|
||||
}
|
||||
|
||||
private class TokenFilter {
|
||||
}
|
||||
|
||||
private class WhitespaceTokenizer extends Tokenizer {
|
||||
private WhitespaceTokenizer(TokenStream s) {
|
||||
}
|
||||
|
||||
private WhitespaceTokenizer() {
|
||||
}
|
||||
}
|
||||
|
||||
private class LowerCaseFilter extends TokenFilter {
|
||||
public LowerCaseFilter(TokenStream src) {
|
||||
super();
|
||||
}
|
||||
|
||||
private LowerCaseFilter() {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// "Cast 1st argument to 'Supplier<Tokenizer>'" "true"
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
class OverloadCast {
|
||||
|
||||
public void runMe() {
|
||||
new OverloadCast((Supplier<Tokenizer>) WhitespaceTokenizer::new, src -> new LowerCaseFilter(src));
|
||||
}
|
||||
|
||||
private OverloadCast(Supplier<Tokenizer> tokenizerFactory, Function<TokenStream, TokenFilter> filterCreator) {
|
||||
}
|
||||
|
||||
private OverloadCast(Function<TokenStream, TokenFilter> filterCreator, Function<String, String> readerWrapper) {
|
||||
}
|
||||
|
||||
private class Tokenizer { }
|
||||
|
||||
private class TokenStream { }
|
||||
|
||||
private class TokenFilter { }
|
||||
|
||||
private class WhitespaceTokenizer extends Tokenizer {
|
||||
private WhitespaceTokenizer(TokenStream s) {
|
||||
}
|
||||
|
||||
private WhitespaceTokenizer() {
|
||||
}
|
||||
}
|
||||
|
||||
private class LowerCaseFilter extends TokenFilter {
|
||||
public LowerCaseFilter(TokenStream src) {
|
||||
super();
|
||||
}
|
||||
|
||||
private LowerCaseFilter() {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// "Cast 1st argument to 'Supplier<Tokenizer>'" "true"
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
class OverloadCast {
|
||||
|
||||
public void runMe() {
|
||||
new Over<caret>loadCast(WhitespaceTokenizer::new, src -> new LowerCaseFilter(src));
|
||||
}
|
||||
|
||||
private OverloadCast(Supplier<Tokenizer> tokenizerFactory, Function<TokenStream, TokenFilter> filterCreator) {
|
||||
}
|
||||
|
||||
private OverloadCast(Function<TokenStream, TokenFilter> filterCreator, Function<String, String> readerWrapper) {
|
||||
}
|
||||
|
||||
private class Tokenizer { }
|
||||
|
||||
private class TokenStream { }
|
||||
|
||||
private class TokenFilter { }
|
||||
|
||||
private class WhitespaceTokenizer extends Tokenizer {
|
||||
private WhitespaceTokenizer(TokenStream s) {
|
||||
}
|
||||
|
||||
private WhitespaceTokenizer() {
|
||||
}
|
||||
}
|
||||
|
||||
private class LowerCaseFilter extends TokenFilter {
|
||||
public LowerCaseFilter(TokenStream src) {
|
||||
super();
|
||||
}
|
||||
|
||||
private LowerCaseFilter() {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.java.codeInsight.daemon.lambda;
|
||||
|
||||
import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase;
|
||||
@@ -114,6 +100,7 @@ public class Diamond8HighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
public void testNestedDiamondsAnonymousCase() { doTest();}
|
||||
|
||||
public void testDiamondsUncheckedWarning() { doTest();}
|
||||
public void testWrongNumberOfArguments() { doTest();}
|
||||
|
||||
private void doTest() {
|
||||
doTest(BASE_PATH + "/" + getTestName(false) + ".java", false, false);
|
||||
|
||||
@@ -148,6 +148,7 @@ class NewLambdaHighlightingTest extends LightJavaCodeInsightFixtureTestCase5 {
|
||||
@Test void testPolyExpressionInVoidCompatibleLambdaReturn() { doTest(); }
|
||||
@Test void testStopAtTypeCastWhenSearchForTopMostNode() { doTest(); }
|
||||
@Test void testLambdaWithExplicitTypeAndTargetTypeParameter() { doTest(); }
|
||||
@Test void testAmbiguousConstructorCallWithLambdaInside() { doTest(); }
|
||||
|
||||
@Override
|
||||
protected @NotNull String getRelativePath() {
|
||||
|
||||
Reference in New Issue
Block a user