@@ -21,24 +21,22 @@ import com.intellij.CommonBundle
21
21
import com.intellij.codeInsight.template.*
22
22
import com.intellij.codeInsight.template.impl.*
23
23
import com.intellij.codeInsight.template.macro.VariableOfTypeMacro
24
- import com.intellij.openapi.application.Application
25
24
import com.intellij.openapi.application.ApplicationManager
26
25
import com.intellij.openapi.command.undo.UndoUtil
27
26
import com.intellij.openapi.editor.Editor
28
27
import com.intellij.openapi.module.Module
29
28
import com.intellij.openapi.ui.Messages
30
29
import com.intellij.psi.*
31
- import com.intellij.psi.codeStyle.JavaCodeStyleManager
32
30
import com.intellij.psi.util.PsiTreeUtil
33
31
import org.jetbrains.android.actions.CreateXmlResourceDialog
34
32
import org.jetbrains.android.facet.AndroidFacet
35
33
import org.jetbrains.android.util.AndroidBundle
36
34
import org.jetbrains.android.util.AndroidResourceUtil
37
35
import org.jetbrains.kotlin.builtins.isExtensionFunctionType
38
- import org.jetbrains.kotlin.descriptors.ClassDescriptor
39
- import org.jetbrains.kotlin.descriptors.FunctionDescriptor
36
+ import org.jetbrains.kotlin.descriptors.*
40
37
import org.jetbrains.kotlin.idea.caches.resolve.analyze
41
38
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
39
+ import org.jetbrains.kotlin.idea.core.ShortenReferences
42
40
import org.jetbrains.kotlin.idea.intentions.SelfTargetingIntention
43
41
import org.jetbrains.kotlin.psi.*
44
42
import org.jetbrains.kotlin.resolve.BindingContext
@@ -48,15 +46,24 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
48
46
49
47
class KotlinAndroidAddStringResource : SelfTargetingIntention <KtLiteralStringTemplateEntry >(KtLiteralStringTemplateEntry : :class.java,
50
48
" Extract string resource" ) {
51
- private val GET_STRING_METHOD = " getString"
52
- private val EXTRACT_RESOURCE_DIALOG_TITLE = " Extract Resource"
53
- private val PACKAGE_NOT_FOUND_ERROR = " package.not.found.error"
49
+ private companion object {
50
+ private val CLASS_CONTEXT = " android.content.Context"
51
+ private val CLASS_FRAGMENT = " android.app.Fragment"
52
+ private val CLASS_SUPPORT_FRAGMENT = " android.support.v4.app.Fragment"
53
+ private val CLASS_VIEW = " android.view.View"
54
+
55
+ private val GET_STRING_METHOD = " getString"
56
+ private val EXTRACT_RESOURCE_DIALOG_TITLE = " Extract Resource"
57
+ private val PACKAGE_NOT_FOUND_ERROR = " package.not.found.error"
58
+ }
54
59
55
60
override fun isApplicableTo (element : KtLiteralStringTemplateEntry , caretOffset : Int ): Boolean {
56
61
if (AndroidFacet .getInstance(element.containingFile) == null ) {
57
62
return false
58
63
}
59
64
65
+ // Should not be available to strings with template expressions
66
+ // only to strings with single KtLiteralStringTemplateEntry inside
60
67
return element.parent.children.size == 1
61
68
}
62
69
@@ -70,7 +77,7 @@ class KotlinAndroidAddStringResource : SelfTargetingIntention<KtLiteralStringTem
70
77
throw IllegalStateException (" This intention requires android facet." )
71
78
}
72
79
73
- val file = element.containingFile
80
+ val file = element.containingFile as KtFile
74
81
val project = file.project
75
82
76
83
val manifestPackage = getManifestPackage(facet)
@@ -79,8 +86,7 @@ class KotlinAndroidAddStringResource : SelfTargetingIntention<KtLiteralStringTem
79
86
return
80
87
}
81
88
82
- val parameters = getCreateXmlResourceParameters(facet.module, element) ? :
83
- return
89
+ val parameters = getCreateXmlResourceParameters(facet.module, element) ? : return
84
90
85
91
if (! AndroidResourceUtil .createValueResource(facet.module, parameters.name, ResourceType .STRING ,
86
92
parameters.fileName, parameters.directoryNames, parameters.value)) {
@@ -93,7 +99,6 @@ class KotlinAndroidAddStringResource : SelfTargetingIntention<KtLiteralStringTem
93
99
}
94
100
95
101
private fun getCreateXmlResourceParameters (module : Module , element : KtLiteralStringTemplateEntry ): CreateXmlResourceParameters ? {
96
-
97
102
val stringValue = element.text
98
103
99
104
val showDialog = ! ApplicationManager .getApplication().isUnitTestMode
@@ -111,7 +116,7 @@ class KotlinAndroidAddStringResource : SelfTargetingIntention<KtLiteralStringTem
111
116
dialog.dirNames)
112
117
}
113
118
114
- private fun createResourceReference (module : Module , editor : Editor , file : PsiFile , element : PsiElement , aPackage : String ,
119
+ private fun createResourceReference (module : Module , editor : Editor , file : KtFile , element : PsiElement , aPackage : String ,
115
120
resName : String , resType : ResourceType ) {
116
121
val rFieldName = AndroidResourceUtil .getRJavaFieldName(resName)
117
122
val fieldName = " $aPackage .R.$resType .$rFieldName "
@@ -123,7 +128,7 @@ class KotlinAndroidAddStringResource : SelfTargetingIntention<KtLiteralStringTem
123
128
else {
124
129
template = TemplateImpl (" " , " \$ context\$ .$GET_STRING_METHOD ($fieldName )" , " " )
125
130
val marker = MacroCallNode (VariableOfTypeMacro ())
126
- marker.addParameter(ConstantNode (" android.content.Context " ))
131
+ marker.addParameter(ConstantNode (CLASS_CONTEXT ))
127
132
template.addVariable(" context" , marker, ConstantNode (" context" ), true )
128
133
}
129
134
@@ -136,18 +141,18 @@ class KotlinAndroidAddStringResource : SelfTargetingIntention<KtLiteralStringTem
136
141
137
142
TemplateManager .getInstance(module.project).startTemplate(editor, template, false , null , object : TemplateEditingAdapter () {
138
143
override fun waitingForInput (template : Template ? ) {
139
- JavaCodeStyleManager .getInstance(module.project).shortenClassReferences (file, marker.startOffset, marker.endOffset)
144
+ ShortenReferences . DEFAULT .process (file, marker.startOffset, marker.endOffset)
140
145
}
141
146
142
147
override fun beforeTemplateFinished (state : TemplateState ? , template : Template ? ) {
143
- JavaCodeStyleManager .getInstance(module.project).shortenClassReferences (file, marker.startOffset, marker.endOffset)
148
+ ShortenReferences . DEFAULT .process (file, marker.startOffset, marker.endOffset)
144
149
}
145
150
})
146
151
}
147
152
148
153
private fun needContextReceiver (element : PsiElement ): Boolean {
149
- val classesWithGetSting = listOf (" android.content.Context " , " android.app.Fragment " , " android.support.v4.app.Fragment " )
150
- val viewClass = listOf (" android.view.View " )
154
+ val classesWithGetSting = listOf (CLASS_CONTEXT , CLASS_FRAGMENT , CLASS_SUPPORT_FRAGMENT )
155
+ val viewClass = listOf (CLASS_VIEW )
151
156
var parent = PsiTreeUtil .findFirstParent(element, true ) { it is KtClassOrObject || it is KtFunction || it is KtLambdaExpression }
152
157
153
158
while (parent != null ) {
@@ -184,7 +189,7 @@ class KotlinAndroidAddStringResource : SelfTargetingIntention<KtLiteralStringTem
184
189
185
190
private fun KtFunction.isSubclassExtensionOfAny (baseClasses : Collection <String >): Boolean {
186
191
val descriptor = resolveToDescriptor() as FunctionDescriptor
187
- val extendedTypeDescriptor = descriptor.extensionReceiverParameter?.type?.constructor ?.declarationDescriptor as ? ClassDescriptor
192
+ val extendedTypeDescriptor = descriptor.extensionReceiverParameter?.type?.constructor ?.declarationDescriptor
188
193
return extendedTypeDescriptor != null && baseClasses.any { extendedTypeDescriptor.isSubclassOf(it) }
189
194
}
190
195
@@ -197,7 +202,7 @@ class KotlinAndroidAddStringResource : SelfTargetingIntention<KtLiteralStringTem
197
202
}
198
203
199
204
val extendedTypeDescriptor = type.arguments.first().type.constructor .declarationDescriptor
200
- if (extendedTypeDescriptor is ClassDescriptor ) {
205
+ if (extendedTypeDescriptor != null ) {
201
206
return baseClasses.any { extendedTypeDescriptor.isSubclassOf(it) }
202
207
}
203
208
@@ -210,9 +215,11 @@ class KotlinAndroidAddStringResource : SelfTargetingIntention<KtLiteralStringTem
210
215
return baseClasses.any { declarationDescriptor?.isSubclassOf(it) ? : false }
211
216
}
212
217
213
- private fun ClassDescriptor.isSubclassOf (className : String ): Boolean {
214
- return fqNameSafe.asString() == className || defaultType.constructor .supertypes.any {
215
- (it.constructor .declarationDescriptor as ? ClassDescriptor )?.isSubclassOf(className) ? : false
216
- }
218
+ private fun ClassifierDescriptor.isSubclassOf (className : String ): Boolean {
219
+ return fqNameSafe.asString() == className || isStrictSubclassOf(className)
220
+ }
221
+
222
+ private fun ClassifierDescriptor.isStrictSubclassOf (className : String ) = defaultType.constructor .supertypes.any {
223
+ it.constructor .declarationDescriptor?.isSubclassOf(className) ? : false
217
224
}
218
225
}
0 commit comments