diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index be1cc85c181..22cb1cc0afa 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -40,6 +40,7 @@ import org.jetbrains.kotlin.idea.AbstractSmartSelectionTest import org.jetbrains.kotlin.idea.actions.AbstractGotoTestOrCodeActionTest import org.jetbrains.kotlin.idea.caches.resolve.* import org.jetbrains.kotlin.idea.codeInsight.* +import org.jetbrains.kotlin.idea.codeInsight.codevision.AbstractKotlinCodeVisionProviderTest import org.jetbrains.kotlin.idea.codeInsight.generate.AbstractCodeInsightActionTest import org.jetbrains.kotlin.idea.codeInsight.generate.AbstractGenerateHashCodeAndEqualsActionTest import org.jetbrains.kotlin.idea.codeInsight.generate.AbstractGenerateTestSupportMethodActionTest @@ -867,6 +868,10 @@ fun main() { model("codeInsight/postfix") } + testClass { + model("codeInsight/codeVision") + } + testClass { model("script/definition/highlighting", extension = null, recursive = false) model("script/definition/complex", extension = null, recursive = false, testMethod = "doComplexTest") diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.192 b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.192 new file mode 100644 index 00000000000..b7bcf867702 --- /dev/null +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.192 @@ -0,0 +1,1580 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.generators.tests + +import org.jetbrains.kotlin.AbstractDataFlowValueRenderingTest +import org.jetbrains.kotlin.addImport.AbstractAddImportTest +import org.jetbrains.kotlin.addImportAlias.AbstractAddImportAliasTest +import org.jetbrains.kotlin.allopen.AbstractBytecodeListingTestForAllOpen +import org.jetbrains.kotlin.android.parcel.AbstractParcelBoxTest +import org.jetbrains.kotlin.android.parcel.AbstractParcelBytecodeListingTest +import org.jetbrains.kotlin.android.parcel.AbstractParcelIrBoxTest +import org.jetbrains.kotlin.android.parcel.AbstractParcelIrBytecodeListingTest +import org.jetbrains.kotlin.android.synthetic.test.AbstractAndroidBoxTest +import org.jetbrains.kotlin.android.synthetic.test.AbstractAndroidBytecodeShapeTest +import org.jetbrains.kotlin.android.synthetic.test.AbstractAndroidIrBoxTest +import org.jetbrains.kotlin.android.synthetic.test.AbstractAndroidSyntheticPropertyDescriptorTest +import org.jetbrains.kotlin.asJava.classes.AbstractUltraLightClassLoadingTest +import org.jetbrains.kotlin.asJava.classes.AbstractUltraLightClassSanityTest +import org.jetbrains.kotlin.asJava.classes.AbstractUltraLightFacadeClassTest +import org.jetbrains.kotlin.asJava.classes.AbstractUltraLightScriptLoadingTest +import org.jetbrains.kotlin.checkers.* +import org.jetbrains.kotlin.copyright.AbstractUpdateKotlinCopyrightTest +import org.jetbrains.kotlin.findUsages.AbstractFindUsagesTest +import org.jetbrains.kotlin.findUsages.AbstractFindUsagesWithDisableComponentSearchTest +import org.jetbrains.kotlin.findUsages.AbstractKotlinFindUsagesWithLibraryTest +import org.jetbrains.kotlin.fir.plugin.AbstractFirAllOpenDiagnosticTest +import org.jetbrains.kotlin.formatter.AbstractFormatterTest +import org.jetbrains.kotlin.formatter.AbstractTypingIndentationTestBase +import org.jetbrains.kotlin.generators.tests.generator.TestGroup +import org.jetbrains.kotlin.generators.tests.generator.muteExtraSuffix +import org.jetbrains.kotlin.generators.tests.generator.testGroup +import org.jetbrains.kotlin.generators.util.KT_OR_KTS +import org.jetbrains.kotlin.generators.util.KT_OR_KTS_WITHOUT_DOTS_IN_NAME +import org.jetbrains.kotlin.generators.util.KT_WITHOUT_DOTS_IN_NAME +import org.jetbrains.kotlin.idea.AbstractExpressionSelectionTest +import org.jetbrains.kotlin.idea.AbstractSmartSelectionTest +import org.jetbrains.kotlin.idea.actions.AbstractGotoTestOrCodeActionTest +import org.jetbrains.kotlin.idea.caches.resolve.* +import org.jetbrains.kotlin.idea.codeInsight.* +import org.jetbrains.kotlin.idea.codeInsight.generate.AbstractCodeInsightActionTest +import org.jetbrains.kotlin.idea.codeInsight.generate.AbstractGenerateHashCodeAndEqualsActionTest +import org.jetbrains.kotlin.idea.codeInsight.generate.AbstractGenerateTestSupportMethodActionTest +import org.jetbrains.kotlin.idea.codeInsight.generate.AbstractGenerateToStringActionTest +import org.jetbrains.kotlin.idea.codeInsight.moveUpDown.AbstractMoveLeftRightTest +import org.jetbrains.kotlin.idea.codeInsight.moveUpDown.AbstractMoveStatementTest +import org.jetbrains.kotlin.idea.codeInsight.postfix.AbstractPostfixTemplateProviderTest +import org.jetbrains.kotlin.idea.codeInsight.surroundWith.AbstractSurroundWithTest +import org.jetbrains.kotlin.idea.codeInsight.unwrap.AbstractUnwrapRemoveTest +import org.jetbrains.kotlin.idea.completion.test.* +import org.jetbrains.kotlin.idea.completion.test.handlers.AbstractBasicCompletionHandlerTest +import org.jetbrains.kotlin.idea.completion.test.handlers.AbstractCompletionCharFilterTest +import org.jetbrains.kotlin.idea.completion.test.handlers.AbstractKeywordCompletionHandlerTest +import org.jetbrains.kotlin.idea.completion.test.handlers.AbstractSmartCompletionHandlerTest +import org.jetbrains.kotlin.idea.completion.test.weighers.AbstractBasicCompletionWeigherTest +import org.jetbrains.kotlin.idea.completion.test.weighers.AbstractSmartCompletionWeigherTest +import org.jetbrains.kotlin.idea.configuration.AbstractGradleConfigureProjectByChangingFileTest +import org.jetbrains.kotlin.idea.conversion.copy.AbstractJavaToKotlinCopyPasteConversionTest +import org.jetbrains.kotlin.idea.conversion.copy.AbstractLiteralKotlinToKotlinCopyPasteTest +import org.jetbrains.kotlin.idea.conversion.copy.AbstractLiteralTextToKotlinCopyPasteTest +import org.jetbrains.kotlin.idea.conversion.copy.AbstractTextJavaToKotlinCopyPasteConversionTest +import org.jetbrains.kotlin.idea.coverage.AbstractKotlinCoverageOutputFilesTest +import org.jetbrains.kotlin.idea.debugger.evaluate.AbstractCodeFragmentAutoImportTest +import org.jetbrains.kotlin.idea.debugger.evaluate.AbstractCodeFragmentCompletionHandlerTest +import org.jetbrains.kotlin.idea.debugger.evaluate.AbstractCodeFragmentCompletionTest +import org.jetbrains.kotlin.idea.debugger.evaluate.AbstractCodeFragmentHighlightingTest +import org.jetbrains.kotlin.idea.debugger.test.* +import org.jetbrains.kotlin.idea.debugger.test.sequence.exec.AbstractSequenceTraceTestCase +import org.jetbrains.kotlin.idea.decompiler.navigation.AbstractNavigateJavaToLibrarySourceTest +import org.jetbrains.kotlin.idea.decompiler.navigation.AbstractNavigateToDecompiledLibraryTest +import org.jetbrains.kotlin.idea.decompiler.navigation.AbstractNavigateToLibrarySourceTest +import org.jetbrains.kotlin.idea.decompiler.navigation.AbstractNavigateToLibrarySourceTestWithJS +import org.jetbrains.kotlin.idea.decompiler.stubBuilder.AbstractClsStubBuilderTest +import org.jetbrains.kotlin.idea.decompiler.stubBuilder.AbstractLoadJavaClsStubTest +import org.jetbrains.kotlin.idea.decompiler.textBuilder.AbstractCommonDecompiledTextFromJsMetadataTest +import org.jetbrains.kotlin.idea.decompiler.textBuilder.AbstractCommonDecompiledTextTest +import org.jetbrains.kotlin.idea.decompiler.textBuilder.AbstractJsDecompiledTextFromJsMetadataTest +import org.jetbrains.kotlin.idea.decompiler.textBuilder.AbstractJvmDecompiledTextTest +import org.jetbrains.kotlin.idea.editor.AbstractMultiLineStringIndentTest +import org.jetbrains.kotlin.idea.editor.backspaceHandler.AbstractBackspaceHandlerTest +import org.jetbrains.kotlin.idea.editor.quickDoc.AbstractQuickDocProviderTest +import org.jetbrains.kotlin.idea.filters.AbstractKotlinExceptionFilterTest +import org.jetbrains.kotlin.idea.fir.AbstractFirLazyResolveTest +import org.jetbrains.kotlin.idea.fir.AbstractFirMultiModuleResolveTest +import org.jetbrains.kotlin.idea.folding.AbstractKotlinFoldingTest +import org.jetbrains.kotlin.idea.hierarchy.AbstractHierarchyTest +import org.jetbrains.kotlin.idea.hierarchy.AbstractHierarchyWithLibTest +import org.jetbrains.kotlin.idea.highlighter.* +import org.jetbrains.kotlin.idea.imports.AbstractJsOptimizeImportsTest +import org.jetbrains.kotlin.idea.imports.AbstractJvmOptimizeImportsTest +import org.jetbrains.kotlin.idea.index.AbstractKotlinTypeAliasByExpansionShortNameIndexTest +import org.jetbrains.kotlin.idea.inspections.AbstractLocalInspectionTest +import org.jetbrains.kotlin.idea.inspections.AbstractMultiFileLocalInspectionTest +import org.jetbrains.kotlin.idea.intentions.AbstractConcatenatedStringGeneratorTest +import org.jetbrains.kotlin.idea.intentions.AbstractIntentionTest +import org.jetbrains.kotlin.idea.intentions.AbstractIntentionTest2 +import org.jetbrains.kotlin.idea.intentions.AbstractMultiFileIntentionTest +import org.jetbrains.kotlin.idea.intentions.declarations.AbstractJoinLinesTest +import org.jetbrains.kotlin.idea.internal.AbstractBytecodeToolWindowTest +import org.jetbrains.kotlin.idea.kdoc.AbstractKDocHighlightingTest +import org.jetbrains.kotlin.idea.kdoc.AbstractKDocTypingTest +import org.jetbrains.kotlin.idea.maven.AbstractKotlinMavenInspectionTest +import org.jetbrains.kotlin.idea.maven.configuration.AbstractMavenConfigureProjectByChangingFileTest +import org.jetbrains.kotlin.idea.navigation.* +import org.jetbrains.kotlin.idea.parameterInfo.AbstractParameterInfoTest +import org.jetbrains.kotlin.idea.perf.* +import org.jetbrains.kotlin.idea.quickfix.AbstractQuickFixMultiFileTest +import org.jetbrains.kotlin.idea.quickfix.AbstractQuickFixMultiModuleTest +import org.jetbrains.kotlin.idea.quickfix.AbstractQuickFixTest +import org.jetbrains.kotlin.idea.refactoring.AbstractNameSuggestionProviderTest +import org.jetbrains.kotlin.idea.refactoring.copy.AbstractCopyTest +import org.jetbrains.kotlin.idea.refactoring.copy.AbstractMultiModuleCopyTest +import org.jetbrains.kotlin.idea.refactoring.inline.AbstractInlineTest +import org.jetbrains.kotlin.idea.refactoring.introduce.AbstractExtractionTest +import org.jetbrains.kotlin.idea.refactoring.move.AbstractMoveTest +import org.jetbrains.kotlin.idea.refactoring.move.AbstractMultiModuleMoveTest +import org.jetbrains.kotlin.idea.refactoring.pullUp.AbstractPullUpTest +import org.jetbrains.kotlin.idea.refactoring.pushDown.AbstractPushDownTest +import org.jetbrains.kotlin.idea.refactoring.rename.AbstractMultiModuleRenameTest +import org.jetbrains.kotlin.idea.refactoring.rename.AbstractRenameTest +import org.jetbrains.kotlin.idea.refactoring.safeDelete.AbstractMultiModuleSafeDeleteTest +import org.jetbrains.kotlin.idea.refactoring.safeDelete.AbstractSafeDeleteTest +import org.jetbrains.kotlin.idea.repl.AbstractIdeReplCompletionTest +import org.jetbrains.kotlin.idea.resolve.* +import org.jetbrains.kotlin.idea.scratch.AbstractScratchLineMarkersTest +import org.jetbrains.kotlin.idea.scratch.AbstractScratchRunActionTest +import org.jetbrains.kotlin.idea.script.AbstractScriptConfigurationCompletionTest +import org.jetbrains.kotlin.idea.script.AbstractScriptConfigurationHighlightingTest +import org.jetbrains.kotlin.idea.script.AbstractScriptConfigurationNavigationTest +import org.jetbrains.kotlin.idea.script.AbstractScriptDefinitionsOrderTest +import org.jetbrains.kotlin.idea.slicer.AbstractSlicerLeafGroupingTest +import org.jetbrains.kotlin.idea.slicer.AbstractSlicerMultiplatformTest +import org.jetbrains.kotlin.idea.slicer.AbstractSlicerNullnessGroupingTest +import org.jetbrains.kotlin.idea.slicer.AbstractSlicerTreeTest +import org.jetbrains.kotlin.idea.structureView.AbstractKotlinFileStructureTest +import org.jetbrains.kotlin.idea.stubs.AbstractMultiFileHighlightingTest +import org.jetbrains.kotlin.idea.stubs.AbstractResolveByStubTest +import org.jetbrains.kotlin.idea.stubs.AbstractStubBuilderTest +import org.jetbrains.kotlin.incremental.* +import org.jetbrains.kotlin.j2k.AbstractJavaToKotlinConverterForWebDemoTest +import org.jetbrains.kotlin.j2k.AbstractJavaToKotlinConverterMultiFileTest +import org.jetbrains.kotlin.j2k.AbstractJavaToKotlinConverterSingleFileTest +import org.jetbrains.kotlin.jps.build.* +import org.jetbrains.kotlin.jps.build.dependeciestxt.actualizeMppJpsIncTestCaseDirs +import org.jetbrains.kotlin.jps.incremental.AbstractJsProtoComparisonTest +import org.jetbrains.kotlin.jps.incremental.AbstractJvmProtoComparisonTest +import org.jetbrains.kotlin.jvm.abi.AbstractCompareJvmAbiTest +import org.jetbrains.kotlin.jvm.abi.AbstractCompileAgainstJvmAbiTest +import org.jetbrains.kotlin.jvm.abi.AbstractJvmAbiContentTest +import org.jetbrains.kotlin.kapt.cli.test.AbstractArgumentParsingTest +import org.jetbrains.kotlin.kapt.cli.test.AbstractKaptToolIntegrationTest +import org.jetbrains.kotlin.kapt3.test.AbstractClassFileToSourceStubConverterTest +import org.jetbrains.kotlin.kapt3.test.AbstractIrClassFileToSourceStubConverterTest +import org.jetbrains.kotlin.kapt3.test.AbstractIrKotlinKaptContextTest +import org.jetbrains.kotlin.kapt3.test.AbstractKotlinKaptContextTest +import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinConverterMultiFileTest +import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinConverterSingleFileTest +import org.jetbrains.kotlin.nj2k.AbstractNewJavaToKotlinCopyPasteConversionTest +import org.jetbrains.kotlin.nj2k.AbstractTextNewJavaToKotlinCopyPasteConversionTest +import org.jetbrains.kotlin.nj2k.inference.common.AbstractCommonConstraintCollectorTest +import org.jetbrains.kotlin.nj2k.inference.mutability.AbstractMutabilityInferenceTest +import org.jetbrains.kotlin.nj2k.inference.nullability.AbstractNullabilityInferenceTest +import org.jetbrains.kotlin.noarg.AbstractBlackBoxCodegenTestForNoArg +import org.jetbrains.kotlin.noarg.AbstractBytecodeListingTestForNoArg +import org.jetbrains.kotlin.psi.patternMatching.AbstractPsiUnifierTest +import org.jetbrains.kotlin.samWithReceiver.AbstractSamWithReceiverScriptTest +import org.jetbrains.kotlin.samWithReceiver.AbstractSamWithReceiverTest +import org.jetbrains.kotlin.search.AbstractAnnotatedMembersSearchTest +import org.jetbrains.kotlin.search.AbstractInheritorsSearchTest +import org.jetbrains.kotlin.shortenRefs.AbstractShortenRefsTest +import org.jetbrains.kotlin.test.TargetBackend +import org.jetbrains.kotlin.tools.projectWizard.cli.AbstractProjectTemplateBuildFileGenerationTest +import org.jetbrains.kotlin.tools.projectWizard.cli.AbstractYamlBuildFileGenerationTest +import org.jetbrains.kotlin.tools.projectWizard.wizard.AbstractProjectTemplateNewWizardProjectImportTest +import org.jetbrains.kotlin.tools.projectWizard.wizard.AbstractYamlNewWizardProjectImportTest +import org.jetbrains.kotlinx.serialization.AbstractSerializationIrBytecodeListingTest +import org.jetbrains.kotlinx.serialization.AbstractSerializationPluginBytecodeListingTest +import org.jetbrains.kotlinx.serialization.AbstractSerializationPluginDiagnosticTest + +fun main() { + System.setProperty("java.awt.headless", "true") + + testGroup("idea/jvm-debugger/jvm-debugger-test/test", "idea/jvm-debugger/jvm-debugger-test/testData") { + testClass { + model( + "stepping/stepIntoAndSmartStepInto", + pattern = KT_WITHOUT_DOTS_IN_NAME, + testMethod = "doStepIntoTest", + testClassName = "StepInto" + ) + model( + "stepping/stepIntoAndSmartStepInto", + pattern = KT_WITHOUT_DOTS_IN_NAME, + testMethod = "doSmartStepIntoTest", + testClassName = "SmartStepInto" + ) + model( + "stepping/stepInto", + pattern = KT_WITHOUT_DOTS_IN_NAME, + testMethod = "doStepIntoTest", + testClassName = "StepIntoOnly" + ) + model("stepping/stepOut", pattern = KT_WITHOUT_DOTS_IN_NAME, testMethod = "doStepOutTest") + model("stepping/stepOver", pattern = KT_WITHOUT_DOTS_IN_NAME, testMethod = "doStepOverTest") + model("stepping/filters", pattern = KT_WITHOUT_DOTS_IN_NAME, testMethod = "doStepIntoTest") + model("stepping/custom", pattern = KT_WITHOUT_DOTS_IN_NAME, testMethod = "doCustomTest") + } + + testClass { + model("evaluation/singleBreakpoint", testMethod = "doSingleBreakpointTest") + model("evaluation/multipleBreakpoints", testMethod = "doMultipleBreakpointsTest") + } + + testClass { + model("selectExpression", recursive = false) + model("selectExpression/disallowMethodCalls", testMethod = "doTestWoMethodCalls") + } + + testClass { + model("positionManager", recursive = false, extension = "kt", testClassName = "SingleFile") + model("positionManager", recursive = false, extension = null, testClassName = "MultiFile") + } + + testClass { + model("smartStepInto") + } + + testClass { + model("breakpointApplicability") + } + + testClass { + model("fileRanking") + } + + testClass { + model("asyncStackTrace") + } + + testClass { + model("coroutines") + } + + testClass { + // TODO: implement mapping logic for terminal operations + model("sequence/streams/sequence", excludeDirs = listOf("terminal")) + } + + testClass { + model("continuation") + } + + testClass { + model("xcoroutines") + } + } + + testGroup("idea/tests", "idea/testData") { + testClass { + model("resolve/additionalLazyResolve") + } + + testClass { + model("resolve/partialBodyResolve") + } + + testClass { + model("checker", recursive = false) + model("checker/regression") + model("checker/recovery") + model("checker/rendering") + model("checker/scripts", extension = "kts") + model("checker/duplicateJvmSignature") + model("checker/infos", testMethod = "doTestWithInfos") + model("checker/diagnosticsMessage") + } + + testClass { + model("kotlinAndJavaChecker/javaAgainstKotlin") + model("kotlinAndJavaChecker/javaWithKotlin") + } + + testClass { + model("kotlinAndJavaChecker/javaAgainstKotlin") + model("kotlinAndJavaChecker/javaWithKotlin") + } + + testClass { + model("kotlinAndJavaChecker/javaAgainstKotlin") + } + + testClass { + model("unifier") + } + + testClass { + model("checker/codeFragments", extension = "kt", recursive = false) + model("checker/codeFragments/imports", testMethod = "doTestWithImport", extension = "kt") + } + + testClass { + model("quickfix.special/codeFragmentAutoImport", extension = "kt", recursive = false) + } + + testClass { + model("checker/js") + } + + testClass { + model("quickfix", pattern = "^([\\w\\-_]+)\\.kt$", filenameStartsLowerCase = true) + } + + testClass { + model("navigation/gotoSuper", extension = "test", recursive = false) + } + + testClass { + model("navigation/gotoTypeDeclaration", extension = "test") + } + + testClass { + model("navigation/gotoDeclaration", extension = "test") + } + + testClass { + model( + "parameterInfo", + pattern = "^([\\w\\-_]+)\\.kt$", recursive = true, + excludeDirs = listOf("withLib1/sharedLib", "withLib2/sharedLib", "withLib3/sharedLib") + ) + } + + testClass { + model("navigation/gotoClass", testMethod = "doClassTest") + model("navigation/gotoSymbol", testMethod = "doSymbolTest") + } + + testClass(annotations = listOf(muteExtraSuffix(".libsrc"))) { + model("decompiler/navigation/usercode") + } + + testClass(annotations = listOf(muteExtraSuffix(".libsrc"))) { + model("decompiler/navigation/userJavaCode", pattern = "^(.+)\\.java$") + } + + testClass(annotations = listOf(muteExtraSuffix(".libsrcjs"))) { + model("decompiler/navigation/usercode", testClassName = "UsercodeWithJSModule") + } + + testClass { + model("decompiler/navigation/usercode") + } + + testClass { + model("navigation/implementations", recursive = false) + } + + testClass { + model("navigation/gotoTestOrCode", pattern = "^(.+)\\.main\\..+\$") + } + + testClass { + model("search/inheritance") + } + + testClass { + model("search/annotations") + } + + testClass { + model("quickfix", pattern = """^(\w+)\.((before\.Main\.\w+)|(test))$""", testMethod = "doTestWithExtraFile") + } + + testClass { + model("typealiasExpansionIndex") + } + + testClass { + model("highlighter") + } + + testClass { + model("dslHighlighter") + } + + testClass { + model("usageHighlighter") + } + + testClass { + model("folding/noCollapse") + model("folding/checkCollapse", testMethod = "doSettingsFoldingTest") + } + + testClass { + model("codeInsight/surroundWith/if", testMethod = "doTestWithIfSurrounder") + model("codeInsight/surroundWith/ifElse", testMethod = "doTestWithIfElseSurrounder") + model("codeInsight/surroundWith/ifElseExpression", testMethod = "doTestWithIfElseExpressionSurrounder") + model("codeInsight/surroundWith/ifElseExpressionBraces", testMethod = "doTestWithIfElseExpressionBracesSurrounder") + model("codeInsight/surroundWith/not", testMethod = "doTestWithNotSurrounder") + model("codeInsight/surroundWith/parentheses", testMethod = "doTestWithParenthesesSurrounder") + model("codeInsight/surroundWith/stringTemplate", testMethod = "doTestWithStringTemplateSurrounder") + model("codeInsight/surroundWith/when", testMethod = "doTestWithWhenSurrounder") + model("codeInsight/surroundWith/tryCatch", testMethod = "doTestWithTryCatchSurrounder") + model("codeInsight/surroundWith/tryCatchExpression", testMethod = "doTestWithTryCatchExpressionSurrounder") + model("codeInsight/surroundWith/tryCatchFinally", testMethod = "doTestWithTryCatchFinallySurrounder") + model("codeInsight/surroundWith/tryCatchFinallyExpression", testMethod = "doTestWithTryCatchFinallyExpressionSurrounder") + model("codeInsight/surroundWith/tryFinally", testMethod = "doTestWithTryFinallySurrounder") + model("codeInsight/surroundWith/functionLiteral", testMethod = "doTestWithFunctionLiteralSurrounder") + model("codeInsight/surroundWith/withIfExpression", testMethod = "doTestWithSurroundWithIfExpression") + model("codeInsight/surroundWith/withIfElseExpression", testMethod = "doTestWithSurroundWithIfElseExpression") + } + + testClass { + model("joinLines") + } + + testClass { + model("codeInsight/breadcrumbs") + } + + testClass { + model("intentions", pattern = "^([\\w\\-_]+)\\.(kt|kts)$") + } + + testClass { + model("intentions/loopToCallChain", pattern = "^([\\w\\-_]+)\\.kt$") + } + + testClass { + model("concatenatedStringGenerator", pattern = "^([\\w\\-_]+)\\.kt$") + } + + testClass { + model("intentions", pattern = "^(inspections\\.test)$", singleClass = true) + model("inspections", pattern = "^(inspections\\.test)$", singleClass = true) + model("inspectionsLocal", pattern = "^(inspections\\.test)$", singleClass = true) + } + + testClass { + model("inspectionsLocal", pattern = "^([\\w\\-_]+)\\.(kt|kts)$") + } + + testClass { + model("hierarchy/class/type", extension = null, recursive = false, testMethod = "doTypeClassHierarchyTest") + model("hierarchy/class/super", extension = null, recursive = false, testMethod = "doSuperClassHierarchyTest") + model("hierarchy/class/sub", extension = null, recursive = false, testMethod = "doSubClassHierarchyTest") + model("hierarchy/calls/callers", extension = null, recursive = false, testMethod = "doCallerHierarchyTest") + model("hierarchy/calls/callersJava", extension = null, recursive = false, testMethod = "doCallerJavaHierarchyTest") + model("hierarchy/calls/callees", extension = null, recursive = false, testMethod = "doCalleeHierarchyTest") + model("hierarchy/overrides", extension = null, recursive = false, testMethod = "doOverrideHierarchyTest") + } + + testClass { + model("hierarchy/withLib", extension = null, recursive = false) + } + + testClass { + model("codeInsight/moveUpDown/classBodyDeclarations", pattern = KT_OR_KTS, testMethod = "doTestClassBodyDeclaration") + model("codeInsight/moveUpDown/closingBraces", testMethod = "doTestExpression") + model("codeInsight/moveUpDown/expressions", pattern = KT_OR_KTS, testMethod = "doTestExpression") + model("codeInsight/moveUpDown/parametersAndArguments", testMethod = "doTestExpression") + model("codeInsight/moveUpDown/trailingComma", testMethod = "doTestExpressionWithTrailingComma") + } + + testClass { + model("codeInsight/moveLeftRight") + } + + testClass { + model("refactoring/inline", pattern = "^(\\w+)\\.kt$") + } + + testClass { + model("codeInsight/unwrapAndRemove/removeExpression", testMethod = "doTestExpressionRemover") + model("codeInsight/unwrapAndRemove/unwrapThen", testMethod = "doTestThenUnwrapper") + model("codeInsight/unwrapAndRemove/unwrapElse", testMethod = "doTestElseUnwrapper") + model("codeInsight/unwrapAndRemove/removeElse", testMethod = "doTestElseRemover") + model("codeInsight/unwrapAndRemove/unwrapLoop", testMethod = "doTestLoopUnwrapper") + model("codeInsight/unwrapAndRemove/unwrapTry", testMethod = "doTestTryUnwrapper") + model("codeInsight/unwrapAndRemove/unwrapCatch", testMethod = "doTestCatchUnwrapper") + model("codeInsight/unwrapAndRemove/removeCatch", testMethod = "doTestCatchRemover") + model("codeInsight/unwrapAndRemove/unwrapFinally", testMethod = "doTestFinallyUnwrapper") + model("codeInsight/unwrapAndRemove/removeFinally", testMethod = "doTestFinallyRemover") + model("codeInsight/unwrapAndRemove/unwrapLambda", testMethod = "doTestLambdaUnwrapper") + model("codeInsight/unwrapAndRemove/unwrapFunctionParameter", testMethod = "doTestFunctionParameterUnwrapper") + } + + testClass { + model("codeInsight/expressionType") + } + + testClass { + model("codeInsight/renderingKDoc") + } + + testClass { + model("editor/backspaceHandler") + } + + testClass { + model("editor/enterHandler/multilineString") + } + + testClass { + model("editor/quickDoc", pattern = """^([^_]+)\.(kt|java)$""") + } + + testClass { + model("refactoring/safeDelete/deleteClass/kotlinClass", testMethod = "doClassTest") + model("refactoring/safeDelete/deleteClass/kotlinClassWithJava", testMethod = "doClassTestWithJava") + model("refactoring/safeDelete/deleteClass/javaClassWithKotlin", extension = "java", testMethod = "doJavaClassTest") + model("refactoring/safeDelete/deleteObject/kotlinObject", testMethod = "doObjectTest") + model("refactoring/safeDelete/deleteFunction/kotlinFunction", testMethod = "doFunctionTest") + model("refactoring/safeDelete/deleteFunction/kotlinFunctionWithJava", testMethod = "doFunctionTestWithJava") + model("refactoring/safeDelete/deleteFunction/javaFunctionWithKotlin", testMethod = "doJavaMethodTest") + model("refactoring/safeDelete/deleteProperty/kotlinProperty", testMethod = "doPropertyTest") + model("refactoring/safeDelete/deleteProperty/kotlinPropertyWithJava", testMethod = "doPropertyTestWithJava") + model("refactoring/safeDelete/deleteProperty/javaPropertyWithKotlin", testMethod = "doJavaPropertyTest") + model("refactoring/safeDelete/deleteTypeAlias/kotlinTypeAlias", testMethod = "doTypeAliasTest") + model("refactoring/safeDelete/deleteTypeParameter/kotlinTypeParameter", testMethod = "doTypeParameterTest") + model("refactoring/safeDelete/deleteTypeParameter/kotlinTypeParameterWithJava", testMethod = "doTypeParameterTestWithJava") + model("refactoring/safeDelete/deleteValueParameter/kotlinValueParameter", testMethod = "doValueParameterTest") + model("refactoring/safeDelete/deleteValueParameter/kotlinValueParameterWithJava", testMethod = "doValueParameterTestWithJava") + } + + testClass { + model("resolve/references", pattern = KT_WITHOUT_DOTS_IN_NAME) + } + + testClass { + model("resolve/referenceInJava/binaryAndSource", extension = "java") + model("resolve/referenceInJava/sourceOnly", extension = "java") + } + + testClass { + model("resolve/referenceInJava/binaryAndSource", extension = "java") + } + + testClass { + model("resolve/referenceWithLib", recursive = false) + } + + testClass { + model("resolve/referenceInLib", recursive = false) + } + + testClass { + model("resolve/referenceToJavaWithWrongFileStructure", recursive = false) + } + + testClass { + model("findUsages/kotlin", pattern = """^(.+)\.0\.(kt|kts)$""") + model("findUsages/java", pattern = """^(.+)\.0\.java$""") + model("findUsages/propertyFiles", pattern = """^(.+)\.0\.properties$""") + } + + testClass { + model("findUsages/kotlin/conventions/components", pattern = """^(.+)\.0\.(kt|kts)$""") + } + + testClass { + model("findUsages/libraryUsages", pattern = """^(.+)\.0\.kt$""") + } + + testClass { + model("refactoring/move", extension = "test", singleClass = true) + } + + testClass { + model("refactoring/copy", extension = "test", singleClass = true) + } + + testClass { + model("refactoring/moveMultiModule", extension = "test", singleClass = true) + } + + testClass { + model("refactoring/copyMultiModule", extension = "test", singleClass = true) + } + + testClass { + model("refactoring/safeDeleteMultiModule", extension = "test", singleClass = true) + } + + testClass { + model("multiFileIntentions", extension = "test", singleClass = true, filenameStartsLowerCase = true) + } + + testClass { + model("multiFileLocalInspections", extension = "test", singleClass = true, filenameStartsLowerCase = true) + } + + testClass { + model("multiFileInspections", extension = "test", singleClass = true) + } + + testClass { + model("formatter", pattern = """^([^\.]+)\.after\.kt.*$""") + model( + "formatter/trailingComma", pattern = """^([^\.]+)\.call\.after\.kt.*$""", + testMethod = "doTestCallSite", testClassName = "FormatterCallSite" + ) + model( + "formatter", pattern = """^([^\.]+)\.after\.inv\.kt.*$""", + testMethod = "doTestInverted", testClassName = "FormatterInverted" + ) + model( + "formatter/trailingComma", pattern = """^([^\.]+)\.call\.after\.inv\.kt.*$""", + testMethod = "doTestInvertedCallSite", testClassName = "FormatterInvertedCallSite" + ) + } + + testClass { + model( + "indentationOnNewline", pattern = """^([^\.]+)\.after\.kt.*$""", testMethod = "doNewlineTest", + testClassName = "DirectSettings" + ) + model( + "indentationOnNewline", pattern = """^([^\.]+)\.after\.inv\.kt.*$""", testMethod = "doNewlineTestWithInvert", + testClassName = "InvertedSettings" + ) + } + + testClass { + model("diagnosticMessage", recursive = false) + } + + testClass { + model("diagnosticMessage/js", recursive = false, targetBackend = TargetBackend.JS) + } + + testClass { + model("refactoring/rename", extension = "test", singleClass = true) + } + + testClass { + model("refactoring/renameMultiModule", extension = "test", singleClass = true) + } + + testClass { + model("codeInsight/outOfBlock", pattern = KT_OR_KTS) + } + + testClass { + model("codeInsight/changeLocality", pattern = KT_OR_KTS) + } + + testClass { + model("dataFlowValueRendering") + } + + testClass { + model("copyPaste/conversion", pattern = """^([^\.]+)\.java$""") + } + + testClass { + model("copyPaste/plainTextConversion", pattern = """^([^\.]+)\.txt$""") + } + + testClass { + model("copyPaste/plainTextLiteral", pattern = """^([^\.]+)\.txt$""") + } + + testClass { + model("copyPaste/literal", pattern = """^([^\.]+)\.kt$""") + } + + testClass { + model( + "copyPaste/imports", + pattern = KT_WITHOUT_DOTS_IN_NAME, + testMethod = "doTestCopy", + testClassName = "Copy", + recursive = false + ) + model( + "copyPaste/imports", + pattern = KT_WITHOUT_DOTS_IN_NAME, + testMethod = "doTestCut", + testClassName = "Cut", + recursive = false + ) + } + + testClass { + model("copyPaste/moveDeclarations", pattern = KT_WITHOUT_DOTS_IN_NAME, testMethod = "doTest") + } + + testClass { + model("copyright", pattern = KT_OR_KTS, testMethod = "doTest") + } + + testClass { + model("exitPoints") + } + + testClass { + model("codeInsight/lineMarker") + } + + testClass { + model("codeInsightInLibrary/lineMarker", testMethod = "doTestWithLibrary") + } + + testClass { + model("multiModuleLineMarker", extension = null, recursive = false) + } + + testClass { + model("shortenRefs", pattern = KT_WITHOUT_DOTS_IN_NAME) + } + testClass { + model("addImport", pattern = KT_WITHOUT_DOTS_IN_NAME) + } + + testClass { + model("addImportAlias", pattern = KT_WITHOUT_DOTS_IN_NAME) + } + + testClass { + model("smartSelection", testMethod = "doTestSmartSelection", pattern = KT_WITHOUT_DOTS_IN_NAME) + } + + testClass { + model("structureView/fileStructure", pattern = KT_WITHOUT_DOTS_IN_NAME) + } + + testClass { + model("expressionSelection", testMethod = "doTestExpressionSelection", pattern = KT_WITHOUT_DOTS_IN_NAME) + } + + testClass { + model("decompiler/decompiledText", pattern = """^([^\.]+)$""") + } + + testClass { + model("decompiler/decompiledTextJvm", pattern = """^([^\.]+)$""") + } + + testClass { + model("decompiler/decompiledText", pattern = """^([^\.]+)$""", targetBackend = TargetBackend.JS) + } + + testClass { + model("decompiler/decompiledTextJs", pattern = """^([^\.]+)$""", targetBackend = TargetBackend.JS) + } + + testClass { + model("decompiler/stubBuilder", extension = null, recursive = false) + } + + testClass { + model("editor/optimizeImports/jvm", pattern = KT_OR_KTS_WITHOUT_DOTS_IN_NAME) + model("editor/optimizeImports/common", pattern = KT_WITHOUT_DOTS_IN_NAME) + } + testClass { + model("editor/optimizeImports/js", pattern = KT_WITHOUT_DOTS_IN_NAME) + model("editor/optimizeImports/common", pattern = KT_WITHOUT_DOTS_IN_NAME) + } + + testClass { + model("debugger/exceptionFilter", pattern = """^([^\.]+)$""", recursive = false) + } + + testClass { + model("stubs", extension = "kt") + } + + testClass { + model("multiFileHighlighting", recursive = false) + } + + testClass { + model("multiModuleHighlighting/multiplatform/", recursive = false, extension = null) + } + + testClass { + model("multiplatform", recursive = false, extension = null) + } + + testClass { + model("multiModuleQuickFix", extension = null, deep = 1) + } + + testClass { + model("navigation/implementations/multiModule", recursive = false, extension = null) + } + + testClass { + model("navigation/relatedSymbols/multiModule", recursive = false, extension = null) + } + + testClass { + model("navigation/gotoSuper/multiModule", recursive = false, extension = null) + } + + testClass { + model("refactoring/introduceVariable", pattern = KT_OR_KTS, testMethod = "doIntroduceVariableTest") + model("refactoring/extractFunction", pattern = KT_OR_KTS, testMethod = "doExtractFunctionTest") + model("refactoring/introduceProperty", pattern = KT_OR_KTS, testMethod = "doIntroducePropertyTest") + model("refactoring/introduceParameter", pattern = KT_OR_KTS, testMethod = "doIntroduceSimpleParameterTest") + model("refactoring/introduceLambdaParameter", pattern = KT_OR_KTS, testMethod = "doIntroduceLambdaParameterTest") + model("refactoring/introduceJavaParameter", extension = "java", testMethod = "doIntroduceJavaParameterTest") + model("refactoring/introduceTypeParameter", pattern = KT_OR_KTS, testMethod = "doIntroduceTypeParameterTest") + model("refactoring/introduceTypeAlias", pattern = KT_OR_KTS, testMethod = "doIntroduceTypeAliasTest") + model("refactoring/extractSuperclass", pattern = KT_OR_KTS_WITHOUT_DOTS_IN_NAME, testMethod = "doExtractSuperclassTest") + model("refactoring/extractInterface", pattern = KT_OR_KTS_WITHOUT_DOTS_IN_NAME, testMethod = "doExtractInterfaceTest") + } + + testClass { + model("refactoring/pullUp/k2k", extension = "kt", singleClass = true, testClassName = "K2K", testMethod = "doKotlinTest") + model("refactoring/pullUp/k2j", extension = "kt", singleClass = true, testClassName = "K2J", testMethod = "doKotlinTest") + model("refactoring/pullUp/j2k", extension = "java", singleClass = true, testClassName = "J2K", testMethod = "doJavaTest") + } + + testClass { + model("refactoring/pushDown/k2k", extension = "kt", singleClass = true, testClassName = "K2K", testMethod = "doKotlinTest") + model("refactoring/pushDown/k2j", extension = "kt", singleClass = true, testClassName = "K2J", testMethod = "doKotlinTest") + model("refactoring/pushDown/j2k", extension = "java", singleClass = true, testClassName = "J2K", testMethod = "doJavaTest") + } + + testClass { + model("coverage/outputFiles") + } + + testClass { + model("internal/toolWindow", recursive = false, extension = null) + } + + testClass("org.jetbrains.kotlin.idea.kdoc.KdocResolveTestGenerated") { + model("kdoc/resolve") + } + + testClass { + model("kdoc/highlighting") + } + + testClass { + model("kdoc/typing") + } + + testClass { + model("codeInsight/generate/testFrameworkSupport") + } + + testClass { + model("codeInsight/generate/equalsWithHashCode") + } + + testClass { + model("codeInsight/generate/secondaryConstructors") + } + + testClass { + model("codeInsight/generate/toString") + } + + testClass { + model("repl/completion") + } + + testClass { + model("codeInsight/postfix") + } + + testClass { + model("script/definition/highlighting", extension = null, recursive = false) + model("script/definition/complex", extension = null, recursive = false, testMethod = "doComplexTest") + } + + testClass { + model("script/definition/navigation", extension = null, recursive = false) + } + + testClass { + model("script/definition/completion", extension = null, recursive = false) + } + + testClass { + model("script/definition/order", extension = null, recursive = false) + } + + testClass { + model("refactoring/nameSuggestionProvider") + } + + testClass { + model("slicer", excludeDirs = listOf("mpp")) + } + + testClass { + model("slicer/inflow", singleClass = true) + } + + testClass { + model("slicer/inflow", singleClass = true) + } + + testClass { + model("slicer/mpp", recursive = false, extension = null) + } + } + + testGroup("idea/idea-fir/tests", "idea/testData") { + testClass { + model("fir/multiModule", recursive = false, extension = null) + } + + testClass { + model("fir/lazyResolve", extension = "test", singleClass = true, filenameStartsLowerCase = true) + } + + testClass { + model("resolve/references", pattern = KT_WITHOUT_DOTS_IN_NAME) + } + + testClass { + model("checker", recursive = false) + model("checker/regression") + model("checker/recovery") + model("checker/rendering") + model("checker/duplicateJvmSignature") + model("checker/infos") + model("checker/diagnosticsMessage") + } + } + + testGroup("idea/scripting-support/test", "idea/scripting-support/testData") { + testClass { + model( + "scratch", + extension = "kts", + testMethod = "doScratchCompilingTest", + testClassName = "ScratchCompiling", + recursive = false + ) + model("scratch", extension = "kts", testMethod = "doScratchReplTest", testClassName = "ScratchRepl", recursive = false) + model( + "scratch/multiFile", + extension = null, + testMethod = "doScratchMultiFileTest", + testClassName = "ScratchMultiFile", + recursive = false + ) + + model( + "worksheet", + extension = "ws.kts", + testMethod = "doWorksheetCompilingTest", + testClassName = "WorksheetCompiling", + recursive = false + ) + model("worksheet", extension = "ws.kts", testMethod = "doWorksheetReplTest", testClassName = "WorksheetRepl", recursive = false) + model( + "worksheet/multiFile", + extension = null, + testMethod = "doWorksheetMultiFileTest", + testClassName = "WorksheetMultiFile", + recursive = false + ) + + model( + "scratch/rightPanelOutput", + extension = "kts", + testMethod = "doRightPreviewPanelOutputTest", + testClassName = "ScratchRightPanelOutput", + recursive = false + ) + } + + testClass { + model("scratch/lineMarker", testMethod = "doScratchTest", pattern = KT_OR_KTS) + } + } + + testGroup("idea/idea-maven/test", "idea/idea-maven/testData") { + testClass { + model("configurator/jvm", extension = null, recursive = false, testMethod = "doTestWithMaven") + model("configurator/js", extension = null, recursive = false, testMethod = "doTestWithJSMaven") + } + + testClass { + model("maven-inspections", pattern = "^([\\w\\-]+).xml$", singleClass = true) + } + } + + testGroup("idea/idea-gradle/tests", "idea/testData") { + testClass { + model("configuration/gradle", extension = null, recursive = false, testMethod = "doTestGradle") + model("configuration/gsk", extension = null, recursive = false, testMethod = "doTestGradle") + } + } + + testGroup("idea/tests", "compiler/testData") { + testClass { + model("loadJava/compiledKotlin") + } + + testClass { + model("loadJava/compiledKotlin", testMethod = "doTestCompiledKotlin") + } + + testClass { + model("asJava/lightClasses", excludeDirs = listOf("delegation", "script"), pattern = KT_WITHOUT_DOTS_IN_NAME) + } + + testClass { + model("asJava/script/ide", pattern = KT_OR_KTS_WITHOUT_DOTS_IN_NAME) + } + + testClass { + model("asJava/lightClasses", pattern = KT_OR_KTS) + } + testClass { + model("asJava/ultraLightClasses", pattern = KT_OR_KTS) + } + testClass { + model("asJava/ultraLightScripts", pattern = KT_OR_KTS) + } + testClass { + model("asJava/ultraLightFacades", pattern = KT_OR_KTS) + } + + testClass { + model( + "asJava/lightClasses", + excludeDirs = listOf("local", "compilationErrors", "ideRegression"), + pattern = KT_OR_KTS_WITHOUT_DOTS_IN_NAME + ) + } + } + + testGroup("idea/idea-completion/tests", "idea/idea-completion/testData") { + testClass { + model("injava", extension = "java", recursive = false) + } + + testClass { + model("injava", extension = "java", recursive = false) + } + + testClass { + model("injava/stdlib", extension = "java", recursive = false) + } + + testClass { + model("weighers/basic", pattern = KT_OR_KTS_WITHOUT_DOTS_IN_NAME) + } + + testClass { + model("weighers/smart", pattern = KT_WITHOUT_DOTS_IN_NAME) + } + + testClass { + model("basic/common") + model("basic/js") + } + + testClass { + model("basic/common") + model("basic/java") + } + + testClass { + model("smart") + } + + testClass { + model("keywords", recursive = false) + } + + testClass { + model("basic/withLib", recursive = false) + } + + testClass { + model("handlers/basic", pattern = KT_WITHOUT_DOTS_IN_NAME) + } + + testClass { + model("handlers/smart") + } + + testClass { + model("handlers/keywords") + } + + testClass { + model("handlers/charFilter", pattern = KT_WITHOUT_DOTS_IN_NAME) + } + + testClass { + model("basic/multifile", extension = null, recursive = false) + } + + testClass { + model("smartMultiFile", extension = null, recursive = false) + } + + testClass("KDocCompletionTestGenerated") { + model("kdoc") + } + + testClass { + model("basic/java8") + } + + testClass { + model("incrementalResolve") + } + + testClass { + model("multiPlatform", recursive = false, extension = null) + } + } + + testGroup( + "libraries/tools/new-project-wizard/new-project-wizard-cli/tests", + "libraries/tools/new-project-wizard/new-project-wizard-cli/testData" + ) { + testClass { + model("buildFileGeneration", recursive = false, extension = null) + } + testClass { + model("projectTemplatesBuildFileGeneration", recursive = false, extension = null) + } + } + + testGroup( + "idea/idea-new-project-wizard/tests", + "libraries/tools/new-project-wizard/new-project-wizard-cli/testData" + ) { + fun TestGroup.TestClass.allBuildSystemTests(relativeRootPath: String) { + for (testClass in listOf("GradleKts", "GradleGroovy", "Maven")) { + model( + relativeRootPath, + recursive = false, + extension = null, + testMethod = "doTest${testClass}", + testClassName = testClass + ) + } + } + testClass { + allBuildSystemTests("buildFileGeneration") + } + testClass { + allBuildSystemTests("projectTemplatesBuildFileGeneration") + } + } + + //TODO: move these tests into idea-completion module + testGroup("idea/tests", "idea/idea-completion/testData") { + testClass { + model("handlers/runtimeCast") + } + + testClass { + model("basic/codeFragments", extension = "kt") + } + } + + testGroup("j2k/tests", "j2k/testData") { + testClass { + model("fileOrElement", extension = "java") + } + } + testGroup("j2k/tests", "j2k/testData") { + testClass { + model("multiFile", extension = null, recursive = false) + } + } + testGroup("j2k/tests", "j2k/testData") { + testClass { + model("fileOrElement", extension = "java") + } + } + + testGroup("nj2k/tests", "nj2k/testData") { + testClass { + model("newJ2k", pattern = """^([^\.]+)\.java$""") + } + testClass { + model("inference/common") + } + testClass { + model("inference/nullability") + } + testClass { + model("inference/mutability") + } + testClass { + model("copyPaste", pattern = """^([^\.]+)\.java$""") + } + testClass { + model("copyPastePlainText", pattern = """^([^\.]+)\.txt$""") + } + testClass { + model("multiFile", extension = null, recursive = false) + } + } + + testGroup("jps-plugin/jps-tests/test", "jps-plugin/testData") { + testClass { + model("incremental/multiModule/common", extension = null, excludeParentDirs = true) + model("incremental/multiModule/jvm", extension = null, excludeParentDirs = true) + model("incremental/multiModule/multiplatform/custom", extension = null, excludeParentDirs = true) + model("incremental/pureKotlin", extension = null, recursive = false) + model("incremental/withJava", extension = null, excludeParentDirs = true) + model("incremental/inlineFunCallSite", extension = null, excludeParentDirs = true) + model("incremental/classHierarchyAffected", extension = null, excludeParentDirs = true) + } + + actualizeMppJpsIncTestCaseDirs(testDataRoot, "incremental/multiModule/multiplatform/withGeneratedContent") + + testClass { + model("incremental/multiModule/common", extension = null, excludeParentDirs = true) + } + + testClass { + model( + "incremental/multiModule/multiplatform/withGeneratedContent", extension = null, excludeParentDirs = true, + testClassName = "MultiplatformMultiModule", recursive = true + ) + } + + testClass { + model("incremental/lookupTracker/jvm", extension = null, recursive = false) + } + testClass { + model("incremental/lookupTracker/js", extension = null, recursive = false) + } + testClass { + // todo: investigate why lookups are different from non-klib js + model("incremental/lookupTracker/jsKlib", extension = null, recursive = false) + } + + testClass { + model("incremental/lazyKotlinCaches", extension = null, excludeParentDirs = true) + model("incremental/changeIncrementalOption", extension = null, excludeParentDirs = true) + } + + testClass { + model("incremental/cacheVersionChanged", extension = null, excludeParentDirs = true) + } + + testClass { + model("incremental/cacheVersionChanged", extension = null, excludeParentDirs = true) + } + } + + testGroup("jps-plugin/jps-tests/test", "jps-plugin/testData") { + fun TestGroup.TestClass.commonProtoComparisonTests() { + model("comparison/classSignatureChange", extension = null, excludeParentDirs = true) + model("comparison/classPrivateOnlyChange", extension = null, excludeParentDirs = true) + model("comparison/classMembersOnlyChanged", extension = null, excludeParentDirs = true) + model("comparison/packageMembers", extension = null, excludeParentDirs = true) + model("comparison/unchanged", extension = null, excludeParentDirs = true) + } + + testClass { + commonProtoComparisonTests() + model("comparison/jvmOnly", extension = null, excludeParentDirs = true) + } + + testClass { + commonProtoComparisonTests() + model("comparison/jsOnly", extension = null, excludeParentDirs = true) + } + } + + testGroup("compiler/incremental-compilation-impl/test", "jps-plugin/testData") { + fun incrementalJvmTestData(targetBackend: TargetBackend): TestGroup.TestClass.() -> Unit = { + model("incremental/pureKotlin", extension = null, recursive = false, targetBackend = targetBackend) + model("incremental/classHierarchyAffected", extension = null, recursive = false, targetBackend = targetBackend) + model("incremental/inlineFunCallSite", extension = null, excludeParentDirs = true, targetBackend = targetBackend) + model("incremental/withJava", extension = null, excludeParentDirs = true, targetBackend = targetBackend) + model("incremental/incrementalJvmCompilerOnly", extension = null, excludeParentDirs = true, targetBackend = targetBackend) + } + testClass(init = incrementalJvmTestData(TargetBackend.JVM)) + testClass(init = incrementalJvmTestData(TargetBackend.JVM_IR)) + + testClass { + model("incremental/pureKotlin", extension = null, recursive = false) + model("incremental/classHierarchyAffected", extension = null, recursive = false) + model("incremental/js", extension = null, excludeParentDirs = true) + } + + testClass(annotations = listOf(muteExtraSuffix(".jsklib"))) { + model("incremental/pureKotlin", extension = null, recursive = false) + model("incremental/classHierarchyAffected", extension = null, recursive = false) + model("incremental/js", extension = null, excludeParentDirs = true) + } + + testClass { + model("incremental/pureKotlin", extension = null, recursive = false) + model("incremental/classHierarchyAffected", extension = null, recursive = false) + model("incremental/js", extension = null, excludeParentDirs = true) + } + + testClass { + model("incremental/pureKotlin", extension = null, recursive = false) + model("incremental/classHierarchyAffected", extension = null, recursive = false) + model("incremental/js", extension = null, excludeParentDirs = true) + model("incremental/scopeExpansion", extension = null, excludeParentDirs = true) + } + + testClass { + model("incremental/js/friendsModuleDisabled", extension = null, recursive = false) + } + + testClass { + model("incremental/mpp/allPlatforms", extension = null, excludeParentDirs = true) + model("incremental/mpp/jvmOnly", extension = null, excludeParentDirs = true) + } + testClass { + model("incremental/mpp/allPlatforms", extension = null, excludeParentDirs = true) + } + } + + testGroup( + "plugins/android-extensions/android-extensions-compiler/test", + "plugins/android-extensions/android-extensions-compiler/testData" + ) { + testClass { + model("descriptors", recursive = false, extension = null) + } + + testClass { + model("codegen/android", recursive = false, extension = null, testMethod = "doCompileAgainstAndroidSdkTest") + model("codegen/android", recursive = false, extension = null, testMethod = "doFakeInvocationTest", testClassName = "Invoke") + } + + testClass { + model( + "codegen/android", recursive = false, extension = null, testMethod = "doCompileAgainstAndroidSdkTest", + targetBackend = TargetBackend.JVM_IR + ) + model( + "codegen/android", recursive = false, extension = null, testMethod = "doFakeInvocationTest", testClassName = "Invoke", + targetBackend = TargetBackend.JVM_IR + ) + } + + testClass { + model("codegen/bytecodeShape", recursive = false, extension = null) + } + + testClass { + model("parcel/box", targetBackend = TargetBackend.JVM) + } + + testClass { + model("parcel/box", targetBackend = TargetBackend.JVM_IR) + } + + testClass { + model("parcel/codegen", targetBackend = TargetBackend.JVM) + } + + testClass { + model("parcel/codegen", targetBackend = TargetBackend.JVM_IR) + } + } + + testGroup("plugins/jvm-abi-gen/test", "plugins/jvm-abi-gen/testData") { + testClass { + model("compare", recursive = false, extension = null) + } + + testClass { + model("content", recursive = false, extension = null) + } + + testClass { + model("compile", recursive = false, extension = null) + } + } + + testGroup("plugins/kapt3/kapt3-compiler/test", "plugins/kapt3/kapt3-compiler/testData") { + testClass { + model("converter") + } + + testClass { + model("kotlinRunner") + } + + testClass { + model("converter", targetBackend = TargetBackend.JVM_IR) + } + + testClass { + model("kotlinRunner", targetBackend = TargetBackend.JVM_IR) + } + } + + testGroup("plugins/kapt3/kapt3-cli/test", "plugins/kapt3/kapt3-cli/testData") { + testClass { + model("argumentParsing", extension = "txt") + } + + testClass { + model("integration", recursive = false, extension = null) + } + } + + testGroup("plugins/allopen/allopen-cli/test", "plugins/allopen/allopen-cli/testData") { + testClass { + model("bytecodeListing", extension = "kt") + } + } + + testGroup("plugins/noarg/noarg-cli/test", "plugins/noarg/noarg-cli/testData") { + testClass { + model("bytecodeListing", extension = "kt") + } + + testClass { + model("box", targetBackend = TargetBackend.JVM) + } + } + + testGroup("plugins/sam-with-receiver/sam-with-receiver-cli/test", "plugins/sam-with-receiver/sam-with-receiver-cli/testData") { + testClass { + model("diagnostics") + } + testClass { + model("script", extension = "kts") + } + } + + testGroup( + "plugins/kotlin-serialization/kotlin-serialization-compiler/test", + "plugins/kotlin-serialization/kotlin-serialization-compiler/testData" + ) { + testClass { + model("diagnostics") + } + + testClass { + model("codegen") + } + + testClass { + model("codegen") + } + } + + testGroup("plugins/fir/fir-plugin-prototype/tests", "plugins/fir/fir-plugin-prototype/testData") { + testClass { + model("") + } + } + + testGroup("idea/performanceTests/test", "idea/testData") { + testClass { + model("copyPaste/conversion", testMethod = "doPerfTest", pattern = """^([^\.]+)\.java$""") + } + + testClass { + model("copyPaste/conversion", testMethod = "doPerfTest", pattern = """^([^\.]+)\.java$""") + } + + testClass { + model("copyPaste/literal", testMethod = "doPerfTest", pattern = """^([^\.]+)\.kt$""") + } + + testClass { + model("highlighter", testMethod = "doPerfTest") + } + + testClass { + model("addImport", testMethod = "doPerfTest", pattern = KT_WITHOUT_DOTS_IN_NAME) + } + + testClass { + model("indentationOnNewline", testMethod = "doPerfTest", pattern = KT_OR_KTS_WITHOUT_DOTS_IN_NAME) + } + } + + testGroup("idea/performanceTests/test", "idea/idea-completion/testData") { + testClass { + model("incrementalResolve", testMethod = "doPerfTest") + } + + testClass { + model("handlers/basic", testMethod = "doPerfTest", pattern = KT_WITHOUT_DOTS_IN_NAME) + } + + testClass { + model("handlers/smart", testMethod = "doPerfTest") + } + + testClass { + model("handlers/keywords", testMethod = "doPerfTest") + } + + testClass { + model("handlers/charFilter", testMethod = "doPerfTest", pattern = KT_WITHOUT_DOTS_IN_NAME) + } + } +/* + testGroup("plugins/android-extensions/android-extensions-idea/tests", "plugins/android-extensions/android-extensions-idea/testData") { + testClass { + model("android/completion", recursive = false, extension = null) + } + + testClass { + model("android/goto", recursive = false, extension = null) + } + + testClass { + model("android/rename", recursive = false, extension = null) + } + + testClass { + model("android/renameLayout", recursive = false, extension = null) + } + + testClass { + model("android/findUsages", recursive = false, extension = null) + } + + testClass { + model("android/usageHighlighting", recursive = false, extension = null) + } + + testClass { + model("android/extraction", recursive = false, extension = null) + } + + testClass { + model("android/parcel/checker", excludeParentDirs = true) + } + + testClass { + model("android/parcel/quickfix", pattern = """^(\w+)\.((before\.Main\.\w+)|(test))$""", testMethod = "doTestWithExtraFile") + } + } + + testGroup("idea/idea-android/tests", "idea/testData") { + testClass { + model("configuration/android-gradle", pattern = """(\w+)_before\.gradle$""", testMethod = "doTestAndroidGradle") + model("configuration/android-gsk", pattern = """(\w+)_before\.gradle.kts$""", testMethod = "doTestAndroidGradle") + } + + testClass { + model("android/intention", pattern = "^([\\w\\-_]+)\\.kt$") + } + + testClass { + model("android/resourceIntention", extension = "test", singleClass = true) + } + + testClass { + model("android/quickfix", pattern = """^(\w+)\.((before\.Main\.\w+)|(test))$""", testMethod = "doTestWithExtraFile") + } + + testClass { + model("android/lint", excludeParentDirs = true) + } + + testClass { + model("android/lintQuickfix", pattern = "^([\\w\\-_]+)\\.kt$") + } + + testClass { + model("android/folding") + } + + testClass { + model("android/gutterIcon") + } + } +*/ +} diff --git a/idea/resources-en/messages/KotlinBundle.properties b/idea/resources-en/messages/KotlinBundle.properties index 7264382be64..08af5456657 100644 --- a/idea/resources-en/messages/KotlinBundle.properties +++ b/idea/resources-en/messages/KotlinBundle.properties @@ -2231,3 +2231,18 @@ title.import.layout=Import Layout title.packages.to.use.import.with=Packages to Use Import with '*' redundant.qualifier.unnecessary.non.direct.parent.class.qualifier=Unnecessary non-direct parent classes qualifiers fix.add.exception.to.throws=Add ''{0}'' + +hints.title.codevision=Code Vision +hints.title.codevision.show.hints.for=Show hints for: +hints.title.codevision.usages=Usages +hints.title.codevision.inheritors=Implementations/Inheritors/Overrides + +hints.codevision.usages.format={0, choice, 1#1 Usage|2#{0,number} Usages} +hints.codevision.usages.too_many.format={0,number}+ Usages +hints.codevision.implementations.format={0, choice, 1#1 Implementation|2#{0,number} Implementations} +hints.codevision.implementations.too_many.format={0,number}+ Implementations +hints.codevision.inheritors.format={0, choice, 1#1 Inheritor|2#{0,number} Inheritors} +hints.codevision.inheritors.to_many.format={0,number}+ Inheritors +hints.codevision.overrides.format={0, choice, 1#1 Override|2#{0,number} Overrides} +hints.codevision.overrides.to_many.format={0,number}+ Overrides +hints.codevision.settings=Settings... \ No newline at end of file diff --git a/idea/resources/META-INF/plugin-common.xml b/idea/resources/META-INF/plugin-common.xml index b66ce3553aa..ffcdcb1c536 100644 --- a/idea/resources/META-INF/plugin-common.xml +++ b/idea/resources/META-INF/plugin-common.xml @@ -3374,6 +3374,9 @@ + + + diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/codevision/KotlinCodeVisionCompat.kt b/idea/src/org/jetbrains/kotlin/idea/codeInsight/codevision/KotlinCodeVisionCompat.kt new file mode 100644 index 00000000000..3dd634298cc --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/codevision/KotlinCodeVisionCompat.kt @@ -0,0 +1,53 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +@file:Suppress("UnstableApiUsage") + +package org.jetbrains.kotlin.idea.codeInsight.codevision + +import com.intellij.codeInsight.hints.ChangeListener +import com.intellij.codeInsight.hints.ImmediateConfigurable +import com.intellij.codeInsight.hints.settings.InlayHintsConfigurable +import com.intellij.internal.statistic.eventLog.FeatureUsageData +import com.intellij.internal.statistic.service.fus.collectors.FUCounterUsageLogger +import com.intellij.openapi.project.Project +import com.intellij.ui.layout.panel +import org.jetbrains.kotlin.idea.KotlinBundle +import javax.swing.JPanel + + +// FIX ME WHEN BUNCH 192 REMOVED +typealias CodeVisionInlayHintsConfigurable = InlayHintsConfigurable + +fun logUsageStatistics(project: Project?, groupId: String, eventId: String) = + FUCounterUsageLogger.getInstance().logEvent(project, groupId, eventId) + +fun logUsageStatistics(project: Project?, groupId: String, eventId: String, data: FeatureUsageData) = + FUCounterUsageLogger.getInstance().logEvent(project, groupId, eventId, data) + +fun createImmediateConfigurable(settings: KotlinCodeVisionProvider.KotlinCodeVisionSettings): ImmediateConfigurable { + return object : ImmediateConfigurable { + override fun createComponent(listener: ChangeListener): JPanel { + return panel {} + } + + override val cases: List + get() = listOf( + ImmediateConfigurable.Case( + KotlinBundle.message("hints.title.codevision.usages"), + "usages", + settings::showUsages + ), + ImmediateConfigurable.Case( + KotlinBundle.message("hints.title.codevision.inheritors"), + "inheritors", + settings::showInheritors + ) + ) + + override val mainCheckboxText: String + get() = KotlinBundle.message("hints.title.codevision.show.hints.for") + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/codevision/KotlinCodeVisionCompat.kt.192 b/idea/src/org/jetbrains/kotlin/idea/codeInsight/codevision/KotlinCodeVisionCompat.kt.192 new file mode 100644 index 00000000000..1fbe053e2a5 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/codevision/KotlinCodeVisionCompat.kt.192 @@ -0,0 +1,51 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.codeInsight.codevision + +import com.intellij.codeInsight.hints.ChangeListener +import com.intellij.codeInsight.hints.ImmediateConfigurable +import com.intellij.codeInsight.hints.config.InlayHintsConfigurable +import com.intellij.internal.statistic.eventLog.FeatureUsageData +import com.intellij.internal.statistic.service.fus.collectors.FUCounterUsageLogger +import com.intellij.openapi.project.Project +import com.intellij.ui.components.JBCheckBox +import com.intellij.ui.layout.panel +import org.jetbrains.kotlin.idea.KotlinBundle +import javax.swing.JPanel + + +typealias CodeVisionInlayHintsConfigurable = InlayHintsConfigurable + +fun logUsageStatistics(project: Project?, groupId: String, eventId: String) { + project?.let { FUCounterUsageLogger.getInstance().logEvent(project, groupId, eventId) } +} + +fun logUsageStatistics(project: Project?, groupId: String, eventId: String, data: FeatureUsageData) { + project?.let { FUCounterUsageLogger.getInstance().logEvent(project, groupId, eventId, data) } +} + +fun createImmediateConfigurable(settings: KotlinCodeVisionProvider.KotlinCodeVisionSettings): ImmediateConfigurable { + return object : ImmediateConfigurable { + val usagesText = KotlinBundle.message("hints.title.codevision.usages") + val inheritorsText = KotlinBundle.message("hints.title.codevision.inheritors") + + private val usagesField = JBCheckBox(usagesText, settings.showUsages) + private val inheritorsField = JBCheckBox(inheritorsText, settings.showInheritors) + + override fun createComponent(listener: ChangeListener): JPanel { + usagesField.isSelected = settings.showUsages + usagesField.addActionListener { settings.showUsages = usagesField.isSelected } + + inheritorsField.isSelected = settings.showInheritors + inheritorsField.addActionListener { settings.showInheritors = inheritorsField.isSelected } + + return panel { + row { usagesField(pushX) } + row { inheritorsField(pushX) } + } + } + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/codevision/KotlinCodeVisionHintsCollector.kt b/idea/src/org/jetbrains/kotlin/idea/codeInsight/codevision/KotlinCodeVisionHintsCollector.kt new file mode 100644 index 00000000000..e0f573ac2a7 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/codevision/KotlinCodeVisionHintsCollector.kt @@ -0,0 +1,262 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.codeInsight.codevision + +import com.intellij.codeInsight.hints.FactoryInlayHintsCollector +import com.intellij.codeInsight.hints.InlayHintsSink +import com.intellij.codeInsight.hints.presentation.AttributesTransformerPresentation +import com.intellij.codeInsight.hints.presentation.InlayPresentation +import com.intellij.codeInsight.hints.presentation.MouseButton +import com.intellij.codeInsight.hints.presentation.PresentationFactory +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.editor.colors.EditorColors +import com.intellij.openapi.editor.colors.EditorColorsManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.roots.ProjectRootModificationTracker +import com.intellij.openapi.util.Key +import com.intellij.openapi.util.text.StringUtil +import com.intellij.psi.PsiElement +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.search.searches.DirectClassInheritorsSearch +import com.intellij.psi.search.searches.MethodReferencesSearch +import com.intellij.psi.search.searches.OverridingMethodsSearch +import com.intellij.psi.search.searches.ReferencesSearch +import com.intellij.psi.util.CachedValue +import com.intellij.psi.util.CachedValueProvider +import com.intellij.psi.util.CachedValuesManager +import com.intellij.psi.util.PsiModificationTracker +import com.intellij.util.ArrayUtil +import com.intellij.util.Processor +import org.jetbrains.kotlin.asJava.LightClassUtil +import org.jetbrains.kotlin.asJava.toLightClass +import org.jetbrains.kotlin.idea.refactoring.isAbstract +import org.jetbrains.kotlin.idea.search.declarationsSearch.toPossiblyFakeLightMethods +import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinDefinitionsSearcher +import org.jetbrains.kotlin.psi.KtClass +import org.jetbrains.kotlin.psi.KtFunction +import org.jetbrains.kotlin.psi.KtFunctionLiteral +import org.jetbrains.kotlin.psi.KtProperty +import org.jetbrains.kotlin.utils.SmartList + + +@Suppress("UnstableApiUsage") +class KotlinCodeVisionHintsCollector( + editor: Editor, private val showUsages: Boolean, private val showInheritors: Boolean, + private val usagesLimit: Int, private val inheritorsLimit: Int +) : FactoryInlayHintsCollector(editor) { + + companion object { + private val hintsKey = Key.create>("CodeVisionHints") + + + fun searchUsages(element: PsiElement, usagesLimit: Int): Usages? { + val countingProcessor = CountingUpToLimitProcessor(usagesLimit) + if (element is KtClass) { + ReferencesSearch.search(element).forEach(countingProcessor) + } else { + element.toPossiblyFakeLightMethods().firstOrNull() // inline methods don't have light analogues (fake needed) + ?.let { MethodReferencesSearch.search(it).forEach(countingProcessor) } + } + + val (usagesNum, limitReached) = countingProcessor + return if (usagesNum > 0) Usages(usagesNum, limitReached) else null + } + + private fun searchFunctionOverrides(function: KtFunction, inheritorsLimit: Int): KotlinCodeVisionLimitedHint? { + return LightClassUtil.getLightClassMethod(function)?.let { it -> + val countingProcessor = CountingUpToLimitProcessor(inheritorsLimit) + OverridingMethodsSearch.search(it, true).forEach(countingProcessor) + val (overridingNum, limitReached) = countingProcessor + + if (overridingNum > 0) { + if (function.isAbstract()) FunctionImplementations(overridingNum, limitReached) + else FunctionOverrides(overridingNum, limitReached) + } else null + } + } + + private fun searchClassInheritors(clazz: KtClass, inheritorsLimit: Int): KotlinCodeVisionLimitedHint? { + return clazz.toLightClass()?.let { + val countingProcessor = CountingUpToLimitProcessor(inheritorsLimit) + DirectClassInheritorsSearch.search(it, clazz.useScope, true).forEach(countingProcessor) + val (inheritorsNum, limitReached) = countingProcessor + if (inheritorsNum > 0) { + if (clazz.isInterface()) InterfaceImplementations(inheritorsNum, limitReached) + else ClassInheritors(inheritorsNum, limitReached) + } else null + } + } + + private fun searchPropertyOverriding(property: KtProperty, inheritorsLimit: Int): KotlinCodeVisionLimitedHint? { + val countingProcessor = CountingUpToLimitProcessor(inheritorsLimit) + KotlinDefinitionsSearcher.processPropertyImplementationsMethods( + property.toPossiblyFakeLightMethods(), + GlobalSearchScope.allScope(property.project), + countingProcessor + ) + val (overridesNum, limitReached) = countingProcessor + return if (overridesNum > 0) PropertyOverrides(overridesNum, limitReached) else null + } + } + + override fun collect(element: PsiElement, editor: Editor, sink: InlayHintsSink): Boolean { + if (!showUsages && !showInheritors) return false + if (!isElementOfInterest(element)) return true + if (editor.project == null) return false + + val hints = retrieveHints(editor.project!!, element) + val inlayPresentations = + hints.takeIf { it.isNotEmpty() }?.let { listOf(prepareBlockElements(element, editor, hints)) } ?: emptyList() + + inlayPresentations.forEach { hintPair -> + sink.addBlockElement( + hintPair.first, + relatesToPrecedingText = true, + showAbove = true, + priority = 0, + presentation = hintPair.second + ) + } + + return true + } + + private fun retrieveHints(project: Project, element: PsiElement): List { + val cachedValueProvider = CachedHintsProvider( + element, showUsages, showInheritors, usagesLimit, inheritorsLimit + ) + + return CachedValuesManager.getManager(project).run { + this.getCachedValue(element, hintsKey, cachedValueProvider, false).takeUnless { isStale(it) } ?: run { + this.createCachedValue(cachedValueProvider).also { element.putUserData(hintsKey, it) }.value + } + }.hints + } + + private fun isStale(cachedValue: CachedHints): Boolean { + return cachedValue.showUsages != showUsages || cachedValue.showInheritors != showInheritors + } + + @Suppress("GrazieInspection") + private fun prepareBlockElements( + element: PsiElement, + editor: Editor, + hints: List + ): Pair { + + assert(hints.isNotEmpty()) { "Attempt to build block elements whereas hints don't exist" } + assert(hints.size <= 2) { "Hints other than usages-implementations are not expected" } + + val offset = element.textRange.startOffset + val line = editor.document.getLineNumber(offset) + val lineStart = editor.document.getLineStartOffset(line) + val indent = offset - lineStart + + /* + * presentations: [][] + * hints: hint[0] hint[1] + */ + val presentations = arrayOfNulls(hints.size * 2) // 2 or 4 + presentations[0] = factory.text(StringUtil.repeat(" ", indent)) + var pInd = 1 + for (hInd in hints.indices) { // handling usages & inheritors + val hint: KotlinCodeVisionHint = hints[hInd] + if (hInd != 0) + presentations[pInd++] = factory.text(" ") + + presentations[pInd++] = createPresentation(factory, element, editor, hint) // either Usages or Inheritors + } + + val filledPresentations = presentations.requireNoNulls() + + val seq = factory.seq(*filledPresentations) + val withAppearingSettings = factory.changeOnHover(seq, { + val spaceAndSettings = arrayOf(factory.text(" "), createSettings(factory, element, editor)) + val withSettings = ArrayUtil.mergeArrays(filledPresentations, spaceAndSettings) + factory.seq(*withSettings) + }) { true } + + return Pair(lineStart, withAppearingSettings) + } + + private fun isElementOfInterest(element: PsiElement): Boolean = + element is KtClass + || (element is KtFunction && element !is KtFunctionLiteral) + || (element is KtProperty && !element.isLocal) + + private fun createPresentation( + factory: PresentationFactory, element: PsiElement, editor: Editor, result: KotlinCodeVisionHint + ): InlayPresentation { + val text = factory.smallText(result.regularText) + return factory.changeOnHover(text, { + val onClick = factory.onClick(text, MouseButton.Left) + { event, _ -> result.onClick(editor, element, event) } + applyReferenceColor(onClick) + }) { true } + } + + private fun applyReferenceColor(presentation: InlayPresentation): InlayPresentation { + return AttributesTransformerPresentation(presentation) { + val attributes = EditorColorsManager.getInstance() + .globalScheme.getAttributes(EditorColors.REFERENCE_HYPERLINK_COLOR).clone() + attributes.apply { effectType = null } + } + } + + private fun createSettings(factory: PresentationFactory, element: PsiElement, editor: Editor): InlayPresentation { + return createPresentation(factory, element, editor, SettingsHint()) + } + + class CachedHintsProvider( + private val element: PsiElement, + private val showUsages: Boolean, + private val showInheritors: Boolean, + private val usagesLimit: Int, + private val inheritorsLimit: Int + ) : CachedValueProvider { + + override fun compute(): CachedValueProvider.Result? { + val hints: MutableList = SmartList() + + if (showUsages) + searchUsages(element, usagesLimit)?.let { hints += it } + + if (showInheritors) { + when (element) { + is KtFunction -> searchFunctionOverrides(element, inheritorsLimit)?.let { hints += it } + is KtClass -> searchClassInheritors(element, inheritorsLimit)?.let { hints += it } + is KtProperty -> searchPropertyOverriding(element, inheritorsLimit)?.let { hints += it } + } + } + + return CachedValueProvider.Result( + CachedHints(hints, this.showUsages, this.showInheritors), + // kotlinOutOfCodeBlockTracker doesn't work for usages: new reference inside the block is not detected + // MODIFICATION_COUNT {+: file reopening -> cache hit, -: any code modification resets all caches (records are in PSI)} + PsiModificationTracker.MODIFICATION_COUNT, + ProjectRootModificationTracker.getInstance(element.project) // tracking project structure changes + ) + } + } + + class CountingUpToLimitProcessor(private val limit: Int) : Processor { + private val findings = mutableSetOf() // for properties it's crucial not to calculate setters and getters together + + override fun process(t: T): Boolean { + findings.add(t) + return findings.size < limit + } + + operator fun component1(): Int = findings.size + operator fun component2(): Boolean = findings.size >= limit + } + + data class CachedHints( + val hints: List, + val showUsages: Boolean, + val showInheritors: Boolean + ) +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/codevision/KotlinCodeVisionLimitedHint.kt b/idea/src/org/jetbrains/kotlin/idea/codeInsight/codevision/KotlinCodeVisionLimitedHint.kt new file mode 100644 index 00000000000..7ce248daf60 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/codevision/KotlinCodeVisionLimitedHint.kt @@ -0,0 +1,131 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.codeInsight.codevision + +import com.intellij.codeInsight.navigation.actions.GotoDeclarationAction +import com.intellij.internal.statistic.eventLog.FeatureUsageData +import com.intellij.openapi.editor.Editor +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.idea.KotlinBundle +import org.jetbrains.kotlin.idea.highlighter.markers.OVERRIDDEN_FUNCTION +import org.jetbrains.kotlin.idea.highlighter.markers.OVERRIDDEN_PROPERTY +import org.jetbrains.kotlin.idea.highlighter.markers.SUBCLASSED_CLASS +import org.jetbrains.kotlin.psi.KtClass +import org.jetbrains.kotlin.psi.KtFunction +import org.jetbrains.kotlin.psi.KtProperty +import java.awt.event.MouseEvent + +abstract class KotlinCodeVisionHint(hintKey: String) { + open val regularText: String = KotlinBundle.message(hintKey) + + abstract fun onClick(editor: Editor, element: PsiElement, event: MouseEvent?) +} + +abstract class KotlinCodeVisionLimitedHint(num: Int, limitReached: Boolean, regularHintKey: String, tooManyHintKey: String) : + KotlinCodeVisionHint(regularHintKey) { + + override val regularText: String = + if (limitReached) KotlinBundle.message(tooManyHintKey, num) else KotlinBundle.message(regularHintKey, num) +} + +private const val IMPLEMENTATIONS_KEY = "hints.codevision.implementations.format" +private const val IMPLEMENTATIONS_TO_MANY_KEY = "hints.codevision.implementations.too_many.format" + +private const val INHERITORS_KEY = "hints.codevision.inheritors.format" +private const val INHERITORS_TO_MANY_KEY = "hints.codevision.inheritors.to_many.format" + +private const val OVERRIDES_KEY = "hints.codevision.overrides.format" +private const val OVERRIDES_TOO_MANY_KEY = "hints.codevision.overrides.to_many.format" + +private const val USAGES_KEY = "hints.codevision.usages.format" +private const val USAGES_TOO_MANY_KEY = "hints.codevision.usages.too_many.format" + +private const val SETTINGS_FORMAT = "hints.codevision.settings" + +// FUS = Feature Usage Statistics +const val FUS_GROUP_ID = "kotlin.code.vision" +const val USAGES_CLICKED_EVENT_ID = "usages.clicked" +const val INHERITORS_CLICKED_EVENT_ID = "inheritors.clicked" +const val SETTING_CLICKED_EVENT_ID = "setting.clicked" + +// FUD = Feature Usage Data +const val FUD_KEY = "location" +const val FUD_FUNCTION = "function" +const val FUD_PROPERTY = "property" +const val FUD_CLASS = "class" +const val FUD_INTERFACE = "interface" + +class Usages(usagesNum: Int, limitReached: Boolean) : + KotlinCodeVisionLimitedHint(usagesNum, limitReached, USAGES_KEY, USAGES_TOO_MANY_KEY) { + + override fun onClick(editor: Editor, element: PsiElement, event: MouseEvent?) { + logUsageStatistics(editor.project, FUS_GROUP_ID, USAGES_CLICKED_EVENT_ID) + GotoDeclarationAction.startFindUsages(editor, editor.project!!, element) + } +} + +class FunctionOverrides(overridesNum: Int, limitReached: Boolean) : + KotlinCodeVisionLimitedHint(overridesNum, limitReached, OVERRIDES_KEY, OVERRIDES_TOO_MANY_KEY) { + + override fun onClick(editor: Editor, element: PsiElement, event: MouseEvent?) { + val data = FeatureUsageData().addData(FUD_KEY, FUD_FUNCTION) + logUsageStatistics(editor.project, FUS_GROUP_ID, INHERITORS_CLICKED_EVENT_ID, data) + val navigationHandler = OVERRIDDEN_FUNCTION.navigationHandler + navigationHandler.navigate(event, (element as KtFunction).nameIdentifier) + } +} + +class FunctionImplementations(implNum: Int, limitReached: Boolean) : + KotlinCodeVisionLimitedHint(implNum, limitReached, IMPLEMENTATIONS_KEY, IMPLEMENTATIONS_TO_MANY_KEY) { + + override fun onClick(editor: Editor, element: PsiElement, event: MouseEvent?) { + val data = FeatureUsageData().addData(FUD_KEY, FUD_FUNCTION) + logUsageStatistics(editor.project, FUS_GROUP_ID, INHERITORS_CLICKED_EVENT_ID, data) + val navigationHandler = OVERRIDDEN_FUNCTION.navigationHandler + navigationHandler.navigate(event, (element as KtFunction).nameIdentifier) + } +} + +class PropertyOverrides(overridesNum: Int, limitReached: Boolean) : + KotlinCodeVisionLimitedHint(overridesNum, limitReached, OVERRIDES_KEY, OVERRIDES_TOO_MANY_KEY) { + + override fun onClick(editor: Editor, element: PsiElement, event: MouseEvent?) { + val data = FeatureUsageData().addData(FUD_KEY, FUD_PROPERTY) + logUsageStatistics(editor.project, FUS_GROUP_ID, INHERITORS_CLICKED_EVENT_ID, data) + val navigationHandler = OVERRIDDEN_PROPERTY.navigationHandler + navigationHandler.navigate(event, (element as KtProperty).nameIdentifier) + } +} + +class ClassInheritors(inheritorsNum: Int, limitReached: Boolean) : + KotlinCodeVisionLimitedHint(inheritorsNum, limitReached, INHERITORS_KEY, INHERITORS_TO_MANY_KEY) { + + override fun onClick(editor: Editor, element: PsiElement, event: MouseEvent?) { + val data = FeatureUsageData().addData(FUD_KEY, FUD_CLASS) + logUsageStatistics(editor.project, FUS_GROUP_ID, INHERITORS_CLICKED_EVENT_ID, data) + val navigationHandler = SUBCLASSED_CLASS.navigationHandler + navigationHandler.navigate(event, (element as KtClass).nameIdentifier) + } +} + +class InterfaceImplementations(implNum: Int, limitReached: Boolean) : + KotlinCodeVisionLimitedHint(implNum, limitReached, IMPLEMENTATIONS_KEY, IMPLEMENTATIONS_TO_MANY_KEY) { + + override fun onClick(editor: Editor, element: PsiElement, event: MouseEvent?) { + val data = FeatureUsageData().addData(FUD_KEY, FUD_INTERFACE) + logUsageStatistics(editor.project, FUS_GROUP_ID, INHERITORS_CLICKED_EVENT_ID, data) + val navigationHandler = SUBCLASSED_CLASS.navigationHandler + navigationHandler.navigate(event, (element as KtClass).nameIdentifier) + } +} + +class SettingsHint : KotlinCodeVisionHint(SETTINGS_FORMAT) { + override fun onClick(editor: Editor, element: PsiElement, event: MouseEvent?) { + val project = element.project + logUsageStatistics(project, FUS_GROUP_ID, SETTING_CLICKED_EVENT_ID) + CodeVisionInlayHintsConfigurable.showSettingsDialogForLanguage(project, element.language) + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/codevision/KotlinCodeVisionProvider.kt b/idea/src/org/jetbrains/kotlin/idea/codeInsight/codevision/KotlinCodeVisionProvider.kt new file mode 100644 index 00000000000..79e3e8a981c --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/codevision/KotlinCodeVisionProvider.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.codeInsight.codevision + +import com.intellij.codeInsight.hints.* +import com.intellij.lang.Language +import com.intellij.openapi.editor.Editor +import com.intellij.psi.PsiFile +import org.jetbrains.kotlin.idea.KotlinBundle +import org.jetbrains.kotlin.idea.KotlinLanguage + +@Suppress("UnstableApiUsage") +class KotlinCodeVisionProvider : InlayHintsProvider { + + override val key: SettingsKey = SettingsKey("CodeVision") + override val name: String = KotlinBundle.message("hints.title.codevision") + override val previewText: String? = null + + var usagesLimit: Int = 100 + var inheritorsLimit: Int = 100 + + override fun isLanguageSupported(language: Language): Boolean = language is KotlinLanguage + + override fun createConfigurable(settings: KotlinCodeVisionSettings): ImmediateConfigurable = createImmediateConfigurable(settings) + + override fun createSettings(): KotlinCodeVisionSettings = KotlinCodeVisionSettings() + + override fun getCollectorFor( + file: PsiFile, editor: Editor, settings: KotlinCodeVisionSettings, sink: InlayHintsSink + ): InlayHintsCollector? { + if (!settings.showUsages && !settings.showInheritors) return null + return KotlinCodeVisionHintsCollector(editor, settings.showUsages, settings.showInheritors, usagesLimit, inheritorsLimit) + } + + data class KotlinCodeVisionSettings(var showUsages: Boolean = false, var showInheritors: Boolean = false) +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/KotlinLineMarkerProvider.kt b/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/KotlinLineMarkerProvider.kt index efb5f708e19..8b70d28bfa9 100644 --- a/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/KotlinLineMarkerProvider.kt +++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/KotlinLineMarkerProvider.kt @@ -144,7 +144,7 @@ interface TestableLineMarkerNavigator { fun getTargetsPopupDescriptor(element: PsiElement?): NavigationPopupDescriptor? } -private val SUBCLASSED_CLASS = MarkerType( +val SUBCLASSED_CLASS = MarkerType( "SUBCLASSED_CLASS", { getPsiClass(it)?.let(::getSubclassedClassTooltip) }, object : LineMarkerNavigator() { @@ -155,7 +155,7 @@ private val SUBCLASSED_CLASS = MarkerType( } }) -private val OVERRIDDEN_FUNCTION = object : MarkerType( +val OVERRIDDEN_FUNCTION = object : MarkerType( "OVERRIDDEN_FUNCTION", { getPsiMethod(it)?.let(::getOverriddenMethodTooltip) }, object : LineMarkerNavigator() { @@ -176,7 +176,7 @@ private val OVERRIDDEN_FUNCTION = object : MarkerType( } } -private val OVERRIDDEN_PROPERTY = object : MarkerType( +val OVERRIDDEN_PROPERTY = object : MarkerType( "OVERRIDDEN_PROPERTY", { it?.let { getOverriddenPropertyTooltip(it.parent as KtNamedDeclaration) } }, object : LineMarkerNavigator() { diff --git a/idea/testData/codeInsight/codeVision/ClassFunctionOverrides.kt b/idea/testData/codeInsight/codeVision/ClassFunctionOverrides.kt new file mode 100644 index 00000000000..beeb30766b3 --- /dev/null +++ b/idea/testData/codeInsight/codeVision/ClassFunctionOverrides.kt @@ -0,0 +1,17 @@ +// MODE: inheritors + +<# block [ 2 Inheritors] #> +abstract class SomeClass { +<# block [ 1 Override] #> + open fun someFun() = "" +<# block [ 2 Implementations] #> + abstract fun someAbstractFun() +} + +class DerivedClassA : SomeClass { + override fun someFun() = "overridden" + override fun someAbstractFun() = "overridden" +} +class DerivedClassB : SomeClass { + override fun someAbstractFun() = "overridden" +} diff --git a/idea/testData/codeInsight/codeVision/ClassInheritors.kt b/idea/testData/codeInsight/codeVision/ClassInheritors.kt new file mode 100644 index 00000000000..12df161f38d --- /dev/null +++ b/idea/testData/codeInsight/codeVision/ClassInheritors.kt @@ -0,0 +1,16 @@ +// MODE: inheritors + +<# block [ 4 Inheritors] #> +open class SomeClass { + class NestedDerivedClass: SomeClass() {} // <== (1): nested class +} +<# block [ 1 Inheritor] #> +open class DerivedClass : SomeClass {} // <== (2): direct derived one +class AnotherDerivedClass : SomeClass {} // <== (3): yet another derived one +class DerivedDerivedClass : DerivedClass { // <== (): indirect inheritor of SomeClass + fun main() { + val someClassInstance = object : SomeClass() { // <== (4): anonymous derived one + val somethingHere = "" + } + } +} \ No newline at end of file diff --git a/idea/testData/codeInsight/codeVision/ClassMethodUsages.kt b/idea/testData/codeInsight/codeVision/ClassMethodUsages.kt new file mode 100644 index 00000000000..120a6151224 --- /dev/null +++ b/idea/testData/codeInsight/codeVision/ClassMethodUsages.kt @@ -0,0 +1,17 @@ +// MODE: usages + +<# block [ 1 Usage] #> +abstract class SomeClass { +<# block [ 3 Usages] #> + abstract fun someFun(): String + fun someOtherFun() = someFun() // <== (1): delegation from another method + val someProperty = someFun() // <== (2): property initializer +} + +fun main() { + val instance = object: SomeClass { +<# block [ 1 Usage] #> + override fun someFun(): String {} // <== (): used below + } + instance.someFun() <== (3): call on an instance +} \ No newline at end of file diff --git a/idea/testData/codeInsight/codeVision/ClassPropertiesOverrides.kt b/idea/testData/codeInsight/codeVision/ClassPropertiesOverrides.kt new file mode 100644 index 00000000000..f678ba45cec --- /dev/null +++ b/idea/testData/codeInsight/codeVision/ClassPropertiesOverrides.kt @@ -0,0 +1,23 @@ +// MODE: inheritors + +<# block [ 1 Inheritor] #> +abstract class SomeClass { +<# block [ 1 Override] #> + abstract val someAbstractProperty: Int +<# block [ 2 Overrides] #> + open val nonAbstractProperty: Int = 10 + open val notToBeOverriddenProperty: Int = 10 +} + +<# block [ 1 Inheritor] #> +open class DerivedClassA : SomeClass() { + override val someAbstractProperty: Int = 5 +<# block [ 1 Override] #> + override val nonAbstractProperty: Int = 15 // NOTE that DerivedClassB overrides both getter and setter but counted once +} + +class DerivedClassB : DerivedClassA() { + override var nonAbstractProperty: Int = 15 + get() = 20 + set(value) {field = value / 2} +} \ No newline at end of file diff --git a/idea/testData/codeInsight/codeVision/ClassPropertyUsages.kt b/idea/testData/codeInsight/codeVision/ClassPropertyUsages.kt new file mode 100644 index 00000000000..bd015569d85 --- /dev/null +++ b/idea/testData/codeInsight/codeVision/ClassPropertyUsages.kt @@ -0,0 +1,13 @@ +// MODE: usages + +<# block [ 1 Usage] #> +interface SomeClass { +<# block [ 3 Usages] #> + var someProperty = "initialized" + fun someFun() = "it's " + someProperty // <== (1): reference from expression +} + +fun main() { + val instance = object: SomeClass {} + val someString = instance.someProperty // <== (2): getter call + instance.someProperty = "anotherValue" // <== (3): setter call \ No newline at end of file diff --git a/idea/testData/codeInsight/codeVision/ClassUsages.kt b/idea/testData/codeInsight/codeVision/ClassUsages.kt new file mode 100644 index 00000000000..eb7c00e52e4 --- /dev/null +++ b/idea/testData/codeInsight/codeVision/ClassUsages.kt @@ -0,0 +1,11 @@ +// MODE: usages + +<# block [ 5 Usages] #> +open class SomeClass {} +class SomeOtherClass : SomeClass {} // <== (1): class extension +class SomeYetOtherClass : SomeClass { // <== (2): class extension +<# block [ 1 Usage] #> + fun acceptsClass(param: SomeClass) {} // <== (3): parameter type + fun returnsInterface(): SomeClass {} // <== (4): return type + fun main() = acceptsClass(object : SomeClass {}) // <== (5): anonymous class instance +} \ No newline at end of file diff --git a/idea/testData/codeInsight/codeVision/GlobalFunctionUsages.kt b/idea/testData/codeInsight/codeVision/GlobalFunctionUsages.kt new file mode 100644 index 00000000000..a136d3191fb --- /dev/null +++ b/idea/testData/codeInsight/codeVision/GlobalFunctionUsages.kt @@ -0,0 +1,12 @@ +// MODE: usages + +<# block [ 3 Usages] #> +fun function(param: String): Int = 1 +<# block [ 1 Usage] #> +fun higherOrderFun(s: String, param: (String) -> Int) = param(s) + +fun main() { + function("someString") + val functionRef = ::function + higherOrderFun("someString", ::function) +} \ No newline at end of file diff --git a/idea/testData/codeInsight/codeVision/InterfaceAbstractMethodImplementation.kt b/idea/testData/codeInsight/codeVision/InterfaceAbstractMethodImplementation.kt new file mode 100644 index 00000000000..01817875aef --- /dev/null +++ b/idea/testData/codeInsight/codeVision/InterfaceAbstractMethodImplementation.kt @@ -0,0 +1,16 @@ +// MODE: inheritors + +<# block [ 1 Implementation] #> +interface SomeInterface { +<# block [ 2 Implementations] #> + fun interfaceMethodA() +} +<# block [ 1 Inheritor] #> +open class SomeClass : SomeInterface { +<# block [ 1 Override] #> + override fun interfaceMethodA() {} // <== (1) +} + +class SomeDerivedClass : SomeClass() { + override fun interfaceMethodA() {} // <== (2) +} \ No newline at end of file diff --git a/idea/testData/codeInsight/codeVision/InterfaceImplementations.kt b/idea/testData/codeInsight/codeVision/InterfaceImplementations.kt new file mode 100644 index 00000000000..12eb35af4b6 --- /dev/null +++ b/idea/testData/codeInsight/codeVision/InterfaceImplementations.kt @@ -0,0 +1,9 @@ +// MODE: inheritors + +<# block [ 3 Implementations] #> +interface SomeInterface {} +interface SomeOtherInterface : SomeInterface {} // <== (1): interface extension +class SomeClass : SomeInterface { // <== (2): interface implementation + fun acceptsInterface(param: SomeInterface) {} + fun main() = acceptsInterface(object : SomeInterface {}) // <== (3): anonymous class instance +} \ No newline at end of file diff --git a/idea/testData/codeInsight/codeVision/InterfaceMethodUsages.kt b/idea/testData/codeInsight/codeVision/InterfaceMethodUsages.kt new file mode 100644 index 00000000000..2a1a0237ea6 --- /dev/null +++ b/idea/testData/codeInsight/codeVision/InterfaceMethodUsages.kt @@ -0,0 +1,17 @@ +// MODE: usages + +<# block [ 1 Usage] #> +interface SomeInterface { +<# block [ 3 Usages] #> + fun someFun(): String + fun someOtherFun() = someFun() // <== (1): delegation from another interface method + val someProperty = someFun() // <== (2): property initializer +} + +fun main() { + val instance = object: SomeInterface { +<# block [ 1 Usage] #> + override fun someFun(): String {} // <== (): used below + } + instance.someFun() <== (3): call on an instance +} \ No newline at end of file diff --git a/idea/testData/codeInsight/codeVision/InterfaceMethodsOverrides.kt b/idea/testData/codeInsight/codeVision/InterfaceMethodsOverrides.kt new file mode 100644 index 00000000000..92a36503f8e --- /dev/null +++ b/idea/testData/codeInsight/codeVision/InterfaceMethodsOverrides.kt @@ -0,0 +1,11 @@ +// MODE: inheritors + +<# block [ 1 Implementation] #> +interface SomeInterface { +<# block [ 1 Override] #> + fun interfaceMethodA() = 10 +} + +class SomeClass : SomeInterface { + override fun interfaceMethodA() = 20 // <== (1) +} \ No newline at end of file diff --git a/idea/testData/codeInsight/codeVision/InterfacePropertiesOverrides.kt b/idea/testData/codeInsight/codeVision/InterfacePropertiesOverrides.kt new file mode 100644 index 00000000000..acd17be6a57 --- /dev/null +++ b/idea/testData/codeInsight/codeVision/InterfacePropertiesOverrides.kt @@ -0,0 +1,11 @@ +// MODE: inheritors + +<# block [ 1 Implementation] #> +interface SomeInterface { +<# block [ 1 Override] #> + open val interfaceProperty: String +} + +class SomeClass : SomeInterface { + override val interfaceProperty: String = "overridden" // <== (1) +} \ No newline at end of file diff --git a/idea/testData/codeInsight/codeVision/InterfacePropertyUsages.kt b/idea/testData/codeInsight/codeVision/InterfacePropertyUsages.kt new file mode 100644 index 00000000000..0bdf05f8fd2 --- /dev/null +++ b/idea/testData/codeInsight/codeVision/InterfacePropertyUsages.kt @@ -0,0 +1,12 @@ +// MODE: usages + +<# block [ 1 Usage] #> +interface SomeInterface { +<# block [ 2 Usages] #> + val someProperty = "initialized" + fun someFun() = "it's " + someProperty // <== (1): +} + +fun main() { + val instance = object: SomeInterface {} + val someString = instance.someProperty // <== (2): call on an instance \ No newline at end of file diff --git a/idea/testData/codeInsight/codeVision/InterfaceUsages.kt b/idea/testData/codeInsight/codeVision/InterfaceUsages.kt new file mode 100644 index 00000000000..468fad411ee --- /dev/null +++ b/idea/testData/codeInsight/codeVision/InterfaceUsages.kt @@ -0,0 +1,11 @@ +// MODE: usages + +<# block [ 5 Usages] #> +interface SomeInterface {} +interface SomeOtherInterface : SomeInterface {} // <== (1): interface extension +class SomeClass : SomeInterface { // <== (2): interface implementation +<# block [ 1 Usage] #> + fun acceptsInterface(param: SomeInterface) {} // <== (3): parameter type + fun returnsInterface(): SomeInterface {} // <== (4): return type + fun main() = acceptsInterface(object : SomeInterface {}) // <== (5): anonymous class instance +} \ No newline at end of file diff --git a/idea/testData/codeInsight/codeVision/TooManyUsagesAndInheritors.kt b/idea/testData/codeInsight/codeVision/TooManyUsagesAndInheritors.kt new file mode 100644 index 00000000000..02e8f045df0 --- /dev/null +++ b/idea/testData/codeInsight/codeVision/TooManyUsagesAndInheritors.kt @@ -0,0 +1,18 @@ +// MODE: usages-&-inheritors +// USAGES-LIMIT: 3 +// INHERITORS-LIMIT: 2 + +<# block [ 3+ Usages 2+ Inheritors] #> +open class SomeClass { + class NestedDerivedClass: SomeClass() {} // <== (1): nested class +} +<# block [ 1 Usage 1 Inheritor] #> +open class DerivedClass : SomeClass {} // <== (2): direct derived one +class AnotherDerivedClass : SomeClass {} // <== (3): yet another derived one +class DerivedDerivedClass : DerivedClass { // <== (): indirect inheritor of SomeClass + fun main() { + val someClassInstance = object : SomeClass() // { <== (4): anonymous derived one + val somethingHere = "" + } + } +} \ No newline at end of file diff --git a/idea/testData/codeInsight/codeVision/UsagesAndInheritanceTogether.kt b/idea/testData/codeInsight/codeVision/UsagesAndInheritanceTogether.kt new file mode 100644 index 00000000000..a3c4d2a4b0b --- /dev/null +++ b/idea/testData/codeInsight/codeVision/UsagesAndInheritanceTogether.kt @@ -0,0 +1,16 @@ +// MODE: usages-&-inheritors + +<# block [ 4 Usages 4 Inheritors] #> +open class SomeClass { + class NestedDerivedClass: SomeClass() {} // <== (1): nested class +} +<# block [ 1 Usage 1 Inheritor] #> +open class DerivedClass : SomeClass {} // <== (2): direct derived one +class AnotherDerivedClass : SomeClass {} // <== (3): yet another derived one +class DerivedDerivedClass : DerivedClass { // <== (): indirect inheritor of SomeClass + fun main() { + val someClassInstance = object : SomeClass() { // <== (4): anonymous derived one + val somethingHere = "" + } + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/codevision/AbstractKotlinCodeVisionProviderTest.kt b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/codevision/AbstractKotlinCodeVisionProviderTest.kt new file mode 100644 index 00000000000..8a51312aef3 --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/codevision/AbstractKotlinCodeVisionProviderTest.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.codeInsight.codevision + +import com.intellij.openapi.util.io.FileUtil +import com.intellij.testFramework.utils.inlays.InlayHintsProviderTestCase +import org.jetbrains.kotlin.idea.codeInsight.codevision.KotlinCodeVisionProvider.KotlinCodeVisionSettings +import org.jetbrains.kotlin.test.InTextDirectivesUtils +import java.io.File + +open class AbstractKotlinCodeVisionProviderTest : InlayHintsProviderTestCase() { // Abstract- prefix is just a convention for GenerateTests + + fun doTest(testPath: String) { // named according to the convention imposed by GenerateTests + assertThatActualHintsMatch(testPath) + } + + private fun assertThatActualHintsMatch(fileName: String) { + val fileContents = FileUtil.loadFile(File(fileName), true) + + val usagesLimit = InTextDirectivesUtils.findStringWithPrefixes(fileContents, "// USAGES-LIMIT: ")?.toInt() ?: 100 + val inheritorsLimit = InTextDirectivesUtils.findStringWithPrefixes(fileContents, "// INHERITORS-LIMIT: ")?.toInt() ?: 100 + + val codeVisionProvider = KotlinCodeVisionProvider() + codeVisionProvider.usagesLimit = usagesLimit + codeVisionProvider.inheritorsLimit = inheritorsLimit + + val mode: KotlinCodeVisionSettings = when (InTextDirectivesUtils.findStringWithPrefixes(fileContents, "// MODE: ")) { + "inheritors" -> inheritorsEnabled() + "usages" -> usagesEnabled() + "usages-&-inheritors" -> usagesAndInheritorsEnabled() + else -> codeVisionDisabled() + } + + testProvider("kotlinCodeVision.kt", fileContents, codeVisionProvider, mode) + } + + private fun usagesAndInheritorsEnabled(): KotlinCodeVisionSettings = KotlinCodeVisionSettings(showUsages = true, showInheritors = true) + + private fun inheritorsEnabled(): KotlinCodeVisionSettings = KotlinCodeVisionSettings(showUsages = false, showInheritors = true) + + private fun usagesEnabled(): KotlinCodeVisionSettings = KotlinCodeVisionSettings(showUsages = true, showInheritors = false) + + private fun codeVisionDisabled(): KotlinCodeVisionSettings = KotlinCodeVisionSettings(showUsages = false, showInheritors = false) +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/codevision/AbstractKotlinCodeVisionProviderTest.kt.192 b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/codevision/AbstractKotlinCodeVisionProviderTest.kt.192 new file mode 100644 index 00000000000..d8405d1dfe3 --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/codevision/AbstractKotlinCodeVisionProviderTest.kt.192 @@ -0,0 +1 @@ +package org.jetbrains.kotlin.idea.codeInsight.codevision \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/codevision/KotlinCodeVisionProviderTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/codevision/KotlinCodeVisionProviderTestGenerated.java new file mode 100644 index 00000000000..e13df987f3b --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/codevision/KotlinCodeVisionProviderTestGenerated.java @@ -0,0 +1,110 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.codeInsight.codevision; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("idea/testData/codeInsight/codeVision") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class KotlinCodeVisionProviderTestGenerated extends AbstractKotlinCodeVisionProviderTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInCodeVision() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/codeInsight/codeVision"), Pattern.compile("^(.+)\\.kt$"), null, true); + } + + @TestMetadata("ClassFunctionOverrides.kt") + public void testClassFunctionOverrides() throws Exception { + runTest("idea/testData/codeInsight/codeVision/ClassFunctionOverrides.kt"); + } + + @TestMetadata("ClassInheritors.kt") + public void testClassInheritors() throws Exception { + runTest("idea/testData/codeInsight/codeVision/ClassInheritors.kt"); + } + + @TestMetadata("ClassMethodUsages.kt") + public void testClassMethodUsages() throws Exception { + runTest("idea/testData/codeInsight/codeVision/ClassMethodUsages.kt"); + } + + @TestMetadata("ClassPropertiesOverrides.kt") + public void testClassPropertiesOverrides() throws Exception { + runTest("idea/testData/codeInsight/codeVision/ClassPropertiesOverrides.kt"); + } + + @TestMetadata("ClassPropertyUsages.kt") + public void testClassPropertyUsages() throws Exception { + runTest("idea/testData/codeInsight/codeVision/ClassPropertyUsages.kt"); + } + + @TestMetadata("ClassUsages.kt") + public void testClassUsages() throws Exception { + runTest("idea/testData/codeInsight/codeVision/ClassUsages.kt"); + } + + @TestMetadata("GlobalFunctionUsages.kt") + public void testGlobalFunctionUsages() throws Exception { + runTest("idea/testData/codeInsight/codeVision/GlobalFunctionUsages.kt"); + } + + @TestMetadata("InterfaceAbstractMethodImplementation.kt") + public void testInterfaceAbstractMethodImplementation() throws Exception { + runTest("idea/testData/codeInsight/codeVision/InterfaceAbstractMethodImplementation.kt"); + } + + @TestMetadata("InterfaceImplementations.kt") + public void testInterfaceImplementations() throws Exception { + runTest("idea/testData/codeInsight/codeVision/InterfaceImplementations.kt"); + } + + @TestMetadata("InterfaceMethodUsages.kt") + public void testInterfaceMethodUsages() throws Exception { + runTest("idea/testData/codeInsight/codeVision/InterfaceMethodUsages.kt"); + } + + @TestMetadata("InterfaceMethodsOverrides.kt") + public void testInterfaceMethodsOverrides() throws Exception { + runTest("idea/testData/codeInsight/codeVision/InterfaceMethodsOverrides.kt"); + } + + @TestMetadata("InterfacePropertiesOverrides.kt") + public void testInterfacePropertiesOverrides() throws Exception { + runTest("idea/testData/codeInsight/codeVision/InterfacePropertiesOverrides.kt"); + } + + @TestMetadata("InterfacePropertyUsages.kt") + public void testInterfacePropertyUsages() throws Exception { + runTest("idea/testData/codeInsight/codeVision/InterfacePropertyUsages.kt"); + } + + @TestMetadata("InterfaceUsages.kt") + public void testInterfaceUsages() throws Exception { + runTest("idea/testData/codeInsight/codeVision/InterfaceUsages.kt"); + } + + @TestMetadata("TooManyUsagesAndInheritors.kt") + public void testTooManyUsagesAndInheritors() throws Exception { + runTest("idea/testData/codeInsight/codeVision/TooManyUsagesAndInheritors.kt"); + } + + @TestMetadata("UsagesAndInheritanceTogether.kt") + public void testUsagesAndInheritanceTogether() throws Exception { + runTest("idea/testData/codeInsight/codeVision/UsagesAndInheritanceTogether.kt"); + } +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/codevision/KotlinCodeVisionProviderTestGenerated.java.192 b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/codevision/KotlinCodeVisionProviderTestGenerated.java.192 new file mode 100644 index 00000000000..971778b8289 --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/codevision/KotlinCodeVisionProviderTestGenerated.java.192 @@ -0,0 +1 @@ +package org.jetbrains.kotlin.idea.codeInsight.codevision; \ No newline at end of file