diff --git a/annotations/com/intellij/refactoring/annotations.xml b/annotations/com/intellij/refactoring/annotations.xml
index 489d1ad655d..46eab669011 100644
--- a/annotations/com/intellij/refactoring/annotations.xml
+++ b/annotations/com/intellij/refactoring/annotations.xml
@@ -3,4 +3,7 @@
name='com.intellij.refactoring.MultiFileTestCase.PerformAction void performAction(com.intellij.openapi.vfs.VirtualFile, com.intellij.openapi.vfs.VirtualFile) 0'>
+ -
+
+
\ No newline at end of file
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetCallExpression.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetCallExpression.java
index 4ec8e3e0efd..9b6245e3ef2 100644
--- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetCallExpression.java
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetCallExpression.java
@@ -19,6 +19,7 @@ package org.jetbrains.jet.lang.psi;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.util.SmartList;
+import jet.runtime.typeinfo.KotlinSignature;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes;
@@ -85,6 +86,7 @@ public class JetCallExpression extends JetReferenceExpression implements JetCall
return result;
}
+ @KotlinSignature("fun getValueArguments(): MutableList")
@Override
@NotNull
public List extends ValueArgument> getValueArguments() {
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt b/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt
index 4e70da3dda2..3e5fd21f5d1 100644
--- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt
@@ -39,8 +39,6 @@ import com.intellij.psi.search.SearchScope
import com.intellij.psi.search.PsiSearchScopeUtil
import org.jetbrains.jet.lang.psi.JetClassBody
import org.jetbrains.jet.lang.psi.JetParameterList
-import org.jetbrains.jet.lang.psi.JetNamedDeclaration
-import com.intellij.psi.PsiNamedElement
import org.jetbrains.jet.lang.psi.JetObjectDeclaration
import org.jetbrains.jet.lang.psi.JetNamedFunction
import org.jetbrains.jet.lang.psi.JetProperty
@@ -49,6 +47,14 @@ import org.jetbrains.jet.lang.psi.JetPropertyAccessor
import org.jetbrains.jet.lang.psi.JetParameter
import com.intellij.psi.PsiParameterList
import com.intellij.psi.PsiParameter
+import org.jetbrains.jet.lang.psi.JetQualifiedExpression
+import org.jetbrains.jet.lang.psi.JetUserType
+import org.jetbrains.jet.lang.resolve.name.FqName
+import org.jetbrains.jet.lang.psi.JetCallExpression
+import com.intellij.psi.PsiPackage
+import com.intellij.psi.PsiClass
+import com.intellij.psi.PsiMember
+import org.jetbrains.jet.lang.psi.JetNamedDeclaration
fun PsiElement.getParentByTypesAndPredicate(
strict : Boolean = false, vararg parentClasses : Class, predicate: (T) -> Boolean
@@ -209,4 +215,65 @@ fun PsiElement.parameterIndex(): Int {
this is PsiParameter && parent is PsiParameterList -> parent.getParameterIndex(this)
else -> -1
}
+}
+
+/**
+ * Returns enclosing qualifying element for given [[JetSimpleNameExpression]]
+ * ([[JetQualifiedExpression]] or [[JetUserType]] or original expression)
+ */
+fun JetSimpleNameExpression.getQualifiedElement(): JetElement {
+ val baseExpression = (getParent() as? JetCallExpression) ?: this
+ val parent = baseExpression.getParent()
+ return when (parent) {
+ is JetQualifiedExpression -> if (parent.getSelectorExpression().isAncestor(baseExpression)) parent else baseExpression
+ is JetUserType -> if (parent.getReferenceExpression().isAncestor(baseExpression)) parent else baseExpression
+ else -> baseExpression
+ }
+}
+
+/**
+ * Returns rightmost selector of the qualified element (null if there is no such selector)
+ */
+fun JetElement.getQualifiedElementSelector(): JetElement? {
+ return when (this) {
+ is JetSimpleNameExpression -> this
+ is JetQualifiedExpression -> {
+ val selector = getSelectorExpression()
+ if (selector is JetCallExpression) selector.getCalleeExpression() else selector
+ }
+ is JetUserType -> getReferenceExpression()
+ else -> this
+ }
+}
+
+/**
+ * Returns outermost qualified element ([[JetQualifiedExpression]] or [[JetUserType]]) in the non-interleaving chain
+ * of qualified elements which enclose given expression
+ * If there is no such elements original expression is returned
+ */
+fun JetSimpleNameExpression.getOutermostNonInterleavingQualifiedElement(): JetElement {
+ var element = ((getParent() as? JetCallExpression) ?: this).getParent()
+ if (element !is JetQualifiedExpression && element !is JetUserType) return this
+
+ while (true) {
+ val parent = element!!.getParent()
+ if (parent !is JetQualifiedExpression && parent !is JetUserType) return element as JetElement
+ element = parent
+ }
+}
+
+/**
+ * Returns FqName for given declaration (either Java or Kotlin)
+ */
+fun PsiElement.getFqName(): FqName? {
+ return when (this) {
+ is PsiPackage -> FqName(getQualifiedName())
+ is PsiClass -> getQualifiedName()?.let { FqName(it) }
+ is PsiMember -> getName()?.let { name ->
+ val prefix = getContainingClass()?.getQualifiedName()
+ FqName(if (prefix != null) "$prefix.$name" else name)
+ }
+ is JetNamedDeclaration -> JetPsiUtil.getFQName(this)
+ else -> null
+ }
}
\ No newline at end of file
diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index 6fd05c835e5..641ede8c6c2 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -166,6 +166,7 @@
implementationClass="org.jetbrains.jet.plugin.codeInsight.surroundWith.statement.KotlinStatementSurroundDescriptor"/>
+
diff --git a/idea/src/org/jetbrains/jet/plugin/codeInsight/KotlinShortenReferencesRefactoringHelper.kt b/idea/src/org/jetbrains/jet/plugin/codeInsight/KotlinShortenReferencesRefactoringHelper.kt
new file mode 100644
index 00000000000..1c43d65d402
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/codeInsight/KotlinShortenReferencesRefactoringHelper.kt
@@ -0,0 +1,87 @@
+/*
+ * 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.codeInsight
+
+import com.intellij.refactoring.RefactoringHelper
+import com.intellij.usageView.UsageInfo
+import com.intellij.openapi.project.Project
+import java.util.HashSet
+import com.intellij.openapi.util.Key
+import com.intellij.openapi.application.ApplicationManager
+import com.intellij.psi.SmartPsiElementPointer
+import org.jetbrains.jet.lang.psi.JetSimpleNameExpression
+import org.jetbrains.jet.lang.resolve.name.FqName
+import org.jetbrains.jet.plugin.refactoring.changeQualifiedName
+import org.jetbrains.jet.lang.psi.psiUtil.getQualifiedElementSelector
+import org.jetbrains.jet.lang.psi.psiUtil.getOutermostNonInterleavingQualifiedElement
+
+public class KotlinShortenReferencesRefactoringHelper: RefactoringHelper> {
+ override fun prepareOperation(usages: Array?): Set? {
+ if (usages != null && usages.isNotEmpty()) {
+ ApplicationManager.getApplication()!!.runWriteAction { usages[0].getProject().getElementsToShorten(true)!!.clear() }
+ }
+ return null
+ }
+
+ override fun performOperation(project: Project, operationData: Set?) {
+ ApplicationManager.getApplication()!!.runWriteAction {
+ project.getElementsToShorten(false)?.let { bindRequests ->
+ project.putUserData(ELEMENTS_TO_SHORTEN_KEY, null)
+ ShortenReferences.process(
+ bindRequests
+ .map() { req -> req.process()?.getOutermostNonInterleavingQualifiedElement() }
+ .filterNotNull()
+ )
+ }
+ }
+ }
+}
+
+private val ELEMENTS_TO_SHORTEN_KEY = Key.create>("ELEMENTS_TO_SHORTEN_KEY")
+
+class ReferenceBindRequest(val refExpression: SmartPsiElementPointer, val fqName: FqName) {
+ fun process(): JetSimpleNameExpression? {
+ fun bindToFqName(expression: JetSimpleNameExpression, fqName: FqName): JetSimpleNameExpression {
+ val qualifier = expression.changeQualifiedName(fqName)
+ val newExpression = qualifier.getQualifiedElementSelector() as JetSimpleNameExpression?
+ assert(newExpression != null) { "No selector in qualified element" }
+
+ return newExpression!!
+ }
+
+ val originalExpression = refExpression.getElement()
+ if (originalExpression == null) return null
+
+ return bindToFqName(originalExpression, fqName)
+ }
+
+}
+
+private fun Project.getElementsToShorten(createIfNeeded: Boolean): MutableSet? {
+ var elementsToShorten = getUserData(ELEMENTS_TO_SHORTEN_KEY)
+ if (createIfNeeded && elementsToShorten == null) {
+ elementsToShorten = HashSet()
+ putUserData(ELEMENTS_TO_SHORTEN_KEY, elementsToShorten)
+ }
+
+ return elementsToShorten
+}
+
+public fun Project.addReferenceBindRequest(request: ReferenceBindRequest) {
+ assert (ApplicationManager.getApplication()!!.isWriteAccessAllowed(), "Write access needed")
+ getElementsToShorten(true)!!.add(request)
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/jetRefactoringUtil.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/jetRefactoringUtil.kt
new file mode 100644
index 00000000000..01e7bba7624
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/refactoring/jetRefactoringUtil.kt
@@ -0,0 +1,51 @@
+/*
+ * 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.refactoring
+
+import org.jetbrains.jet.lang.psi.JetSimpleNameExpression
+import org.jetbrains.jet.lang.resolve.name.FqName
+import org.jetbrains.jet.lang.psi.JetElement
+import org.jetbrains.jet.lang.psi.JetCallExpression
+import org.jetbrains.jet.lang.psi.JetPsiFactory
+import org.jetbrains.jet.lang.psi.psiUtil.getQualifiedElement
+import org.jetbrains.jet.lang.psi.JetUserType
+import org.jetbrains.jet.lang.resolve.name.isOneSegmentFQN
+
+/**
+ * Replace [[JetSimpleNameExpression]] (and its enclosing qualifier) with qualified element given by FqName
+ * Result is either the same as original element, or [[JetQualifiedExpression]], or [[JetUserType]]
+ * Note that FqName may not be empty
+ */
+fun JetSimpleNameExpression.changeQualifiedName(fqName: FqName): JetElement {
+ assert (!fqName.isRoot(), "Can't set empty FqName for element $this")
+
+ val project = getProject()
+
+ val shortName = fqName.shortName().asString()
+ val fqNameBase = (getParent() as? JetCallExpression)?.let { parent ->
+ val callCopy = parent.copy() as JetCallExpression
+ callCopy.getCalleeExpression()!!.replace(JetPsiFactory.createSimpleName(project, shortName)).getParent()!!.getText()
+ } ?: shortName
+
+ val text = if (!fqName.isOneSegmentFQN()) "${fqName.parent().asString()}.$fqNameBase" else fqNameBase
+
+ val elementToReplace = getQualifiedElement()
+ return when (elementToReplace) {
+ is JetUserType -> elementToReplace.replace(JetPsiFactory.createType(project, text).getTypeElement()!!)
+ else -> elementToReplace.replace(JetPsiFactory.createExpression(project, text))
+ } as JetElement
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java b/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java
index 98112b99c96..866198ae0e9 100644
--- a/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java
+++ b/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java
@@ -19,15 +19,19 @@ package org.jetbrains.jet.plugin.references;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
+import com.intellij.psi.SmartPointerManager;
import com.intellij.psi.tree.IElementType;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetPsiFactory;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
+import org.jetbrains.jet.lang.psi.psiUtil.PsiUtilPackage;
+import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lexer.JetTokens;
+import org.jetbrains.jet.plugin.codeInsight.CodeInsightPackage;
+import org.jetbrains.jet.plugin.codeInsight.ReferenceBindRequest;
public class JetSimpleNameReference extends JetSimpleReference {
-
public JetSimpleNameReference(@NotNull JetSimpleNameExpression jetSimpleNameExpression) {
super(jetSimpleNameExpression);
}
@@ -55,6 +59,35 @@ public class JetSimpleNameReference extends JetSimpleReference