Basic implementation of partial body resolve

This commit is contained in:
Valentin Kipyatkov
2014-11-17 20:20:16 +03:00
parent 9809e4fd0a
commit a675b5ba38
56 changed files with 852 additions and 32 deletions
@@ -0,0 +1,128 @@
/*
* 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.resolve
import org.jetbrains.jet.plugin.JetLightCodeInsightFixtureTestCase
import org.jetbrains.jet.lang.psi.JetFile
import org.jetbrains.jet.lang.psi.psiUtil.getParentByType
import org.jetbrains.jet.lang.resolve.BindingContext
import org.jetbrains.jet.JetTestCaseBuilder
import org.jetbrains.jet.plugin.JetWithJdkAndRuntimeLightProjectDescriptor
import org.jetbrains.jet.lang.psi.JetExpression
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
import java.util.HashSet
import org.jetbrains.jet.JetTestUtils
import java.io.File
import org.jetbrains.jet.lang.psi.JetBlockExpression
import org.junit.Assert
import org.jetbrains.jet.lang.types.JetType
import org.jetbrains.jet.lang.psi.psiUtil.parents
import org.jetbrains.jet.renderer.DescriptorRenderer
import org.jetbrains.jet.lang.descriptors.VariableDescriptor
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression
import org.jetbrains.jet.lang.psi.psiUtil.getReceiverExpression
import org.jetbrains.jet.plugin.caches.resolve.getResolutionFacade
public abstract class AbstractPartialBodyResolveTest : JetLightCodeInsightFixtureTestCase() {
override fun getTestDataPath() = JetTestCaseBuilder.getHomeDirectory()
override fun getProjectDescriptor() = JetWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
public fun doTest(testPath: String) {
myFixture.configureByFile(testPath)
val file = myFixture.getFile() as JetFile
val offset = myFixture.getEditor().getCaretModel().getOffset()
val element = file.findElementAt(offset)
val refExpression = element.getParentByType(javaClass<JetSimpleNameExpression>()) ?: error("No JetSimpleNameExpression at caret")
val resolutionFacade = file.getResolutionFacade()
// optimized resolve
val (target1, type1, processedStatements1) = doResolve(refExpression, resolutionFacade.analyzeWithPartialBodyResolve(refExpression))
// full body resolve
val (target2, type2, processedStatements2) = doResolve(refExpression, resolutionFacade.analyze(refExpression))
val set = HashSet(processedStatements2)
assert (set.containsAll(processedStatements1))
set.removeAll(processedStatements1)
val builder = StringBuilder()
builder.append("Resolve target: ${target2.presentation(type2)}\n")
builder.append("Skipped statements:\n")
set.sortBy { it.getTextOffset() }.forEach {
if (!it.parents(withItself = false).any { it in set }) { // do not dump skipped statements which are inside other skipped statement
builder append it.presentation() append "\n"
}
}
JetTestUtils.assertEqualsToFile(File(testPath.substringBeforeLast('.') + ".dump"), builder.toString())
//TODO: discuss that descriptors are different
Assert.assertEquals(target2.presentation(type2), target1.presentation(type1))
}
private fun doResolve(refExpression: JetSimpleNameExpression, bindingContext: BindingContext): Triple<DeclarationDescriptor?, JetType?, Collection<JetExpression>> {
val target = bindingContext[BindingContext.REFERENCE_TARGET, refExpression]
val processedStatements = bindingContext.getSliceContents(BindingContext.PROCESSED)
.filter { it.value }
.map { it.key }
.filter { it.getParent() is JetBlockExpression }
val receiver = refExpression.getReceiverExpression()
val expressionWithType = if (receiver != null) {
refExpression.getParent() as? JetExpression ?: refExpression
}
else {
refExpression
}
val type = bindingContext[BindingContext.EXPRESSION_TYPE, expressionWithType]
return Triple(target, type, processedStatements)
}
private fun DeclarationDescriptor?.presentation(type: JetType?): String {
if (this == null) return "null"
val s = DescriptorRenderer.COMPACT.render(this)
val renderType = this is VariableDescriptor && type != this.getReturnType()
if (!renderType) return s
return s + " smart-casted to " + if (type != null) DescriptorRenderer.COMPACT.renderType(type) else "unknown type"
}
private fun JetExpression.presentation(): String {
val text = getText()
val builder = StringBuilder()
var dropSpace = false
for (c in text) {
when (c) {
' ', '\n', '\r' -> {
if (!dropSpace) builder.append(' ')
dropSpace = true
}
else -> {
builder.append(c)
dropSpace = false
}
}
}
return builder.toString()
}
}
@@ -0,0 +1,140 @@
/*
* 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.resolve;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.jet.JUnit3RunnerWithInners;
import org.jetbrains.jet.JetTestUtils;
import org.jetbrains.jet.test.InnerTestClasses;
import org.jetbrains.jet.test.TestMetadata;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("idea/testData/resolve/partialBodyResolve")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class PartialBodyResolveTestGenerated extends AbstractPartialBodyResolveTest {
public void testAllFilesPresentInPartialBodyResolve() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/resolve/partialBodyResolve"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("As.kt")
public void testAs() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/resolve/partialBodyResolve/As.kt");
doTest(fileName);
}
@TestMetadata("BangBang.kt")
public void testBangBang() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/resolve/partialBodyResolve/BangBang.kt");
doTest(fileName);
}
@TestMetadata("DeclarationsBefore.kt")
public void testDeclarationsBefore() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/resolve/partialBodyResolve/DeclarationsBefore.kt");
doTest(fileName);
}
@TestMetadata("IfBranchesSmartCast.kt")
public void testIfBranchesSmartCast() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/resolve/partialBodyResolve/IfBranchesSmartCast.kt");
doTest(fileName);
}
@TestMetadata("IfEqAutoCast.kt")
public void testIfEqAutoCast() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/resolve/partialBodyResolve/IfEqAutoCast.kt");
doTest(fileName);
}
@TestMetadata("IfNotIsReturn.kt")
public void testIfNotIsReturn() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/resolve/partialBodyResolve/IfNotIsReturn.kt");
doTest(fileName);
}
@TestMetadata("IfNotIsReturn2.kt")
public void testIfNotIsReturn2() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/resolve/partialBodyResolve/IfNotIsReturn2.kt");
doTest(fileName);
}
@TestMetadata("IfNotIsThrow.kt")
public void testIfNotIsThrow() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/resolve/partialBodyResolve/IfNotIsThrow.kt");
doTest(fileName);
}
@TestMetadata("IfNotNullElseReturn.kt")
public void testIfNotNullElseReturn() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/resolve/partialBodyResolve/IfNotNullElseReturn.kt");
doTest(fileName);
}
@TestMetadata("IfNullBreak.kt")
public void testIfNullBreak() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/resolve/partialBodyResolve/IfNullBreak.kt");
doTest(fileName);
}
@TestMetadata("IfNullContinue.kt")
public void testIfNullContinue() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/resolve/partialBodyResolve/IfNullContinue.kt");
doTest(fileName);
}
@TestMetadata("IfNullPrint.kt")
public void testIfNullPrint() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/resolve/partialBodyResolve/IfNullPrint.kt");
doTest(fileName);
}
@TestMetadata("IfNullReturn.kt")
public void testIfNullReturn() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/resolve/partialBodyResolve/IfNullReturn.kt");
doTest(fileName);
}
@TestMetadata("IfReturn.kt")
public void testIfReturn() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/resolve/partialBodyResolve/IfReturn.kt");
doTest(fileName);
}
@TestMetadata("InIfExpressionElse.kt")
public void testInIfExpressionElse() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/resolve/partialBodyResolve/InIfExpressionElse.kt");
doTest(fileName);
}
@TestMetadata("Lambda.kt")
public void testLambda() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/resolve/partialBodyResolve/Lambda.kt");
doTest(fileName);
}
@TestMetadata("Simple.kt")
public void testSimple() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/resolve/partialBodyResolve/Simple.kt");
doTest(fileName);
}
}