Fix operator warning on 'Constr()()'

This commit is contained in:
Yan Zhulanow
2015-09-29 18:44:53 +03:00
parent 7e4fbfaa6d
commit e6c0d4692a
12 changed files with 51 additions and 37 deletions
@@ -217,7 +217,7 @@ public class DelegatedPropertyResolver {
JetPropertyDelegate delegate = property.getDelegate(); JetPropertyDelegate delegate = property.getDelegate();
if (delegate != null) { if (delegate != null) {
PsiElement byKeyword = delegate.getByKeywordNode().getPsi(); PsiElement byKeyword = delegate.getByKeywordNode().getPsi();
symbolUsageValidator.validateCall(resultingCall.getResultingDescriptor(), trace, byKeyword); symbolUsageValidator.validateCall(resultingCall, resultingCall.getResultingDescriptor(), trace, byKeyword);
} }
} }
trace.record(DELEGATED_PROPERTY_RESOLVED_CALL, accessor, resultingCall); trace.record(DELEGATED_PROPERTY_RESOLVED_CALL, accessor, resultingCall);
@@ -86,7 +86,7 @@ public class CallCompleter(
resolvedCall.variableCall.getCall().getCalleeExpression() resolvedCall.variableCall.getCall().getCalleeExpression()
else else
resolvedCall.getCall().getCalleeExpression() resolvedCall.getCall().getCalleeExpression()
symbolUsageValidator.validateCall(resolvedCall.getResultingDescriptor(), context.trace, element!!) symbolUsageValidator.validateCall(resolvedCall, resolvedCall.getResultingDescriptor(), context.trace, element!!)
} }
if (results.isSingleResult() && results.getResultingCall().getStatus().isSuccess()) { if (results.isSingleResult() && results.getResultingCall().getStatus().isSuccess()) {
@@ -33,18 +33,19 @@ import org.jetbrains.kotlin.resolve.annotations.argumentValue
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.PROPERTY_GETTER import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.PROPERTY_GETTER
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.PROPERTY_SETTER import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.PROPERTY_SETTER
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
public class DeprecatedSymbolValidator : SymbolUsageValidator { public class DeprecatedSymbolValidator : SymbolUsageValidator {
private val JAVA_DEPRECATED = FqName(java.lang.Deprecated::class.java.name) private val JAVA_DEPRECATED = FqName(java.lang.Deprecated::class.java.name)
override fun validateCall(targetDescriptor: CallableDescriptor, trace: BindingTrace, element: PsiElement) { override fun validateCall(resolvedCall: ResolvedCall<*>?, targetDescriptor: CallableDescriptor, trace: BindingTrace, element: PsiElement) {
val deprecated = targetDescriptor.getDeprecatedAnnotation() val deprecated = targetDescriptor.getDeprecatedAnnotation()
if (deprecated != null) { if (deprecated != null) {
val (annotation, target) = deprecated val (annotation, target) = deprecated
trace.report(createDeprecationDiagnostic(element, target, annotation)) trace.report(createDeprecationDiagnostic(element, target, annotation))
} }
else if (targetDescriptor is PropertyDescriptor) { else if (targetDescriptor is PropertyDescriptor) {
propertyGetterWorkaround(targetDescriptor, trace, element) propertyGetterWorkaround(resolvedCall, targetDescriptor, trace, element)
} }
} }
@@ -122,8 +123,15 @@ public class DeprecatedSymbolValidator : SymbolUsageValidator {
Errors.DEPRECATED_SYMBOL_WITH_MESSAGE.on(element, descriptor.original, message) Errors.DEPRECATED_SYMBOL_WITH_MESSAGE.on(element, descriptor.original, message)
} }
private val PROPERTY_SET_OPERATIONS = TokenSet.create(JetTokens.EQ, JetTokens.PLUSEQ, JetTokens.MINUSEQ, JetTokens.MULTEQ, JetTokens.DIVEQ, JetTokens.PERCEQ, JetTokens.PLUSPLUS, JetTokens.MINUSMINUS) private val PROPERTY_SET_OPERATIONS = TokenSet.create(JetTokens.EQ, JetTokens.PLUSEQ, JetTokens.MINUSEQ, JetTokens.MULTEQ,
fun propertyGetterWorkaround(propertyDescriptor: PropertyDescriptor, trace: BindingTrace, expression: PsiElement) { JetTokens.DIVEQ, JetTokens.PERCEQ, JetTokens.PLUSPLUS, JetTokens.MINUSMINUS)
fun propertyGetterWorkaround(
resolvedCall: ResolvedCall<*>?,
propertyDescriptor: PropertyDescriptor,
trace: BindingTrace,
expression: PsiElement
) {
// property getters do not come as callable yet, so we analyse surroundings to check for deprecation annotation on getter // property getters do not come as callable yet, so we analyse surroundings to check for deprecation annotation on getter
val binaryExpression = PsiTreeUtil.getParentOfType<JetBinaryExpression>(expression, javaClass<JetBinaryExpression>()) val binaryExpression = PsiTreeUtil.getParentOfType<JetBinaryExpression>(expression, javaClass<JetBinaryExpression>())
if (binaryExpression != null) { if (binaryExpression != null) {
@@ -159,6 +167,6 @@ public class DeprecatedSymbolValidator : SymbolUsageValidator {
return // skip Type::property return // skip Type::property
} }
propertyDescriptor.getGetter()?.let { validateCall(it, trace, expression) } propertyDescriptor.getGetter()?.let { validateCall(resolvedCall, it, trace, expression) }
} }
} }
@@ -23,13 +23,19 @@ import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.JetBinaryExpression import org.jetbrains.kotlin.psi.JetBinaryExpression
import org.jetbrains.kotlin.psi.JetOperationReferenceExpression import org.jetbrains.kotlin.psi.JetOperationReferenceExpression
import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.ErrorUtils
public class InfixValidator : SymbolUsageValidator { public class InfixValidator : SymbolUsageValidator {
override fun validateCall(targetDescriptor: CallableDescriptor, trace: BindingTrace, element: PsiElement) { override fun validateCall(
resolvedCall: ResolvedCall<*>?,
targetDescriptor: CallableDescriptor,
trace: BindingTrace,
element: PsiElement
) {
val functionDescriptor = targetDescriptor as? FunctionDescriptor ?: return val functionDescriptor = targetDescriptor as? FunctionDescriptor ?: return
if (functionDescriptor.isDynamic() || ErrorUtils.isError(functionDescriptor)) return if (functionDescriptor.isDynamic() || ErrorUtils.isError(functionDescriptor)) return
if (isInfixCall(element) && !functionDescriptor.isInfix) { if (isInfixCall(element) && !functionDescriptor.isInfix) {
@@ -21,35 +21,31 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.JetArrayAccessExpression import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.JetElement
import org.jetbrains.kotlin.psi.JetMultiDeclarationEntry
import org.jetbrains.kotlin.psi.JetOperationReferenceExpression
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.bindingContextUtil.get
import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall import org.jetbrains.kotlin.resolve.calls.CallTransformer
import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic
import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.bindingContextUtil.get import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
public class OperatorValidator : SymbolUsageValidator { public class OperatorValidator : SymbolUsageValidator {
override fun validateCall(targetDescriptor: CallableDescriptor, trace: BindingTrace, element: PsiElement) { override fun validateCall(resolvedCall: ResolvedCall<*>?, targetDescriptor: CallableDescriptor, trace: BindingTrace, element: PsiElement) {
val functionDescriptor = targetDescriptor as? FunctionDescriptor ?: return val functionDescriptor = targetDescriptor as? FunctionDescriptor ?: return
if (functionDescriptor.isDynamic() || ErrorUtils.isError(functionDescriptor)) return if (functionDescriptor.isDynamic() || ErrorUtils.isError(functionDescriptor)) return
val jetElement = element as? JetElement ?: return val jetElement = element as? JetElement ?: return
val call = trace.bindingContext[BindingContext.CALL, jetElement] val call = resolvedCall?.call ?: trace.bindingContext[BindingContext.CALL, jetElement]
fun isVariableAsFunctionCall(): Boolean { fun isInvokeCall(): Boolean {
if (call == null) return false return call is CallTransformer.CallForImplicitInvoke
val resolvedCall = trace.bindingContext[BindingContext.RESOLVED_CALL, call] ?: return false
return resolvedCall is VariableAsFunctionResolvedCall
} }
fun isMultiDeclaration(): Boolean { fun isMultiDeclaration(): Boolean {
return call?.callElement is JetMultiDeclarationEntry return (resolvedCall != null) && (call?.callElement is JetMultiDeclarationEntry)
} }
fun isConventionOperator(): Boolean { fun isConventionOperator(): Boolean {
@@ -59,14 +55,14 @@ public class OperatorValidator : SymbolUsageValidator {
fun isArrayAccessExpression() = jetElement is JetArrayAccessExpression fun isArrayAccessExpression() = jetElement is JetArrayAccessExpression
if (isMultiDeclaration()) { if (isMultiDeclaration() || isInvokeCall()) {
if (!functionDescriptor.isOperator && call != null) { if (!functionDescriptor.isOperator && call != null) {
report(call.callElement, functionDescriptor, trace) report(call.callElement, functionDescriptor, trace)
} }
return return
} }
if (isVariableAsFunctionCall() || isConventionOperator() || isArrayAccessExpression()) { if (isConventionOperator() || isArrayAccessExpression()) {
if (!functionDescriptor.isOperator) { if (!functionDescriptor.isOperator) {
report(jetElement, functionDescriptor, trace) report(jetElement, functionDescriptor, trace)
} }
@@ -20,16 +20,17 @@ import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
public interface SymbolUsageValidator { public interface SymbolUsageValidator {
public fun validateTypeUsage(targetDescriptor: ClassifierDescriptor, trace: BindingTrace, element: PsiElement) { } public fun validateTypeUsage(targetDescriptor: ClassifierDescriptor, trace: BindingTrace, element: PsiElement) { }
public fun validateCall(targetDescriptor: CallableDescriptor, trace: BindingTrace, element: PsiElement) { } public fun validateCall(resolvedCall: ResolvedCall<*>?, targetDescriptor: CallableDescriptor, trace: BindingTrace, element: PsiElement) { }
public open class Composite(val validators: List<SymbolUsageValidator>) : SymbolUsageValidator { public open class Composite(val validators: List<SymbolUsageValidator>) : SymbolUsageValidator {
override fun validateCall(targetDescriptor: CallableDescriptor, trace: BindingTrace, element: PsiElement) { override fun validateCall(resolvedCall: ResolvedCall<*>?, targetDescriptor: CallableDescriptor, trace: BindingTrace, element: PsiElement) {
validators.forEach { it.validateCall(targetDescriptor, trace, element) } validators.forEach { it.validateCall(resolvedCall, targetDescriptor, trace, element) }
} }
override fun validateTypeUsage(targetDescriptor: ClassifierDescriptor, trace: BindingTrace, element: PsiElement) { override fun validateTypeUsage(targetDescriptor: ClassifierDescriptor, trace: BindingTrace, element: PsiElement) {
@@ -501,7 +501,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
checker.check(resolvedCall, resolutionContext); checker.check(resolvedCall, resolutionContext);
} }
components.symbolUsageValidator.validateCall(descriptor, trace, expression); components.symbolUsageValidator.validateCall(resolvedCall, descriptor, trace, expression);
} }
private static boolean isDeclaredInClass(ReceiverParameterDescriptor receiver) { private static boolean isDeclaredInClass(ReceiverParameterDescriptor receiver) {
@@ -943,7 +943,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
result = false; result = false;
} else { } else {
if (setter != null) { if (setter != null) {
components.symbolUsageValidator.validateCall(setter, trace, reportOn); components.symbolUsageValidator.validateCall(null, setter, trace, reportOn);
} }
} }
} }
@@ -79,7 +79,7 @@ public class ForLoopConventionsChecker {
checkIfOperatorModifierPresent(loopRangeExpression, iteratorFunction, context.trace); checkIfOperatorModifierPresent(loopRangeExpression, iteratorFunction, context.trace);
symbolUsageValidator.validateCall(iteratorFunction, context.trace, loopRangeExpression); symbolUsageValidator.validateCall(iteratorResolvedCall, iteratorFunction, context.trace, loopRangeExpression);
JetType iteratorType = iteratorFunction.getReturnType(); JetType iteratorType = iteratorFunction.getReturnType();
JetType hasNextType = checkConventionForIterator(context, loopRangeExpression, iteratorType, "hasNext", JetType hasNextType = checkConventionForIterator(context, loopRangeExpression, iteratorType, "hasNext",
@@ -140,7 +140,7 @@ public class ForLoopConventionsChecker {
ResolvedCall<FunctionDescriptor> resolvedCall = nextResolutionResults.getResultingCall(); ResolvedCall<FunctionDescriptor> resolvedCall = nextResolutionResults.getResultingCall();
context.trace.record(resolvedCallKey, loopRangeExpression, resolvedCall); context.trace.record(resolvedCallKey, loopRangeExpression, resolvedCall);
FunctionDescriptor functionDescriptor = resolvedCall.getResultingDescriptor(); FunctionDescriptor functionDescriptor = resolvedCall.getResultingDescriptor();
symbolUsageValidator.validateCall(functionDescriptor, context.trace, loopRangeExpression); symbolUsageValidator.validateCall(resolvedCall, functionDescriptor, context.trace, loopRangeExpression);
checkIfOperatorModifierPresent(loopRangeExpression, functionDescriptor, context.trace); checkIfOperatorModifierPresent(loopRangeExpression, functionDescriptor, context.trace);
@@ -57,7 +57,7 @@ public class MultiDeclarationResolver(
context.trace.record(BindingContext.COMPONENT_RESOLVED_CALL, entry, results.getResultingCall()) context.trace.record(BindingContext.COMPONENT_RESOLVED_CALL, entry, results.getResultingCall())
val functionDescriptor = results.getResultingDescriptor() val functionDescriptor = results.getResultingDescriptor()
symbolUsageValidator.validateCall(functionDescriptor, context.trace, entry) symbolUsageValidator.validateCall(null, functionDescriptor, context.trace, entry)
componentType = functionDescriptor.getReturnType() componentType = functionDescriptor.getReturnType()
if (componentType != null && !TypeUtils.noExpectedType(expectedType) && !JetTypeChecker.DEFAULT.isSubtypeOf(componentType, expectedType)) { if (componentType != null && !TypeUtils.noExpectedType(expectedType) && !JetTypeChecker.DEFAULT.isSubtypeOf(componentType, expectedType)) {
+4 -1
View File
@@ -88,8 +88,11 @@ fun a() {
<!OPERATOR_MODIFIER_REQUIRED!>!<!>a <!OPERATOR_MODIFIER_REQUIRED!>!<!>a
!c !c
<!OPERATOR_MODIFIER_REQUIRED!>a<!>() <!OPERATOR_MODIFIER_REQUIRED!>a()<!>
c() c()
<!OPERATOR_MODIFIER_REQUIRED!>Example()()<!>
Example2()()
} }
abstract class Base { abstract class Base {
@@ -1,10 +1,10 @@
fun testInvoke() { fun testInvoke() {
fun Nothing.invoke() = this operator fun Nothing.invoke() = this
todo()<!UNREACHABLE_CODE!>()<!> todo()<!UNREACHABLE_CODE!>()<!>
} }
fun testInvokeWithLambda() { fun testInvokeWithLambda() {
fun Nothing.invoke(<!UNUSED_PARAMETER!>i<!>: Int, f: () -> Int) = f operator fun Nothing.invoke(<!UNUSED_PARAMETER!>i<!>: Int, f: () -> Int) = f
todo()<!UNREACHABLE_CODE!>(1){ 42 }<!> todo()<!UNREACHABLE_CODE!>(1){ 42 }<!>
} }
@@ -17,7 +17,7 @@ public class J {
// FILE: k.kt // FILE: k.kt
fun test() { fun test() {
J.<!OPERATOR_MODIFIER_REQUIRED!>staticNN<!>() J.<!OPERATOR_MODIFIER_REQUIRED!>staticNN()<!>
J.<!UNSAFE_CALL, OPERATOR_MODIFIER_REQUIRED!>staticN<!>() J.<!OPERATOR_MODIFIER_REQUIRED!><!UNSAFE_CALL!>staticN<!>()<!>
J.<!OPERATOR_MODIFIER_REQUIRED!>staticJ<!>() J.<!OPERATOR_MODIFIER_REQUIRED!>staticJ()<!>
} }