KT-1138 Need better diagnostic for case when method/constructor call is followed by class initializer or simple block
This commit is contained in:
@@ -488,6 +488,10 @@ public interface Errors {
|
||||
|
||||
ParameterizedDiagnosticFactory1<String> UNRESOLVED_IDE_TEMPLATE = new ParameterizedDiagnosticFactory1<String>(ERROR, "Unresolved IDE template: {0}");
|
||||
|
||||
SimpleDiagnosticFactory DANGLING_FUNCTION_LITERAL_ARGUMENT_SUSPECTED = SimpleDiagnosticFactory.create(WARNING, "This expression is treated as an argument to the function call on the previous line. " +
|
||||
"Separate it with a semicolon (;) if it is not intended to be an argument.");
|
||||
|
||||
|
||||
// This field is needed to make the Initializer class load (interfaces cannot have static initializers)
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
Initializer __initializer = Initializer.INSTANCE;
|
||||
|
||||
@@ -386,13 +386,20 @@ public class CallResolver {
|
||||
assert callElement != null;
|
||||
trace.report(UNNECESSARY_SAFE_CALL.on((JetElement) callOperationNode.getTreeParent().getPsi(), callOperationNode, type));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void danglingFunctionLiteralArgumentSuspected(@NotNull BindingTrace trace, @NotNull List<JetExpression> functionLiteralArguments) {
|
||||
for (JetExpression functionLiteralArgument : functionLiteralArguments) {
|
||||
trace.report(DANGLING_FUNCTION_LITERAL_ARGUMENT_SUSPECTED.on(functionLiteralArgument));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TemporaryBindingTrace traceForFirstNonemptyCandidateSet = null;
|
||||
OverloadResolutionResultsImpl<D> resultsForFirstNonemptyCandidateSet = null;
|
||||
for (ResolutionTask<D> task : prioritizedTasks) {
|
||||
TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(trace);
|
||||
OverloadResolutionResultsImpl<D> results = performResolution(temporaryTrace, scope, expectedType, task, tracing);
|
||||
OverloadResolutionResultsImpl<D> results = performResolutionGuardedForExtraFunctionLiteralArguments(temporaryTrace, scope, expectedType, task, tracing);
|
||||
if (results.isSuccess()) {
|
||||
temporaryTrace.commit();
|
||||
|
||||
@@ -421,6 +428,53 @@ public class CallResolver {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@NotNull
|
||||
private <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> performResolutionGuardedForExtraFunctionLiteralArguments(
|
||||
@NotNull BindingTrace trace,
|
||||
@NotNull JetScope scope, @NotNull JetType expectedType,
|
||||
@NotNull ResolutionTask<D> task, @NotNull TracingStrategy tracing
|
||||
) {
|
||||
OverloadResolutionResultsImpl<D> results = performResolution(trace, scope, expectedType, task, tracing);
|
||||
// If resolution fails, we should check for some of the following situations:
|
||||
// class A {
|
||||
// val foo = Bar() // The following is intended to be an anonymous initializer,
|
||||
// // but is treated as a function literal argument
|
||||
// {
|
||||
// ...
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fun foo() {
|
||||
// bar {
|
||||
// buzz()
|
||||
// {...} // intended to be a returned from the outer literal
|
||||
// }
|
||||
// }
|
||||
EnumSet<OverloadResolutionResults.Code> someFailed = EnumSet.of(OverloadResolutionResults.Code.MANY_FAILED_CANDIDATES, OverloadResolutionResults.Code.SINGLE_CANDIDATE_ARGUMENT_MISMATCH);
|
||||
if (someFailed.contains(results.getResultCode()) && !task.getCall().getFunctionLiteralArguments().isEmpty()) {
|
||||
// We have some candidates that failed for some reason
|
||||
// And we have a suspect: the function literal argument
|
||||
// Now, we try to remove this argument and see if it helps
|
||||
Collection<ResolvedCallImpl<D>> newCandidates = Lists.newArrayList();
|
||||
for (ResolvedCallImpl<D> candidate : task.getCandidates()) {
|
||||
newCandidates.add(ResolvedCallImpl.create(candidate.getCandidateDescriptor()));
|
||||
}
|
||||
ResolutionTask<D> newTask = new ResolutionTask<D>(newCandidates, new DelegatingCall(task.getCall()) {
|
||||
@NotNull
|
||||
@Override
|
||||
public List<JetExpression> getFunctionLiteralArguments() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}, task.getDataFlowInfo());
|
||||
OverloadResolutionResultsImpl<D> resultsWithFunctionLiteralsStripped = performResolution(TemporaryBindingTrace.create(trace), scope, expectedType, newTask, tracing);
|
||||
if (resultsWithFunctionLiteralsStripped.isSuccess() || resultsWithFunctionLiteralsStripped.isAmbiguity()) {
|
||||
tracing.danglingFunctionLiteralArgumentSuspected(trace, task.getCall().getFunctionLiteralArguments());
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> performResolution(
|
||||
@NotNull BindingTrace trace,
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.lang.resolve.calls;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class DelegatingCall implements Call {
|
||||
|
||||
private final Call delegate;
|
||||
|
||||
public DelegatingCall(@NotNull Call delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public ASTNode getCallOperationNode() {
|
||||
return delegate.getCallOperationNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ReceiverDescriptor getExplicitReceiver() {
|
||||
return delegate.getExplicitReceiver();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public JetExpression getCalleeExpression() {
|
||||
return delegate.getCalleeExpression();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public JetValueArgumentList getValueArgumentList() {
|
||||
return delegate.getValueArgumentList();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<? extends ValueArgument> getValueArguments() {
|
||||
return delegate.getValueArguments();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<JetExpression> getFunctionLiteralArguments() {
|
||||
return delegate.getFunctionLiteralArguments();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<JetTypeProjection> getTypeArguments() {
|
||||
return delegate.getTypeArguments();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public JetTypeArgumentList getTypeArgumentList() {
|
||||
return delegate.getTypeArgumentList();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ASTNode getCallNode() {
|
||||
return delegate.getCallNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public PsiElement getCallElement() {
|
||||
return delegate.getCallElement();
|
||||
}
|
||||
}
|
||||
@@ -19,12 +19,14 @@ package org.jetbrains.jet.lang.resolve.calls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||
import org.jetbrains.jet.lang.resolve.calls.inference.SolutionStatus;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
@@ -72,6 +74,9 @@ import java.util.Collection;
|
||||
|
||||
@Override
|
||||
public void unnecessarySafeCall(@NotNull BindingTrace trace, @NotNull JetType type) {}
|
||||
|
||||
@Override
|
||||
public void danglingFunctionLiteralArgumentSuspected(@NotNull BindingTrace trace, @NotNull List<JetExpression> functionLiteralArguments) {}
|
||||
};
|
||||
|
||||
<D extends CallableDescriptor> void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCallImpl<D> resolvedCall);
|
||||
@@ -101,4 +106,6 @@ import java.util.Collection;
|
||||
void unsafeCall(@NotNull BindingTrace trace, @NotNull JetType type);
|
||||
|
||||
void unnecessarySafeCall(@NotNull BindingTrace trace, @NotNull JetType type);
|
||||
|
||||
void danglingFunctionLiteralArgumentSuspected(@NotNull BindingTrace trace, @NotNull List<JetExpression> functionLiteralArguments);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
//+JDK
|
||||
|
||||
class Foo() {
|
||||
private val builder = StringBuilder("sdfsd");
|
||||
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
class Foo1() {
|
||||
private val builder = <!NONE_APPLICABLE!>StringBuilder<!>("sdfsd")
|
||||
|
||||
<!DANGLING_FUNCTION_LITERAL_ARGUMENT_SUSPECTED!>{
|
||||
}<!>
|
||||
}
|
||||
|
||||
fun foo() = {
|
||||
<!NONE_APPLICABLE!>println<!>(1)
|
||||
<!DANGLING_FUNCTION_LITERAL_ARGUMENT_SUSPECTED!>{}<!>
|
||||
}
|
||||
|
||||
fun foo1() = {
|
||||
println(1);
|
||||
{}
|
||||
}
|
||||
|
||||
fun println(<!UNUSED_PARAMETER!>i<!> : Int) {}
|
||||
fun println(<!UNUSED_PARAMETER!>s<!> : Byte) {}
|
||||
fun println() {}
|
||||
@@ -32,7 +32,7 @@ fun main(args : Array<String>) {
|
||||
<!UNRESOLVED_REFERENCE!>a<!>.foo1()(<!UNRESOLVED_REFERENCE!>a<!>)
|
||||
|
||||
foo2()({})
|
||||
foo2()<!TOO_MANY_ARGUMENTS!>{}<!>
|
||||
foo2()<!TOO_MANY_ARGUMENTS, DANGLING_FUNCTION_LITERAL_ARGUMENT_SUSPECTED!>{}<!>
|
||||
(foo2()){}
|
||||
(foo2())<!TYPE_MISMATCH!>{<!CANNOT_INFER_PARAMETER_TYPE!>x<!> -> }<!>
|
||||
foo2()(<!TYPE_MISMATCH!>{<!CANNOT_INFER_PARAMETER_TYPE!>x<!> -> }<!>)
|
||||
|
||||
@@ -13,5 +13,5 @@ fun test() {
|
||||
v1({}, <!ERROR_COMPILE_TIME_VALUE!>1<!>, {})
|
||||
v1({}, {}, {it})
|
||||
v1({}) <!VARARG_OUTSIDE_PARENTHESES!>{}<!>
|
||||
v1 <!VARARG_OUTSIDE_PARENTHESES!>{}<!>
|
||||
v1 <!VARARG_OUTSIDE_PARENTHESES, DANGLING_FUNCTION_LITERAL_ARGUMENT_SUSPECTED!>{}<!>
|
||||
}
|
||||
Reference in New Issue
Block a user