Java to Kotlin converter: added auto-conversion run of Kotlin analyzer. Implemented first fix with it - redundant !! removal

This commit is contained in:
Valentin Kipyatkov
2014-07-10 15:05:54 +04:00
parent 69a5b79342
commit acc58173da
11 changed files with 107 additions and 13 deletions
@@ -304,6 +304,9 @@
<item name='com.intellij.psi.PsiExpressionStatement'> <item name='com.intellij.psi.PsiExpressionStatement'>
<annotation name='org.jetbrains.annotations.NotNull'/> <annotation name='org.jetbrains.annotations.NotNull'/>
</item> </item>
<item name='com.intellij.psi.PsiFileFactory com.intellij.psi.PsiFileFactory getInstance(com.intellij.openapi.project.Project) 0'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='com.intellij.psi.PsiForStatement'> <item name='com.intellij.psi.PsiForStatement'>
<annotation name='org.jetbrains.annotations.NotNull'/> <annotation name='org.jetbrains.annotations.NotNull'/>
</item> </item>
@@ -144,23 +144,23 @@ public class JetPsiFactory {
} }
@NotNull @NotNull
public static JetClass createClass(Project project, String text) { public static JetClass createClass(@NotNull Project project, @NotNull String text) {
return createDeclaration(project, text, JetClass.class); return createDeclaration(project, text, JetClass.class);
} }
@NotNull @NotNull
public static JetFile createFile(Project project, String text) { public static JetFile createFile(@NotNull Project project, @NotNull String text) {
return createFile(project, "dummy.kt", text); return createFile(project, "dummy.kt", text);
} }
@NotNull @NotNull
public static JetFile createFile(Project project, String fileName, String text) { public static JetFile createFile(@NotNull Project project, @NotNull String fileName, @NotNull String text) {
return (JetFile) PsiFileFactory.getInstance(project).createFileFromText(fileName, JetFileType.INSTANCE, text, return (JetFile) PsiFileFactory.getInstance(project).createFileFromText(fileName, JetFileType.INSTANCE, text,
LocalTimeCounter.currentTime(), false); LocalTimeCounter.currentTime(), false);
} }
@NotNull @NotNull
public static JetFile createPhysicalFile(Project project, String fileName, String text) { public static JetFile createPhysicalFile(@NotNull Project project, @NotNull String fileName, @NotNull String text) {
return (JetFile) PsiFileFactory.getInstance(project).createFileFromText(fileName, JetFileType.INSTANCE, text, return (JetFile) PsiFileFactory.getInstance(project).createFileFromText(fileName, JetFileType.INSTANCE, text,
LocalTimeCounter.currentTime(), true); LocalTimeCounter.currentTime(), true);
} }
@@ -0,0 +1,71 @@
/*
* 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.j2k
import org.jetbrains.jet.lang.psi.JetPsiFactory
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM
import org.jetbrains.jet.lang.resolve.BindingTraceContext
import org.jetbrains.jet.lang.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.jet.lang.resolve.name.Name
import org.jetbrains.jet.lang.resolve.java.mapping.JavaToKotlinClassMap
import com.intellij.openapi.project.Project
import org.jetbrains.jet.lang.diagnostics.Diagnostic
import org.jetbrains.jet.lang.diagnostics.Errors
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression
import org.jetbrains.jet.lang.psi.JetUnaryExpression
class AfterConversionPass(val project: Project) {
public fun run(kotlinCode: String): String {
val kotlinFile = JetPsiFactory.createFile(project, kotlinCode)
val analyzeExhaust = AnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(
project,
listOf(kotlinFile),
BindingTraceContext(),
{ true },
ModuleDescriptorImpl(Name.special("<module>"), AnalyzerFacadeForJVM.DEFAULT_IMPORTS, JavaToKotlinClassMap.getInstance()),
null,
null
)
val problems = analyzeExhaust.getBindingContext().getDiagnostics()
val fixes = problems.map {
val fix = fixForProblem(it)
if (fix != null) it.getPsiElement() to fix else null
}.filterNotNull()
if (fixes.isEmpty()) return kotlinCode
for ((psiElement, fix) in fixes) {
if (psiElement.isValid()) {
fix()
}
}
return kotlinFile.getText()!!
}
private fun fixForProblem(problem: Diagnostic): (() -> Unit)? {
return when (problem.getFactory()) {
Errors.UNNECESSARY_NOT_NULL_ASSERTION -> { () ->
val exclExclOp = problem.getPsiElement() as JetSimpleNameExpression
val exclExclExpr = exclExclOp.getParent() as JetUnaryExpression
exclExclExpr.replace(exclExclExpr.getBaseExpression()!!)
}
else -> null
}
}
}
+2 -2
View File
@@ -61,7 +61,7 @@ public class Converter private(val project: Project, val settings: ConverterSett
val converted = convertTopElement(element) ?: return "" val converted = convertTopElement(element) ?: return ""
val builder = CodeBuilder(element) val builder = CodeBuilder(element)
builder.append(converted) builder.append(converted)
return builder.result return AfterConversionPass(project).run(builder.result)
} }
private fun convertTopElement(element: PsiElement?): Element? = when (element) { private fun convertTopElement(element: PsiElement?): Element? = when (element) {
@@ -78,7 +78,7 @@ public class Converter private(val project: Project, val settings: ConverterSett
else -> null else -> null
} }
fun convertFile(javaFile: PsiJavaFile): File { private fun convertFile(javaFile: PsiJavaFile): File {
var convertedChildren = javaFile.getChildren().map { var convertedChildren = javaFile.getChildren().map {
if (it is PsiImportList) { if (it is PsiImportList) {
val importList = convertImportList(it) val importList = convertImportList(it)
@@ -21,21 +21,19 @@ import com.intellij.core.JavaCoreProjectEnvironment
import com.intellij.lang.java.JavaLanguage import com.intellij.lang.java.JavaLanguage
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.Disposer
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile import com.intellij.psi.PsiFile
import com.intellij.psi.PsiFileFactory import com.intellij.psi.PsiFileFactory
import com.intellij.psi.PsiJavaFile import com.intellij.psi.PsiJavaFile
import org.jetbrains.jet.utils.PathUtil import org.jetbrains.jet.utils.PathUtil
import java.io.File import java.io.File
import java.net.URLClassLoader import java.net.URLClassLoader
import java.util.HashSet
public object JavaToKotlinTranslator { public object JavaToKotlinTranslator {
private val DISPOSABLE = Disposer.newDisposable() private val DISPOSABLE = Disposer.newDisposable()
private fun createFile(text: String): PsiFile? { private fun createFile(text: String): PsiFile? {
val javaCoreEnvironment: JavaCoreProjectEnvironment? = setUpJavaCoreEnvironment() val javaCoreEnvironment: JavaCoreProjectEnvironment? = setUpJavaCoreEnvironment()
return PsiFileFactory.getInstance(javaCoreEnvironment?.getProject())?.createFileFromText("test.java", JavaLanguage.INSTANCE, text) return PsiFileFactory.getInstance(javaCoreEnvironment?.getProject()!!)?.createFileFromText("test.java", JavaLanguage.INSTANCE, text)
} }
fun createFile(project: Project, text: String): PsiJavaFile { fun createFile(project: Project, text: String): PsiJavaFile {
@@ -2199,6 +2199,11 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("j2k/tests/testData/ast/nullability"), Pattern.compile("^(.+)\\.java$"), true); JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("j2k/tests/testData/ast/nullability"), Pattern.compile("^(.+)\\.java$"), true);
} }
@TestMetadata("autoNotNull.java")
public void testAutoNotNull() throws Exception {
doTest("j2k/tests/testData/ast/nullability/autoNotNull.java");
}
@TestMetadata("FieldAssignedWithNull.java") @TestMetadata("FieldAssignedWithNull.java")
public void testFieldAssignedWithNull() throws Exception { public void testFieldAssignedWithNull() throws Exception {
doTest("j2k/tests/testData/ast/nullability/FieldAssignedWithNull.java"); doTest("j2k/tests/testData/ast/nullability/FieldAssignedWithNull.java");
@@ -10,7 +10,7 @@ public class Test(str: String) {
} }
public fun sout(str: String) { public fun sout(str: String) {
System.out!!.println(str) System.out.println(str)
} }
public fun dummy(str: String): String { public fun dummy(str: String): String {
@@ -17,6 +17,6 @@ class Test {
barNotNull.fooNotNull.execute() barNotNull.fooNotNull.execute()
barNotNull.fooNullable!!.execute() barNotNull.fooNullable!!.execute()
barNullable!!.fooNotNull.execute() barNullable!!.fooNotNull.execute()
barNullable!!.fooNullable!!.execute() barNullable.fooNullable!!.execute()
} }
} }
@@ -8,11 +8,11 @@ import java.io.File
public class Test { public class Test {
class object { class object {
public fun isDir(parent: File?): Boolean { public fun isDir(parent: File?): Boolean {
if (parent == null || !parent!!.exists()) { if (parent == null || !parent.exists()) {
return false return false
} }
val result = true val result = true
if (parent!!.isDirectory()) { if (parent.isDirectory()) {
return true return true
} else } else
return false return false
@@ -0,0 +1,9 @@
//file
class A {
int foo(String s) {
if (s != null) {
return s.length();
}
return -1;
}
}
@@ -0,0 +1,8 @@
class A {
fun foo(s: String?): Int {
if (s != null) {
return s.length()
}
return -1
}
}