From 996636aa623152e49600d5a93ddd3f862dd93c18 Mon Sep 17 00:00:00 2001 From: Mikhail Mutcianko Date: Wed, 30 Jul 2014 21:28:15 +0400 Subject: [PATCH] add goto declaration support for synthetic android properties --- .../resolve/android/AndroidUIXmlParser.kt | 10 +++- .../resolve/android/CliAndroidUIXmlParser.kt | 3 ++ .../android/AndroidGotoDeclarationHandler.kt | 46 +++++++++++++++++++ .../plugin/android/IDEAndroidUIXmlParser.kt | 31 +++++++++++++ 4 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 idea/src/org/jetbrains/jet/plugin/android/AndroidGotoDeclarationHandler.kt 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 80f0350196c..977cea50c74 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 @@ -91,6 +91,8 @@ abstract class AndroidUIXmlParser { protected fun getXmlLayoutFiles(): Collection = fileCache.keySet() + public abstract fun idToXmlAttribute(id: String): PsiElement? + public fun parseToPsi(project: Project): JetFile? { populateQueue(project) val cacheState = doParse() @@ -184,11 +186,15 @@ abstract class AndroidUIXmlParser { lastCachedPsi = null } - protected fun populateQueue(project: Project) { + protected fun getXmlLayouts(project: Project): Collection { 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 } ?: ArrayList(0)) + return watchDir?.getChildren()?.toArrayList()?.map { psiManager.findFile(it) } ?.mapNotNull { it } ?: ArrayList(0) + } + + protected fun populateQueue(project: Project) { + filesToProcess.addAll(getXmlLayouts(project)) } protected abstract fun lazySetup() 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 7f6ca01b903..5d6c5613183 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 @@ -49,6 +49,9 @@ class CliAndroidUIXmlParser(val project: Project, override val searchPath: Strin } } + override fun idToXmlAttribute(id: String): PsiElement? { + return null + } override fun renameId(oldName: String?, newName: String?, allRenames: MutableMap) { return } diff --git a/idea/src/org/jetbrains/jet/plugin/android/AndroidGotoDeclarationHandler.kt b/idea/src/org/jetbrains/jet/plugin/android/AndroidGotoDeclarationHandler.kt new file mode 100644 index 00000000000..d9cbf0c1fa1 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/android/AndroidGotoDeclarationHandler.kt @@ -0,0 +1,46 @@ +/* + * 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.plugin.android + +import com.intellij.codeInsight.navigation.actions.GotoDeclarationHandler +import com.intellij.psi.PsiElement +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.actionSystem.DataContext +import org.jetbrains.jet.lang.psi.JetProperty +import com.intellij.openapi.components.ServiceManager +import org.jetbrains.jet.lang.resolve.android.AndroidUIXmlParser +import com.intellij.psi.util.PsiTreeUtil +import com.intellij.psi.PsiReferenceExpression +import com.intellij.psi.PsiIdentifier +import com.intellij.psi.impl.source.tree.LeafPsiElement + +public class AndroidGotoDeclarationHandler: GotoDeclarationHandler { + override fun getGotoDeclarationTargets(sourceElement: PsiElement?, offset: Int, editor: Editor?): Array? { + if (sourceElement is LeafPsiElement) { + val parser = ServiceManager.getService(sourceElement.getProject(), javaClass()) + val psiElement = parser?.idToXmlAttribute(sourceElement.getText()) + if (psiElement != null) { + return array(psiElement) + } + else return null + } else return null + } + + override fun getActionText(context: DataContext?): String? { + return null + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/android/IDEAndroidUIXmlParser.kt b/idea/src/org/jetbrains/jet/plugin/android/IDEAndroidUIXmlParser.kt index 61d31fa52b2..8526bcd3b18 100644 --- a/idea/src/org/jetbrains/jet/plugin/android/IDEAndroidUIXmlParser.kt +++ b/idea/src/org/jetbrains/jet/plugin/android/IDEAndroidUIXmlParser.kt @@ -29,15 +29,46 @@ import com.intellij.psi.xml.XmlFile import com.intellij.psi.XmlElementVisitor import com.intellij.psi.xml.XmlTag import com.intellij.psi.PsiElement +import java.util.HashMap +import com.intellij.psi.xml.XmlAttribute class IDEAndroidUIXmlParser(val project: Project): AndroidUIXmlParser() { override val searchPath: String? = project.getBasePath() + "/res/layout/" override var androidAppPackage: String = "" + val idToXmlAttributeCache = HashMap() + + private fun setupElementCache() { + for (file in getXmlLayouts(project)) { + if (file is XmlFile) { + file.accept(object : XmlElementVisitor() { + override fun visitElement(element: PsiElement) { + element.acceptChildren(this) + } + override fun visitXmlTag(tag: XmlTag?) { + val idPrefix = "@+id/" + val attribute = tag?.getAttribute("android:id") + val s = attribute?.getValue() + if (attribute != null && (s?.startsWith(idPrefix) ?: false)) { + idToXmlAttributeCache[s!!.replace(idPrefix, "")] = attribute + } + tag?.acceptChildren(this) + } + }) + } + } + + } + + override fun idToXmlAttribute(id: String): PsiElement? { + return idToXmlAttributeCache[id] + } + override protected fun lazySetup() { if (listenerSetUp) return androidAppPackage = readManifest()._package populateQueue(project) + setupElementCache() listenerSetUp = true }