Compare commits

...

13 Commits

Author SHA1 Message Date
Alexey Sedunov
4f411f2abe Introduce Type Parameter
#KT-13155 Fixed
2016-07-26 19:27:45 +03:00
Alexey Sedunov
9de9928837 Introduce Type Alias: Allow adding/removing alias parameters 2016-07-26 19:27:44 +03:00
Alexey Sedunov
88dc0e3b76 Create from Usage: Implement "Create type parameter" quickfix
#KT-11525 Fixed
2016-07-26 19:27:43 +03:00
Alexey Sedunov
82324130be Create from Usage: Implement "Create type alias" quickfix
#KT-12904 Fixed
2016-07-26 19:27:42 +03:00
Alexey Sedunov
0fdcdff24c Quick Fixes: Use simple name in "Change function return type" quickfix 2016-07-26 19:27:41 +03:00
Alexey Sedunov
fbd7f9935f Override/Implement Members: Support "Copy JavaDoc" options for library classes
#KT-12997 Fixed
2016-07-26 19:27:41 +03:00
Alexey Sedunov
38c09653b9 Introduce Variable: Skip leading/trailing comments inside selection
#KT-13054 Fixed
2016-07-26 19:27:40 +03:00
Alexey Sedunov
a77a7696d8 Introduce Variable: Retain entered name after changing "Specify type explicitly" option
#KT-13128 Fixed
2016-07-26 19:27:39 +03:00
Alexey Sedunov
9076fa223a Extract Function: Extract Function: Fix generation of destructuring declarations
#KT-13010 Fixed
2016-07-26 19:27:38 +03:00
Alexey Sedunov
88500aaa73 Extract Function/Parameter/Type Alias: Automatically quote declaration name when necessary
#KT-13157 Fixed
2016-07-26 19:27:37 +03:00
Alexey Sedunov
2faf4b9866 Presentation: Render function signature in RefactoringDescriptionLocation
#KT-12943 Fixed
2016-07-26 19:27:37 +03:00
Alexey Sedunov
0ef2b38b09 Introduce Variable: Do not suggest expressions without type
#KT-12922 Fixed
2016-07-26 19:27:36 +03:00
Alexey Sedunov
7efb895757 Rename: Fix function description in super method warning dialog
#KT-12945 Fixed
2016-07-26 19:27:35 +03:00
144 changed files with 1459 additions and 219 deletions

View File

