diff --git a/build.xml b/build.xml
index ca883bdc774..f6acbc49418 100644
--- a/build.xml
+++ b/build.xml
@@ -662,6 +662,7 @@
+
diff --git a/plugins/android-compiler-plugin/android-compiler-plugin.iml b/plugins/android-compiler-plugin/android-compiler-plugin.iml
index aa09ebb97a7..e7ad5d837a6 100644
--- a/plugins/android-compiler-plugin/android-compiler-plugin.iml
+++ b/plugins/android-compiler-plugin/android-compiler-plugin.iml
@@ -18,5 +18,7 @@
+
+
\ No newline at end of file
diff --git a/plugins/android-compiler-plugin/src/AndroidComponentRegistrar.kt b/plugins/android-compiler-plugin/src/AndroidComponentRegistrar.kt
index f609a5e8c56..9207c04e70d 100644
--- a/plugins/android-compiler-plugin/src/AndroidComponentRegistrar.kt
+++ b/plugins/android-compiler-plugin/src/AndroidComponentRegistrar.kt
@@ -40,9 +40,6 @@ import org.jetbrains.kotlin.psi.JetClassBody
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.CompilerConfigurationKey
-import org.jetbrains.kotlin.lang.resolve.android.AndroidConst
-import org.jetbrains.kotlin.lang.resolve.android.AndroidUIXmlProcessor
-import org.jetbrains.kotlin.lang.resolve.android.CliAndroidUIXmlProcessor
import org.jetbrains.kotlin.resolve.scopes.receivers.ClassReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.psi.JetThisExpression
@@ -52,6 +49,9 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.codegen.state.*
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.resolve.*
+import com.intellij.openapi.extensions.*
+import com.intellij.psi.impl.*
+import org.jetbrains.kotlin.lang.resolve.android.*
public object AndroidConfigurationKeys {
@@ -241,9 +241,12 @@ public class AndroidComponentRegistrar : ComponentRegistrar {
if (androidResPath != null && androidManifest != null) {
project.registerService(javaClass(), CliAndroidUIXmlProcessor(project, androidManifest, androidResPath))
+ project.registerService(javaClass(), CliAndroidResourceManager(project, androidManifest, androidResPath))
ExternalDeclarationsProvider.registerExtension(project, CliAndroidDeclarationsProvider(project))
ExpressionCodegenExtension.registerExtension(project, AndroidExpressionCodegenExtension())
+ Extensions.getArea(project).getExtensionPoint(
+ PsiTreeChangePreprocessor.EP_NAME).registerExtension(AndroidPsiTreeChangePreprocessor())
}
}
}
\ No newline at end of file
diff --git a/plugins/android-compiler-plugin/src/org/jetbrains/kotlin/lang/resolve/android/AndroidPsiTreeChangePreprocessor.kt b/plugins/android-compiler-plugin/src/org/jetbrains/kotlin/lang/resolve/android/AndroidPsiTreeChangePreprocessor.kt
new file mode 100644
index 00000000000..f8702bd995f
--- /dev/null
+++ b/plugins/android-compiler-plugin/src/org/jetbrains/kotlin/lang/resolve/android/AndroidPsiTreeChangePreprocessor.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2010-2015 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.kotlin.lang.resolve.android
+
+import com.intellij.ide.highlighter.XmlFileType
+import com.intellij.openapi.components.ServiceManager
+import com.intellij.psi.impl.*
+import com.intellij.openapi.util.*
+import com.intellij.openapi.roots.*
+import com.intellij.openapi.module.*
+import com.intellij.openapi.project.Project
+import com.intellij.psi.PsiFile
+
+public class AndroidPsiTreeChangePreprocessor : PsiTreeChangePreprocessor, SimpleModificationTracker() {
+
+ default object {
+ private val HANDLED_EVENTS = setOf(
+ PsiTreeChangeEventImpl.PsiEventType.CHILD_ADDED,
+ PsiTreeChangeEventImpl.PsiEventType.CHILD_MOVED,
+ PsiTreeChangeEventImpl.PsiEventType.CHILD_REMOVED,
+ PsiTreeChangeEventImpl.PsiEventType.CHILD_REPLACED,
+ PsiTreeChangeEventImpl.PsiEventType.CHILDREN_CHANGED)
+ }
+
+ override fun treeChanged(event: PsiTreeChangeEventImpl) {
+ if (event.getCode() in HANDLED_EVENTS) {
+ val file = event.getFile()
+ if (file != null) {
+ val project = file.getProject()
+
+ val projectFileIndex = ProjectRootManager.getInstance(project).getFileIndex()
+ val module = projectFileIndex.getModuleForFile(file.getVirtualFile())
+ if (module != null) {
+ val resourceManager = AndroidResourceManager.getInstance(module)
+ val mainResDirectory = resourceManager.getMainResDirectory()
+ val baseDirectory = file.getParent()?.getParent()?.getVirtualFile()
+
+ //File from res/ directory was modified
+ if (mainResDirectory == baseDirectory && file.isLayoutXmlFile()) {
+ incModificationCount()
+ }
+ }
+ }
+ }
+ }
+
+ private fun PsiFile.isLayoutXmlFile(): Boolean {
+ if (getFileType() != XmlFileType.INSTANCE) return false
+ return getParent()?.getName()?.startsWith("layout") ?: false
+ }
+
+}
\ No newline at end of file
diff --git a/plugins/android-compiler-plugin/src/org/jetbrains/kotlin/lang/resolve/android/AndroidResourceManager.kt b/plugins/android-compiler-plugin/src/org/jetbrains/kotlin/lang/resolve/android/AndroidResourceManager.kt
index f3b992233ce..475d658fd01 100644
--- a/plugins/android-compiler-plugin/src/org/jetbrains/kotlin/lang/resolve/android/AndroidResourceManager.kt
+++ b/plugins/android-compiler-plugin/src/org/jetbrains/kotlin/lang/resolve/android/AndroidResourceManager.kt
@@ -23,6 +23,9 @@ import com.intellij.psi.PsiManager
import com.intellij.openapi.util.*
import com.intellij.openapi.vfs.impl.*
import com.intellij.openapi.vfs.*
+import com.intellij.openapi.components.*
+import com.intellij.openapi.extensions.*
+import com.intellij.openapi.module.*
public abstract class AndroidResourceManager(val project: Project) {
@@ -61,11 +64,18 @@ public abstract class AndroidResourceManager(val project: Project) {
.sortBy { it.getName() }
}
- fun getMainLayoutDirectory(): VirtualFile? {
+ fun getMainResDirectory(): VirtualFile? {
val info = androidModuleInfo
if (info == null) return null
return VirtualFileManager.getInstance().findFileByUrl("file://" + info.mainResDirectory)
}
+ default object {
+ public fun getInstance(module: Module): AndroidResourceManager {
+ val service = ModuleServiceManager.getService(module, javaClass())
+ return service ?: module.getComponent(javaClass())
+ }
+ }
+
}
diff --git a/plugins/android-compiler-plugin/src/org/jetbrains/kotlin/lang/resolve/android/AndroidUIXmlProcessor.kt b/plugins/android-compiler-plugin/src/org/jetbrains/kotlin/lang/resolve/android/AndroidUIXmlProcessor.kt
index c955484f844..83b366283c5 100644
--- a/plugins/android-compiler-plugin/src/org/jetbrains/kotlin/lang/resolve/android/AndroidUIXmlProcessor.kt
+++ b/plugins/android-compiler-plugin/src/org/jetbrains/kotlin/lang/resolve/android/AndroidUIXmlProcessor.kt
@@ -37,7 +37,6 @@ import org.xml.sax.helpers.DefaultHandler
import org.xml.sax.Attributes
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 com.intellij.openapi.diagnostic.Logger
@@ -52,6 +51,7 @@ import com.intellij.openapi.util.*
import com.intellij.openapi.vfs.impl.*
import com.intellij.openapi.vfs.*
import kotlin.properties.*
+import com.intellij.psi.impl.*
public abstract class AndroidUIXmlProcessor(protected val project: Project) {
@@ -64,13 +64,11 @@ public abstract class AndroidUIXmlProcessor(protected val project: Project) {
public abstract val resourceManager: AndroidResourceManager
- private val vfsTracker: VfsModificationTracker by Delegates.lazy {
- VfsModificationTracker(project, resourceManager.getMainLayoutDirectory())
- }
+ public abstract val psiTreeChangePreprocessor: PsiTreeChangePreprocessor
private val cachedSources: CachedValue> by Delegates.lazy {
cachedValue {
- Result.create(parse(), vfsTracker)
+ Result.create(parse(), psiTreeChangePreprocessor)
}
}
@@ -136,58 +134,4 @@ public abstract class AndroidUIXmlProcessor(protected val project: Project) {
return CachedValuesManager.getManager(project).createCachedValue(result, false)
}
-}
-
-private class VfsModificationTracker(project: Project, resDirectory: VirtualFile?): SimpleModificationTracker() {
- {
- val connection = project.getMessageBus().connect();
- connection.subscribe(VirtualFileManager.VFS_CHANGES, BulkVirtualFileListenerAdapter(
- object : VirtualFileListener {
- fun incModificationCountIfLayout(file: VirtualFile) {
- if (resDirectory == null) {
- incModificationCount()
- } else {
- val probablyLayoutDir = file.getParent()
- val probablyResDir = file.getParent()?.getParent()
- if (resDirectory == probablyResDir && probablyLayoutDir?.getName()?.startsWith("layout") ?: false) {
- incModificationCount()
- }
- }
- }
-
- override fun contentsChanged(event: VirtualFileEvent) {
- incModificationCountIfLayout(event.getFile())
- }
-
- override fun propertyChanged(event: VirtualFilePropertyEvent) {
- incModificationCountIfLayout(event.getFile())
- }
-
- override fun fileCreated(event: VirtualFileEvent) {
- incModificationCountIfLayout(event.getFile())
- }
-
- override fun fileDeleted(event: VirtualFileEvent) {
- incModificationCountIfLayout(event.getFile())
- }
-
- override fun fileMoved(event: VirtualFileMoveEvent) {
- incModificationCountIfLayout(event.getFile())
- }
-
- override fun fileCopied(event: VirtualFileCopyEvent) {
- incModificationCountIfLayout(event.getFile())
- }
-
- override fun beforePropertyChange(event: VirtualFilePropertyEvent) {}
-
- override fun beforeContentsChange(event: VirtualFileEvent) {}
-
- override fun beforeFileDeletion(event: VirtualFileEvent) {}
-
- override fun beforeFileMovement(event: VirtualFileMoveEvent) {}
- }
- ))
- }
-}
-
+}
\ No newline at end of file
diff --git a/plugins/android-compiler-plugin/src/org/jetbrains/kotlin/lang/resolve/android/CliAndroidUIXmlProcessor.kt b/plugins/android-compiler-plugin/src/org/jetbrains/kotlin/lang/resolve/android/CliAndroidUIXmlProcessor.kt
index c802eb48081..be7faa2a097 100644
--- a/plugins/android-compiler-plugin/src/org/jetbrains/kotlin/lang/resolve/android/CliAndroidUIXmlProcessor.kt
+++ b/plugins/android-compiler-plugin/src/org/jetbrains/kotlin/lang/resolve/android/CliAndroidUIXmlProcessor.kt
@@ -21,6 +21,8 @@ import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import java.io.ByteArrayInputStream
import kotlin.properties.Delegates
+import com.intellij.psi.impl.*
+import com.intellij.openapi.components.*
public class CliAndroidUIXmlProcessor(
project: Project,
@@ -32,6 +34,10 @@ public class CliAndroidUIXmlProcessor(
CliAndroidResourceManager(project, manifestPath, mainResDirectory)
}
+ override val psiTreeChangePreprocessor: PsiTreeChangePreprocessor by Delegates.lazy {
+ project.getExtensions(PsiTreeChangePreprocessor.EP_NAME).first { it is AndroidPsiTreeChangePreprocessor }
+ }
+
override fun parseSingleFile(file: PsiFile): Collection {
val widgets: MutableCollection = ArrayList()
val handler = AndroidXmlHandler(resourceManager, { id, clazz -> widgets.add(AndroidWidget(id, clazz)) })
diff --git a/plugins/android-compiler-plugin/tests/org/jetbrains/kotlin/lang/resolve/android/test/CompilerTestUtils.kt b/plugins/android-compiler-plugin/tests/org/jetbrains/kotlin/lang/resolve/android/test/CompilerTestUtils.kt
index 4345437b070..f71d789ef34 100644
--- a/plugins/android-compiler-plugin/tests/org/jetbrains/kotlin/lang/resolve/android/test/CompilerTestUtils.kt
+++ b/plugins/android-compiler-plugin/tests/org/jetbrains/kotlin/lang/resolve/android/test/CompilerTestUtils.kt
@@ -16,7 +16,9 @@
package org.jetbrains.kotlin.lang.resolve.android.test
+import com.intellij.openapi.extensions.Extensions
import com.intellij.openapi.project.Project
+import com.intellij.psi.impl.PsiTreeChangePreprocessor
import org.jetbrains.kotlin.extensions.ExternalDeclarationsProvider
import org.jetbrains.kotlin.android.AndroidConfigurationKeys
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension
@@ -27,6 +29,7 @@ import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.cli.jvm.compiler.JetCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
+import org.jetbrains.kotlin.lang.resolve.android.AndroidPsiTreeChangePreprocessor
import org.jetbrains.kotlin.lang.resolve.android.CliAndroidUIXmlProcessor
private class AndroidTestExternalDeclarationsProvider(
@@ -51,5 +54,6 @@ fun UsefulTestCase.createAndroidTestEnvironment(
val project = myEnvironment.getProject()
ExternalDeclarationsProvider.registerExtension(project, AndroidTestExternalDeclarationsProvider(project, resPath, manifestPath))
ExpressionCodegenExtension.registerExtension(project, AndroidExpressionCodegenExtension())
+ Extensions.getArea(project).getExtensionPoint(PsiTreeChangePreprocessor.EP_NAME).registerExtension(AndroidPsiTreeChangePreprocessor())
return myEnvironment
}
diff --git a/plugins/android-idea-plugin/src/META-INF/plugin.xml b/plugins/android-idea-plugin/src/META-INF/plugin.xml
index 6e41fbe2ca6..de5cbff9256 100644
--- a/plugins/android-idea-plugin/src/META-INF/plugin.xml
+++ b/plugins/android-idea-plugin/src/META-INF/plugin.xml
@@ -14,8 +14,11 @@
+
+
diff --git a/plugins/android-idea-plugin/src/org/jetbrains/kotlin/plugin/android/IDEAndroidUIXmlProcessor.kt b/plugins/android-idea-plugin/src/org/jetbrains/kotlin/plugin/android/IDEAndroidUIXmlProcessor.kt
index b631e07949f..9edd7fe2252 100644
--- a/plugins/android-idea-plugin/src/org/jetbrains/kotlin/plugin/android/IDEAndroidUIXmlProcessor.kt
+++ b/plugins/android-idea-plugin/src/org/jetbrains/kotlin/plugin/android/IDEAndroidUIXmlProcessor.kt
@@ -16,17 +16,23 @@
package org.jetbrains.kotlin.plugin.android
+import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.module.Module
import org.jetbrains.kotlin.plugin.android.IDEAndroidResourceManager
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.plugin.android.AndroidXmlVisitor
-import org.jetbrains.kotlin.lang.resolve.android.AndroidUIXmlProcessor
-import org.jetbrains.kotlin.lang.resolve.android.AndroidWidget
+import com.intellij.psi.impl.*
+import kotlin.properties.*
+import org.jetbrains.kotlin.lang.resolve.android.*
class IDEAndroidUIXmlProcessor(val module: Module) : AndroidUIXmlProcessor(module.getProject()) {
override val resourceManager: IDEAndroidResourceManager = IDEAndroidResourceManager(module)
+ override val psiTreeChangePreprocessor by Delegates.lazy {
+ module.getProject().getExtensions(PsiTreeChangePreprocessor.EP_NAME).first { it is AndroidPsiTreeChangePreprocessor }
+ }
+
override fun parseSingleFile(file: PsiFile): List {
val widgets = arrayListOf()
file.accept(AndroidXmlVisitor(resourceManager, { id, wClass, valueElement ->