Inspection (and quickfix) for extension propeties conflicting with synthetic ones

This commit is contained in:
Valentin Kipyatkov
2015-08-31 19:08:01 +03:00
parent d41e01c0e4
commit 10f7d6d7dd
45 changed files with 620 additions and 16 deletions
@@ -68,6 +68,8 @@ public object DirectiveBasedActionUtils {
"Edit intention settings", "Edit intention settings",
"Edit inspection profile setting", "Edit inspection profile setting",
"Inject language or reference", "Inject language or reference",
"Suppress '" "Suppress '",
"Run inspection on",
"Inspection '"
) )
} }
@@ -0,0 +1,5 @@
<html>
<body>
This inspection reports extension properties that conflict with synthetic ones automatically produced from Java get/set-methods and that should be either removed or renamed to avoid breaking code by future changes in the compiler.
</body>
</html>
+7
View File
@@ -1138,6 +1138,13 @@
level="WARNING" level="WARNING"
/> />
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.ConflictingExtensionPropertyInspection"
displayName="Extension property conflicts with synthetic one"
groupName="Kotlin"
enabledByDefault="true"
level="WARNING"
/>
<project.converterProvider implementation="org.jetbrains.kotlin.idea.converters.JetRunConfigurationSettingsFormatConverterProvider"/> <project.converterProvider implementation="org.jetbrains.kotlin.idea.converters.JetRunConfigurationSettingsFormatConverterProvider"/>
<fileType.fileViewProviderFactory filetype="KJSM" implementationClass="com.intellij.psi.ClassFileViewProviderFactory"/> <fileType.fileViewProviderFactory filetype="KJSM" implementationClass="com.intellij.psi.ClassFileViewProviderFactory"/>
@@ -0,0 +1,195 @@
/*
* Copyright 2010-2015 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.kotlin.idea.inspections
import com.intellij.codeInspection.*
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.progress.Task
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.util.ui.UIUtil
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getFileTopLevelScope
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.core.targetDescriptors
import org.jetbrains.kotlin.idea.imports.importableFqName
import org.jetbrains.kotlin.idea.quickfix.JetIntentionAction
import org.jetbrains.kotlin.idea.references.JetSimpleNameReference
import org.jetbrains.kotlin.idea.stubindex.JetSourceFilterScope
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.scopes.FileScope
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
public class ConflictingExtensionPropertyInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
val file = session.file as? JetFile ?: return PsiElementVisitor.EMPTY_VISITOR
val fileScope = file.getResolutionFacade().getFileTopLevelScope(file)
return object : JetVisitorVoid() {
override fun visitProperty(property: JetProperty) {
super.visitProperty(property)
if (property.receiverTypeReference != null) {
val nameElement = property.nameIdentifier ?: return
val conflictingExtension = conflictingSyntheticExtension(property.resolveToDescriptor() as PropertyDescriptor, fileScope)
if (conflictingExtension != null) {
val problemDescriptor = holder.manager.createProblemDescriptor(
nameElement,
//TODO: review message
"This property conflicts with synthetic extension and should be removed to avoid breaking code by future changes in the compiler",
createQuickFix(property, conflictingExtension),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
true
)
holder.registerProblem(problemDescriptor)
}
}
}
}
}
private fun conflictingSyntheticExtension(descriptor: PropertyDescriptor, fileScope: FileScope): SyntheticJavaPropertyDescriptor? {
val extensionReceiverType = descriptor.extensionReceiverParameter?.type ?: return null
return fileScope
.getSyntheticExtensionProperties(listOf(extensionReceiverType), descriptor.name, NoLookupLocation.FROM_IDE)
.firstIsInstanceOrNull()
}
private fun createQuickFix(declaration: JetProperty, syntheticProperty: SyntheticJavaPropertyDescriptor): LocalQuickFix? {
val getter = declaration.getter ?: return null
val setter = declaration.setter
if (!checkGetterBodyIsGetMethodCall(getter, syntheticProperty.getMethod)) return null
if (setter != null) {
val setMethod = syntheticProperty.setMethod ?: return null // synthetic property is val but our property is var
if (!checkSetterBodyIsSetMethodCall(setter, setMethod)) return null
}
return IntentionWrapper(DeleteRedundantExtensionAction(declaration), declaration.containingFile)
}
private fun checkGetterBodyIsGetMethodCall(getter: JetPropertyAccessor, getMethod: FunctionDescriptor): Boolean {
if (getter.hasBlockBody()) {
val statement = (getter.bodyExpression as? JetBlockExpression)?.statements?.singleOrNull() ?: return false
return (statement as? JetReturnExpression)?.returnedExpression.isGetMethodCall(getMethod)
}
else {
return getter.bodyExpression.isGetMethodCall(getMethod)
}
}
private fun checkSetterBodyIsSetMethodCall(setter: JetPropertyAccessor, setMethod: FunctionDescriptor): Boolean {
val valueParameterName = setter.valueParameters.singleOrNull()?.nameAsName ?: return false
if (!setter.hasBlockBody()) return false
val statement = (setter.bodyExpression as? JetBlockExpression)?.statements?.singleOrNull() ?: return false
return statement.isSetMethodCall(setMethod, valueParameterName)
}
private fun JetExpression?.isGetMethodCall(getMethod: FunctionDescriptor): Boolean {
when (this) {
is JetCallExpression -> {
val resolvedCall = getResolvedCall(analyze())
return resolvedCall != null && resolvedCall.status.isSuccess && resolvedCall.resultingDescriptor.original == getMethod.original
}
is JetQualifiedExpression -> {
val receiver = receiverExpression
return receiver is JetThisExpression && receiver.labelQualifier == null && selectorExpression.isGetMethodCall(getMethod)
}
else -> return false
}
}
private fun JetExpression?.isSetMethodCall(setMethod: FunctionDescriptor, valueParameterName: Name): Boolean {
when (this) {
is JetCallExpression -> {
if ((valueArguments.singleOrNull()?.getArgumentExpression() as? JetSimpleNameExpression)?.getReferencedNameAsName() != valueParameterName) return false
val resolvedCall = getResolvedCall(analyze())
return resolvedCall != null && resolvedCall.status.isSuccess && resolvedCall.resultingDescriptor.original == setMethod.original
}
is JetQualifiedExpression -> {
val receiver = receiverExpression
return receiver is JetThisExpression && receiver.labelQualifier == null && selectorExpression.isSetMethodCall(setMethod, valueParameterName)
}
else -> return false
}
}
private class DeleteRedundantExtensionAction(property: JetProperty) : JetIntentionAction<JetProperty>(property) {
private val LOG = Logger.getInstance(DeleteRedundantExtensionAction::class.java);
override fun getFamilyName() = "Delete redundant extension property"
override fun getText() = familyName
override fun startInWriteAction() = false
override fun invoke(project: Project, editor: Editor?, file: JetFile) {
val declaration = element
val fqName = declaration.resolveToDescriptor().importableFqName
if (fqName != null) {
ProgressManager.getInstance().run(
object : Task.Modal(project, "Searching for imports to delete", true) {
override fun run(indicator: ProgressIndicator) {
val importsToDelete = runReadAction {
val searchScope = JetSourceFilterScope.kotlinSources(GlobalSearchScope.projectScope(project), project)
ReferencesSearch.search(declaration, searchScope)
.filterIsInstance<JetSimpleNameReference>()
.map { ref -> ref.expression.getStrictParentOfType<JetImportDirective>() }
.filterNotNull()
.filter { import -> !import.isAllUnder && import.targetDescriptors().size() == 1 }
}
UIUtil.invokeLaterIfNeeded {
project.executeWriteCommand(text) {
importsToDelete.forEach { import ->
try {
import.delete()
}
catch(e: Exception) {
LOG.error(e)
}
}
declaration.delete()
}
}
}
})
}
else {
project.executeWriteCommand(text) { declaration.delete() }
}
}
}
}
@@ -0,0 +1,16 @@
import java.io.File
import java.io.Serializable
val File.name: String
get() = getName()
val Serializable.name: String
get() = ""
val File.parent: File
get() = getParentFile()
class MyFile : File("")
val MyFile.isFile: Boolean
get() = isFile()
@@ -0,0 +1,28 @@
<problems>
<problem>
<file>File.kt</file>
<line>4</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="File.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Extension property conflicts with automatically produced one</problem_class>
<description>This property conflicts with synthetic extension and should be removed to avoid breaking code by future changes in the compiler</description>
</problem>
<problem>
<file>File.kt</file>
<line>10</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="File.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Extension property conflicts with automatically produced one</problem_class>
<description>This property conflicts with synthetic extension and should be removed to avoid breaking code by future changes in the compiler</description>
</problem>
<problem>
<file>File.kt</file>
<line>15</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="File.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Extension property conflicts with automatically produced one</problem_class>
<description>This property conflicts with synthetic extension and should be removed to avoid breaking code by future changes in the compiler</description>
</problem>
</problems>
@@ -0,0 +1 @@
// INSPECTION_CLASS: org.jetbrains.kotlin.idea.inspections.ConflictingExtensionPropertyInspection
@@ -1,5 +1,4 @@
// "class org.jetbrains.kotlin.idea.quickfix.DeprecatedSymbolUsageFix" "false" // "class org.jetbrains.kotlin.idea.quickfix.DeprecatedSymbolUsageFix" "false"
// ACTION: Inspection 'DEPRECATED_SYMBOL_WITH_MESSAGE' options
fun foo() { fun foo() {
val c = JavaClass() val c = JavaClass()
@@ -0,0 +1 @@
org.jetbrains.kotlin.idea.inspections.ConflictingExtensionPropertyInspection
@@ -0,0 +1,7 @@
// "Delete redundant extension property" "true"
var Thread.<caret>priority: Int
get() = this.getPriority()
set(value) {
this.setPriority(value)
}
@@ -0,0 +1,2 @@
// "Delete redundant extension property" "true"
@@ -0,0 +1,7 @@
// "Delete redundant extension property" "true"
import java.io.File
class C {
val File.<caret>name: String
get() = getName()
}
@@ -0,0 +1,5 @@
// "Delete redundant extension property" "true"
import java.io.File
class C {
}
@@ -0,0 +1,4 @@
package test
fun foo() {
}
@@ -0,0 +1,8 @@
package test
import java.io.File
import utils.*
fun foo(file: File) {
print(file.name)
}
@@ -0,0 +1,7 @@
package test
import java.io.File
fun foo(file: File) {
print(file.name)
}
@@ -0,0 +1,6 @@
// "Delete redundant extension property" "true"
package utils
import java.io.File
// WITH_RUNTIME
@@ -0,0 +1,6 @@
package test
import utils.name
fun foo() {
}
@@ -0,0 +1,9 @@
// "Delete redundant extension property" "true"
package utils
import java.io.File
val File.<caret>name: String
get() = getName()
// WITH_RUNTIME
@@ -0,0 +1,8 @@
package test
import java.io.File
import utils.*
fun foo(file: File) {
print(file.name)
}
@@ -0,0 +1,8 @@
package test
import java.io.File
import utils.name
fun foo(file: File) {
print(file.name)
}
@@ -0,0 +1,9 @@
package test
import java.io.File
import utils.name
fun foo(file: File, thread: Thread) {
print(file.name)
print(thread.name)
}
@@ -0,0 +1,9 @@
// "Delete redundant extension property" "true"
package utils
import java.io.File
val Thread.name: String
get() = getName()
// WITH_RUNTIME
@@ -0,0 +1,12 @@
// "Delete redundant extension property" "true"
package utils
import java.io.File
val File.<caret>name: String
get() = getName()
val Thread.name: String
get() = getName()
// WITH_RUNTIME
@@ -0,0 +1,9 @@
package test
import java.io.File
import utils.name
fun foo(file: File, thread: Thread) {
print(file.name)
print(thread.name)
}
@@ -0,0 +1,5 @@
// "Delete redundant extension property" "true"
import java.io.File
val File.<caret>name: String
get() { return getName() }
@@ -0,0 +1,3 @@
// "Delete redundant extension property" "true"
import java.io.File
@@ -0,0 +1,5 @@
// "Delete redundant extension property" "true"
import java.io.File
val File.<caret>name: String
get() = getName()
@@ -0,0 +1,3 @@
// "Delete redundant extension property" "true"
import java.io.File
@@ -0,0 +1,4 @@
// "Delete redundant extension property" "true"
val Thread.<caret>priority: Int
get() = getPriority()
@@ -0,0 +1,2 @@
// "Delete redundant extension property" "true"
@@ -0,0 +1,6 @@
// "Delete redundant extension property" "false"
import java.io.File
var File.<caret>name: String
get() = getName()
set(value) {}
@@ -0,0 +1,7 @@
// "Delete redundant extension property" "true"
var Thread.<caret>priority: Int
get() = getPriority()
set(value) {
setPriority(value)
}
@@ -0,0 +1,2 @@
// "Delete redundant extension property" "true"
@@ -0,0 +1,7 @@
// "Delete redundant extension property" "false"
// ACTION: Convert property to function
class C : Thread() {
val Thread.<caret>priority: Int
get() = this@C.getPriority()
}
@@ -0,0 +1,9 @@
// "Delete redundant extension property" "false"
class C : Thread() {
var Thread.<caret>priority: Int
get() = getPriority()
set(value) {
this@C.setPriority(value)
}
}
@@ -0,0 +1,7 @@
// "Delete redundant extension property" "false"
var Thread.<caret>priority: Int
get() = getPriority() + 1
set(value) {
setPriority(value)
}
@@ -0,0 +1,6 @@
// "Delete redundant extension property" "false"
// ACTION: Convert property to function
import java.io.File
public val File.<caret>parent: File?
get() = getParentFile()
@@ -0,0 +1,8 @@
// "Delete redundant extension property" "false"
var Thread.<caret>priority: Int
get() = this.getPriority()
set(value) {
this.setPriority(value)
System.out.print("set")
}
@@ -94,6 +94,12 @@ public class JetInspectionTestGenerated extends AbstractJetInspectionTest {
JetTestUtils.assertAllTestsPresentInSingleGeneratedClass(this.getClass(), new File("idea/testData/inspections"), Pattern.compile("^(inspections\\.test)$")); JetTestUtils.assertAllTestsPresentInSingleGeneratedClass(this.getClass(), new File("idea/testData/inspections"), Pattern.compile("^(inspections\\.test)$"));
} }
@TestMetadata("conflictingExtensionProperty/inspectionData/inspections.test")
public void testConflictingExtensionProperty_inspectionData_Inspections_test() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/inspections/conflictingExtensionProperty/inspectionData/inspections.test");
doTest(fileName);
}
@TestMetadata("redundantSamConstructor/inspectionData/inspections.test") @TestMetadata("redundantSamConstructor/inspectionData/inspections.test")
public void testRedundantSamConstructor_inspectionData_Inspections_test() throws Exception { public void testRedundantSamConstructor_inspectionData_Inspections_test() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/inspections/redundantSamConstructor/inspectionData/inspections.test"); String fileName = JetTestUtils.navigationMetadata("idea/testData/inspections/redundantSamConstructor/inspectionData/inspections.test");
@@ -21,18 +21,24 @@ import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.codeInsight.daemon.quickFix.LightQuickFixTestCase; import com.intellij.codeInsight.daemon.quickFix.LightQuickFixTestCase;
import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler; import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler;
import com.intellij.codeInspection.InspectionEP;
import com.intellij.codeInspection.InspectionProfileEntry;
import com.intellij.codeInspection.LocalInspectionEP;
import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.io.FileUtil;
import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFile;
import com.intellij.util.ArrayUtil; import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.UIUtil;
import junit.framework.ComparisonFailure; import junit.framework.ComparisonFailure;
import kotlin.KotlinPackage; import kotlin.KotlinPackage;
import kotlin.jvm.functions.Function1; import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.idea.KotlinDaemonAnalyzerTestCase; import org.jetbrains.kotlin.idea.KotlinDaemonAnalyzerTestCase;
import org.jetbrains.kotlin.idea.quickfix.utils.UtilsPackage;
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil; import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil;
import org.jetbrains.kotlin.idea.test.DirectiveBasedActionUtils; import org.jetbrains.kotlin.idea.test.DirectiveBasedActionUtils;
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase; import org.jetbrains.kotlin.idea.test.PluginTestCaseBase;
@@ -42,6 +48,7 @@ import org.jetbrains.kotlin.test.JetTestUtils;
import java.io.File; import java.io.File;
import java.io.FilenameFilter; import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@@ -65,9 +72,35 @@ public abstract class AbstractQuickFixMultiFileTest extends KotlinDaemonAnalyzer
} }
protected void doTestWithExtraFile(String beforeFileName) throws Exception { protected void doTestWithExtraFile(String beforeFileName) throws Exception {
enableInspections(beforeFileName);
doTest(beforeFileName, true); doTest(beforeFileName, true);
} }
private void enableInspections(String beforeFileName) throws IOException, ClassNotFoundException {
File inspectionFile = UtilsPackage.findInspectionFile(new File(beforeFileName).getParentFile());
if (inspectionFile != null) {
String className = FileUtil.loadFile(inspectionFile).trim();
Class<?> inspectionClass = Class.forName(className);
enableInspectionTools(inspectionClass);
}
}
private void enableInspectionTools(@NotNull Class<?> klass) {
List<InspectionEP> eps = ContainerUtil.newArrayList();
ContainerUtil.addAll(eps, Extensions.getExtensions(LocalInspectionEP.LOCAL_INSPECTION));
ContainerUtil.addAll(eps, Extensions.getExtensions(InspectionEP.GLOBAL_INSPECTION));
InspectionProfileEntry tool = null;
for (InspectionEP ep : eps) {
if (klass.getName().equals(ep.implementationClass)) {
tool = ep.instantiateTool();
}
}
assert tool != null : "Could not find inspection tool for class: " + klass;
enableInspectionTools(tool);
}
@Override @Override
protected void setUp() throws Exception { protected void setUp() throws Exception {
super.setUp(); super.setUp();
@@ -41,6 +41,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.idea.KotlinLightQuickFixTestCase; import org.jetbrains.kotlin.idea.KotlinLightQuickFixTestCase;
import org.jetbrains.kotlin.idea.js.KotlinJavaScriptLibraryManager; import org.jetbrains.kotlin.idea.js.KotlinJavaScriptLibraryManager;
import org.jetbrains.kotlin.idea.quickfix.utils.UtilsPackage;
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil; import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil;
import org.jetbrains.kotlin.idea.test.DirectiveBasedActionUtils; import org.jetbrains.kotlin.idea.test.DirectiveBasedActionUtils;
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase; import org.jetbrains.kotlin.idea.test.PluginTestCaseBase;
@@ -64,19 +65,6 @@ public abstract class AbstractQuickFixTest extends KotlinLightQuickFixTestCase {
((StartupManagerImpl) StartupManager.getInstance(getProject())).runPostStartupActivities(); ((StartupManagerImpl) StartupManager.getInstance(getProject())).runPostStartupActivities();
} }
@Nullable
private static File findInspectionFile(@NotNull File startDir) {
File currentDir = startDir;
while (currentDir != null) {
File inspectionFile = new File(currentDir, ".inspection");
if (inspectionFile.exists()) {
return inspectionFile;
}
currentDir = currentDir.getParentFile();
}
return null;
}
protected void doTest(@NotNull String beforeFileName) throws Exception { protected void doTest(@NotNull String beforeFileName) throws Exception {
try { try {
configureRuntimeIfNeeded(beforeFileName); configureRuntimeIfNeeded(beforeFileName);
@@ -184,7 +172,7 @@ public abstract class AbstractQuickFixTest extends KotlinLightQuickFixTestCase {
} }
private void enableInspections(String beforeFileName) throws IOException, ClassNotFoundException { private void enableInspections(String beforeFileName) throws IOException, ClassNotFoundException {
File inspectionFile = findInspectionFile(new File(beforeFileName).getParentFile()); File inspectionFile = UtilsPackage.findInspectionFile(new File(beforeFileName).getParentFile());
if (inspectionFile != null) { if (inspectionFile != null) {
String className = FileUtil.loadFile(inspectionFile).trim(); String className = FileUtil.loadFile(inspectionFile).trim();
Class<?> inspectionClass = Class.forName(className); Class<?> inspectionClass = Class.forName(className);
@@ -990,6 +990,27 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/migration"), Pattern.compile("^(\\w+)\\.before\\.Main\\.kt$"), true); JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/migration"), Pattern.compile("^(\\w+)\\.before\\.Main\\.kt$"), true);
} }
@TestMetadata("idea/testData/quickfix/migration/deleteRedundantExtension")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class DeleteRedundantExtension extends AbstractQuickFixMultiFileTest {
public void testAllFilesPresentInDeleteRedundantExtension() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/migration/deleteRedundantExtension"), Pattern.compile("^(\\w+)\\.before\\.Main\\.kt$"), true);
}
@TestMetadata("removeImports.before.Main.kt")
public void testRemoveImports() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/deleteRedundantExtension/removeImports.before.Main.kt");
doTestWithExtraFile(fileName);
}
@TestMetadata("removeImportsOverloads.before.Main.kt")
public void testRemoveImportsOverloads() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/deleteRedundantExtension/removeImportsOverloads.before.Main.kt");
doTestWithExtraFile(fileName);
}
}
@TestMetadata("idea/testData/quickfix/migration/javaAnnotationPositionedArguments") @TestMetadata("idea/testData/quickfix/migration/javaAnnotationPositionedArguments")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -3923,6 +3923,87 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/migration"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true); JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/migration"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
} }
@TestMetadata("idea/testData/quickfix/migration/deleteRedundantExtension")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class DeleteRedundantExtension extends AbstractQuickFixTest {
public void testAllFilesPresentInDeleteRedundantExtension() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/migration/deleteRedundantExtension"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
}
@TestMetadata("explicitThis.kt")
public void testExplicitThis() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/deleteRedundantExtension/explicitThis.kt");
doTest(fileName);
}
@TestMetadata("memberExtension.kt")
public void testMemberExtension() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/deleteRedundantExtension/memberExtension.kt");
doTest(fileName);
}
@TestMetadata("returnInGetter.kt")
public void testReturnInGetter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/deleteRedundantExtension/returnInGetter.kt");
doTest(fileName);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/deleteRedundantExtension/simple.kt");
doTest(fileName);
}
@TestMetadata("valInsteadOfVar.kt")
public void testValInsteadOfVar() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/deleteRedundantExtension/valInsteadOfVar.kt");
doTest(fileName);
}
@TestMetadata("varInsteadOfVal.kt")
public void testVarInsteadOfVal() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/deleteRedundantExtension/varInsteadOfVal.kt");
doTest(fileName);
}
@TestMetadata("withSetter.kt")
public void testWithSetter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/deleteRedundantExtension/withSetter.kt");
doTest(fileName);
}
@TestMetadata("wrongExplicitThis.kt")
public void testWrongExplicitThis() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/deleteRedundantExtension/wrongExplicitThis.kt");
doTest(fileName);
}
@TestMetadata("wrongExplicitThis2.kt")
public void testWrongExplicitThis2() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/deleteRedundantExtension/wrongExplicitThis2.kt");
doTest(fileName);
}
@TestMetadata("wrongGetter.kt")
public void testWrongGetter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/deleteRedundantExtension/wrongGetter.kt");
doTest(fileName);
}
@TestMetadata("wrongGetter2.kt")
public void testWrongGetter2() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/deleteRedundantExtension/wrongGetter2.kt");
doTest(fileName);
}
@TestMetadata("wrongSetter.kt")
public void testWrongSetter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/deleteRedundantExtension/wrongSetter.kt");
doTest(fileName);
}
}
@TestMetadata("idea/testData/quickfix/migration/lambdaSyntax") @TestMetadata("idea/testData/quickfix/migration/lambdaSyntax")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -0,0 +1,31 @@
/*
* Copyright 2010-2015 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.kotlin.idea.quickfix.utils
import java.io.File
fun findInspectionFile(startDir: File): File? {
var currentDir: File? = startDir
while (currentDir != null) {
val inspectionFile = File(currentDir, ".inspection")
if (inspectionFile.exists()) {
return inspectionFile
}
currentDir = currentDir.parentFile
}
return null
}