@@ -10,6 +10,7 @@
###### New features
- [`KT-12903`](https://youtrack.jetbrains.com/issue/KT-12903) Implement "Inline type alias" refactoring
- [`KT-12902`](https://youtrack.jetbrains.com/issue/KT-12902) Implement "Introduce type alias" refactoring
- [`KT-12904`](https://youtrack.jetbrains.com/issue/KT-12904) Implement "Create type alias from usage" quick fix
## 1.1-M01 (EAP-1)
@@ -152,6 +153,7 @@ These artifacts include extensions for the types available in the latter JDKs, s
- [`KT-13084`](https://youtrack.jetbrains.com/issue/KT-13084) Run test method action executes all tests from same kotlin file
- [`KT-12718`](https://youtrack.jetbrains.com/issue/KT-12718) Deadlock due to index reentering
- [`KT-13114`](https://youtrack.jetbrains.com/issue/KT-13114) 'Unused declaration' option 'JUnit static methods' is always enabled
- [`KT-12997`](https://youtrack.jetbrains.com/issue/KT-12997) Override/Implement Members: Support "Copy JavaDoc" options for library classes
#### Highlighting
@@ -183,6 +185,7 @@ These artifacts include extensions for the types available in the latter JDKs, s
- [`KT-13055`](https://youtrack.jetbrains.com/issue/KT-13055) Exception in "Specify Type Explicitly" intention
- [`KT-12942`](https://youtrack.jetbrains.com/issue/KT-12942) "Replace 'when' with 'if'" intention changes semantics when 'if' statements are used
- [`KT-12646`](https://youtrack.jetbrains.com/issue/KT-12646) 'Convert to block body' should use partial body resolve
- [`KT-12919`](https://youtrack.jetbrains.com/issue/KT-12919) Use simple name in "Change function return type" quickfix
##### New features
@@ -195,6 +198,7 @@ These artifacts include extensions for the types available in the latter JDKs, s
- [`KT-10668`](https://youtrack.jetbrains.com/issue/KT-10668) Support "Create member/extension" corresponding to the extension receiver of enclosing function
- [`KT-12553`](https://youtrack.jetbrains.com/issue/KT-12553) Show versions in inspection about different version of Kotlin plugin in Maven and IDE plugin
- [`KT-12730`](https://youtrack.jetbrains.com/issue/KT-12730) Warn about using different versions of Kotlin Gradle plugin and bundled compiler
- [`KT-11525`](https://youtrack.jetbrains.com/issue/KT-11525) Implement "Create type parameter" quickfix
#### Refactorings
@@ -203,10 +207,18 @@ These artifacts include extensions for the types available in the latter JDKs, s
- [`KT-12413`](https://youtrack.jetbrains.com/issue/KT-12413) Change Signature: Fix bogus warning about unresolved type parameters/invalid functional type replacement
- [`KT-12084`](https://youtrack.jetbrains.com/issue/KT-12084) Introduce Property: Do not skip outer classes if extractable expression is contained in object literal
- [`KT-13082`](https://youtrack.jetbrains.com/issue/KT-13082) Rename: Fix exception on property rename preview
- [`KT-12945`](https://youtrack.jetbrains.com/issue/KT-12945) Rename: Fix function description in super method warning dialog
- [`KT-12922`](https://youtrack.jetbrains.com/issue/KT-12922) Introduce Variable: Do not suggest expressions without type
- [`KT-12943`](https://youtrack.jetbrains.com/issue/KT-12943) Rename: Show function signatures in "Rename Overloads" dialog
- [`KT-13157`](https://youtrack.jetbrains.com/issue/KT-13157) Extract Function: Automatically quote function name if necessary
- [`KT-13010`](https://youtrack.jetbrains.com/issue/KT-13010) Extract Function: Fix generation of destructuring declarations
- [`KT-13128`](https://youtrack.jetbrains.com/issue/KT-13128) Introduce Variable: Retain entered name after changing "Specify type explicitly" option
- [`KT-13054`](https://youtrack.jetbrains.com/issue/KT-13054) Introduce Variable: Skip leading/trailing comments inside selection
##### New features
- [`KT-12017`](https://youtrack.jetbrains.com/issue/KT-12017) Inline Property: Support "Do not show this dialog" and "Inline this occurrence" options
- [`KT-13155`](https://youtrack.jetbrains.com/issue/KT-13155) Implement "Introduce Type Parameter" refactoring
#### Debugger

View File

@@ -18,18 +18,21 @@ package org.jetbrains.kotlin.psi
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiWhiteSpace
import org.jetbrains.kotlin.lexer.KtToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.psiUtil.siblings
object EditCommaSeparatedListHelper {
fun <TItem: KtElement> addItem(list: KtElement, allItems: List<TItem>, item: TItem): TItem {
return addItemBefore(list, allItems, item, null)
@JvmOverloads
fun <TItem: KtElement> addItem(list: KtElement, allItems: List<TItem>, item: TItem, prefix: KtToken = KtTokens.LPAR): TItem {
return addItemBefore(list, allItems, item, null, prefix)
}
fun <TItem: KtElement> addItemAfter(list: KtElement, allItems: List<TItem>, item: TItem, anchor: TItem?): TItem {
@JvmOverloads
fun <TItem: KtElement> addItemAfter(list: KtElement, allItems: List<TItem>, item: TItem, anchor: TItem?, prefix: KtToken = KtTokens.LPAR): TItem {
assert(anchor == null || anchor.parent == list)
if (allItems.isEmpty()) {
if (list.firstChild.node.elementType == KtTokens.LPAR) {
if (list.firstChild.node.elementType == prefix) {
return list.addAfter(item, list.firstChild) as TItem
}
else {
@@ -49,7 +52,8 @@ object EditCommaSeparatedListHelper {
}
}
fun <TItem: KtElement> addItemBefore(list: KtElement, allItems: List<TItem>, item: TItem, anchor: TItem?): TItem {
@JvmOverloads
fun <TItem: KtElement> addItemBefore(list: KtElement, allItems: List<TItem>, item: TItem, anchor: TItem?, prefix: KtToken = KtTokens.LPAR): TItem {
val anchorAfter: TItem?
if (allItems.isEmpty()) {
assert(anchor == null)
@@ -65,7 +69,7 @@ object EditCommaSeparatedListHelper {
anchorAfter = allItems.get(allItems.size - 1)
}
}
return addItemAfter(list, allItems, item, anchorAfter)
return addItemAfter(list, allItems, item, anchorAfter, prefix)
}
fun <TItem: KtElement> removeItem(item: TItem) {

View File

@@ -90,6 +90,8 @@ class KtPsiFactory(private val project: Project) {
return (property.getInitializer() as KtCallExpression).typeArgumentList!!
}
fun createTypeArgument(text: String) = createTypeArguments("<$text>").arguments.first()
fun createType(type: String): KtTypeReference {
val typeReference = createTypeIfPossible(type)
if (typeReference == null || typeReference.text != type) {
@@ -106,9 +108,12 @@ class KtPsiFactory(private val project: Project) {
}
fun createTypeAlias(name: String, typeParameters: List<String>, typeElement: KtTypeElement): KtTypeAlias {
return createTypeAlias(name, typeParameters, "X").apply { getTypeReference()!!.replace(createType(typeElement)) }
}
fun createTypeAlias(name: String, typeParameters: List<String>, body: String): KtTypeAlias {
val typeParametersText = if (typeParameters.isNotEmpty()) typeParameters.joinToString(prefix = "<", postfix = ">") else ""
return createDeclaration<KtTypeAlias>("typealias $name$typeParametersText = X")
.apply { getTypeReference()!!.replace(createType(typeElement)) }
return createDeclaration<KtTypeAlias>("typealias $name$typeParametersText = $body")
}
fun createStar(): PsiElement {
@@ -313,6 +318,10 @@ class KtPsiFactory(private val project: Project) {
return createFunction("fun foo$text{}").getValueParameterList()!!
}
fun createTypeParameterList(text: String) = createClass("class Foo$text").typeParameterList!!
fun createTypeParameter(text: String) = createTypeParameterList("<$text>").parameters.first()!!
fun createFunctionLiteralParameterList(text: String): KtParameterList {
return (createExpression("{ $text -> 0}") as KtLambdaExpression).functionLiteral.valueParameterList!!
}

View File

@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.psi;
import com.intellij.lang.ASTNode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.psi.stubs.KotlinPlaceHolderStub;
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes;
@@ -43,7 +44,7 @@ public class KtTypeArgumentList extends KtElementImplStub<KotlinPlaceHolderStub<
}
@NotNull
public KtTypeProjection addArgument(@NotNull KtTypeProjection argument) {
return EditCommaSeparatedListHelper.INSTANCE.addItem(this, getArguments(), argument);
public KtTypeProjection addArgument(@NotNull KtTypeProjection typeArgument) {
return EditCommaSeparatedListHelper.INSTANCE.addItem(this, getArguments(), typeArgument, KtTokens.LT);
}
}

View File

@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.psi;
import com.intellij.lang.ASTNode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.psi.stubs.KotlinPlaceHolderStub;
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes;
@@ -37,6 +38,11 @@ public class KtTypeParameterList extends KtElementImplStub<KotlinPlaceHolderStub
return getStubOrPsiChildrenAsList(KtStubElementTypes.TYPE_PARAMETER);
}
@NotNull
public KtTypeParameter addParameter(@NotNull KtTypeParameter typeParameter) {
return EditCommaSeparatedListHelper.INSTANCE.addItem(this, getParameters(), typeParameter, KtTokens.LT);
}
@Override
public <R, D> R accept(@NotNull KtVisitor<R, D> visitor, D data) {
return visitor.visitTypeParameterList(this, data);

View File

@@ -32,7 +32,9 @@ import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.utils.takeSnapshot
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.noTypeInfo
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice
operator fun <K, V: Any> BindingContext.get(slice: ReadOnlySlice<K, V>, key: K): V? = get(slice, key)
@@ -95,4 +97,19 @@ fun KtExpression.isUnreachableCode(context: BindingContext): Boolean = context[B
fun KtExpression.getReferenceTargets(context: BindingContext): Collection<DeclarationDescriptor> {
val targetDescriptor = if (this is KtReferenceExpression) context[BindingContext.REFERENCE_TARGET, this] else null
return targetDescriptor?.let { listOf(it) } ?: context[BindingContext.AMBIGUOUS_REFERENCE_TARGET, this].orEmpty()
}
fun KtTypeReference.getAbbreviatedTypeOrType(context: BindingContext) =
context[BindingContext.ABBREVIATED_TYPE, this] ?: context[BindingContext.TYPE, this]
fun KtTypeElement.getAbbreviatedTypeOrType(context: BindingContext): KotlinType? {
val parent = parent
return when (parent) {
is KtTypeReference -> parent.getAbbreviatedTypeOrType(context)
is KtNullableType -> {
val outerType = parent.getAbbreviatedTypeOrType(context)
if (this is KtNullableType) outerType else outerType?.makeNotNullable()
}
else -> null
}
}

View File

@@ -190,6 +190,7 @@ interface DescriptorRendererOptions {
var renderAccessors: Boolean
var renderDefaultAnnotationArguments: Boolean
var alwaysRenderModifiers: Boolean
var renderConstructorKeyword: Boolean
}
object ExcludedTypeAnnotations {

View File

@@ -626,10 +626,14 @@ internal class DescriptorRendererImpl(
renderVisibility(constructor.visibility, builder)
renderMemberKind(constructor, builder)
builder.append(renderKeyword("constructor"))
if (renderConstructorKeyword) {
builder.append(renderKeyword("constructor"))
}
if (secondaryConstructorsAsPrimary) {
val classDescriptor = constructor.containingDeclaration
builder.append(" ")
if (renderConstructorKeyword) {
builder.append(" ")
}
renderName(classDescriptor, builder)
renderTypeParameters(constructor.typeParameters, builder, false)
}

View File

@@ -97,4 +97,6 @@ internal class DescriptorRendererOptionsImpl : DescriptorRendererOptions {
+ ExcludedTypeAnnotations.internalAnnotationsForResolve)
override var alwaysRenderModifiers by property(false)
override var renderConstructorKeyword by property(true)
}

View File

@@ -771,6 +771,7 @@ fun main(args: Array<String>) {
model("refactoring/introduceParameter", pattern = kotlinFileOrScript, testMethod = "doIntroduceSimpleParameterTest")
model("refactoring/introduceLambdaParameter", pattern = kotlinFileOrScript, testMethod = "doIntroduceLambdaParameterTest")
model("refactoring/introduceJavaParameter", extension = "java", testMethod = "doIntroduceJavaParameterTest")
model("refactoring/introduceTypeParameter", pattern = kotlinFileOrScript, testMethod = "doIntroduceTypeParameterTest")
model("refactoring/introduceTypeAlias", pattern = kotlinFileOrScript, testMethod = "doIntroduceTypeAliasTest")
}

View File

@@ -104,7 +104,7 @@ fun OverrideMemberChooserObject.generateMember(project: Project, copyDoc: Boolea
}
if (copyDoc) {
val superDeclaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptor)
val superDeclaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptor)?.navigationElement
val kDoc = when (superDeclaration) {
is KtDeclaration ->
findDocComment(superDeclaration)

View File

@@ -271,4 +271,18 @@ fun dropEnclosingParenthesesIfPossible(expression: KtExpression): KtExpression {
val parent = expression.parent as? KtParenthesizedExpression ?: return expression
if (!KtPsiUtil.areParenthesesUseless(parent)) return expression
return parent.replaced(expression)
}
fun KtTypeParameterListOwner.addTypeParameter(typeParameter: KtTypeParameter): KtTypeParameter? {
typeParameterList?.let { return it.addParameter(typeParameter) }
val list = KtPsiFactory(this).createTypeParameterList("<X>")
list.parameters[0].replace(typeParameter)
val leftAnchor = when (this) {
is KtClass -> nameIdentifier ?: getClassOrInterfaceKeyword()
is KtNamedFunction -> funKeyword
is KtProperty -> valOrVarKeyword
else -> null
} ?: return null
return (addAfter(list, leftAnchor) as KtTypeParameterList).parameters.first()
}

View File

@@ -157,10 +157,16 @@
<add-to-group group-id="IntroduceActionsGroup" anchor="after" relative-to-action="ExtractFunction"/>
</action>
<action id="IntroduceTypeParameter" class="org.jetbrains.kotlin.idea.refactoring.introduce.introduceTypeParameter.IntroduceTypeParameterAction"
text="T_ype Parameter...">
<keyboard-shortcut keymap="$default" first-keystroke="control alt shift Y"/>
<add-to-group group-id="IntroduceActionsGroup" anchor="after" relative-to-action="ExtractFunctionToScope"/>
</action>
<action id="IntroduceTypeAlias" class="org.jetbrains.kotlin.idea.refactoring.introduce.introduceTypeAlias.IntroduceTypeAliasAction"
text="Type _Alias...">
<keyboard-shortcut keymap="$default" first-keystroke="control alt shift A"/>
<add-to-group group-id="IntroduceActionsGroup" anchor="after" relative-to-action="ExtractFunctionToScope"/>
<add-to-group group-id="IntroduceActionsGroup" anchor="after" relative-to-action="IntroduceTypeParameter"/>
</action>
<!-- Kotlin Console REPL-->

View File

@@ -242,7 +242,7 @@ public class CodeInsightUtils {
@Nullable
public static PsiElement getElementAtOffsetIgnoreWhitespaceBefore(@NotNull PsiFile file, int offset) {
PsiElement element = file.findElementAt(offset);
if (element instanceof PsiWhiteSpace) {
if (element instanceof PsiWhiteSpace || element instanceof PsiComment) {
return file.findElementAt(element.getTextRange().getEndOffset());
}
return element;
@@ -251,7 +251,7 @@ public class CodeInsightUtils {
@Nullable
public static PsiElement getElementAtOffsetIgnoreWhitespaceAfter(@NotNull PsiFile file, int offset) {
PsiElement element = file.findElementAt(offset - 1);
if (element instanceof PsiWhiteSpace) {
if (element instanceof PsiWhiteSpace || element instanceof PsiComment) {
return file.findElementAt(element.getTextRange().getStartOffset() - 1);
}
return element;

View File

@@ -28,16 +28,24 @@ import com.intellij.usageView.UsageViewShortNameLocation
import com.intellij.usageView.UsageViewTypeLocation
import org.jetbrains.kotlin.asJava.KtLightClassForFacade
import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.refactoring.rename.RenameJavaSyntheticPropertyHandler
import org.jetbrains.kotlin.idea.refactoring.rename.RenameKotlinPropertyProcessor
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
class KotlinElementDescriptionProvider : ElementDescriptionProvider {
companion object {
val REFACTORING_RENDERER = DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES.withOptions {
withoutReturnType = true
renderConstructorKeyword = false
}
}
override fun getElementDescription(element: PsiElement, location: ElementDescriptionLocation): String? {
val shouldUnwrap = location !is UsageViewShortNameLocation && location !is UsageViewLongNameLocation
val targetElement = if (shouldUnwrap) element.unwrapped ?: element else element
@@ -57,34 +65,31 @@ class KotlinElementDescriptionProvider : ElementDescriptionProvider {
else -> null
}
fun targetDescriptor(): DeclarationDescriptor? {
val descriptor = (targetElement as KtDeclaration).descriptor ?: return null
if (descriptor is ConstructorDescriptor) {
return descriptor.containingDeclaration
}
return descriptor
}
if (targetElement !is PsiNamedElement || targetElement.language != KotlinLanguage.INSTANCE) return null
return when(location) {
is UsageViewTypeLocation -> elementKind()
is UsageViewShortNameLocation, is UsageViewLongNameLocation -> targetElement.name
is RefactoringDescriptionLocation -> {
val kind = elementKind() ?: return null
val descriptor = targetDescriptor() ?: return null
val desc =
if (location.includeParent() && targetElement !is KtTypeParameter && targetElement !is KtParameter) {
DescriptorUtils.getFqName(descriptor).asString()
}
else {
descriptor.name.asString()
}
val descriptor = (targetElement as KtDeclaration).descriptor ?: return null
val renderFqName = location.includeParent() &&
targetElement !is KtTypeParameter &&
targetElement !is KtParameter &&
targetElement !is KtConstructor<*>
val desc = when (descriptor) {
is FunctionDescriptor -> {
val baseText = REFACTORING_RENDERER.render(descriptor)
val parentFqName = if (renderFqName) descriptor.containingDeclaration.fqNameSafe else null
if (parentFqName?.isRoot ?: true) baseText else "${parentFqName!!.asString()}.$baseText"
}
else -> if (renderFqName) DescriptorUtils.getFqName(descriptor).asString() else descriptor.name.asString()
}
"$kind ${CommonRefactoringUtil.htmlEmphasize(desc)}"
}
is HighlightUsagesDescriptionLocation -> {
val kind = elementKind() ?: return null
val descriptor = targetDescriptor() ?: return null
val descriptor = (targetElement as KtDeclaration).descriptor ?: return null
"$kind ${descriptor.name.asString()}"
}
else -> null

View File

@@ -22,6 +22,7 @@ import com.intellij.psi.PsiDirectory
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiPackage
import org.jetbrains.kotlin.asJava.KtLightElement
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
@@ -78,6 +79,7 @@ class KotlinFindUsagesProvider : FindUsagesProvider {
val funDescription = "$name$paramsDescription" + (returnTypeDescription?.let { ": $it" } ?: "")
return funDescription + (element.containerDescription?.let { " of $it" } ?: "")
}
is KtLightElement<*, *> -> element.kotlinOrigin?.let { getDescriptiveName(it) } ?: ""
else -> ""
}
}

View File

@@ -22,11 +22,13 @@ import com.intellij.openapi.util.TextRange
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.psi.KtCallElement
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.KtTypeArgumentList
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.ErrorUtils
class InsertExplicitTypeArgumentsIntention : SelfTargetingRangeIntention<KtCallExpression>(KtCallExpression::class.java, "Add explicit type arguments"), LowPriorityAction {
@@ -34,17 +36,10 @@ class InsertExplicitTypeArgumentsIntention : SelfTargetingRangeIntention<KtCallE
return if (isApplicableTo(element, element.analyze())) element.calleeExpression!!.textRange else null
}
override fun applyTo(element: KtCallExpression, editor: Editor?) {
val argumentList = createTypeArguments(element, element.analyze())!!
val callee = element.calleeExpression!!
val newArgumentList = element.addAfter(argumentList, callee) as KtTypeArgumentList
ShortenReferences.DEFAULT.process(newArgumentList)
}
override fun applyTo(element: KtCallExpression, editor: Editor?) = applyTo(element)
companion object {
fun isApplicableTo(element: KtCallExpression, bindingContext: BindingContext): Boolean {
fun isApplicableTo(element: KtCallElement, bindingContext: BindingContext = element.analyze(BodyResolveMode.PARTIAL)): Boolean {
if (!element.typeArguments.isEmpty()) return false
if (element.calleeExpression == null) return false
@@ -53,7 +48,18 @@ class InsertExplicitTypeArgumentsIntention : SelfTargetingRangeIntention<KtCallE
return typeArgs.isNotEmpty() && typeArgs.values.none { ErrorUtils.containsErrorType(it) }
}
fun createTypeArguments(element: KtCallExpression, bindingContext: BindingContext): KtTypeArgumentList? {
fun applyTo(element: KtCallElement, shortenReferences: Boolean = true) {
val argumentList = createTypeArguments(element, element.analyze())!!
val callee = element.calleeExpression!!
val newArgumentList = element.addAfter(argumentList, callee) as KtTypeArgumentList
if (shortenReferences) {
ShortenReferences.DEFAULT.process(newArgumentList)
}
}
fun createTypeArguments(element: KtCallElement, bindingContext: BindingContext): KtTypeArgumentList? {
val resolvedCall = element.getResolvedCall(bindingContext) ?: return null
val args = resolvedCall.typeArguments

View File

@@ -68,7 +68,7 @@ class ChangeFunctionReturnTypeFix(element: KtFunction, type: KotlinType) : Kotli
return changeFunctionLiteralReturnTypeFix.text
}
val functionName = element.fqName?.asString() ?: element.name
val functionName = element.name
if (isUnitType && element.hasBlockBody()) {
return if (functionName == null)

View File

@@ -47,7 +47,7 @@ abstract class KotlinSingleIntentionActionFactoryWithDelegate<E : KtElement, D :
}
abstract class KotlinIntentionActionFactoryWithDelegate<E : KtElement, D : Any> : KotlinIntentionActionsFactory() {
protected abstract fun getElementOfInterest(diagnostic: Diagnostic): E?
abstract fun getElementOfInterest(diagnostic: Diagnostic): E?
protected abstract fun createFixes(
originalElementPointer: SmartPsiElementPointer<E>,
@@ -55,7 +55,7 @@ abstract class KotlinIntentionActionFactoryWithDelegate<E : KtElement, D : Any>
quickFixDataFactory: () -> D?
): List<QuickFixWithDelegateFactory>
protected abstract fun extractFixData(element: E, diagnostic: Diagnostic): D?
abstract fun extractFixData(element: E, diagnostic: Diagnostic): D?
override final fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction> {
val diagnosticMessage = DefaultErrorMessages.render(diagnostic)

View File

@@ -28,6 +28,8 @@ import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.CreateClas
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.CreateClassFromConstructorCallActionFactory
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.CreateClassFromReferenceExpressionActionFactory
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.CreateClassFromTypeReferenceActionFactory
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createTypeAlias.CreateTypeAliasFromTypeReferenceActionFactory
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createTypeParameter.CreateTypeParameterByRefActionFactory
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable.CreateLocalVariableActionFactory
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable.CreateParameterByNamedArgumentActionFactory
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable.CreateParameterByRefActionFactory
@@ -332,10 +334,15 @@ class QuickFixRegistrar : QuickFixContributor {
DELEGATE_SPECIAL_FUNCTION_MISSING.registerFactory(CreatePropertyDelegateAccessorsActionFactory)
DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE.registerFactory(CreatePropertyDelegateAccessorsActionFactory)
UNRESOLVED_REFERENCE.registerFactory(CreateClassFromTypeReferenceActionFactory,
CreateClassFromReferenceExpressionActionFactory,
CreateClassFromCallWithConstructorCalleeActionFactory,
PlatformUnresolvedProvider)
UNRESOLVED_REFERENCE.registerFactory(
CreateClassFromTypeReferenceActionFactory,
CreateClassFromReferenceExpressionActionFactory,
CreateClassFromCallWithConstructorCalleeActionFactory
)
UNRESOLVED_REFERENCE.registerFactory(CreateTypeAliasFromTypeReferenceActionFactory)
UNRESOLVED_REFERENCE.registerFactory(PlatformUnresolvedProvider)
PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED.registerFactory(InsertDelegationCallQuickfix.InsertThisDelegationCallFactory)
@@ -399,5 +406,7 @@ class QuickFixRegistrar : QuickFixContributor {
UNUSED_LAMBDA_EXPRESSION.registerFactory(AddRunToLambdaFix)
WRONG_LONG_SUFFIX.registerFactory(WrongLongSuffixFix)
UNRESOLVED_REFERENCE.registerFactory(CreateTypeParameterByRefActionFactory)
}
}

View File

@@ -74,7 +74,6 @@ import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
import java.util.*
import kotlin.properties.Delegates
/**
* Represents a single choice for a type (e.g. parameter type or return type).
@@ -507,86 +506,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
return assignmentToReplace.replace(declaration) as KtCallableDeclaration
}
val newLine = psiFactory.createNewLine()
fun calcNecessaryEmptyLines(decl: KtDeclaration, after: Boolean): Int {
var lineBreaksPresent: Int = 0
var neighbor: PsiElement? = null
siblingsLoop@
for (sibling in decl.siblings(forward = after, withItself = false)) {
when (sibling) {
is PsiWhiteSpace -> lineBreaksPresent += (sibling.text ?: "").count { it == '\n' }
else -> {
neighbor = sibling
break@siblingsLoop
}
}
}
val neighborType = neighbor?.node?.elementType
val lineBreaksNeeded = when {
neighborType == KtTokens.LBRACE || neighborType == KtTokens.RBRACE -> 1
neighbor is KtDeclaration && (neighbor !is KtProperty || decl !is KtProperty) -> 2
else -> 1
}
return Math.max(lineBreaksNeeded - lineBreaksPresent, 0)
}
val actualContainer = (containingElement as? KtClassOrObject)?.getOrCreateBody() ?: containingElement
fun addNextToOriginalElementContainer(addBefore: Boolean): KtNamedDeclaration {
val sibling = config.originalElement.parentsWithSelf.first { it.parent == actualContainer }
return if (addBefore) {
actualContainer.addBefore(declaration, sibling)
}
else {
actualContainer.addAfter(declaration, sibling)
} as KtNamedDeclaration
}
val declarationInPlace = when {
actualContainer.isAncestor(config.originalElement, true) -> {
val insertToBlock = containingElement is KtBlockExpression
if (insertToBlock) {
val parent = containingElement.parent
if (parent is KtFunctionLiteral) {
if (!parent.isMultiLine()) {
parent.addBefore(newLine, containingElement)
parent.addAfter(newLine, containingElement)
}
}
}
addNextToOriginalElementContainer(insertToBlock || declaration is KtProperty)
}
containingElement is KtFile -> containingElement.add(declaration) as KtNamedDeclaration
containingElement is PsiClass -> {
if (declaration is KtSecondaryConstructor) {
val wrappingClass = psiFactory.createClass("class ${containingElement.name} {\n}")
addDeclarationToClassOrObject(wrappingClass, declaration)
(jetFileToEdit.add(wrappingClass) as KtClass).declarations.first() as KtNamedDeclaration
}
else {
jetFileToEdit.add(declaration) as KtNamedDeclaration
}
}
containingElement is KtClassOrObject -> {
insertMember(null, containingElement, declaration, containingElement.declarations.lastOrNull())
}
else -> throw AssertionError("Invalid containing element: ${containingElement.text}")
}
val parent = declarationInPlace.parent
calcNecessaryEmptyLines(declarationInPlace, false).let {
if (it > 0) parent.addBefore(psiFactory.createNewLine(it), declarationInPlace)
}
calcNecessaryEmptyLines(declarationInPlace, true).let {
if (it > 0) parent.addAfter(psiFactory.createNewLine(it), declarationInPlace)
}
val declarationInPlace = placeDeclarationInContainer(declaration, containingElement, config.originalElement, jetFileToEdit)
if (declarationInPlace is KtSecondaryConstructor) {
val containingClass = declarationInPlace.containingClassOrObject!!
@@ -602,19 +522,6 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
}
}
private fun addDeclarationToClassOrObject(classOrObject: KtClassOrObject,
declaration: KtNamedDeclaration): KtNamedDeclaration {
val classBody = classOrObject.getOrCreateBody()
return if (declaration is KtNamedFunction) {
val anchor = PsiTreeUtil.skipSiblingsBackward(
classBody.rBrace ?: classBody.lastChild!!,
PsiWhiteSpace::class.java
)
classBody.addAfter(declaration, anchor) as KtNamedDeclaration
}
else classBody.addAfter(declaration, classBody.lBrace!!) as KtNamedDeclaration
}
private fun getTypeParameterRenames(scope: HierarchicalScope): Map<TypeParameterDescriptor, String> {
val allTypeParametersNotInScope = LinkedHashSet<TypeParameterDescriptor>()
@@ -1030,6 +937,112 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
}
}
// TODO: Simplify and use formatter as much as possible
@Suppress("UNCHECKED_CAST")
internal fun <D : KtNamedDeclaration> placeDeclarationInContainer(
declaration: D,
container: PsiElement,
anchor: PsiElement,
fileToEdit: KtFile = container.containingFile as KtFile
): D {
val psiFactory = KtPsiFactory(container)
val newLine = psiFactory.createNewLine()
fun calcNecessaryEmptyLines(decl: KtDeclaration, after: Boolean): Int {
var lineBreaksPresent: Int = 0
var neighbor: PsiElement? = null
siblingsLoop@
for (sibling in decl.siblings(forward = after, withItself = false)) {
when (sibling) {
is PsiWhiteSpace -> lineBreaksPresent += (sibling.text ?: "").count { it == '\n' }
else -> {
neighbor = sibling
break@siblingsLoop
}
}
}
val neighborType = neighbor?.node?.elementType
val lineBreaksNeeded = when {
neighborType == KtTokens.LBRACE || neighborType == KtTokens.RBRACE -> 1
neighbor is KtDeclaration && (neighbor !is KtProperty || decl !is KtProperty) -> 2
else -> 1
}
return Math.max(lineBreaksNeeded - lineBreaksPresent, 0)
}
val actualContainer = (container as? KtClassOrObject)?.getOrCreateBody() ?: container
fun addDeclarationToClassOrObject(classOrObject: KtClassOrObject,
declaration: KtNamedDeclaration): KtNamedDeclaration {
val classBody = classOrObject.getOrCreateBody()
return if (declaration is KtNamedFunction) {
val neighbor = PsiTreeUtil.skipSiblingsBackward(
classBody.rBrace ?: classBody.lastChild!!,
PsiWhiteSpace::class.java
)
classBody.addAfter(declaration, neighbor) as KtNamedDeclaration
}
else classBody.addAfter(declaration, classBody.lBrace!!) as KtNamedDeclaration
}
fun addNextToOriginalElementContainer(addBefore: Boolean): D {
val sibling = anchor.parentsWithSelf.first { it.parent == actualContainer }
return if (addBefore) {
actualContainer.addBefore(declaration, sibling)
}
else {
actualContainer.addAfter(declaration, sibling)
} as D
}
val declarationInPlace = when {
actualContainer.isAncestor(anchor, true) -> {
val insertToBlock = container is KtBlockExpression
if (insertToBlock) {
val parent = container.parent
if (parent is KtFunctionLiteral) {
if (!parent.isMultiLine()) {
parent.addBefore(newLine, container)
parent.addAfter(newLine, container)
}
}
}
addNextToOriginalElementContainer(insertToBlock || declaration is KtProperty)
}
container is KtFile -> container.add(declaration) as D
container is PsiClass -> {
if (declaration is KtSecondaryConstructor) {
val wrappingClass = psiFactory.createClass("class ${container.name} {\n}")
addDeclarationToClassOrObject(wrappingClass, declaration)
(fileToEdit.add(wrappingClass) as KtClass).declarations.first() as D
}
else {
fileToEdit.add(declaration) as D
}
}
container is KtClassOrObject -> {
insertMember(null, container, declaration, container.declarations.lastOrNull())
}
else -> throw AssertionError("Invalid containing element: ${container.text}")
}
val parent = declarationInPlace.parent
calcNecessaryEmptyLines(declarationInPlace, false).let {
if (it > 0) parent.addBefore(psiFactory.createNewLine(it), declarationInPlace)
}
calcNecessaryEmptyLines(declarationInPlace, true).let {
if (it > 0) parent.addAfter(psiFactory.createNewLine(it), declarationInPlace)
}
return declarationInPlace
}
internal fun KtNamedDeclaration.getReturnTypeReference(): KtTypeReference? {
return when (this) {
is KtCallableDeclaration -> typeReference

View File

@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder
import com.intellij.refactoring.psi.SearchUtils
import org.jetbrains.kotlin.cfg.pseudocode.*
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
@@ -46,6 +47,10 @@ internal operator fun KotlinType.contains(inner: KotlinType): Boolean {
return KotlinTypeChecker.DEFAULT.equalTypes(this, inner) || arguments.any { inner in it.type }
}
internal operator fun KotlinType.contains(descriptor: ClassifierDescriptor): Boolean {
return constructor.declarationDescriptor == descriptor || arguments.any { descriptor in it.type }
}
private fun KotlinType.render(typeParameterNameMap: Map<TypeParameterDescriptor, String>, fq: Boolean): String {
val substitution = typeParameterNameMap
.mapValues {

View File

@@ -24,22 +24,23 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.PsiPackage
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.refactoring.canRefactor
import org.jetbrains.kotlin.idea.quickfix.DelegatingIntentionAction
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.containsStarProjections
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.guessTypes
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.noSubstitutions
import org.jetbrains.kotlin.psi.Call
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.idea.refactoring.canRefactor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.bindingContextUtil.getAbbreviatedTypeOrType
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.scopes.receivers.Qualifier
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.descriptors.ClassKind as ClassDescriptorKind
@@ -129,3 +130,21 @@ internal fun KtSimpleNameExpression.getCreatePackageFixIfApplicable(targetParent
override fun getText(): String = "Create package '$fullName'"
}
}
internal fun getUpperBoundType(ktTypeElement: KtTypeElement): KotlinType? {
val context = ktTypeElement.analyze(BodyResolveMode.PARTIAL)
val containingTypeArg = (ktTypeElement.parent as? KtTypeReference)?.parent as? KtTypeProjection ?: return null
val argumentList = containingTypeArg.parent as? KtTypeArgumentList ?: return null
val containingTypeRef = (argumentList.parent as? KtTypeElement)?.parent as? KtTypeReference ?: return null
val containingType = containingTypeRef.getAbbreviatedTypeOrType(context) ?: return null
return containingType.arguments.getOrNull(argumentList.arguments.indexOf(containingTypeArg))?.type
}
internal fun getBoundingTypeParameter(element: KtTypeElement): TypeParameterDescriptor? {
val context = element.analyze(BodyResolveMode.PARTIAL)
val containingTypeArg = (element.parent as? KtTypeReference)?.parent as? KtTypeProjection ?: return null
val argumentList = containingTypeArg.parent as? KtTypeArgumentList ?: return null
val containingTypeRef = (argumentList.parent as? KtTypeElement)?.parent as? KtTypeReference ?: return null
val containingType = containingTypeRef.getAbbreviatedTypeOrType(context) ?: return null
return containingType.constructor.parameters.getOrNull(argumentList.arguments.indexOf(containingTypeArg))
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright 2010-2016 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.idea.quickfix.createFromUsage.createTypeAlias
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.core.CollectingNameValidator
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
import org.jetbrains.kotlin.idea.core.NewDeclarationNameValidator
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.contains
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.CreateClassFromTypeReferenceActionFactory
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.getBoundingTypeParameter
import org.jetbrains.kotlin.psi.KtUserType
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch
object CreateTypeAliasFromTypeReferenceActionFactory : CreateTypeAliasFromUsageFactory<KtUserType>() {
override fun getElementOfInterest(diagnostic: Diagnostic) = CreateClassFromTypeReferenceActionFactory.getElementOfInterest(diagnostic)
override fun extractFixData(element: KtUserType, diagnostic: Diagnostic): TypeAliasInfo? {
if (element.getParentOfTypeAndBranch<KtUserType>(true) { qualifier } != null) return null
val classInfo = CreateClassFromTypeReferenceActionFactory.extractFixData(element, diagnostic) ?: return null
val boundingTypeParameter = getBoundingTypeParameter(element)
val expectedType = if (boundingTypeParameter != null) {
val upperBound = boundingTypeParameter.upperBounds.singleOrNull() ?: return null
if (boundingTypeParameter in upperBound) return null
upperBound
}
else null
val validator = CollectingNameValidator(
filter = NewDeclarationNameValidator(classInfo.targetParent, null, NewDeclarationNameValidator.Target.FUNCTIONS_AND_CLASSES)
)
val typeParameterNames = KotlinNameSuggester.suggestNamesForTypeParameters(classInfo.typeArguments.size, validator)
return TypeAliasInfo(classInfo.name, classInfo.targetParent, typeParameterNames, expectedType)
}
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright 2010-2016 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.idea.quickfix.createFromUsage.createTypeAlias
import org.jetbrains.kotlin.idea.quickfix.IntentionActionPriority
import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactoryWithDelegate
import org.jetbrains.kotlin.psi.KtElement
abstract class CreateTypeAliasFromUsageFactory<E : KtElement> :
KotlinSingleIntentionActionFactoryWithDelegate<E, TypeAliasInfo>(IntentionActionPriority.LOW) {
override fun createFix(originalElement: E, data: TypeAliasInfo) = CreateTypeAliasFromUsageFix(originalElement, data)
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright 2010-2016 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.idea.quickfix.createFromUsage.createTypeAlias
import com.intellij.codeInsight.intention.LowPriorityAction
import com.intellij.codeInsight.template.TemplateBuilderImpl
import com.intellij.codeInsight.template.impl.ConstantNode
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.intentions.ChooseStringExpression
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.CreateFromUsageFixBase
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.placeDeclarationInContainer
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.types.KotlinType
class TypeAliasInfo(
val name: String,
val targetParent: PsiElement,
val typeParameterNames: List<String>,
val expectedType: KotlinType?
)
class CreateTypeAliasFromUsageFix<E : KtElement>(
element: E,
val aliasInfo: TypeAliasInfo
) : CreateFromUsageFixBase<E>(element), LowPriorityAction {
override fun getText() = "Create type alias '${aliasInfo.name}'"
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
if (editor == null) return
val typeAliasProto = KtPsiFactory(project).createTypeAlias(aliasInfo.name, aliasInfo.typeParameterNames, "Dummy")
val typeAlias = placeDeclarationInContainer(typeAliasProto, aliasInfo.targetParent, element)
if (!ApplicationManager.getApplication().isUnitTestMode) {
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.document)
val aliasBody = typeAlias.getTypeReference()!!
with(TemplateBuilderImpl(typeAlias)) {
for ((typeParameter, typeParameterName) in (typeAlias.typeParameters zip aliasInfo.typeParameterNames)) {
replaceElement(typeParameter, ChooseStringExpression(listOf(typeParameterName)))
}
val defaultBodyText = aliasInfo.expectedType?.let { IdeDescriptorRenderers.SOURCE_CODE.renderType(it) } ?: ""
replaceElement(aliasBody, ConstantNode(defaultBodyText))
run(editor, true)
}
}
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2010-2016 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.idea.quickfix.createFromUsage.createTypeParameter
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactoryWithDelegate
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.getUpperBoundType
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch
import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.kotlin.types.KotlinType
data class CreateTypeParameterData(
val name: String,
val declaration: KtTypeParameterListOwner,
val upperBoundType: KotlinType?
)
object CreateTypeParameterByRefActionFactory : KotlinSingleIntentionActionFactoryWithDelegate<KtUserType, CreateTypeParameterData>() {
override fun getElementOfInterest(diagnostic: Diagnostic): KtUserType? {
val ktUserType = diagnostic.psiElement.getParentOfTypeAndBranch<KtUserType> { referenceExpression } ?: return null
if (ktUserType.qualifier != null) return null
if (ktUserType.getParentOfTypeAndBranch<KtUserType>(true) { qualifier } != null) return null
if (ktUserType.typeArgumentList != null) return null
return ktUserType
}
override fun extractFixData(element: KtUserType, diagnostic: Diagnostic): CreateTypeParameterData? {
val name = element.referencedName ?: return null
val declaration = element.parents.firstOrNull {
it is KtProperty || it is KtNamedFunction || it is KtClass
} as? KtTypeParameterListOwner ?: return null
val upperBoundType = getUpperBoundType(element)
return CreateTypeParameterData(name, declaration, upperBoundType)
}
override fun createFix(originalElement: KtUserType, data: CreateTypeParameterData) = CreateTypeParameterFromUsageFix(originalElement, data)
}

View File

@@ -0,0 +1,126 @@
/*
* Copyright 2010-2016 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.idea.quickfix.createFromUsage.createTypeParameter
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.search.searches.ReferencesSearch
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.idea.core.addTypeParameter
import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.intentions.InsertExplicitTypeArgumentsIntention
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.CreateFromUsageFixBase
import org.jetbrains.kotlin.idea.refactoring.runSynchronouslyWithProgress
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.typeUtil.isNullableAny
import org.jetbrains.kotlin.utils.SmartList
class CreateTypeParameterFromUsageFix(
originalElement: KtTypeElement,
private val data: CreateTypeParameterData
) : CreateFromUsageFixBase<KtTypeElement>(originalElement) {
override fun getText() = "Create type parameter '${data.name}'"
override fun startInWriteAction() = false
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
doInvoke()
}
fun doInvoke(): KtTypeParameter? {
val declaration = data.declaration
val project = declaration.project
val usages = project.runSynchronouslyWithProgress("Searching ${declaration.name}...", true) {
runReadAction {
ReferencesSearch
.search(declaration)
.mapNotNull {
it.element.getParentOfTypeAndBranch<KtUserType> { referenceExpression } ?:
it.element.getParentOfTypeAndBranch<KtCallElement> { calleeExpression }
}
.toSet()
}
} ?: return null
return runWriteAction {
val psiFactory = KtPsiFactory(project)
val elementsToShorten = SmartList<KtElement>()
val upperBoundType = data.upperBoundType
val upperBoundText = if (upperBoundType != null && !upperBoundType.isNullableAny()) {
IdeDescriptorRenderers.SOURCE_CODE.renderType(upperBoundType)
}
else null
val upperBound = upperBoundText?.let { psiFactory.createType(it) }
val newTypeParameterText = if (upperBound != null) "${data.name} : ${upperBound.text}" else data.name
val newTypeParameter = declaration.addTypeParameter(psiFactory.createTypeParameter(newTypeParameterText))!!
elementsToShorten += newTypeParameter
val callsToExplicateArguments = SmartList<KtCallElement>()
usages.forEach {
when (it) {
is KtUserType -> {
val typeArgumentList = it.typeArgumentList
if (typeArgumentList != null) {
typeArgumentList.addBefore(psiFactory.createComma(), typeArgumentList.lastChild)
}
else {
it.addAfter(psiFactory.createTypeArguments("<>"), it.referenceExpression!!)
}
}
is KtCallElement -> {
if (it.analyze(BodyResolveMode.PARTIAL).diagnostics.forElement(it.calleeExpression!!).any {
it.factory in Errors.TYPE_INFERENCE_ERRORS
}) {
callsToExplicateArguments += it
}
}
}
}
callsToExplicateArguments.forEach {
val typeArgumentList = it.typeArgumentList
if (typeArgumentList == null) {
InsertExplicitTypeArgumentsIntention.applyTo(it, shortenReferences = false)
val newTypeArgument = it.typeArguments.lastOrNull()
if (upperBound != null && newTypeArgument != null && newTypeArgument.text == "kotlin.Any") {
newTypeArgument.replaced(psiFactory.createTypeArgument(upperBound.text))
}
elementsToShorten += it.typeArgumentList
}
else {
val newTypeArgument = psiFactory.createTypeArgument(upperBoundText ?: "kotlin.Any")
elementsToShorten += typeArgumentList.addArgument(newTypeArgument)
}
}
ShortenReferences.DEFAULT.process(elementsToShorten)
newTypeParameter
}
}
}

View File

@@ -431,7 +431,7 @@ public class KotlinRefactoringUtil {
KtExpression expression = (KtExpression)element;
BindingContext bindingContext = ResolutionUtils.analyze(expression, BodyResolveMode.FULL);
KotlinType expressionType = bindingContext.getType(expression);
if (expressionType != null && KotlinBuiltIns.isUnit(expressionType)) {
if (expressionType == null || KotlinBuiltIns.isUnit(expressionType)) {
addElement = false;
}
}

View File

@@ -24,6 +24,8 @@ import com.intellij.refactoring.introduce.inplace.AbstractInplaceIntroducer
import com.intellij.refactoring.rename.inplace.InplaceRefactoring
import com.intellij.util.ui.FormBuilder
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
import org.jetbrains.kotlin.idea.core.quoteIfNeeded
import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.psi.*
@@ -62,6 +64,13 @@ abstract class AbstractKotlinInplaceIntroducer<D: KtNamedDeclaration>(
}
}
protected fun updateVariableName() {
val currentName = inputName.quoteIfNeeded()
if (KotlinNameSuggester.isIdentifier(currentName)) {
localVariable.setName(currentName)
}
}
override fun getActionName(): String? = null
override fun restoreExpression(

View File

@@ -31,6 +31,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.idea.KotlinFileType;
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester;
import org.jetbrains.kotlin.idea.core.UtilsKt;
import org.jetbrains.kotlin.idea.refactoring.KotlinRefactoringUtilKt;
import org.jetbrains.kotlin.idea.refactoring.KotlinRefactoringBundle;
import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.*;
@@ -91,7 +92,7 @@ public class KotlinExtractFunctionDialog extends DialogWrapper {
}
private String getFunctionName() {
return functionNameField.getEnteredName();
return UtilsKt.quoteIfNeeded(functionNameField.getEnteredName());
}
private String getVisibility() {

View File

@@ -270,7 +270,7 @@ private fun makeCall(
}
}
val calleeName = declaration.name
val calleeName = declaration.name?.quoteIfNeeded()
val callText = when (declaration) {
is KtNamedFunction -> {
val argumentsText = arguments.joinToString(separator = ", ", prefix = "(", postfix = ")")
@@ -300,7 +300,7 @@ private fun makeCall(
val entries = declarationsToMerge.map { p -> p.name + (p.typeReference?.let { ": ${it.text}" } ?: "") }
anchorInBlock?.replace(
psiFactory.createDeclaration("${if (isVar) "var" else "val"} (${entries.joinToString()}) = $callText")
psiFactory.createDestructuringDeclaration("${if (isVar) "var" else "val"} (${entries.joinToString()}) = $callText")
)
return

View File

@@ -27,6 +27,7 @@ import com.intellij.ui.NonFocusableCheckBox
import com.intellij.usageView.BaseUsageViewDescriptor
import com.intellij.usageView.UsageInfo
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.core.quoteIfNeeded
import org.jetbrains.kotlin.idea.refactoring.isMultiLine
import org.jetbrains.kotlin.idea.refactoring.runRefactoringWithPostprocessing
import org.jetbrains.kotlin.idea.refactoring.validateElement
@@ -230,7 +231,7 @@ class KotlinIntroduceParameterDialog private constructor(
override fun canRun() {
val psiFactory = KtPsiFactory(myProject)
psiFactory.createSimpleName(nameField.enteredName).validateElement("Invalid parameter name")
psiFactory.createSimpleName(nameField.enteredName.quoteIfNeeded()).validateElement("Invalid parameter name")
psiFactory.createType(typeField.enteredName).validateElement("Invalid parameter type")
}
@@ -256,7 +257,7 @@ class KotlinIntroduceParameterDialog private constructor(
return KtPsiFactory(myProject).createExpression(text)
}
val chosenName = nameField.enteredName
val chosenName = nameField.enteredName.quoteIfNeeded()
var chosenType = typeField.enteredName
var newArgumentValue = descriptor.newArgumentValue
var newReplacer = descriptor.occurrenceReplacer

View File

@@ -37,10 +37,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
import org.jetbrains.kotlin.idea.core.NewDeclarationNameValidator
import org.jetbrains.kotlin.idea.core.moveInsideParenthesesAndReplaceWith
import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.core.*
import org.jetbrains.kotlin.idea.refactoring.KotlinRefactoringBundle
import org.jetbrains.kotlin.idea.refactoring.changeSignature.*
import org.jetbrains.kotlin.idea.refactoring.introduce.*
@@ -179,8 +176,6 @@ fun IntroduceParameterDescriptor.performRefactoring() {
}
}
private fun isObjectOrNonInnerClass(e: PsiElement): Boolean = e is KtObjectDeclaration || (e is KtClass && !e.isInner())
fun selectNewParameterContext(
editor: Editor,
file: KtFile,
@@ -319,7 +314,7 @@ open class KotlinIntroduceParameterHandler(
originalRange = originalExpression.toRange(),
callable = targetParent,
callableDescriptor = functionDescriptor,
newParameterName = suggestedNames.first(),
newParameterName = suggestedNames.first().quoteIfNeeded(),
newParameterTypeText = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(replacementType),
argumentValue = originalExpression,
withDefaultValue = false,

View File

@@ -0,0 +1,21 @@
/*
* Copyright 2010-2016 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.idea.refactoring.introduce.introduceTypeAlias
class IntroduceTypeAliasParameterEditor(val originalDescriptor: IntroduceTypeAliasDescriptor) {
}

View File

@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.core.CollectingNameValidator
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
import org.jetbrains.kotlin.idea.core.compareDescriptors
import org.jetbrains.kotlin.idea.core.quoteIfNeeded
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.idea.util.psi.patternMatching.KotlinPsiRange
import org.jetbrains.kotlin.idea.util.psi.patternMatching.KotlinPsiUnifier
@@ -149,7 +150,7 @@ fun IntroduceTypeAliasDescriptor.validate(): IntroduceTypeAliasDescriptorWithCon
}
fun findDuplicates(typeAlias: KtTypeAlias): Map<KotlinPsiRange, () -> Unit> {
val aliasName = typeAlias.name ?: return emptyMap()
val aliasName = typeAlias.name?.quoteIfNeeded() ?: return emptyMap()
val typeAliasDescriptor = typeAlias.resolveToDescriptor() as TypeAliasDescriptor
val unifierParameters = typeAliasDescriptor.declaredTypeParameters.map { UnifierParameter(it, null) }

View File

@@ -29,6 +29,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.idea.KotlinFileType;
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester;
import org.jetbrains.kotlin.idea.core.UtilsKt;
import org.jetbrains.kotlin.idea.refactoring.KotlinRefactoringUtilKt;
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceTypeAlias.IntroduceTypeAliasDescriptor;
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceTypeAlias.IntroduceTypeAliasImplKt;
@@ -93,7 +94,7 @@ public class KotlinIntroduceTypeAliasDialog extends DialogWrapper {
}
private String getAliasName() {
return aliasNameField.getEnteredName();
return UtilsKt.quoteIfNeeded(aliasNameField.getEnteredName());
}
@Nullable

View File

@@ -0,0 +1,136 @@
/*
* Copyright 2010-2016 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.idea.refactoring.introduce.introduceTypeParameter
import com.intellij.lang.refactoring.RefactoringSupportProvider
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.refactoring.RefactoringActionHandler
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createTypeParameter.CreateTypeParameterData
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createTypeParameter.CreateTypeParameterFromUsageFix
import org.jetbrains.kotlin.idea.refactoring.introduce.AbstractIntroduceAction
import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.processDuplicates
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceTypeAlias.KotlinIntroduceTypeAliasHandler
import org.jetbrains.kotlin.idea.refactoring.introduce.isObjectOrNonInnerClass
import org.jetbrains.kotlin.idea.refactoring.introduce.selectElementsWithTargetParent
import org.jetbrains.kotlin.idea.refactoring.introduce.showErrorHint
import org.jetbrains.kotlin.idea.util.application.executeCommand
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.idea.util.psi.patternMatching.KotlinPsiUnifier
import org.jetbrains.kotlin.idea.util.psi.patternMatching.toRange
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.kotlin.resolve.bindingContextUtil.getAbbreviatedTypeOrType
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier
import org.jetbrains.kotlin.utils.keysToMap
object KotlinIntroduceTypeParameterHandler : RefactoringActionHandler {
@JvmField
val REFACTORING_NAME = "Introduce Type Parameter"
fun selectElements(editor: Editor, file: KtFile, continuation: (elements: List<PsiElement>, targetParent: PsiElement) -> Unit) {
selectElementsWithTargetParent(
REFACTORING_NAME,
editor,
file,
"Introduce type parameter to declaration",
listOf(CodeInsightUtils.ElementKind.TYPE_ELEMENT),
{ elements, parent ->
val stopAt = parent.parents.firstOrNull(::isObjectOrNonInnerClass)?.parent
(if (stopAt != null) parent.parents.takeWhile { it != stopAt } else parent.parents)
.filter {
((it is KtClass && !it.isInterface() && it !is KtEnumEntry) ||
it is KtNamedFunction ||
(it is KtProperty && !it.isLocal) ||
it is KtTypeAlias) &&
it is KtTypeParameterListOwner &&
it.nameIdentifier != null
}
.toList()
},
continuation
)
}
fun doInvoke(project: Project, editor: Editor, elements: List<PsiElement>, targetParent: PsiElement) {
val targetOwner = targetParent as KtTypeParameterListOwner
val typeToExtract = elements.singleOrNull() as? KtTypeElement
?: return showErrorHint(project, editor, "No type to refactor", REFACTORING_NAME)
val scope = targetOwner.getResolutionScope()
val initialName = KotlinNameSuggester.suggestNamesForTypeParameters(1) {
scope.findClassifier(Name.identifier(it), NoLookupLocation.FROM_IDE) == null
}.single()
val context = typeToExtract.analyze(BodyResolveMode.PARTIAL)
val upperBoundType = typeToExtract.getAbbreviatedTypeOrType(context)
val duplicateRanges = typeToExtract
.toRange()
.match(targetParent, KotlinPsiUnifier.DEFAULT)
.filterNot {
val textRange = it.range.getTextRange()
typeToExtract.textRange.intersects(textRange) || targetOwner.typeParameterList?.textRange?.intersects(textRange) ?: false
}
.mapNotNull { it.range.elements.toRange() }
project.executeCommand(REFACTORING_NAME) {
val newTypeParameter = CreateTypeParameterFromUsageFix(
typeToExtract,
CreateTypeParameterData(initialName, targetOwner, upperBoundType)
).doInvoke() ?: return@executeCommand
val newName = newTypeParameter.name ?: return@executeCommand
val parameterRefElement = KtPsiFactory(project).createType(newName).typeElement!!
runWriteAction { typeToExtract.replace(parameterRefElement) }
processDuplicates(
duplicateRanges.keysToMap {
fun() {
it.elements.singleOrNull()?.replace(parameterRefElement)
}
},
project,
editor
)
}
}
override fun invoke(project: Project, editor: Editor, file: PsiFile, dataContext: DataContext?) {
if (file !is KtFile) return
selectElements(editor, file) { elements, targetParent -> doInvoke(project, editor, elements, targetParent) }
}
override fun invoke(project: Project, elements: Array<out PsiElement>, dataContext: DataContext?) {
throw AssertionError("${KotlinIntroduceTypeAliasHandler.REFACTORING_NAME} can only be invoked from editor")
}
}
class IntroduceTypeParameterAction : AbstractIntroduceAction() {
override fun getRefactoringHandler(provider: RefactoringSupportProvider) = KotlinIntroduceTypeParameterHandler
}

View File

@@ -216,3 +216,5 @@ fun KtExpression.mustBeParenthesizedInInitializerPosition(): Boolean {
if (left?.mustBeParenthesizedInInitializerPosition() ?: false) return true
return PsiChildRange(left, operationReference).any { (it is PsiWhiteSpace) && it.textContains('\n') }
}
fun isObjectOrNonInnerClass(e: PsiElement): Boolean = e is KtObjectDeclaration || (e is KtClass && !e.isInner())

View File

@@ -28,6 +28,8 @@ import com.intellij.psi.PsiFile
import com.intellij.psi.PsiReference
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil
import com.intellij.ui.NonFocusableCheckBox
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
import org.jetbrains.kotlin.idea.core.quoteIfNeeded
import org.jetbrains.kotlin.idea.intentions.SpecifyTypeExplicitlyIntention
import org.jetbrains.kotlin.idea.refactoring.introduce.AbstractKotlinInplaceIntroducer
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
@@ -86,6 +88,7 @@ class KotlinVariableInplaceIntroducer(
expressionTypeCheckBox.setMnemonic('t')
expressionTypeCheckBox.addActionListener {
runWriteCommandAndRestart {
updateVariableName()
if (expressionTypeCheckBox.isSelected) {
val renderedType = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(expressionType)
addedVariable.setTypeReference(KtPsiFactory(myProject).createType(renderedType))

View File

@@ -251,10 +251,7 @@ class MoveKotlinDeclarationsProcessor(
}
}
fun render(declaration: PsiElement): String {
val text = RefactoringUIUtil.getDescription(declaration, false)
return if (declaration is KtFunction) "$text()" else text
}
fun render(declaration: PsiElement) = RefactoringUIUtil.getDescription(declaration, false)
fun checkVisibilityInUsages(usages: List<UsageInfo>) {
val declarationToContainers = HashMap<KtNamedDeclaration, MutableSet<PsiElement>>()

View File

@@ -1,4 +1,4 @@
// SHOULD_FAIL_WITH: Function foo already exists
// SHOULD_FAIL_WITH: Function foo() on A already exists
class A(val n: Int) {
val <caret>foo: Boolean = n > 1
}

View File

@@ -1,4 +1,4 @@
// SHOULD_FAIL_WITH: Function <b><code>foo</code></b> is overridden by declaration(s) in a subclass
// SHOULD_FAIL_WITH: Function <b><code>foo()</code></b> is overridden by declaration(s) in a subclass
open class A {
open fun <caret>foo() {

View File

@@ -1,5 +1,6 @@
// "class org.jetbrains.kotlin.idea.quickfix.AutoImportFix" "false"
// ACTION: Create interface 'SomeTest'
// ACTION: Create type alias 'SomeTest'
// ERROR: Unresolved reference: SomeTest
package testing

View File

@@ -1,5 +1,7 @@
// "Create class 'A'" "false"
// ACTION: Create interface 'A'
// ACTION: Create type alias 'A'
// ACTION: Create type parameter 'A'
// ACTION: Create test
// ERROR: Unresolved reference: A
package p

View File

@@ -1,6 +1,7 @@
// "Create annotation 'A'" "false"
// ACTION: Create class 'A'
// ACTION: Create interface 'A'
// ACTION: Create type alias 'A'
// ACTION: Convert to block body
// ACTION: Remove explicit type specification
// ERROR: Unresolved reference: A

View File

@@ -5,5 +5,6 @@
// ACTION: Create class 'A'
// ACTION: Create enum 'A'
// ACTION: Create interface 'A'
// ACTION: Create type alias 'A'
// ERROR: Unresolved reference: A
internal fun foo(): J.<caret>A = throw Throwable("")

View File

@@ -3,8 +3,10 @@
// ACTION: Create class 'A'
// ACTION: Create interface 'A'
// ACTION: Create enum 'A'
// ACTION: Create type alias 'A'
// ACTION: Convert to block body
// ACTION: Remove explicit type specification
// ACTION: Create type parameter 'A'
// ERROR: Unresolved reference: A
package p

View File

@@ -1,6 +1,7 @@
// "Create enum 'A'" "false"
// ACTION: Create class 'A'
// ACTION: Create interface 'A'
// ACTION: Create type alias 'A'
// ACTION: Convert to block body
// ACTION: Remove explicit type specification
// ERROR: Unresolved reference: A

View File

@@ -3,8 +3,10 @@
// ACTION: Create class 'A'
// ACTION: Create interface 'A'
// ACTION: Create enum 'A'
// ACTION: Create type alias 'A'
// ACTION: Convert to block body
// ACTION: Remove explicit type specification
// ACTION: Create type parameter 'A'
// ERROR: Unresolved reference: A
package p

View File

@@ -1,6 +1,7 @@
// "Create object 'A'" "false"
// ACTION: Create class 'A'
// ACTION: Create interface 'A'
// ACTION: Create type alias 'A'
// ACTION: Convert to block body
// ACTION: Remove explicit type specification
// ERROR: Unresolved reference: A

View File

@@ -0,0 +1,5 @@
// "Create type alias 'A'" "true"
// ERROR: Unresolved reference: Dummy
package p
fun foo(): p.<caret>A = throw Throwable("")

View File

@@ -0,0 +1,7 @@
// "Create type alias 'A'" "true"
// ERROR: Unresolved reference: Dummy
package p
fun foo(): p.A = throw Throwable("")
typealias A = Dummy

View File

@@ -0,0 +1,7 @@
// "Create type alias 'A'" "false"
// ACTION: Convert to block body
// ACTION: Remove explicit type specification
// ERROR: Unresolved reference: A
package p
internal fun foo(): Int.<caret>A = throw Throwable("")

View File

@@ -0,0 +1,4 @@
// "Create type alias 'X'" "true"
open class A<T>
class B : A<B.<caret>X>()

View File

@@ -0,0 +1,6 @@
// "Create type alias 'X'" "true"
open class A<T>
class B : A<B.X>() {
typealias X = Dummy
}

View File

@@ -0,0 +1,6 @@
// "Create type alias 'X'" "true"
open class A<T>
class B : A<B.<caret>X>() {
}

View File

@@ -0,0 +1,7 @@
// "Create type alias 'X'" "true"
open class A<T>
class B : A<B.X>() {
typealias X = Dummy
}

View File

@@ -0,0 +1,5 @@
// "Create type alias 'A'" "true"
// ERROR: Unresolved reference: Dummy
package p
fun foo(): <caret>A = throw Throwable("")

View File

@@ -0,0 +1,7 @@
// "Create type alias 'A'" "true"
// ERROR: Unresolved reference: Dummy
package p
fun foo(): A = throw Throwable("")
typealias A = Dummy

View File

@@ -0,0 +1,5 @@
// "Create type alias 'A'" "true"
// ERROR: Unresolved reference: Dummy
package p
fun foo(): <caret>A<*, String> = throw Throwable("")

View File

@@ -0,0 +1,7 @@
// "Create type alias 'A'" "true"
// ERROR: Unresolved reference: Dummy
package p
fun foo(): A<*, String> = throw Throwable("")
typealias A<T, U> = Dummy

View File

@@ -0,0 +1,5 @@
// "Create type alias 'A'" "true"
// ERROR: Unresolved reference: Dummy
package p
fun foo(): <caret>A<Int, String> = throw Throwable("")

View File

@@ -0,0 +1,7 @@
// "Create type alias 'A'" "true"
// ERROR: Unresolved reference: Dummy
package p
fun foo(): A<Int, String> = throw Throwable("")
typealias A<T, U> = Dummy

View File

@@ -0,0 +1,11 @@
// "Create type alias 'A'" "false"
// ACTION: Convert to block body
// ACTION: Create class 'A'
// ACTION: Create enum 'A'
// ACTION: Create interface 'A'
// ACTION: Create object 'A'
// ACTION: Remove explicit type specification
// ERROR: Unresolved reference: A
package p
fun foo(): <caret>A.B = throw Throwable("")

View File

@@ -0,0 +1,11 @@
// "Create type alias 'X'" "false"
// ACTION: Create class 'X'
// ACTION: Create interface 'X'
// ERROR: Unresolved reference: X
package p
open class A<T : List<T>>
fun foo(a: A<<caret>X<Int>>) {
}

View File

@@ -0,0 +1,9 @@
// "Create type alias 'A'" "true"
// ERROR: Unresolved reference: Dummy
package p
class T {
}
fun foo(): T.<caret>A = throw Throwable("")

View File

@@ -0,0 +1,10 @@
// "Create type alias 'A'" "true"
// ERROR: Unresolved reference: Dummy
package p
class T {
typealias A = Dummy
}
fun foo(): T.A = throw Throwable("")

View File

@@ -0,0 +1,7 @@
// "Create type alias 'A'" "true"
// ERROR: Unresolved reference: Dummy
package p
class T
fun foo(): T.<caret>A = throw Throwable("")

View File

@@ -0,0 +1,9 @@
// "Create type alias 'A'" "true"
// ERROR: Unresolved reference: Dummy
package p
class T {
typealias A = Dummy
}
fun foo(): T.A = throw Throwable("")

View File

@@ -0,0 +1,13 @@
// "Create type parameter 'X'" "true"
open class Foo(x: <caret>X)
class Bar : Foo(1)
fun test() {
Foo(1)
Foo("2")
object : Foo("2") {
}
}

View File

@@ -0,0 +1,13 @@
// "Create type parameter 'X'" "true"
open class Foo<X>(x: X)
class Bar : Foo<>(1)
fun test() {
Foo(1)
Foo("2")
object : Foo<>("2") {
}
}

View File

@@ -0,0 +1,15 @@
// "Create type parameter 'X'" "true"
class A<T>
open class Foo(x: A<<caret>X>)
class Bar : Foo(A())
fun test() {
Foo(A())
Foo(A<Int>())
object : Foo(A<Int>()) {
}
}

View File

@@ -0,0 +1,15 @@
// "Create type parameter 'X'" "true"
class A<T>
open class Foo<X>(x: A<X>)
class Bar : Foo<>(A())
fun test() {
Foo<Any>(A())
Foo(A<Int>())
object : Foo<>(A<Int>()) {
}
}

View File

@@ -0,0 +1,17 @@
// "Create type parameter 'X'" "true"
class A<T : List<T>>
interface I : List<I>
open class Foo(x: A<<caret>X>)
class Bar : Foo(A())
fun test() {
Foo(A())
Foo(A<I>())
object : Foo(A<I>()) {
}
}

View File

@@ -0,0 +1,17 @@
// "Create type parameter 'X'" "true"
class A<T : List<T>>
interface I : List<I>
open class Foo<X : List<X>>(x: A<X>)
class Bar : Foo<>(A())
fun test() {
Foo<List<>>(A())
Foo(A<I>())
object : Foo<>(A<I>()) {
}
}

View File

@@ -0,0 +1,15 @@
// "Create type parameter 'X'" "true"
class A<T : List<Int>>
open class Foo(x: A<<caret>X>)
class Bar : Foo(A())
fun test() {
Foo(A())
Foo(A<List<Int>>())
object : Foo(A<List<Int>>()) {
}
}

View File

@@ -0,0 +1,15 @@
// "Create type parameter 'X'" "true"
class A<T : List<Int>>
open class Foo<X : List<Int>>(x: A<X>)
class Bar : Foo<>(A())
fun test() {
Foo<List<Int>>(A())
Foo(A<List<Int>>())
object : Foo<>(A<List<Int>>()) {
}
}

View File

@@ -0,0 +1,9 @@
// "Create type parameter 'X'" "true"
fun foo(x: <caret>X) {
}
fun test() {
foo(1)
foo("2")
}

View File

@@ -0,0 +1,9 @@
// "Create type parameter 'X'" "true"
fun <X> foo(x: X) {
}
fun test() {
foo(1)
foo("2")
}

View File

@@ -0,0 +1,11 @@
// "Create type parameter 'X'" "true"
class A<T>
fun foo(x: A<<caret>X>) {
}
fun test() {
foo(A())
foo(A<Int>())
}

View File

@@ -0,0 +1,11 @@
// "Create type parameter 'X'" "true"
class A<T>
fun <X> foo(x: A<X>) {
}
fun test() {
foo<Any>(A())
foo(A<Int>())
}

View File

@@ -0,0 +1,13 @@
// "Create type parameter 'X'" "true"
class A<T : List<T>>
interface I : List<I>
fun foo(x: A<<caret>X>) {
}
fun test() {
foo(A())
foo(A<I>())
}

View File

@@ -0,0 +1,13 @@
// "Create type parameter 'X'" "true"
class A<T : List<T>>
interface I : List<I>
fun <X : List<X>> foo(x: A<X>) {
}
fun test() {
foo<List<>>(A())
foo(A<I>())
}

View File

@@ -0,0 +1,11 @@
// "Create type parameter 'X'" "true"
class A<T : List<Int>>
fun foo(x: A<<caret>X>) {
}
fun test() {
foo(A())
foo(A<List<Int>>())
}

View File

@@ -0,0 +1,11 @@
// "Create type parameter 'X'" "true"
class A<T : List<Int>>
fun <X : List<Int>> foo(x: A<X>) {
}
fun test() {
foo<List<Int>>(A())
foo(A<List<Int>>())
}

View File

@@ -0,0 +1,13 @@
// "Create type parameter 'X'" "false"
// ACTION: Create annotation 'X'
// ACTION: Create class 'X'
// ACTION: Create enum 'X'
// ACTION: Create interface 'X'
// ACTION: Create type alias 'X'
// ERROR: Unresolved reference: X
class A
fun foo(x: A.<caret>X) {
}

View File

@@ -0,0 +1,12 @@
// "Create type parameter 'X'" "false"
// ACTION: Create class 'X'
// ACTION: Create enum 'X'
// ACTION: Create interface 'X'
// ACTION: Create object 'X'
// ERROR: Unresolved reference: X
class A
fun foo(x: <caret>X.Y) {
}

View File

@@ -0,0 +1,11 @@
// "Create type parameter 'X'" "false"
// ACTION: Create class 'X'
// ACTION: Create interface 'X'
// ACTION: Create type alias 'X'
// ERROR: Unresolved reference: X
class A
fun foo(x: <caret>X<Int>) {
}

View File

@@ -1,4 +1,4 @@
// "Change 'A.foo' function return type to 'Long'" "true"
// "Change 'foo' function return type to 'Long'" "true"
interface A {
fun foo(): Int
}

View File

@@ -1,4 +1,4 @@
// "Change 'A.foo' function return type to 'Long'" "true"
// "Change 'foo' function return type to 'Long'" "true"
interface A {
fun foo(): Long
}

View File

@@ -1,4 +1,4 @@
// "Change 'B.foo' function return type to 'T'" "true"
// "Change 'foo' function return type to 'T'" "true"
open class S {}
open class T : S() {}

View File

@@ -1,4 +1,4 @@
// "Change 'B.foo' function return type to 'T'" "true"
// "Change 'foo' function return type to 'T'" "true"
open class S {}
open class T : S() {}

View File

@@ -1,4 +1,4 @@
// "Change 'B.foo' function return type to 'Int'" "true"
// "Change 'foo' function return type to 'Int'" "true"
abstract class A {
abstract fun foo() : Int;
}

View File

@@ -1,4 +1,4 @@
// "Change 'B.foo' function return type to 'Int'" "true"
// "Change 'foo' function return type to 'Int'" "true"
abstract class A {
abstract fun foo() : Int;
}

View File

@@ -1,4 +1,4 @@
// "Change 'B.foo' function return type to 'Int'" "true"
// "Change 'foo' function return type to 'Int'" "true"
abstract class A {
abstract fun foo() : Int;
}

View File

@@ -1,4 +1,4 @@
// "Change 'B.foo' function return type to 'Int'" "true"
// "Change 'foo' function return type to 'Int'" "true"
abstract class A {
abstract fun foo() : Int;
}

View File

@@ -1,4 +1,4 @@
// "Remove explicitly specified return type in 'A.remove' function" "true"
// "Remove explicitly specified return type in 'remove' function" "true"
abstract class A : java.util.Iterator<Int> {
public abstract override fun remove() : Int<caret>;
}

View File

@@ -1,4 +1,4 @@
// "Remove explicitly specified return type in 'A.remove' function" "true"
// "Remove explicitly specified return type in 'remove' function" "true"
abstract class A : java.util.Iterator<Int> {
public abstract override fun remove();
}

View File

@@ -3,6 +3,7 @@
// ACTION: Create class 'X'
// ACTION: Create enum 'X'
// ACTION: Create interface 'X'
// ACTION: Create type alias 'X'
// ERROR: Unresolved reference: X
// ERROR: Unresolved reference: X
class A {

Some files were not shown because too many files have changed in this diff Show More