Name synthetic files after layout names
This commit is contained in:
+3
-1
@@ -22,7 +22,9 @@ import org.jetbrains.kotlin.lexer.JetTokens
|
||||
|
||||
public object AndroidConst {
|
||||
val ANDROID_USER_PACKAGE: Key<String> = Key.create<String>("ANDROID_USER_PACKAGE")
|
||||
val SYNTHETIC_FILENAME: String = "ANDROIDXML"
|
||||
val SYNTHETIC_FILENAME_PREFIX: String = "ANDROIDXML_"
|
||||
val LAYOUT_POSTFIX: String = "_LAYOUT"
|
||||
val VIEW_LAYOUT_POSTFIX: String = "_VIEW"
|
||||
val SYNTHETIC_PACKAGE: String = "kotlinx.android.synthetic"
|
||||
val SYNTHETIC_PACKAGE_PATH_LENGTH = SYNTHETIC_PACKAGE.count { it == '.' } + 1
|
||||
|
||||
|
||||
+36
-18
@@ -54,6 +54,8 @@ import kotlin.properties.*
|
||||
import com.intellij.psi.impl.*
|
||||
import org.jetbrains.kotlin.types.Flexibility
|
||||
|
||||
public class AndroidSyntheticFile(val name: String, val contents: String)
|
||||
|
||||
public abstract class AndroidUIXmlProcessor(protected val project: Project) {
|
||||
|
||||
public class NoAndroidManifestFound : Exception("No android manifest file found in project root")
|
||||
@@ -62,15 +64,16 @@ public abstract class AndroidUIXmlProcessor(protected val project: Project) {
|
||||
|
||||
public abstract val resourceManager: AndroidResourceManager
|
||||
|
||||
protected abstract val cachedSources: CachedValue<List<String>>
|
||||
protected abstract val cachedSources: CachedValue<List<AndroidSyntheticFile>>
|
||||
|
||||
private val cachedJetFiles: CachedValue<List<JetFile>> by Delegates.lazy {
|
||||
cachedValue {
|
||||
val psiManager = PsiManager.getInstance(project)
|
||||
val applicationPackage = resourceManager.androidModuleInfo?.applicationPackage
|
||||
|
||||
val jetFiles = cachedSources.getValue().mapIndexed { index, text ->
|
||||
val virtualFile = LightVirtualFile(AndroidConst.SYNTHETIC_FILENAME + index + ".kt", text)
|
||||
val jetFiles = cachedSources.getValue().mapIndexed { index, syntheticFile ->
|
||||
val fileName = AndroidConst.SYNTHETIC_FILENAME_PREFIX + syntheticFile.name + ".kt"
|
||||
val virtualFile = LightVirtualFile(fileName, syntheticFile.contents)
|
||||
val jetFile = psiManager.findFile(virtualFile) as JetFile
|
||||
if (applicationPackage != null) {
|
||||
jetFile.putUserData(AndroidConst.ANDROID_USER_PACKAGE, applicationPackage)
|
||||
@@ -82,10 +85,14 @@ public abstract class AndroidUIXmlProcessor(protected val project: Project) {
|
||||
}
|
||||
}
|
||||
|
||||
public fun parse(generateCommonFiles: Boolean = true): List<String> {
|
||||
public fun parse(generateCommonFiles: Boolean = true): List<AndroidSyntheticFile> {
|
||||
val commonFiles = if (generateCommonFiles) {
|
||||
val clearCacheFile = renderLayoutFile(AndroidConst.SYNTHETIC_PACKAGE) {} +
|
||||
renderClearCacheFunction("android.app.Activity") + renderClearCacheFunction("android.app.Fragment")
|
||||
val clearCacheFile = renderSyntheticFile("clearCache") {
|
||||
writePackage(AndroidConst.SYNTHETIC_PACKAGE)
|
||||
writeAndroidImports()
|
||||
writeClearCacheFunction("android.app.Activity")
|
||||
writeClearCacheFunction("android.app.Fragment")
|
||||
}
|
||||
|
||||
listOf(clearCacheFile,
|
||||
FLEXIBLE_TYPE_FILE,
|
||||
@@ -98,14 +105,15 @@ public abstract class AndroidUIXmlProcessor(protected val project: Project) {
|
||||
val files = entry.getValue()
|
||||
val widgets = parseLayout(files)
|
||||
|
||||
val layoutPackage = files[0].genSyntheticPackageName()
|
||||
val layoutName = files[0].getName().substringBefore('.')
|
||||
val packageName = AndroidConst.SYNTHETIC_PACKAGE + "." + files[0].getEscapedLayoutName()
|
||||
|
||||
val mainLayoutFile = renderLayoutFile(layoutPackage, widgets) {
|
||||
val mainLayoutFile = renderLayoutFile(layoutName + AndroidConst.LAYOUT_POSTFIX, packageName, widgets) {
|
||||
writeSyntheticProperty("android.app.Activity", it, "findViewById(0)")
|
||||
writeSyntheticProperty("android.app.Fragment", it, "getView().findViewById(0)")
|
||||
}
|
||||
|
||||
val viewLayoutFile = renderLayoutFile("$layoutPackage.view", widgets) {
|
||||
val viewLayoutFile = renderLayoutFile(layoutName + AndroidConst.VIEW_LAYOUT_POSTFIX, "$packageName.view", widgets) {
|
||||
writeSyntheticProperty("android.view.View", it, "findViewById(0)")
|
||||
}
|
||||
|
||||
@@ -118,16 +126,23 @@ public abstract class AndroidUIXmlProcessor(protected val project: Project) {
|
||||
protected abstract fun parseLayout(files: List<PsiFile>): List<AndroidWidget>
|
||||
|
||||
private fun renderLayoutFile(
|
||||
name: String,
|
||||
packageName: String,
|
||||
widgets: List<AndroidWidget> = listOf(),
|
||||
widgetWriter: KotlinStringWriter.(AndroidWidget) -> Unit
|
||||
): String {
|
||||
): AndroidSyntheticFile {
|
||||
val stringWriter = KotlinStringWriter()
|
||||
stringWriter.writePackage(packageName)
|
||||
stringWriter.writeAndroidImports()
|
||||
widgets.forEach { stringWriter.widgetWriter(it) }
|
||||
|
||||
return stringWriter.toStringBuffer().toString()
|
||||
return AndroidSyntheticFile(name, stringWriter.toStringBuffer().toString())
|
||||
}
|
||||
|
||||
private fun renderSyntheticFile(filename: String, init: KotlinStringWriter.() -> Unit): AndroidSyntheticFile {
|
||||
val stringWriter = KotlinStringWriter()
|
||||
stringWriter.init()
|
||||
return AndroidSyntheticFile(filename, stringWriter.toStringBuffer().toString())
|
||||
}
|
||||
|
||||
private fun KotlinStringWriter.writeAndroidImports() {
|
||||
@@ -135,8 +150,8 @@ public abstract class AndroidUIXmlProcessor(protected val project: Project) {
|
||||
writeEmptyLine()
|
||||
}
|
||||
|
||||
private fun PsiFile.genSyntheticPackageName(): String {
|
||||
return AndroidConst.SYNTHETIC_PACKAGE + "." + escapeAndroidIdentifier(getName().substringBefore('.'))
|
||||
private fun PsiFile.getEscapedLayoutName(): String {
|
||||
return escapeAndroidIdentifier(getName().substringBefore('.'))
|
||||
}
|
||||
|
||||
private fun KotlinStringWriter.writeSyntheticProperty(receiver: String, widget: AndroidWidget, stubCall: String) {
|
||||
@@ -149,7 +164,9 @@ public abstract class AndroidUIXmlProcessor(protected val project: Project) {
|
||||
getterBody = body)
|
||||
}
|
||||
|
||||
private fun renderClearCacheFunction(receiver: String) = "public fun $receiver.${AndroidConst.CLEAR_FUNCTION_NAME}() {}\n"
|
||||
private fun KotlinStringWriter.writeClearCacheFunction(receiver: String) {
|
||||
writeText("public fun $receiver.${AndroidConst.CLEAR_FUNCTION_NAME}() {}\n")
|
||||
}
|
||||
|
||||
protected fun <T> cachedValue(result: () -> CachedValueProvider.Result<T>): CachedValue<T> {
|
||||
return CachedValuesManager.getManager(project).createCachedValue(result, false)
|
||||
@@ -187,13 +204,14 @@ public abstract class AndroidUIXmlProcessor(protected val project: Project) {
|
||||
"android.support.v4.widget.*",
|
||||
Flexibility.FLEXIBLE_TYPE_CLASSIFIER.asSingleFqName().asString())
|
||||
|
||||
private val FLEXIBLE_TYPE_FILE = "package $EXPLICIT_FLEXIBLE_PACKAGE\n\nclass $EXPLICIT_FLEXIBLE_CLASS_NAME<L, U>"
|
||||
private val FLEXIBLE_TYPE_FILE =
|
||||
AndroidSyntheticFile("ft", "package $EXPLICIT_FLEXIBLE_PACKAGE\n\nclass $EXPLICIT_FLEXIBLE_CLASS_NAME<L, U>")
|
||||
|
||||
private val FAKE_SUPPORT_V4_WIDGET_FILE = "package android.support.v4.widget"
|
||||
private val FAKE_SUPPORT_V4_WIDGET_FILE = AndroidSyntheticFile("supportv4_widget", "package android.support.v4.widget")
|
||||
|
||||
private val FAKE_SUPPORT_V4_VIEW_FILE = "package android.support.v4.view"
|
||||
private val FAKE_SUPPORT_V4_VIEW_FILE = AndroidSyntheticFile("supportv4_view", "package android.support.v4.view")
|
||||
|
||||
private val FAKE_SUPPORT_V4_APP_FILE = "package android.support.v4.app"
|
||||
private val FAKE_SUPPORT_V4_APP_FILE = AndroidSyntheticFile("supportv4_app", "package android.support.v4.app")
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -37,7 +37,7 @@ public class CliAndroidUIXmlProcessor(
|
||||
CliAndroidResourceManager(project, manifestPath, mainResDirectory)
|
||||
}
|
||||
|
||||
override val cachedSources: CachedValue<List<String>> by Delegates.lazy {
|
||||
override val cachedSources: CachedValue<List<AndroidSyntheticFile>> by Delegates.lazy {
|
||||
cachedValue {
|
||||
Result.create(parse(), ModificationTracker.NEVER_CHANGED)
|
||||
}
|
||||
|
||||
+4
@@ -69,6 +69,10 @@ class KotlinStringWriter : KotlinWriter {
|
||||
body.newLine()
|
||||
}
|
||||
|
||||
fun writeText(text: String) {
|
||||
body.writeln(text)
|
||||
}
|
||||
|
||||
override fun toStringBuffer(): StringBuffer {
|
||||
ctx.absorbChildren()
|
||||
return ctx.buffer
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package kotlinx.android.synthetic.layout
|
||||
package kotlinx.android.synthetic.test
|
||||
|
||||
import android.app.*
|
||||
import android.view.*
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package kotlinx.android.synthetic.layout.view
|
||||
package kotlinx.android.synthetic.test.view
|
||||
|
||||
import android.app.*
|
||||
import android.view.*
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package kotlinx.android.synthetic.layout
|
||||
package kotlinx.android.synthetic.test
|
||||
|
||||
import android.app.*
|
||||
import android.view.*
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package kotlinx.android.synthetic.layout.view
|
||||
package kotlinx.android.synthetic.test.view
|
||||
|
||||
import android.app.*
|
||||
import android.view.*
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package kotlinx.android.synthetic.layout
|
||||
package kotlinx.android.synthetic.test
|
||||
|
||||
import android.app.*
|
||||
import android.view.*
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package kotlinx.android.synthetic.layout.view
|
||||
package kotlinx.android.synthetic.test.view
|
||||
|
||||
import android.app.*
|
||||
import android.view.*
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package kotlinx.android.synthetic.layout1
|
||||
package kotlinx.android.synthetic.test1
|
||||
|
||||
import android.app.*
|
||||
import android.view.*
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package kotlinx.android.synthetic.layout1.view
|
||||
package kotlinx.android.synthetic.test1.view
|
||||
|
||||
import android.app.*
|
||||
import android.view.*
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package kotlinx.android.synthetic.layout
|
||||
package kotlinx.android.synthetic.test
|
||||
|
||||
import android.app.*
|
||||
import android.view.*
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package kotlinx.android.synthetic.layout.view
|
||||
package kotlinx.android.synthetic.test.view
|
||||
|
||||
import android.app.*
|
||||
import android.view.*
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package kotlinx.android.synthetic.layout
|
||||
package kotlinx.android.synthetic.test
|
||||
|
||||
import android.app.*
|
||||
import android.view.*
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package kotlinx.android.synthetic.layout.view
|
||||
package kotlinx.android.synthetic.test.view
|
||||
|
||||
import android.app.*
|
||||
import android.view.*
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package kotlinx.android.synthetic.layout
|
||||
package kotlinx.android.synthetic.test
|
||||
|
||||
import android.app.*
|
||||
import android.view.*
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package kotlinx.android.synthetic.layout.view
|
||||
package kotlinx.android.synthetic.test.view
|
||||
|
||||
import android.app.*
|
||||
import android.view.*
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package kotlinx.android.synthetic.layout
|
||||
package kotlinx.android.synthetic.test
|
||||
|
||||
import android.app.*
|
||||
import android.view.*
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package kotlinx.android.synthetic.layout.view
|
||||
package kotlinx.android.synthetic.test.view
|
||||
|
||||
import android.app.*
|
||||
import android.view.*
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package kotlinx.android.synthetic.layout
|
||||
package kotlinx.android.synthetic.test
|
||||
|
||||
import android.app.*
|
||||
import android.view.*
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package kotlinx.android.synthetic.layout.view
|
||||
package kotlinx.android.synthetic.test.view
|
||||
|
||||
import android.app.*
|
||||
import android.view.*
|
||||
+12
-9
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.test.JetTestUtils
|
||||
import org.jetbrains.kotlin.test.ConfigurationKind
|
||||
import org.jetbrains.kotlin.test.TestJdkKind
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||
import org.jetbrains.kotlin.lang.resolve.android.AndroidConst
|
||||
import org.jetbrains.kotlin.lang.resolve.android.CliAndroidUIXmlProcessor
|
||||
import org.jetbrains.kotlin.lang.resolve.android.AndroidUIXmlProcessor
|
||||
import kotlin.test.*
|
||||
@@ -30,19 +31,21 @@ import kotlin.test.*
|
||||
public abstract class AbstractAndroidXml2KConversionTest : UsefulTestCase() {
|
||||
|
||||
public fun doTest(path: String) {
|
||||
val jetCoreEnvironment = getEnvironment(path)
|
||||
val jetCoreEnvironment = getEnvironment()
|
||||
val parser = CliAndroidUIXmlProcessor(jetCoreEnvironment.project, path + "AndroidManifest.xml", path + "/res")
|
||||
|
||||
val actual = parser.parse(false)
|
||||
val actual = parser.parse(false).toMap { it.name }
|
||||
|
||||
val layoutFiles = File(path).listFiles {
|
||||
it.isFile() && it.name.startsWith("layout") && it.name.endsWith(".kt")
|
||||
}?.sortBy { it.name } ?: listOf()
|
||||
val expectedLayoutFiles = File(path).listFiles {
|
||||
it.isFile() && it.name.endsWith(".kt")
|
||||
}?.toMap { it.name.substringBefore(".kt") } ?: mapOf()
|
||||
|
||||
assertEquals(layoutFiles.size(), actual.size())
|
||||
assertEquals(expectedLayoutFiles.size(), actual.size())
|
||||
|
||||
for ((index, file) in layoutFiles.withIndex()) {
|
||||
JetTestUtils.assertEqualsToFile(file, actual[index])
|
||||
for ((name, file) in expectedLayoutFiles) {
|
||||
val actualContents = actual[name]
|
||||
assertNotNull(actualContents, "File $name was not generated")
|
||||
JetTestUtils.assertEqualsToFile(file, actualContents!!.contents)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +58,7 @@ public abstract class AbstractAndroidXml2KConversionTest : UsefulTestCase() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getEnvironment(testPath: String): KotlinCoreEnvironment {
|
||||
private fun getEnvironment(): KotlinCoreEnvironment {
|
||||
val configuration = JetTestUtils.compilerConfigurationForTests(ConfigurationKind.ALL, TestJdkKind.MOCK_JDK)
|
||||
return KotlinCoreEnvironment.createForTests(getTestRootDisposable()!!, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
|
||||
}
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ class IDEAndroidUIXmlProcessor(val module: Module) : AndroidUIXmlProcessor(modul
|
||||
module.getProject().getExtensions(PsiTreeChangePreprocessor.EP_NAME).first { it is AndroidPsiTreeChangePreprocessor }
|
||||
}
|
||||
|
||||
override val cachedSources: CachedValue<List<String>> by Delegates.lazy {
|
||||
override val cachedSources: CachedValue<List<AndroidSyntheticFile>> by Delegates.lazy {
|
||||
cachedValue {
|
||||
Result.create(parse(), psiTreeChangePreprocessor)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user