From c24fccc659df2c62baa060083d72b7a9958bed37 Mon Sep 17 00:00:00 2001 From: Mikhail Mutcianko Date: Fri, 25 Jul 2014 15:22:52 +0400 Subject: [PATCH] fix xml resolving - replace VirtualFileListener based approach with direct PsiFile reading --- .../resolve/android/AndroidUIXmlParser.kt | 43 +++++++++++++------ .../resolve/android/CliAndroidUIXmlParser.kt | 4 +- .../plugin/android/IDEAndroidUIXmlParser.kt | 24 +---------- 3 files changed, 33 insertions(+), 38 deletions(-) diff --git a/compiler/frontend.android/src/org/jetbrains/jet/lang/resolve/android/AndroidUIXmlParser.kt b/compiler/frontend.android/src/org/jetbrains/jet/lang/resolve/android/AndroidUIXmlParser.kt index b42114e5355..5f37504ee88 100644 --- a/compiler/frontend.android/src/org/jetbrains/jet/lang/resolve/android/AndroidUIXmlParser.kt +++ b/compiler/frontend.android/src/org/jetbrains/jet/lang/resolve/android/AndroidUIXmlParser.kt @@ -40,6 +40,13 @@ import org.xml.sax.helpers.DefaultHandler import org.xml.sax.Attributes import org.jetbrains.kotlin.resolve.android.AndroidConst.* import com.intellij.psi.PsiFileFactory +import com.intellij.psi.util.PsiModificationTracker +import com.intellij.psi.impl.PsiModificationTrackerImpl +import java.util.Queue +import com.intellij.psi.PsiFile +import org.xml.sax.InputSource +import java.io.ByteArrayInputStream +import com.intellij.openapi.diagnostic.Log abstract class AndroidUIXmlParser { @@ -53,18 +60,18 @@ abstract class AndroidUIXmlParser { "android.view.View", "android.widget.*") - abstract val searchPath: String? - abstract val androidAppPackage: String + protected abstract val searchPath: String? + protected abstract val androidAppPackage: String - val saxParser = initSAX() + private val saxParser = initSAX() - val fileCache = HashMap() - var lastCachedPsi: JetFile? = null - val fileModificationTime = HashMap() + private val fileCache = HashMap() + private var lastCachedPsi: JetFile? = null + private val fileModificationTime = HashMap() - val filesToProcess = ConcurrentLinkedQueue() - var listenerSetUp = false - volatile var invalidateCaches = false + protected val filesToProcess: Queue = ConcurrentLinkedQueue() + protected var listenerSetUp: Boolean = false + protected volatile var invalidateCaches: Boolean = false public fun parseToString(): String? { val cacheState = doParse() @@ -73,6 +80,7 @@ abstract class AndroidUIXmlParser { } public fun parseToPsi(project: Project): JetFile? { + populateQueue(project) val cacheState = doParse() if (cacheState == null) return null return if (cacheState == CacheAction.MISS || lastCachedPsi == null) { @@ -126,7 +134,7 @@ abstract class AndroidUIXmlParser { return kw } - private fun parseSingleFileWithCache(file: VirtualFile): Pair { + private fun parseSingleFileWithCache(file: PsiFile): Pair { val lastRecorded = fileModificationTime[file] ?: -1 if (file.getModificationStamp() > lastRecorded) return Pair(parseSingleFile(file), CacheAction.MISS) @@ -134,17 +142,19 @@ abstract class AndroidUIXmlParser { return Pair(fileCache[file]!!, CacheAction.HIT) } - private fun parseSingleFile(file: VirtualFile): String { + private fun parseSingleFile(file: PsiFile): String { val ids: MutableCollection = ArrayList() val handler = AndroidXmlHandler({ id, wClass -> ids.add(AndroidWidget(id, wClass)) }) fileModificationTime[file] = file.getModificationStamp() try { - saxParser.parse(file.getInputStream()!!, handler) + val source = InputSource(ByteArrayInputStream(file.getText()!!.getBytes("utf-8"))) + saxParser.parse(source, handler) val res = produceKotlinProperties(KotlinStringWriter(), ids).toString() fileCache[file] = res return res } catch (e: Exception) { - fileCache[file] = "" + Log.print(e.getMessage()) + invalidateCaches() return "" } } @@ -177,6 +187,13 @@ abstract class AndroidUIXmlParser { invalidateCaches = false } + protected fun populateQueue(project: Project) { + val fileManager = VirtualFileManager.getInstance() + val watchDir = fileManager.findFileByUrl("file://" + searchPath) + val psiManager = PsiManager.getInstance(project) + filesToProcess.addAll(watchDir?.getChildren()?.toArrayList()?.map { psiManager.findFile(it) } ?.mapNotNull { it }) + } + protected abstract fun lazySetup() protected fun readManifest(): AndroidManifest { diff --git a/compiler/frontend.android/src/org/jetbrains/jet/lang/resolve/android/CliAndroidUIXmlParser.kt b/compiler/frontend.android/src/org/jetbrains/jet/lang/resolve/android/CliAndroidUIXmlParser.kt index 646140ee700..8b1c195208e 100644 --- a/compiler/frontend.android/src/org/jetbrains/jet/lang/resolve/android/CliAndroidUIXmlParser.kt +++ b/compiler/frontend.android/src/org/jetbrains/jet/lang/resolve/android/CliAndroidUIXmlParser.kt @@ -25,9 +25,7 @@ class CliAndroidUIXmlParser(val project: Project, override val searchPath: Strin override var androidAppPackage: String = "" override fun lazySetup() { - val fileManager = VirtualFileManager.getInstance() - val watchDir = fileManager.findFileByUrl("file://" + searchPath) - filesToProcess.addAll(watchDir?.getChildren()?.toArrayList() ?: ArrayList(0)) + populateQueue(project) androidAppPackage = readManifest()._package } } diff --git a/idea/src/org/jetbrains/jet/plugin/android/IDEAndroidUIXmlParser.kt b/idea/src/org/jetbrains/jet/plugin/android/IDEAndroidUIXmlParser.kt index 50471152e6f..30df9b02db8 100644 --- a/idea/src/org/jetbrains/jet/plugin/android/IDEAndroidUIXmlParser.kt +++ b/idea/src/org/jetbrains/jet/plugin/android/IDEAndroidUIXmlParser.kt @@ -23,34 +23,14 @@ import java.util.ArrayList import com.intellij.openapi.vfs.VirtualFileAdapter import com.intellij.openapi.vfs.VirtualFileEvent -class IDEAndroidUIXmlParser(project: Project): AndroidUIXmlParser() { +class IDEAndroidUIXmlParser(val project: Project): AndroidUIXmlParser() { override val searchPath: String? = project.getBasePath() + "/res/layout/" override var androidAppPackage: String = "" override protected fun lazySetup() { if (listenerSetUp) return androidAppPackage = readManifest()._package - val fileManager = VirtualFileManager.getInstance() - val watchDir = fileManager.findFileByUrl("file://" + searchPath) - filesToProcess.addAll(watchDir?.getChildren()?.toArrayList() ?: ArrayList(0)) - fileManager.addVirtualFileListener(object : VirtualFileAdapter() { - override fun contentsChanged(event: VirtualFileEvent) { - if (event.getParent() == watchDir) - filesToProcess.add(event.getFile()) - } - override fun fileCreated(event: VirtualFileEvent) { - if (event.getParent() == watchDir) - super.fileCreated(event) - } - override fun fileDeleted(event: VirtualFileEvent) { - if (event.getParent() == watchDir) { - // ignore potential synchronisation issues - it doesn't really matter if invalidation and - // file processing will be handled in different passes - invalidateCaches = true - filesToProcess.addAll(watchDir?.getChildren()?.toArrayList() ?: ArrayList(0)) - } - } - }) + populateQueue(project) listenerSetUp = true } }