KT-10631 Consider creating a synthetic property even when the setter returns 'this'

#KT-10631 Fixed
This commit is contained in:
Valentin Kipyatkov
2016-01-19 15:27:41 +03:00
parent eef68e0a94
commit a1d760fc36
15 changed files with 88 additions and 24 deletions
@@ -35,7 +35,7 @@ import org.jetbrains.kotlin.resolve.scopes.utils.collectDescriptorsFiltered
import org.jetbrains.kotlin.resolve.scopes.utils.memberScopeAsImportingScope
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.types.typeUtil.isUnit
import java.util.*
class ReferenceVariantsHelper(
@@ -92,7 +92,11 @@ class ReferenceVariantsHelper(
for (variant in variants) {
if (variant is SyntheticJavaPropertyDescriptor) {
accessorMethodsToRemove.add(variant.getMethod.original)
accessorMethodsToRemove.addIfNotNull(variant.setMethod?.original)
val setter = variant.setMethod
if (setter != null && setter.returnType?.isUnit() == true) { // we do not filter out non-Unit setters
accessorMethodsToRemove.add(setter.original)
}
}
}
@@ -0,0 +1,5 @@
interface JavaClass{
public int getSomething();
public JavaClass setSomething(int value);
}
@@ -0,0 +1,7 @@
fun foo(javaClass: JavaClass) {
javaClass.<caret>
}
// EXIST: { lookupString: "something", attributes: "bold" }
// EXIST: { lookupString: "setSomething", attributes: "bold" }
// ABSENT: getSomething
@@ -353,6 +353,12 @@ public class MultiFileJvmBasicCompletionTestGenerated extends AbstractMultiFileJ
doTest(fileName);
}
@TestMetadata("SyntheticExtensionNonVoidSetter")
public void testSyntheticExtensionNonVoidSetter() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/multifile/SyntheticExtensionNonVoidSetter/");
doTest(fileName);
}
@TestMetadata("TopLevelFunction")
public void testTopLevelFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/multifile/TopLevelFunction/");
@@ -53,6 +53,7 @@ import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.typeUtil.isUnit
class UsePropertyAccessSyntaxInspection : IntentionBasedInspection<KtCallExpression>(UsePropertyAccessSyntaxIntention()), CleanupLocalInspectionTool
@@ -95,6 +96,14 @@ class UsePropertyAccessSyntaxIntention : SelfTargetingOffsetIndependentIntention
if (!checkWillResolveToProperty(resolvedCall, property, bindingContext, resolutionScope, dataFlowInfo, expectedType, resolutionFacade)) return null
val isSetUsage = callExpression.valueArguments.size == 1
if (isSetUsage && bindingContext[BindingContext.USED_AS_EXPRESSION, qualifiedExpression] == true) {
// call to the setter used as expression can be converted in the only case when it's used as body expression for some declaration and its type is Unit
val parent = qualifiedExpression.parent
if (parent !is KtDeclarationWithBody || qualifiedExpression != parent.bodyExpression) return null
if (function.returnType?.isUnit() != true) return null
}
if (isSetUsage && property.type != function.valueParameters.single().type) {
val qualifiedExpressionCopy = qualifiedExpression.copied()
val callExpressionCopy = ((qualifiedExpressionCopy as? KtQualifiedExpression)?.selectorExpression ?: qualifiedExpressionCopy) as KtCallExpression
@@ -157,7 +166,6 @@ class UsePropertyAccessSyntaxIntention : SelfTargetingOffsetIndependentIntention
return callExpression.replaced(newExpression)
}
//TODO: what if it was used as expression (of type Unit)?
private fun replaceWithPropertySet(callExpression: KtCallExpression, propertyName: Name): KtExpression {
val call = callExpression.getQualifiedExpressionForSelector() ?: callExpression
val callParent = call.parent
@@ -0,0 +1,7 @@
public interface JavaInterface {
Object getSomething1();
JavaInterface setSomething1(Object value);
int getSomething2();
JavaInterface setSomething2(int value);
}
@@ -0,0 +1,7 @@
// IS_APPLICABLE: false
// WITH_RUNTIME
fun foo(j: JavaInterface) {
j.<caret>setSomething1("").setSomething2(1)
}
@@ -0,0 +1,4 @@
public interface JavaInterface {
Object getSomething();
JavaInterface setSomething(Object value);
}
@@ -0,0 +1,5 @@
// IS_APPLICABLE: false
// WITH_RUNTIME
fun foo(j: JavaInterface): JavaInterface = j.<caret>setSomething("")
@@ -9059,6 +9059,18 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
doTest(fileName);
}
@TestMetadata("nonVoidSetter1.kt")
public void testNonVoidSetter1() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/usePropertyAccessSyntax/nonVoidSetter1.kt");
doTest(fileName);
}
@TestMetadata("nonVoidSetter2.kt")
public void testNonVoidSetter2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/usePropertyAccessSyntax/nonVoidSetter2.kt");
doTest(fileName);
}
@TestMetadata("propertyTypeIsMoreSpecific1.kt")
public void testPropertyTypeIsMoreSpecific1() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/usePropertyAccessSyntax/propertyTypeIsMoreSpecific1.kt");