diff --git a/annotations/com/intellij/debugger/actions/annotations.xml b/annotations/com/intellij/debugger/actions/annotations.xml new file mode 100644 index 00000000000..b0e4938b1d5 --- /dev/null +++ b/annotations/com/intellij/debugger/actions/annotations.xml @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/annotations/com/intellij/util/annotations.xml b/annotations/com/intellij/util/annotations.xml index b8e4ab96ac5..b6951be234c 100644 --- a/annotations/com/intellij/util/annotations.xml +++ b/annotations/com/intellij/util/annotations.xml @@ -8,4 +8,10 @@ + + + + + + \ No newline at end of file diff --git a/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.kt b/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.kt index c25e47f8fff..b4bd920e8a5 100644 --- a/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.kt +++ b/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.kt @@ -99,6 +99,7 @@ import org.jetbrains.jet.plugin.refactoring.move.AbstractJetMoveTest import org.jetbrains.jet.cfg.AbstractDataFlowTest import org.jetbrains.jet.plugin.libraries.AbstractDecompiledTextTest import org.jetbrains.jet.plugin.imports.AbstractOptimizeImportsTest +import org.jetbrains.jet.plugin.debugger.AbstractSmartStepIntoTest fun main(args: Array) { System.setProperty("java.awt.headless", "true") @@ -524,6 +525,10 @@ fun main(args: Array) { testClass(javaClass()) { model("editor/optimizeImports", extension = null, recursive = false) } + + testClass(javaClass()) { + model("debugger/smartStepInto") + } } testGroup("j2k/tests/test", "j2k/tests/testData") { diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 459b79600ba..196efef5488 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -299,6 +299,7 @@ id="kotlinJavaSafeDeleteDelegate" language="jet" implementationClass="org.jetbrains.jet.plugin.refactoring.safeDelete.KotlinJavaSafeDeleteDelegate"/> + diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/KotlinSmartStepIntoHandler.kt b/idea/src/org/jetbrains/jet/plugin/debugger/KotlinSmartStepIntoHandler.kt new file mode 100644 index 00000000000..893285f977d --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/debugger/KotlinSmartStepIntoHandler.kt @@ -0,0 +1,190 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.plugin.debugger + +import com.intellij.debugger.actions.JvmSmartStepIntoHandler +import com.intellij.debugger.SourcePosition +import com.intellij.debugger.actions.SmartStepTarget +import java.util.Collections +import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.debugger.actions.MethodSmartStepTarget +import com.intellij.util.containers.OrderedSet +import com.intellij.util.Range +import org.jetbrains.jet.lang.resolve.BindingContext +import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache +import org.jetbrains.jet.asJava.LightClassUtil +import org.jetbrains.jet.lang.resolve.BindingContextUtils +import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor +import com.intellij.psi.PsiElement +import com.intellij.util.text.CharArrayUtil +import org.jetbrains.jet.lang.psi.* +import org.jetbrains.jet.lang.descriptors.PropertyDescriptor + +public class KotlinSmartStepIntoHandler : JvmSmartStepIntoHandler() { + + override fun isAvailable(position: SourcePosition?) = position?.getFile() is JetFile + + override fun findSmartStepTargets(position: SourcePosition): List { + if (position.getLine() < 0) return Collections.emptyList() + + val file = position.getFile() + val vFile = file.getVirtualFile() + if (vFile == null) return Collections.emptyList() + + val doc = FileDocumentManager.getInstance()?.getDocument(vFile) + if (doc == null) return Collections.emptyList() + + val line = position.getLine() + if (line >= doc.getLineCount()) return Collections.emptyList() + + val lineStartOffset = doc.getLineStartOffset(line) + val offsetWithoutTab = CharArrayUtil.shiftForward(doc.getCharsSequence(), lineStartOffset, " \t") + val elementAtOffset = file.findElementAt(offsetWithoutTab) + if (elementAtOffset == null) return Collections.emptyList() + + val element = getTopmostElementAtOffset(elementAtOffset, lineStartOffset) + + if (element !is JetElement) return Collections.emptyList() + + val elementTextRange = element.getTextRange() + if (elementTextRange == null) return Collections.emptyList() + + val lines = Range(doc.getLineNumber(elementTextRange.getStartOffset()), doc.getLineNumber(elementTextRange.getEndOffset())) + val bindingContext = AnalyzerFacadeWithCache.getContextForElement(element) + val result = OrderedSet() + + // TODO support class initializers, local functions, delegated properties with specified type, setter for properties + element.accept(object: JetTreeVisitorVoid() { + + override fun visitFunctionLiteralExpression(expression: JetFunctionLiteralExpression) { + // skip calls in function literals + } + + override fun visitObjectLiteralExpression(expression: JetObjectLiteralExpression) { + // skip calls in object declarations + } + + override fun visitIfExpression(expression: JetIfExpression) { + expression.getCondition()?.accept(this) + } + + override fun visitWhileExpression(expression: JetWhileExpression) { + expression.getCondition()?.accept(this) + } + + override fun visitDoWhileExpression(expression: JetDoWhileExpression) { + expression.getCondition()?.accept(this) + } + + override fun visitForExpression(expression: JetForExpression) { + expression.getLoopRange()?.accept(this) + } + + override fun visitWhenExpression(expression: JetWhenExpression) { + expression.getSubjectExpression()?.accept(this) + } + + override fun visitArrayAccessExpression(expression: JetArrayAccessExpression) { + recordFunction(expression) + super.visitArrayAccessExpression(expression) + } + + override fun visitUnaryExpression(expression: JetUnaryExpression) { + recordFunction(expression.getOperationReference()) + super.visitUnaryExpression(expression) + } + + override fun visitBinaryExpression(expression: JetBinaryExpression) { + recordFunction(expression.getOperationReference()) + super.visitBinaryExpression(expression) + } + + override fun visitCallExpression(expression: JetCallExpression) { + val calleeExpression = expression.getCalleeExpression() + if (calleeExpression != null) { + recordFunction(calleeExpression) + } + super.visitCallExpression(expression) + } + + override fun visitSimpleNameExpression(expression: JetSimpleNameExpression) { + val resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression) + if (resolvedCall != null) { + val propertyDescriptor = resolvedCall.getResultingDescriptor() + if (propertyDescriptor is PropertyDescriptor) { + val getterDescriptor = propertyDescriptor.getGetter() + if (getterDescriptor != null && !getterDescriptor.isDefault()) { + val delegatedResolvedCall = bindingContext.get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, getterDescriptor) + if (delegatedResolvedCall == null) { + val getter = BindingContextUtils.callableDescriptorToDeclaration(bindingContext, getterDescriptor) + if (getter is JetPropertyAccessor && (getter.getBodyExpression() != null || getter.getEqualsToken() != null)) { + val psiMethod = LightClassUtil.getLightClassAccessorMethod(getter) + if (psiMethod != null) { + result.add(MethodSmartStepTarget(psiMethod, null, expression, false, lines)) + } + } + } + else { + val delegatedPropertyGetterDescriptor = delegatedResolvedCall.getResultingDescriptor() + if (delegatedPropertyGetterDescriptor is CallableMemberDescriptor) { + val function = BindingContextUtils.callableDescriptorToDeclaration(bindingContext, delegatedPropertyGetterDescriptor) + if (function is JetNamedFunction) { + val psiMethod = LightClassUtil.getLightClassMethod(function) + if (psiMethod != null) { + result.add(MethodSmartStepTarget(psiMethod, "${propertyDescriptor.getName()}.", expression, false, lines)) + } + } + } + } + } + } + } + super.visitSimpleNameExpression(expression) + } + + private fun recordFunction(expression: JetExpression) { + val resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression) + if (resolvedCall == null) return + + val descriptor = resolvedCall.getResultingDescriptor() + if (descriptor is CallableMemberDescriptor) { + val function = BindingContextUtils.callableDescriptorToDeclaration(bindingContext, descriptor) + if (function is JetNamedFunction) { + val psiMethod = LightClassUtil.getLightClassMethod(function) + if (psiMethod != null) { + result.add(MethodSmartStepTarget(method = psiMethod, label = null, + highlightElement = expression, + needBreakpointRequest = false, lines = lines)) + } + } + } + } + }, null) + + return result + } + + private fun getTopmostElementAtOffset(element: PsiElement, offset: Int): PsiElement? { + var resultElement: PsiElement? = element + while (resultElement?.getParent()?.getTextRange() != null && + resultElement?.getParent()?.getTextRange()!!.getStartOffset() >= offset) { + resultElement = resultElement!!.getParent() + } + + return resultElement + } +} \ No newline at end of file diff --git a/idea/testData/debugger/smartStepInto/annotation.kt b/idea/testData/debugger/smartStepInto/annotation.kt new file mode 100644 index 00000000000..1ad6b6aa118 --- /dev/null +++ b/idea/testData/debugger/smartStepInto/annotation.kt @@ -0,0 +1,9 @@ +fun foo() { + [Ann() Ann] val a = bar() +} + +annotation class Ann + +fun bar() = 1 + +// EXISTS: bar() \ No newline at end of file diff --git a/idea/testData/debugger/smartStepInto/arrayAccess.kt b/idea/testData/debugger/smartStepInto/arrayAccess.kt new file mode 100644 index 00000000000..d45350bbb9c --- /dev/null +++ b/idea/testData/debugger/smartStepInto/arrayAccess.kt @@ -0,0 +1,10 @@ +fun foo() { + val a = A() + a[1] +} + +class A { + fun get(i: Int) = 1 +} + +// EXISTS: get(int) \ No newline at end of file diff --git a/idea/testData/debugger/smartStepInto/callChain.kt b/idea/testData/debugger/smartStepInto/callChain.kt new file mode 100644 index 00000000000..3ef9f69afee --- /dev/null +++ b/idea/testData/debugger/smartStepInto/callChain.kt @@ -0,0 +1,13 @@ +fun foo() { + A().getB().f1() +} + +class A { + fun getB() = B() +} + +class B { + fun f1() {} +} + +// EXISTS: getB(), f1() \ No newline at end of file diff --git a/idea/testData/debugger/smartStepInto/conventionMethod.kt b/idea/testData/debugger/smartStepInto/conventionMethod.kt new file mode 100644 index 00000000000..ce349621e2f --- /dev/null +++ b/idea/testData/debugger/smartStepInto/conventionMethod.kt @@ -0,0 +1,11 @@ +class A { + fun plus(a: A) {} +} + +fun foo() { + f1() + A() + A() +} + +fun f1() = A() + +// EXISTS: plus(A), f1() \ No newline at end of file diff --git a/idea/testData/debugger/smartStepInto/delegatedPropertyGetter.kt b/idea/testData/debugger/smartStepInto/delegatedPropertyGetter.kt new file mode 100644 index 00000000000..61996cb63f3 --- /dev/null +++ b/idea/testData/debugger/smartStepInto/delegatedPropertyGetter.kt @@ -0,0 +1,11 @@ +fun foo() { + a +} + +val a by Delegate() + +class Delegate { + fun get(t: Any?, p: PropertyMetadata) = 1 +} + +// EXISTS: a.get(Object\, PropertyMetadata) \ No newline at end of file diff --git a/idea/testData/debugger/smartStepInto/doWhile.kt b/idea/testData/debugger/smartStepInto/doWhile.kt new file mode 100644 index 00000000000..e5178aaf013 --- /dev/null +++ b/idea/testData/debugger/smartStepInto/doWhile.kt @@ -0,0 +1,10 @@ +fun foo() { + do { + f2() + } while (f1()) +} + +fun f1() = true +fun f2() {} + +// EXISTS: f1() \ No newline at end of file diff --git a/idea/testData/debugger/smartStepInto/dotQualified.kt b/idea/testData/debugger/smartStepInto/dotQualified.kt new file mode 100644 index 00000000000..7f07291a5af --- /dev/null +++ b/idea/testData/debugger/smartStepInto/dotQualified.kt @@ -0,0 +1,12 @@ +fun foo() { + val a = A() + a.f1(f2()) +} + +class A { + fun f1(): Int = 1 +} + +fun f2() {} + +// EXISTS: f1(), f2() \ No newline at end of file diff --git a/idea/testData/debugger/smartStepInto/dotQualifiedInParam.kt b/idea/testData/debugger/smartStepInto/dotQualifiedInParam.kt new file mode 100644 index 00000000000..57471ec6a85 --- /dev/null +++ b/idea/testData/debugger/smartStepInto/dotQualifiedInParam.kt @@ -0,0 +1,12 @@ +fun foo() { + val a = A() + f2(a.f1()) +} + +class A { + fun f1() = 1 +} + +fun f2(i: Int) {} + +// EXISTS: f1(), f2(int) \ No newline at end of file diff --git a/idea/testData/debugger/smartStepInto/empty.kt b/idea/testData/debugger/smartStepInto/empty.kt new file mode 100644 index 00000000000..672b9e305ba --- /dev/null +++ b/idea/testData/debugger/smartStepInto/empty.kt @@ -0,0 +1,3 @@ +fun foo() { + val a = 1 +} \ No newline at end of file diff --git a/idea/testData/debugger/smartStepInto/for.kt b/idea/testData/debugger/smartStepInto/for.kt new file mode 100644 index 00000000000..30edaa79991 --- /dev/null +++ b/idea/testData/debugger/smartStepInto/for.kt @@ -0,0 +1,11 @@ +fun foo() { + val a = 1 + for (a in f1()) { + f2() + } +} + +fun f1() = 1..2 +fun f2() {} + +// EXISTS: f1() \ No newline at end of file diff --git a/idea/testData/debugger/smartStepInto/funLiteral.kt b/idea/testData/debugger/smartStepInto/funLiteral.kt new file mode 100644 index 00000000000..f17391eda06 --- /dev/null +++ b/idea/testData/debugger/smartStepInto/funLiteral.kt @@ -0,0 +1,10 @@ +fun foo() { + f1() { + f2() + } +} + +fun f1(f: () -> Unit) {} +fun f2() {} + +// EXISTS: f1(Function0) \ No newline at end of file diff --git a/idea/testData/debugger/smartStepInto/if.kt b/idea/testData/debugger/smartStepInto/if.kt new file mode 100644 index 00000000000..f47defc3c72 --- /dev/null +++ b/idea/testData/debugger/smartStepInto/if.kt @@ -0,0 +1,10 @@ +fun foo() { + if (f1()) { + f2() + } +} + +fun f1() = true +fun f2() {} + +// EXISTS: f1() \ No newline at end of file diff --git a/idea/testData/debugger/smartStepInto/infixCall.kt b/idea/testData/debugger/smartStepInto/infixCall.kt new file mode 100644 index 00000000000..3e12514eb58 --- /dev/null +++ b/idea/testData/debugger/smartStepInto/infixCall.kt @@ -0,0 +1,12 @@ +fun foo() { + val a = A() + f2(a f1 1) +} + +class A { + fun f1(i: Int) = 1 +} + +fun f2(i: Int) {} + +// EXISTS: f1(int), f2(int) \ No newline at end of file diff --git a/idea/testData/debugger/smartStepInto/invoke.kt b/idea/testData/debugger/smartStepInto/invoke.kt new file mode 100644 index 00000000000..0c836c2efe0 --- /dev/null +++ b/idea/testData/debugger/smartStepInto/invoke.kt @@ -0,0 +1,10 @@ +fun foo() { + val a = A() + a() +} + +class A { + fun invoke() {} +} + +// EXISTS: invoke() \ No newline at end of file diff --git a/idea/testData/debugger/smartStepInto/multiline.kt b/idea/testData/debugger/smartStepInto/multiline.kt new file mode 100644 index 00000000000..8091a6162d9 --- /dev/null +++ b/idea/testData/debugger/smartStepInto/multiline.kt @@ -0,0 +1,12 @@ +fun foo() { + f1( + f2(), + f3() + ) +} + +fun f1(vararg i: Int) {} +fun f2() = 1 +fun f3() = 1 + +// EXISTS: f1(int...), f2(), f3() \ No newline at end of file diff --git a/idea/testData/debugger/smartStepInto/multilineCallChain.kt b/idea/testData/debugger/smartStepInto/multilineCallChain.kt new file mode 100644 index 00000000000..605998a1bd4 --- /dev/null +++ b/idea/testData/debugger/smartStepInto/multilineCallChain.kt @@ -0,0 +1,15 @@ +fun foo() { + A() + .getB() + .f1() +} + +class A { + fun getB() = B() +} + +class B { + fun f1() {} +} + +// EXISTS: getB(), f1() \ No newline at end of file diff --git a/idea/testData/debugger/smartStepInto/object.kt b/idea/testData/debugger/smartStepInto/object.kt new file mode 100644 index 00000000000..a020d4286c0 --- /dev/null +++ b/idea/testData/debugger/smartStepInto/object.kt @@ -0,0 +1,9 @@ +fun foo() { + val a = object { + fun f() { + f2() + } + } +} + +fun f2() {} \ No newline at end of file diff --git a/idea/testData/debugger/smartStepInto/param.kt b/idea/testData/debugger/smartStepInto/param.kt new file mode 100644 index 00000000000..222ad3d7a0e --- /dev/null +++ b/idea/testData/debugger/smartStepInto/param.kt @@ -0,0 +1,8 @@ +fun foo() { + f1(f2()) +} + +fun f1(i: Int) = 1 +fun f2() {} + +// EXISTS: f1(int), f2() \ No newline at end of file diff --git a/idea/testData/debugger/smartStepInto/parantesized.kt b/idea/testData/debugger/smartStepInto/parantesized.kt new file mode 100644 index 00000000000..b3522e22073 --- /dev/null +++ b/idea/testData/debugger/smartStepInto/parantesized.kt @@ -0,0 +1,7 @@ +fun foo() { + (bar()) +} + +fun bar() {} + +// EXISTS: bar() \ No newline at end of file diff --git a/idea/testData/debugger/smartStepInto/propertyGetter.kt b/idea/testData/debugger/smartStepInto/propertyGetter.kt new file mode 100644 index 00000000000..a836dee2a5d --- /dev/null +++ b/idea/testData/debugger/smartStepInto/propertyGetter.kt @@ -0,0 +1,18 @@ +fun foo() { + a + b + c + d +} + +val a = 1 + +val b = 1 + get + +val c: Int + get() = 1 + +val d: Int + get() { + return 1 + } + +// EXISTS: getC(), getD() \ No newline at end of file diff --git a/idea/testData/debugger/smartStepInto/simple.kt b/idea/testData/debugger/smartStepInto/simple.kt new file mode 100644 index 00000000000..6db3a601e0e --- /dev/null +++ b/idea/testData/debugger/smartStepInto/simple.kt @@ -0,0 +1,7 @@ +fun foo() { + bar() +} + +fun bar() {} + +// EXISTS: bar() \ No newline at end of file diff --git a/idea/testData/debugger/smartStepInto/stringTemplate.kt b/idea/testData/debugger/smartStepInto/stringTemplate.kt new file mode 100644 index 00000000000..c5a5916ad3b --- /dev/null +++ b/idea/testData/debugger/smartStepInto/stringTemplate.kt @@ -0,0 +1,8 @@ +fun foo() { + f2("aaa${f1()}") +} + +fun f1() = "1" +fun f2(s: String) {} + +// EXISTS: f1(), f2(String) \ No newline at end of file diff --git a/idea/testData/debugger/smartStepInto/unary.kt b/idea/testData/debugger/smartStepInto/unary.kt new file mode 100644 index 00000000000..34b4f9af166 --- /dev/null +++ b/idea/testData/debugger/smartStepInto/unary.kt @@ -0,0 +1,9 @@ +class A { + fun plus() {} + fun minus() {} +} + +fun foo() { + +A() || A()- +} +// EXISTS: plus(), minus() \ No newline at end of file diff --git a/idea/testData/debugger/smartStepInto/when.kt b/idea/testData/debugger/smartStepInto/when.kt new file mode 100644 index 00000000000..1b783f4ae81 --- /dev/null +++ b/idea/testData/debugger/smartStepInto/when.kt @@ -0,0 +1,13 @@ +fun foo() { + when (f1()) { + true -> f2() + else -> { + f2() + } + } +} + +fun f1() = true +fun f2() {} + +// EXISTS: f1() \ No newline at end of file diff --git a/idea/testData/debugger/smartStepInto/while.kt b/idea/testData/debugger/smartStepInto/while.kt new file mode 100644 index 00000000000..0e4ff9ef4d7 --- /dev/null +++ b/idea/testData/debugger/smartStepInto/while.kt @@ -0,0 +1,10 @@ +fun foo() { + while (f1()) { + f2() + } +} + +fun f1() = true +fun f2() {} + +// EXISTS: f1() \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/debugger/AbstractSmartStepIntoTest.kt b/idea/tests/org/jetbrains/jet/plugin/debugger/AbstractSmartStepIntoTest.kt new file mode 100644 index 00000000000..3ded7b3e39f --- /dev/null +++ b/idea/tests/org/jetbrains/jet/plugin/debugger/AbstractSmartStepIntoTest.kt @@ -0,0 +1,109 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.plugin.debugger + +import com.intellij.debugger.SourcePosition +import com.intellij.psi.PsiElement +import com.intellij.debugger.actions.SmartStepTarget +import org.jetbrains.jet.plugin.JetLightCodeInsightFixtureTestCase +import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture +import org.jetbrains.jet.plugin.PluginTestCaseBase +import com.intellij.debugger.actions.MethodSmartStepTarget +import org.jetbrains.jet.InTextDirectivesUtils +import com.intellij.psi.util.PsiFormatUtil +import com.intellij.psi.PsiSubstitutor +import com.intellij.psi.util.PsiFormatUtilBase + +abstract class AbstractSmartStepIntoTest : JetLightCodeInsightFixtureTestCase() { + private val fixture: JavaCodeInsightTestFixture + get() = myFixture!! + + protected fun doTest(path: String) { + fixture.configureByFile(path) + + val offset = fixture.getCaretOffset() + val line = fixture.getDocument(fixture.getFile())!!.getLineNumber(offset) + + val position = object: SourcePosition() { + override fun getFile() = fixture.getFile()!! + override fun getElementAt(): PsiElement? = throw UnsupportedOperationException() + override fun getLine() = line + override fun getOffset() = offset + override fun openEditor(requestFocus: Boolean) = fixture.getEditor() + override fun navigate(requestFocus: Boolean) { + } + override fun canNavigate() = false + override fun canNavigateToSource() = false + } + + val actual = KotlinSmartStepIntoHandler().findSmartStepTargets(position).map { renderTarget(it) } + + val expected = InTextDirectivesUtils.findListWithPrefixes(fixture.getFile()?.getText()!!.replace("\\,", "+++"), "// EXISTS: ").map { it.replace("+++", ",") } + + for (actualTargetName in actual) { + assert(expected.contains(actualTargetName), "Unexpected step into target was found: ${actualTargetName}\n${renderTableWithResults(expected, actual)}") + } + + for (expectedTargetName in expected) { + assert(actual.contains(expectedTargetName), "Missed step into target: ${expectedTargetName}\n${renderTableWithResults(expected, actual)}") + } + } + + private fun renderTableWithResults(expected: List, actual: List): String { + val sb = StringBuilder() + + val maxExtStrSize = (expected.maxBy { it.size }?.size ?: 0) + 5 + val longerList = if (expected.size < actual.size) actual else expected + val shorterList = if (expected.size < actual.size) expected else actual + for ((i, element) in longerList.withIndices()) { + sb.append(element) + sb.append(" ".repeat(maxExtStrSize - element.size)) + if (i < shorterList.size) sb.append(shorterList[i]) + sb.append("\n") + } + + return sb.toString() + } + + private fun renderTarget(target: SmartStepTarget): String { + val sb = StringBuilder() + + val label = target.getLabel() + if (label != null) { + sb.append(label) + } + when (target) { + is MethodSmartStepTarget -> { + sb.append(PsiFormatUtil.formatMethod( + target.getMethod(), + PsiSubstitutor.EMPTY, + PsiFormatUtilBase.SHOW_NAME or PsiFormatUtilBase.SHOW_PARAMETERS, + PsiFormatUtilBase.SHOW_TYPE, + 999 + )) + } + else -> { + sb.append("Renderer for ${target.javaClass} should be implemented") + } + } + return sb.toString() + } + + override fun getTestDataPath(): String? { + return PluginTestCaseBase.getTestDataPathBase() + "/debugger/smartStepInto" + } +} diff --git a/idea/tests/org/jetbrains/jet/plugin/debugger/SmartStepIntoTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/debugger/SmartStepIntoTestGenerated.java new file mode 100644 index 00000000000..dddae58b916 --- /dev/null +++ b/idea/tests/org/jetbrains/jet/plugin/debugger/SmartStepIntoTestGenerated.java @@ -0,0 +1,164 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.plugin.debugger; + +import junit.framework.Assert; +import junit.framework.Test; +import junit.framework.TestSuite; + +import java.io.File; +import java.util.regex.Pattern; +import org.jetbrains.jet.JetTestUtils; +import org.jetbrains.jet.test.InnerTestClasses; +import org.jetbrains.jet.test.TestMetadata; + +import org.jetbrains.jet.plugin.debugger.AbstractSmartStepIntoTest; + +/** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("idea/testData/debugger/smartStepInto") +public class SmartStepIntoTestGenerated extends AbstractSmartStepIntoTest { + public void testAllFilesPresentInSmartStepInto() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/debugger/smartStepInto"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("annotation.kt") + public void testAnnotation() throws Exception { + doTest("idea/testData/debugger/smartStepInto/annotation.kt"); + } + + @TestMetadata("arrayAccess.kt") + public void testArrayAccess() throws Exception { + doTest("idea/testData/debugger/smartStepInto/arrayAccess.kt"); + } + + @TestMetadata("callChain.kt") + public void testCallChain() throws Exception { + doTest("idea/testData/debugger/smartStepInto/callChain.kt"); + } + + @TestMetadata("conventionMethod.kt") + public void testConventionMethod() throws Exception { + doTest("idea/testData/debugger/smartStepInto/conventionMethod.kt"); + } + + @TestMetadata("delegatedPropertyGetter.kt") + public void testDelegatedPropertyGetter() throws Exception { + doTest("idea/testData/debugger/smartStepInto/delegatedPropertyGetter.kt"); + } + + @TestMetadata("doWhile.kt") + public void testDoWhile() throws Exception { + doTest("idea/testData/debugger/smartStepInto/doWhile.kt"); + } + + @TestMetadata("dotQualified.kt") + public void testDotQualified() throws Exception { + doTest("idea/testData/debugger/smartStepInto/dotQualified.kt"); + } + + @TestMetadata("dotQualifiedInParam.kt") + public void testDotQualifiedInParam() throws Exception { + doTest("idea/testData/debugger/smartStepInto/dotQualifiedInParam.kt"); + } + + @TestMetadata("empty.kt") + public void testEmpty() throws Exception { + doTest("idea/testData/debugger/smartStepInto/empty.kt"); + } + + @TestMetadata("for.kt") + public void testFor() throws Exception { + doTest("idea/testData/debugger/smartStepInto/for.kt"); + } + + @TestMetadata("funLiteral.kt") + public void testFunLiteral() throws Exception { + doTest("idea/testData/debugger/smartStepInto/funLiteral.kt"); + } + + @TestMetadata("if.kt") + public void testIf() throws Exception { + doTest("idea/testData/debugger/smartStepInto/if.kt"); + } + + @TestMetadata("infixCall.kt") + public void testInfixCall() throws Exception { + doTest("idea/testData/debugger/smartStepInto/infixCall.kt"); + } + + @TestMetadata("invoke.kt") + public void testInvoke() throws Exception { + doTest("idea/testData/debugger/smartStepInto/invoke.kt"); + } + + @TestMetadata("multiline.kt") + public void testMultiline() throws Exception { + doTest("idea/testData/debugger/smartStepInto/multiline.kt"); + } + + @TestMetadata("multilineCallChain.kt") + public void testMultilineCallChain() throws Exception { + doTest("idea/testData/debugger/smartStepInto/multilineCallChain.kt"); + } + + @TestMetadata("object.kt") + public void testObject() throws Exception { + doTest("idea/testData/debugger/smartStepInto/object.kt"); + } + + @TestMetadata("param.kt") + public void testParam() throws Exception { + doTest("idea/testData/debugger/smartStepInto/param.kt"); + } + + @TestMetadata("parantesized.kt") + public void testParantesized() throws Exception { + doTest("idea/testData/debugger/smartStepInto/parantesized.kt"); + } + + @TestMetadata("propertyGetter.kt") + public void testPropertyGetter() throws Exception { + doTest("idea/testData/debugger/smartStepInto/propertyGetter.kt"); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + doTest("idea/testData/debugger/smartStepInto/simple.kt"); + } + + @TestMetadata("stringTemplate.kt") + public void testStringTemplate() throws Exception { + doTest("idea/testData/debugger/smartStepInto/stringTemplate.kt"); + } + + @TestMetadata("unary.kt") + public void testUnary() throws Exception { + doTest("idea/testData/debugger/smartStepInto/unary.kt"); + } + + @TestMetadata("when.kt") + public void testWhen() throws Exception { + doTest("idea/testData/debugger/smartStepInto/when.kt"); + } + + @TestMetadata("while.kt") + public void testWhile() throws Exception { + doTest("idea/testData/debugger/smartStepInto/while.kt"); + } + +}