diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt index 480b75696f5..e3af2785581 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt @@ -281,7 +281,7 @@ class ControlFlowInformationProvider private constructor( private fun reportUnreachableCode(unreachableCode: UnreachableCode) { for (element in unreachableCode.elements) { - trace.report(Errors.UNREACHABLE_CODE.on(element, unreachableCode.getUnreachableTextRanges(element))) + trace.report(Errors.UNREACHABLE_CODE.on(element, unreachableCode.reachableElements, unreachableCode.unreachableElements)) } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/UnreachableCode.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/UnreachableCode.kt index 6818f88eee9..51e57bb4de9 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/UnreachableCode.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/UnreachableCode.kt @@ -29,97 +29,112 @@ import java.util.* interface UnreachableCode { val elements: Set - fun getUnreachableTextRanges(element: KtElement): List + val reachableElements: Set + val unreachableElements: Set + + companion object { + fun getUnreachableTextRanges( + element: KtElement, + reachableElements: Set, + unreachableElements: Set + ): List { + return if (element.hasChildrenInSet(reachableElements)) { + with( + element.getLeavesOrReachableChildren(reachableElements, unreachableElements) + .removeReachableElementsWithMeaninglessSiblings(reachableElements).mergeAdjacentTextRanges() + ) { + if (isNotEmpty()) this + // Specific case like condition in when: + // element is dead but its only child is alive and has the same text range + else listOf(element.textRange.endOffset.let { TextRange(it, it) }) + } + } else { + listOf(element.textRange!!) + } + } + + private fun KtElement.hasChildrenInSet(set: Set): Boolean = + PsiTreeUtil.collectElements(this) { it != this }.any { it in set } + + private fun KtElement.getLeavesOrReachableChildren( + reachableElements: Set, + unreachableElements: Set + ): List { + val children = ArrayList() + acceptChildren(object : PsiElementVisitor() { + override fun visitElement(element: PsiElement) { + val isReachable = + element is KtElement && reachableElements.contains(element) && !element.hasChildrenInSet(unreachableElements) + if (isReachable || element.children.isEmpty()) { + children.add(element) + } else { + element.acceptChildren(this) + } + } + }) + return children + } + + private fun List.removeReachableElementsWithMeaninglessSiblings(reachableElements: Set): List { + fun PsiElement.isMeaningless() = this is PsiWhiteSpace + || this.node?.elementType == KtTokens.COMMA + || this is PsiComment + + val childrenToRemove = HashSet() + fun collectSiblingsIfMeaningless(elementIndex: Int, direction: Int) { + val index = elementIndex + direction + if (index !in 0 until size) return + + val element = this[index] + if (element.isMeaningless()) { + childrenToRemove.add(element) + collectSiblingsIfMeaningless(index, direction) + } + } + for ((index, element) in this.withIndex()) { + if (reachableElements.contains(element)) { + childrenToRemove.add(element) + collectSiblingsIfMeaningless(index, -1) + collectSiblingsIfMeaningless(index, 1) + } + } + return this.filter { it !in childrenToRemove } + } + + + private fun List.mergeAdjacentTextRanges(): List { + val result = ArrayList() + val lastRange = fold(null as TextRange?) { currentTextRange, element -> + + val elementRange = element.textRange!! + when { + currentTextRange == null -> { + elementRange + } + currentTextRange.endOffset == elementRange.startOffset -> { + currentTextRange.union(elementRange) + } + else -> { + result.add(currentTextRange) + elementRange + } + } + } + if (lastRange != null) { + result.add(lastRange) + } + return result + } + } + } class UnreachableCodeImpl( - private val reachableElements: Set, - private val unreachableElements: Set + override val reachableElements: Set, + override val unreachableElements: Set ) : UnreachableCode { // This is needed in order to highlight only '1 < 2' and not '1', '<' and '2' as well override val elements: Set = KtPsiUtil.findRootExpressions(unreachableElements) - override fun getUnreachableTextRanges(element: KtElement): List { - return if (element.hasChildrenInSet(reachableElements)) { - with(element.getLeavesOrReachableChildren().removeReachableElementsWithMeaninglessSiblings().mergeAdjacentTextRanges()) { - if (isNotEmpty()) this - // Specific case like condition in when: - // element is dead but its only child is alive and has the same text range - else listOf(element.textRange.endOffset.let { TextRange(it, it) }) - } - } else { - listOf(element.textRange!!) - } - } - - private fun KtElement.hasChildrenInSet(set: Set): Boolean = - PsiTreeUtil.collectElements(this) { it != this }.any { it in set } - - private fun KtElement.getLeavesOrReachableChildren(): List { - val children = ArrayList() - acceptChildren(object : PsiElementVisitor() { - override fun visitElement(element: PsiElement) { - val isReachable = - element is KtElement && reachableElements.contains(element) && !element.hasChildrenInSet(unreachableElements) - if (isReachable || element.children.isEmpty()) { - children.add(element) - } else { - element.acceptChildren(this) - } - } - }) - return children - } - - private fun List.removeReachableElementsWithMeaninglessSiblings(): List { - fun PsiElement.isMeaningless() = this is PsiWhiteSpace - || this.node?.elementType == KtTokens.COMMA - || this is PsiComment - - val childrenToRemove = HashSet() - fun collectSiblingsIfMeaningless(elementIndex: Int, direction: Int) { - val index = elementIndex + direction - if (index !in 0..(size - 1)) return - - val element = this[index] - if (element.isMeaningless()) { - childrenToRemove.add(element) - collectSiblingsIfMeaningless(index, direction) - } - } - for ((index, element) in this.withIndex()) { - if (reachableElements.contains(element)) { - childrenToRemove.add(element) - collectSiblingsIfMeaningless(index, -1) - collectSiblingsIfMeaningless(index, 1) - } - } - return this.filter { it !in childrenToRemove } - } - - - private fun List.mergeAdjacentTextRanges(): List { - val result = ArrayList() - val lastRange = fold(null as TextRange?) { currentTextRange, element -> - - val elementRange = element.textRange!! - when { - currentTextRange == null -> { - elementRange - } - currentTextRange.endOffset == elementRange.startOffset -> { - currentTextRange.union(elementRange) - } - else -> { - result.add(currentTextRange) - elementRange - } - } - } - if (lastRange != null) { - result.add(lastRange) - } - return result - } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index c9685a67bb8..c78403cf9e2 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -6,7 +6,6 @@ package org.jetbrains.kotlin.diagnostics; import com.google.common.collect.ImmutableSet; -import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; import com.intellij.psi.impl.source.tree.LeafPsiElement; import kotlin.Pair; @@ -37,6 +36,7 @@ import java.lang.reflect.Modifier; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Set; import static org.jetbrains.kotlin.diagnostics.PositioningStrategies.*; import static org.jetbrains.kotlin.diagnostics.Severity.*; @@ -886,7 +886,7 @@ public interface Errors { // Control flow / Data flow - DiagnosticFactory1> UNREACHABLE_CODE = DiagnosticFactory1.create( + DiagnosticFactory2, Set> UNREACHABLE_CODE = DiagnosticFactory2.create( WARNING, PositioningStrategies.UNREACHABLE_CODE); DiagnosticFactory0 VARIABLE_WITH_NO_TYPE_NO_INITIALIZER = DiagnosticFactory0.create(ERROR, DECLARATION_NAME); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt index 708a434cd74..9cd0f7c4f91 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt @@ -21,6 +21,7 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiNameIdentifierOwner import com.intellij.psi.tree.TokenSet import org.jetbrains.kotlin.KtNodeTypes +import org.jetbrains.kotlin.cfg.UnreachableCode import org.jetbrains.kotlin.diagnostics.Errors.ACTUAL_WITHOUT_EXPECT import org.jetbrains.kotlin.diagnostics.Errors.NO_ACTUAL_FOR_EXPECT import org.jetbrains.kotlin.lexer.KtModifierKeywordToken @@ -579,7 +580,8 @@ object PositioningStrategies { @JvmField val UNREACHABLE_CODE: PositioningStrategy = object : PositioningStrategy() { override fun markDiagnostic(diagnostic: ParametrizedDiagnostic): List { - return Errors.UNREACHABLE_CODE.cast(diagnostic).a + val unreachableCode = Errors.UNREACHABLE_CODE.cast(diagnostic) + return UnreachableCode.getUnreachableTextRanges(unreachableCode.psiElement, unreachableCode.a, unreachableCode.b) } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index d4b58caf50c..61a295479b1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -351,7 +351,7 @@ public class DefaultErrorMessages { MAP.put(VAL_OR_VAR_ON_CATCH_PARAMETER, "''{0}'' on catch parameter is not allowed", TO_STRING); MAP.put(VAL_OR_VAR_ON_SECONDARY_CONSTRUCTOR_PARAMETER, "''{0}'' on secondary constructor parameter is not allowed", TO_STRING); - MAP.put(UNREACHABLE_CODE, "Unreachable code", TO_STRING); + MAP.put(UNREACHABLE_CODE, "Unreachable code", EMPTY, EMPTY); MAP.put(MANY_COMPANION_OBJECTS, "Only one companion object is allowed per class"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt index 4e05d947d0b..fb49caa3beb 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt @@ -67,6 +67,9 @@ object Renderers { element.toString() } + @JvmField + val EMPTY = Renderer { "" } + @JvmField val STRING = Renderer { it } diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index c107b02810d..03e5e6e629e 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -620,6 +620,10 @@ fun main(args: Array) { model("codeInsight/outOfBlock", pattern = KT_OR_KTS) } + testClass { + model("codeInsight/changeLocality", pattern = KT_OR_KTS) + } + testClass { model("dataFlowValueRendering") } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListener.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListener.kt index 223396650b4..0e6d7a12062 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListener.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListener.kt @@ -93,8 +93,9 @@ class KotlinCodeBlockModificationListener( // skip change if it contains only virtual/fake change if (changedElements.isNotEmpty() && - // ignore formatting (whitespaces etc) + // ignore formatting (whitespaces etc) change (isFormattingChange(changeSet) || + // ignore comment change isCommentChange(changeSet) || changedElements.all { !it.psi.isPhysical }) ) return @@ -215,6 +216,20 @@ class KotlinCodeBlockModificationListener( changeSet.getChangesByElement(it).affectedChildren.all { c -> c is PsiWhiteSpace } } + /** + * Has to be aligned with [getInsideCodeBlockModificationScope] : + * + * result of analysis has to be reflected in dirty scope, + * the only difference is whitespaces and comments + */ + fun getInsideCodeBlockModificationDirtyScope(element: PsiElement): PsiElement? { + if (!element.isPhysical) return null + // dirty scope for whitespaces and comments is the element itself + if (element is PsiWhiteSpace || element is PsiComment || element is KDoc) return element + + return getInsideCodeBlockModificationScope(element)?.blockDeclaration ?: null + } + fun getInsideCodeBlockModificationScope(element: PsiElement): BlockModificationScopeElement? { val lambda = element.getTopmostParentOfType() if (lambda is KtLambdaExpression) { @@ -259,13 +274,10 @@ class KotlinCodeBlockModificationListener( val declaration = if (blockDeclaration.initializer != null) blockDeclaration else - KtPsiUtil.getTopmostParentOfTypes( - blockDeclaration, - // property could be initialized on a class level - KtClass::class.java, - // ktFile to check top level property declarations - KtFile::class.java - ) as KtElement + // property could be initialized on a class level + KtPsiUtil.getTopmostParentOfTypes(blockDeclaration, KtClass::class.java) as? KtElement ?: + // ktFile to check top level property declarations + return null return BlockModificationScopeElement(declaration, expression) } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinChangeLocalityDetector.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinChangeLocalityDetector.kt index 00bb262e31d..9a62a2f1e08 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinChangeLocalityDetector.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinChangeLocalityDetector.kt @@ -18,13 +18,12 @@ package org.jetbrains.kotlin.idea.highlighter import com.intellij.codeInsight.daemon.ChangeLocalityDetector import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationListener.Companion.getInsideCodeBlockModificationScope +import org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationListener.Companion.getInsideCodeBlockModificationDirtyScope class KotlinChangeLocalityDetector : ChangeLocalityDetector { override fun getChangeHighlightingDirtyScopeFor(element: PsiElement): PsiElement? { - val modificationScope = - getInsideCodeBlockModificationScope(element) ?: return null - - return modificationScope.blockDeclaration + // in some cases it returns a bit wider scope for the element as it is not possible to track changes here + // e.g.: delete a space in expression `foo( )` results to entire expression `foo()` + return getInsideCodeBlockModificationDirtyScope(element) } } \ No newline at end of file diff --git a/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/DirectiveBasedActionUtils.kt b/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/DirectiveBasedActionUtils.kt index 5cef91e6daa..4005b10a5f7 100644 --- a/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/DirectiveBasedActionUtils.kt +++ b/idea/idea-test-framework/test/org/jetbrains/kotlin/idea/test/DirectiveBasedActionUtils.kt @@ -21,18 +21,36 @@ object DirectiveBasedActionUtils { return } - val expectedErrors = InTextDirectivesUtils.findLinesWithPrefixesRemoved(file.text, "// ERROR:").sorted() + checkForUnexpected(file, diagnosticsProvider, "// ERROR:", "errors", Severity.ERROR) + } + + fun checkForUnexpectedWarnings(file: KtFile, diagnosticsProvider: (KtFile) -> Diagnostics = { it.analyzeWithContent().diagnostics }) { + if (InTextDirectivesUtils.findLinesWithPrefixesRemoved(file.text, "// ENABLE-WARNINGS").isEmpty()) { + return + } + + checkForUnexpected(file, diagnosticsProvider, "// WARNING:", "warnings", Severity.WARNING) + } + + private fun checkForUnexpected( + file: KtFile, + diagnosticsProvider: (KtFile) -> Diagnostics, + directive: String, + name: String, + severity: Severity + ) { + val expected = InTextDirectivesUtils.findLinesWithPrefixesRemoved(file.text, directive).sorted() val diagnostics = diagnosticsProvider(file) - val actualErrors = diagnostics - .filter { it.severity == Severity.ERROR } + val actual = diagnostics + .filter { it.severity == severity } .map { DefaultErrorMessages.render(it).replace("\n", "
") } .sorted() UsefulTestCase.assertOrderedEquals( - "All actual errors should be mentioned in test data with // ERROR: directive. But no unnecessary errors should be me mentioned", - actualErrors, - expectedErrors + "All actual $name should be mentioned in test data with '$directive' directive. But no unnecessary $name should be me mentioned", + actual, + expected ) } diff --git a/idea/testData/codeInsight/changeLocality/Comment.kt b/idea/testData/codeInsight/changeLocality/Comment.kt new file mode 100644 index 00000000000..a40941e802f --- /dev/null +++ b/idea/testData/codeInsight/changeLocality/Comment.kt @@ -0,0 +1,17 @@ +// SCOPE: '// some change' + +class Comment { + fun q() { + + } + + val someValue: String + get() { + return "X" + } + + fun baa() { + // some change + val list = listOf(TODO("")) + } +} \ No newline at end of file diff --git a/idea/testData/codeInsight/changeLocality/InMethod.kt b/idea/testData/codeInsight/changeLocality/InMethod.kt new file mode 100644 index 00000000000..414991e121b --- /dev/null +++ b/idea/testData/codeInsight/changeLocality/InMethod.kt @@ -0,0 +1,18 @@ +// SCOPE: 'fun baa() {' +// SCOPE: ' val list = listOf("Z")' +// SCOPE: ' }' + +class Comment { + fun q() { + + } + + val someValue: String + get() { + return "X" + } + + fun baa() { + val list = listOf("Z") + } +} \ No newline at end of file diff --git a/idea/testData/codeInsight/outOfBlock/InGlobalPropertyWithGetter.kt b/idea/testData/codeInsight/outOfBlock/InGlobalPropertyWithGetter.kt index 141c538d3af..7b2ee39d4c8 100644 --- a/idea/testData/codeInsight/outOfBlock/InGlobalPropertyWithGetter.kt +++ b/idea/testData/codeInsight/outOfBlock/InGlobalPropertyWithGetter.kt @@ -1,5 +1,7 @@ -// OUT_OF_CODE_BLOCK: FALSE -// ERROR: Unresolved reference: awhen +// OUT_OF_CODE_BLOCK: TRUE +// TYPE: 'z' +// ERROR: Unresolved reference: zwhen + enum class A { e1, e2, e3 } @@ -12,4 +14,7 @@ val B.foo: Int A.e1 -> 1 A.e2 -> 4 } - } \ No newline at end of file + } + +// TODO: Investigate +// SKIP_ANALYZE_CHECK diff --git a/idea/testData/codeInsight/outOfBlock/InMethodUnreacableCode.kt b/idea/testData/codeInsight/outOfBlock/InMethodUnreacableCode.kt new file mode 100644 index 00000000000..ead9962b331 --- /dev/null +++ b/idea/testData/codeInsight/outOfBlock/InMethodUnreacableCode.kt @@ -0,0 +1,11 @@ +// OUT_OF_CODE_BLOCK: FALSE +// TYPE: '1' +// ENABLE-WARNINGS +// WARNING: Unreachable code + +fun test() { + return + + val a = +} + diff --git a/idea/testData/codeInsight/outOfBlock/InUninitializedPropertyAccessor.kt b/idea/testData/codeInsight/outOfBlock/InUninitializedPropertyAccessor.kt index a9a3d865f75..0e2c1f7ddaf 100644 --- a/idea/testData/codeInsight/outOfBlock/InUninitializedPropertyAccessor.kt +++ b/idea/testData/codeInsight/outOfBlock/InUninitializedPropertyAccessor.kt @@ -1,4 +1,4 @@ -// OUT_OF_CODE_BLOCK: FALSE +// OUT_OF_CODE_BLOCK: TRUE // TYPE: '//' // ERROR: Property must be initialized @@ -6,4 +6,7 @@ var prop1: Int set(value) { println("prop.setter") field = value - } \ No newline at end of file + } + +// TODO: Investigate +// SKIP_ANALYZE_CHECK diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractChangeLocalityDetectorTest.kt b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractChangeLocalityDetectorTest.kt new file mode 100644 index 00000000000..38d60e3b6b4 --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractChangeLocalityDetectorTest.kt @@ -0,0 +1,41 @@ +/* + * 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.idea.codeInsight + +import com.intellij.psi.PsiElement +import com.intellij.psi.util.PsiTreeUtil +import org.jetbrains.kotlin.idea.highlighter.KotlinChangeLocalityDetector +import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.test.InTextDirectivesUtils + +private const val SCOPE_DIRECTIVE = "// SCOPE:" + +abstract class AbstractChangeLocalityDetectorTest : KotlinLightCodeInsightFixtureTestCase() { + + protected fun doTest(unused: String?) { + val ktFile = myFixture.configureByFile(fileName()) as KtFile + + val expectedScopeLines = InTextDirectivesUtils.findListWithPrefixes(ktFile.text, SCOPE_DIRECTIVE) + assertTrue("scope has to be specified with $SCOPE_DIRECTIVE", expectedScopeLines.isNotEmpty()) + val selectionModel = editor.selectionModel + assertTrue("changed item has to be specified in Diagnostics = { it.analyzeWithAllCompilerChecks().bindingContext.diagnostics } + DirectiveBasedActionUtils.checkForUnexpectedWarnings(ktFile, diagnosticsProvider) + DirectiveBasedActionUtils.checkForUnexpectedErrors(ktFile, diagnosticsProvider) } private fun checkOOBWithDescriptorsResolve(expectedOutOfBlock: Boolean) { @@ -83,14 +85,14 @@ abstract class AbstractOutOfBlockModificationTest : KotlinLightCodeInsightFixtur val ktElement = ktExpression ?: ktDeclaration ?: return val facade = ktElement.containingKtFile.getResolutionFacade() val session = facade.getFrontendService(ResolveSession::class.java) + session.forceResolveAll() val context = session.bindingContext if (ktExpression != null && ktExpression !== ktDeclaration) { - val expressionProcessed = context.get( - BindingContext.PROCESSED, - if (ktExpression is KtFunctionLiteral) ktExpression.getParent() as KtLambdaExpression else ktExpression - ) === java.lang.Boolean.TRUE - TestCase.assertEquals( + val expression = if (ktExpression is KtFunctionLiteral) ktExpression.getParent() as KtLambdaExpression else ktExpression + val processed = context.get(BindingContext.PROCESSED, expression) + val expressionProcessed = processed === java.lang.Boolean.TRUE + assertEquals( "Expected out-of-block should result expression analyzed and vise versa", expectedOutOfBlock, expressionProcessed ) @@ -100,7 +102,7 @@ abstract class AbstractOutOfBlockModificationTest : KotlinLightCodeInsightFixtur BindingContext.DECLARATION_TO_DESCRIPTOR, ktDeclaration ) != null - TestCase.assertEquals( + assertEquals( "Expected out-of-block should result declaration analyzed and vise versa", expectedOutOfBlock, declarationProcessed ) diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/ChangeLocalityDetectorTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/ChangeLocalityDetectorTestGenerated.java new file mode 100644 index 00000000000..b8c718dd23a --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/ChangeLocalityDetectorTestGenerated.java @@ -0,0 +1,40 @@ +/* + * 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.idea.codeInsight; + +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/changeLocality") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class ChangeLocalityDetectorTestGenerated extends AbstractChangeLocalityDetectorTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInChangeLocality() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/codeInsight/changeLocality"), Pattern.compile("^(.+)\\.(kt|kts)$"), true); + } + + @TestMetadata("Comment.kt") + public void testComment() throws Exception { + runTest("idea/testData/codeInsight/changeLocality/Comment.kt"); + } + + @TestMetadata("InMethod.kt") + public void testInMethod() throws Exception { + runTest("idea/testData/codeInsight/changeLocality/InMethod.kt"); + } +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/OutOfBlockModificationTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/OutOfBlockModificationTestGenerated.java index 54e7f9498cc..b73f09b0082 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/OutOfBlockModificationTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/OutOfBlockModificationTestGenerated.java @@ -178,6 +178,11 @@ public class OutOfBlockModificationTestGenerated extends AbstractOutOfBlockModif runTest("idea/testData/codeInsight/outOfBlock/InMethod.kt"); } + @TestMetadata("InMethodUnreacableCode.kt") + public void testInMethodUnreacableCode() throws Exception { + runTest("idea/testData/codeInsight/outOfBlock/InMethodUnreacableCode.kt"); + } + @TestMetadata("InNestedClass.kt") public void testInNestedClass() throws Exception { runTest("idea/testData/codeInsight/outOfBlock/InNestedClass.kt");