Resource Bundles: Implement references on Kotlin string literals
#KT-6946 In Progress
This commit is contained in:
@@ -405,3 +405,5 @@ public fun JetDeclaration.visibilityModifier(): PsiElement? {
|
|||||||
|
|
||||||
public fun JetDeclaration.visibilityModifierType(): JetModifierKeywordToken?
|
public fun JetDeclaration.visibilityModifierType(): JetModifierKeywordToken?
|
||||||
= visibilityModifier()?.node?.elementType as JetModifierKeywordToken?
|
= visibilityModifier()?.node?.elementType as JetModifierKeywordToken?
|
||||||
|
|
||||||
|
public fun JetStringTemplateExpression.isPlain() = entries.all { it is JetLiteralStringTemplateEntry }
|
||||||
@@ -158,7 +158,7 @@ public final class InTextDirectivesUtils {
|
|||||||
List<String> resultPrefixes = Lists.newArrayList();
|
List<String> resultPrefixes = Lists.newArrayList();
|
||||||
|
|
||||||
for (String prefix : prefixes) {
|
for (String prefix : prefixes) {
|
||||||
if (prefix.startsWith("//")) {
|
if (prefix.startsWith("//") || prefix.startsWith("##")) {
|
||||||
resultPrefixes.add(StringUtil.trimLeading(prefix.substring(2)));
|
resultPrefixes.add(StringUtil.trimLeading(prefix.substring(2)));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -181,7 +181,7 @@ public final class InTextDirectivesUtils {
|
|||||||
|
|
||||||
while ((line = reader.readLine()) != null) {
|
while ((line = reader.readLine()) != null) {
|
||||||
line = line.trim();
|
line = line.trim();
|
||||||
if (line.startsWith("//")) {
|
if (line.startsWith("//") || line.startsWith("##")) {
|
||||||
String uncommentedLine = line.substring(2).trim();
|
String uncommentedLine = line.substring(2).trim();
|
||||||
if (!uncommentedLine.isEmpty()) {
|
if (!uncommentedLine.isEmpty()) {
|
||||||
result.add(uncommentedLine);
|
result.add(uncommentedLine);
|
||||||
|
|||||||
@@ -525,6 +525,7 @@ fun main(args: Array<String>) {
|
|||||||
testClass(javaClass<AbstractJetFindUsagesTest>()) {
|
testClass(javaClass<AbstractJetFindUsagesTest>()) {
|
||||||
model("findUsages/kotlin", pattern = """^(.+)\.0\.kt$""")
|
model("findUsages/kotlin", pattern = """^(.+)\.0\.kt$""")
|
||||||
model("findUsages/java", pattern = """^(.+)\.0\.java$""")
|
model("findUsages/java", pattern = """^(.+)\.0\.java$""")
|
||||||
|
model("findUsages/propertyFiles", pattern = """^(.+)\.0\.properties$""")
|
||||||
}
|
}
|
||||||
|
|
||||||
testClass(javaClass<AbstractKotlinFindUsagesWithLibraryTest>()) {
|
testClass(javaClass<AbstractKotlinFindUsagesWithLibraryTest>()) {
|
||||||
|
|||||||
@@ -17,22 +17,17 @@
|
|||||||
package org.jetbrains.kotlin.idea.findUsages
|
package org.jetbrains.kotlin.idea.findUsages
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.kotlin.lexer.JetTokens
|
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
|
||||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
|
||||||
import org.jetbrains.kotlin.descriptors.PackageViewDescriptor
|
|
||||||
import com.intellij.psi.PsiPackage
|
import com.intellij.psi.PsiPackage
|
||||||
import com.intellij.psi.PsiReferenceExpression
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
|
||||||
import org.jetbrains.kotlin.idea.findUsages.UsageTypeEnum.*
|
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
|
import org.jetbrains.kotlin.idea.findUsages.UsageTypeEnum.*
|
||||||
import org.jetbrains.kotlin.idea.references.*
|
import org.jetbrains.kotlin.idea.references.*
|
||||||
|
import org.jetbrains.kotlin.lexer.JetTokens
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
|
||||||
public object UsageTypeUtils {
|
public object UsageTypeUtils {
|
||||||
@@ -41,6 +36,7 @@ public object UsageTypeUtils {
|
|||||||
is JetForExpression -> return IMPLICIT_ITERATION
|
is JetForExpression -> return IMPLICIT_ITERATION
|
||||||
is JetMultiDeclaration -> return READ
|
is JetMultiDeclaration -> return READ
|
||||||
is JetPropertyDelegate -> return PROPERTY_DELEGATION
|
is JetPropertyDelegate -> return PROPERTY_DELEGATION
|
||||||
|
is JetStringTemplateExpression -> return USAGE_IN_STRING_LITERAL
|
||||||
}
|
}
|
||||||
|
|
||||||
val refExpr = element?.getNonStrictParentOfType<JetReferenceExpression>()
|
val refExpr = element?.getNonStrictParentOfType<JetReferenceExpression>()
|
||||||
@@ -249,5 +245,7 @@ enum class UsageTypeEnum {
|
|||||||
CLASS_CAST_TO,
|
CLASS_CAST_TO,
|
||||||
ANNOTATION,
|
ANNOTATION,
|
||||||
CLASS_NEW_OPERATOR,
|
CLASS_NEW_OPERATOR,
|
||||||
NAMED_ARGUMENT
|
NAMED_ARGUMENT,
|
||||||
|
|
||||||
|
USAGE_IN_STRING_LITERAL
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -361,6 +361,7 @@
|
|||||||
<weigher key="completion" implementationClass="org.jetbrains.kotlin.idea.completion.KotlinLookupElementProximityWeigher" id="kotlin.proximity" order="after proximity"/>
|
<weigher key="completion" implementationClass="org.jetbrains.kotlin.idea.completion.KotlinLookupElementProximityWeigher" id="kotlin.proximity" order="after proximity"/>
|
||||||
|
|
||||||
<psi.referenceContributor language="jet" implementation="org.jetbrains.kotlin.idea.references.JetReferenceContributor"/>
|
<psi.referenceContributor language="jet" implementation="org.jetbrains.kotlin.idea.references.JetReferenceContributor"/>
|
||||||
|
<psi.referenceContributor language="jet" implementation="org.jetbrains.kotlin.idea.properties.KotlinPropertiesReferenceContributor"/>
|
||||||
|
|
||||||
<renamePsiElementProcessor id="KotlinClass"
|
<renamePsiElementProcessor id="KotlinClass"
|
||||||
implementation="org.jetbrains.kotlin.idea.refactoring.rename.RenameKotlinClassProcessor"
|
implementation="org.jetbrains.kotlin.idea.refactoring.rename.RenameKotlinClassProcessor"
|
||||||
|
|||||||
@@ -72,6 +72,8 @@ public object JetUsageTypeProvider : UsageTypeProviderEx {
|
|||||||
ANNOTATION -> UsageType.ANNOTATION
|
ANNOTATION -> UsageType.ANNOTATION
|
||||||
CLASS_NEW_OPERATOR -> UsageType.CLASS_NEW_OPERATOR
|
CLASS_NEW_OPERATOR -> UsageType.CLASS_NEW_OPERATOR
|
||||||
NAMED_ARGUMENT -> JetUsageTypes.NAMED_ARGUMENT
|
NAMED_ARGUMENT -> JetUsageTypes.NAMED_ARGUMENT
|
||||||
|
|
||||||
|
USAGE_IN_STRING_LITERAL -> UsageType.LITERAL_USAGE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2015 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.properties
|
||||||
|
|
||||||
|
import com.intellij.patterns.PlatformPatterns
|
||||||
|
import com.intellij.psi.PsiReferenceContributor
|
||||||
|
import com.intellij.psi.PsiReferenceRegistrar
|
||||||
|
import org.jetbrains.kotlin.psi.JetLiteralStringTemplateEntry
|
||||||
|
import org.jetbrains.kotlin.psi.JetStringTemplateExpression
|
||||||
|
|
||||||
|
public class KotlinPropertiesReferenceContributor : PsiReferenceContributor() {
|
||||||
|
override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) {
|
||||||
|
registrar.registerReferenceProvider(
|
||||||
|
PlatformPatterns.psiElement(JetStringTemplateExpression::class.java),
|
||||||
|
KotlinPropertyKeyReferenceProvider
|
||||||
|
)
|
||||||
|
|
||||||
|
registrar.registerReferenceProvider(
|
||||||
|
PlatformPatterns.psiElement(JetStringTemplateExpression::class.java),
|
||||||
|
KotlinResourceBundleNameReferenceProvider
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2015 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.properties
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.AnnotationUtil
|
||||||
|
import com.intellij.lang.properties.ResourceBundleReference
|
||||||
|
import com.intellij.lang.properties.references.PropertyReference
|
||||||
|
import com.intellij.psi.ElementManipulators
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiReference
|
||||||
|
import com.intellij.psi.PsiReferenceProvider
|
||||||
|
import com.intellij.psi.search.LocalSearchScope
|
||||||
|
import com.intellij.util.ProcessingContext
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
|
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||||
|
import org.jetbrains.kotlin.idea.references.mainReference
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.isPlain
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getParentResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||||
|
|
||||||
|
private val PROPERTY_KEY = FqName(AnnotationUtil.PROPERTY_KEY)
|
||||||
|
private val PROPERTY_KEY_RESOURCE_BUNDLE = Name.identifier(AnnotationUtil.PROPERTY_KEY_RESOURCE_BUNDLE_PARAMETER)
|
||||||
|
|
||||||
|
private fun AnnotationDescriptor.getBundleName(): String? {
|
||||||
|
return allValueArguments.entrySet().singleOrNull { it.key.name == PROPERTY_KEY_RESOURCE_BUNDLE }?.value?.value as? String
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun DeclarationDescriptor.getBundleNameByAnnotation(): String? {
|
||||||
|
return (annotations.findAnnotation(PROPERTY_KEY) ?: annotations.findExternalAnnotation(PROPERTY_KEY))?.getBundleName()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun JetExpression.getBundleNameByContext(): String? {
|
||||||
|
val expression = JetPsiUtil.safeDeparenthesize(this)
|
||||||
|
val parent = expression.parent
|
||||||
|
|
||||||
|
(parent as? JetProperty)?.let { return it.resolveToDescriptor().getBundleNameByAnnotation() }
|
||||||
|
|
||||||
|
val bindingContext = expression.analyze(BodyResolveMode.PARTIAL)
|
||||||
|
val resolvedCall =
|
||||||
|
if (parent is JetQualifiedExpression && expression == parent.receiverExpression) {
|
||||||
|
parent.selectorExpression.getResolvedCall(bindingContext)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
expression.getParentResolvedCall(bindingContext)
|
||||||
|
} ?: return null
|
||||||
|
val callable = resolvedCall.resultingDescriptor
|
||||||
|
|
||||||
|
if ((resolvedCall.extensionReceiver as? ExpressionReceiver)?.expression == expression) {
|
||||||
|
val returnTypeAnnotations = callable.returnType?.annotations ?: return null
|
||||||
|
return Annotations
|
||||||
|
.findUseSiteTargetedAnnotation(returnTypeAnnotations, AnnotationUseSiteTarget.RECEIVER, PROPERTY_KEY)
|
||||||
|
?.getBundleName()
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolvedCall.valueArguments.entrySet()
|
||||||
|
.singleOrNull { it.value.arguments.any { it.getArgumentExpression() == expression } }
|
||||||
|
?.key
|
||||||
|
?.getBundleNameByAnnotation()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun JetAnnotationEntry.getPropertyKeyResolvedCall(): ResolvedCall<*>? {
|
||||||
|
val resolvedCall = getResolvedCall(analyze(BodyResolveMode.PARTIAL)) ?: return null
|
||||||
|
val klass = (resolvedCall.resultingDescriptor as? ConstructorDescriptor)?.containingDeclaration ?: return null
|
||||||
|
if (klass.kind != ClassKind.ANNOTATION_CLASS || klass.importableFqName != PROPERTY_KEY) return null
|
||||||
|
return resolvedCall
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun JetStringTemplateExpression.isBundleName(): Boolean {
|
||||||
|
val parent = JetPsiUtil.safeDeparenthesize(this).parent
|
||||||
|
when (parent) {
|
||||||
|
is JetValueArgument -> {
|
||||||
|
val resolvedCall = parent.getStrictParentOfType<JetAnnotationEntry>()?.getPropertyKeyResolvedCall() ?: return false
|
||||||
|
val valueParameter = (resolvedCall.getArgumentMapping(parent) as? ArgumentMatch)?.valueParameter ?: return false
|
||||||
|
if (valueParameter.name != PROPERTY_KEY_RESOURCE_BUNDLE) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
is JetProperty -> {
|
||||||
|
val contexts = (parent.useScope as? LocalSearchScope)?.scope ?: arrayOf(parent.containingFile)
|
||||||
|
return contexts.any {
|
||||||
|
it.anyDescendantOfType<JetAnnotationEntry> f@ { entry ->
|
||||||
|
if (!entry.valueArguments.any { it.getArgumentName()?.asName == PROPERTY_KEY_RESOURCE_BUNDLE }) return@f false
|
||||||
|
val resolvedCall = entry.getPropertyKeyResolvedCall() ?: return@f false
|
||||||
|
val parameter = resolvedCall.resultingDescriptor.valueParameters.singleOrNull { it.name == PROPERTY_KEY_RESOURCE_BUNDLE }
|
||||||
|
?: return@f false
|
||||||
|
val valueArgument = resolvedCall.valueArguments[parameter] as? ExpressionValueArgument ?: return@f false
|
||||||
|
val bundleNameExpression = valueArgument.valueArgument?.getArgumentExpression() ?: return@f false
|
||||||
|
bundleNameExpression is JetSimpleNameExpression && bundleNameExpression.mainReference.resolve() == parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
public object KotlinPropertyKeyReferenceProvider : PsiReferenceProvider() {
|
||||||
|
override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array<out PsiReference> {
|
||||||
|
if (!(element is JetStringTemplateExpression && element.isPlain())) return PsiReference.EMPTY_ARRAY
|
||||||
|
val bundleName = element.getBundleNameByContext() ?: return PsiReference.EMPTY_ARRAY
|
||||||
|
return arrayOf(PropertyReference(ElementManipulators.getValueText(element), element, bundleName, false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public object KotlinResourceBundleNameReferenceProvider : PsiReferenceProvider() {
|
||||||
|
override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array<out PsiReference> {
|
||||||
|
if (!(element is JetStringTemplateExpression && element.isPlain() && element.isBundleName())) return PsiReference.EMPTY_ARRAY
|
||||||
|
return arrayOf(ResourceBundleReference(element))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// PSI_ELEMENT: com.intellij.lang.properties.psi.PropertiesFile
|
||||||
|
// FIND_BY_REF
|
||||||
|
import org.jetbrains.annotations.PropertyKey
|
||||||
|
|
||||||
|
public fun message(@PropertyKey(resourceBundle = "<caret>idea.testData.findUsages.kotlin.propertyFiles.propertyFileUsagesByRef.2") key: String) = key
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
message("foo.bar")
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import org.jetbrains.annotations.PropertyKey;
|
||||||
|
|
||||||
|
class A {
|
||||||
|
static String message(@PropertyKey(resourceBundle = "idea.testData.findUsages.kotlin.propertyFiles.propertyFileUsagesByRef.2") String key, Object... args) {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test() {
|
||||||
|
message("foo.bar");
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
foo.bar = test
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package org.jetbrains.annotations
|
||||||
|
|
||||||
|
@Retention(AnnotationRetention.BINARY)
|
||||||
|
@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.LOCAL_VARIABLE, AnnotationTarget.FIELD)
|
||||||
|
public annotation class PropertyKey(public val resourceBundle: String)
|
||||||
+2
@@ -0,0 +1,2 @@
|
|||||||
|
[propertyFileUsagesByRef.0.kt] Usage in string constants (5: 51) public fun message(@PropertyKey(resourceBundle = "idea.testData.findUsages.kotlin.propertyFiles.propertyFileUsagesByRef.2") key: String) = key
|
||||||
|
[propertyFileUsagesByRef.1.java] Method parameter declaration (4: 58) static String message(@PropertyKey(resourceBundle = "idea.testData.findUsages.kotlin.propertyFiles.propertyFileUsagesByRef.2") String key, Object... args) {
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// PSI_ELEMENT: com.intellij.lang.properties.psi.Property
|
||||||
|
// FIND_BY_REF
|
||||||
|
import org.jetbrains.annotations.PropertyKey
|
||||||
|
|
||||||
|
public fun message(@PropertyKey(resourceBundle = "idea.testData.findUsages.kotlin.propertyFiles.propertyUsagesByRef.2") key: String) = key
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
message("<caret>foo.bar")
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
class A {
|
||||||
|
void test() {
|
||||||
|
PropertyUsages_1Kt.message("foo.bar");
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
foo.bar = test
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package org.jetbrains.annotations
|
||||||
|
|
||||||
|
@Retention(AnnotationRetention.BINARY)
|
||||||
|
@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.LOCAL_VARIABLE, AnnotationTarget.FIELD)
|
||||||
|
public annotation class PropertyKey(public val resourceBundle: String)
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
[propertyUsagesByRef.0.kt] Usage in string constants (8: 14) message("foo.bar")
|
||||||
|
[propertyUsagesByRef.1.java] Usage in string constants (3: 37) PropertyUsages_1Kt.message("foo.bar");
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
## FIND_FILE_USAGES
|
||||||
|
foo.bar = test
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import org.jetbrains.annotations.PropertyKey
|
||||||
|
|
||||||
|
private val BUNDLE_NAME = "idea.testData.findUsages.propertyFiles.propertyFileUsages.0"
|
||||||
|
|
||||||
|
public fun message(@PropertyKey(resourceBundle = "idea.testData.findUsages.propertyFiles.propertyFileUsages.0") key: String) = key
|
||||||
|
public fun message2(@PropertyKey(resourceBundle = BUNDLE_NAME) key: String) = key
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
message("foo.bar")
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package org.jetbrains.annotations
|
||||||
|
|
||||||
|
@Retention(AnnotationRetention.BINARY)
|
||||||
|
@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.LOCAL_VARIABLE, AnnotationTarget.FIELD)
|
||||||
|
public annotation class PropertyKey(public val resourceBundle: String)
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
Usage in string constants (3: 28) private val BUNDLE_NAME = "idea.testData.findUsages.propertyFiles.propertyFileUsages.0"
|
||||||
|
Usage in string constants (5: 51) public fun message(@PropertyKey(resourceBundle = "idea.testData.findUsages.propertyFiles.propertyFileUsages.0") key: String) = key
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
foo<caret>.bar = test
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import org.jetbrains.annotations.PropertyKey
|
||||||
|
|
||||||
|
public fun message(@PropertyKey(resourceBundle = "idea.testData.findUsages.propertyFiles.propertyUsages.0") key: String) = key
|
||||||
|
|
||||||
|
public fun String.infixMessage(@PropertyKey(resourceBundle = "idea.testData.findUsages.propertyFiles.propertyUsages.0") key: String) = key
|
||||||
|
|
||||||
|
public fun @receiver:PropertyKey(resourceBundle = "idea.testData.findUsages.propertyFiles.propertyUsages.0") String.infixMessage2(s: String) = this
|
||||||
|
|
||||||
|
public fun @receiver:PropertyKey(resourceBundle = "idea.testData.findUsages.propertyFiles.propertyUsages.0") String.minus() = this
|
||||||
|
|
||||||
|
public fun Int.get(@PropertyKey(resourceBundle = "idea.testData.findUsages.propertyFiles.propertyUsages.0") key: String) = this
|
||||||
|
|
||||||
|
public fun @receiver:PropertyKey(resourceBundle = "idea.testData.findUsages.propertyFiles.propertyUsages.0") String.get(s: String) = this
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
@PropertyKey(resourceBundle = "idea.testData.findUsages.propertyFiles.propertyUsages.0") val s1 = "foo.bar"
|
||||||
|
@PropertyKey(resourceBundle = "idea.testData.findUsages.propertyFiles.propertyUsages.0") val s2 = "foo.baz"
|
||||||
|
message("foo.bar")
|
||||||
|
message("foo.baz")
|
||||||
|
|
||||||
|
"test" infixMessage "foo.bar"
|
||||||
|
"foo.bar" infixMessage "test"
|
||||||
|
"foo.bar" infixMessage2 "test"
|
||||||
|
"test" infixMessage2 "foo.bar"
|
||||||
|
"foo.bar".infixMessage2("test")
|
||||||
|
-"foo.bar"
|
||||||
|
1["foo.bar"]
|
||||||
|
"foo.bar"["test"]
|
||||||
|
"test"["foo.bar"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
class A {
|
||||||
|
void test() {
|
||||||
|
@PropertyKey(resourceBundle = "idea.testData.findUsages.propertyFiles.propertyUsages.0") String s1 = "foo.bar"
|
||||||
|
@PropertyKey(resourceBundle = "idea.testData.findUsages.propertyFiles.propertyUsages.0") String s2 = "foo.baz"
|
||||||
|
PropertyUsages_1Kt.message("foo.bar");
|
||||||
|
PropertyUsages_1Kt.message("foo.baz");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package org.jetbrains.annotations
|
||||||
|
|
||||||
|
@Retention(AnnotationRetention.BINARY)
|
||||||
|
@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.LOCAL_VARIABLE, AnnotationTarget.FIELD)
|
||||||
|
public annotation class PropertyKey(public val resourceBundle: String)
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
[propertyUsages.1.kt] Usage in string constants (16: 104) @PropertyKey(resourceBundle = "idea.testData.findUsages.propertyFiles.propertyUsages.0") val s1 = "foo.bar"
|
||||||
|
[propertyUsages.1.kt] Usage in string constants (18: 14) message("foo.bar")
|
||||||
|
[propertyUsages.1.kt] Usage in string constants (21: 26) "test" infixMessage "foo.bar"
|
||||||
|
[propertyUsages.1.kt] Usage in string constants (23: 6) "foo.bar" infixMessage2 "test"
|
||||||
|
[propertyUsages.1.kt] Usage in string constants (25: 6) "foo.bar".infixMessage2("test")
|
||||||
|
[propertyUsages.1.kt] Usage in string constants (26: 7) -"foo.bar"
|
||||||
|
[propertyUsages.1.kt] Usage in string constants (27: 8) 1["foo.bar"]
|
||||||
|
[propertyUsages.1.kt] Usage in string constants (28: 6) "foo.bar"["test"]
|
||||||
|
[propertyUsages.2.java] Usage in string constants (3: 111) @PropertyKey(resourceBundle = "idea.testData.findUsages.propertyFiles.propertyUsages.0") String s1 = "foo.bar"
|
||||||
|
[propertyUsages.2.java] Usage in string constants (5: 37) PropertyUsages_1Kt.message("foo.bar");
|
||||||
@@ -22,11 +22,12 @@ import com.google.common.base.Predicates;
|
|||||||
import com.google.common.collect.Collections2;
|
import com.google.common.collect.Collections2;
|
||||||
import com.google.common.collect.Ordering;
|
import com.google.common.collect.Ordering;
|
||||||
import com.intellij.codeInsight.JavaTargetElementEvaluator;
|
import com.intellij.codeInsight.JavaTargetElementEvaluator;
|
||||||
import com.intellij.codeInsight.TargetElementUtil;
|
|
||||||
import com.intellij.codeInsight.TargetElementUtilBase;
|
import com.intellij.codeInsight.TargetElementUtilBase;
|
||||||
import com.intellij.find.FindManager;
|
import com.intellij.find.FindManager;
|
||||||
import com.intellij.find.findUsages.*;
|
import com.intellij.find.findUsages.*;
|
||||||
import com.intellij.find.impl.FindManagerImpl;
|
import com.intellij.find.impl.FindManagerImpl;
|
||||||
|
import com.intellij.lang.properties.psi.PropertiesFile;
|
||||||
|
import com.intellij.lang.properties.psi.Property;
|
||||||
import com.intellij.openapi.extensions.Extensions;
|
import com.intellij.openapi.extensions.Extensions;
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
import com.intellij.openapi.util.io.FileUtil;
|
import com.intellij.openapi.util.io.FileUtil;
|
||||||
@@ -296,11 +297,21 @@ public abstract class AbstractJetFindUsagesTest extends JetLightCodeInsightFixtu
|
|||||||
String mainFileText = FileUtil.loadFile(mainFile, true);
|
String mainFileText = FileUtil.loadFile(mainFile, true);
|
||||||
final String prefix = mainFileName.substring(0, mainFileName.indexOf('.') + 1);
|
final String prefix = mainFileName.substring(0, mainFileName.indexOf('.') + 1);
|
||||||
|
|
||||||
List<String> caretElementClassNames = InTextDirectivesUtils.findLinesWithPrefixesRemoved(mainFileText, "// PSI_ELEMENT: ");
|
boolean isPropertiesFile = FileUtilRt.getExtension(path).equals("properties");
|
||||||
assert caretElementClassNames.size() == 1;
|
|
||||||
//noinspection unchecked
|
|
||||||
|
|
||||||
Class<T> caretElementClass = (Class<T>)Class.forName(caretElementClassNames.get(0));
|
Class<T> caretElementClass;
|
||||||
|
if (!isPropertiesFile) {
|
||||||
|
List<String> caretElementClassNames = InTextDirectivesUtils.findLinesWithPrefixesRemoved(mainFileText, "// PSI_ELEMENT: ");
|
||||||
|
assert caretElementClassNames.size() == 1;
|
||||||
|
//noinspection unchecked
|
||||||
|
caretElementClass = (Class<T>)Class.forName(caretElementClassNames.get(0));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//noinspection unchecked
|
||||||
|
caretElementClass = (Class<T>) (InTextDirectivesUtils.isDirectiveDefined(mainFileText, "## FIND_FILE_USAGES")
|
||||||
|
? PropertiesFile.class
|
||||||
|
: Property.class);
|
||||||
|
}
|
||||||
|
|
||||||
OptionsParser parser = OptionsParser.getParserByPsiElementClass(caretElementClass);
|
OptionsParser parser = OptionsParser.getParserByPsiElementClass(caretElementClass);
|
||||||
|
|
||||||
@@ -317,6 +328,7 @@ public abstract class AbstractJetFindUsagesTest extends JetLightCodeInsightFixtu
|
|||||||
return ext.equals("kt")
|
return ext.equals("kt")
|
||||||
|| ext.equals("java")
|
|| ext.equals("java")
|
||||||
|| ext.equals("xml")
|
|| ext.equals("xml")
|
||||||
|
|| ext.equals("properties")
|
||||||
|| (ext.equals("txt") && !name.endsWith(".results.txt"));
|
|| (ext.equals("txt") && !name.endsWith(".results.txt"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1036,6 +1036,27 @@ public class JetFindUsagesTestGenerated extends AbstractJetFindUsagesTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("idea/testData/findUsages/kotlin/propertyFiles")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class PropertyFiles extends AbstractJetFindUsagesTest {
|
||||||
|
public void testAllFilesPresentInPropertyFiles() throws Exception {
|
||||||
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/findUsages/kotlin/propertyFiles"), Pattern.compile("^(.+)\\.0\\.kt$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("propertyFileUsagesByRef.0.kt")
|
||||||
|
public void testPropertyFileUsagesByRef() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/propertyFiles/propertyFileUsagesByRef.0.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("propertyUsagesByRef.0.kt")
|
||||||
|
public void testPropertyUsagesByRef() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/propertyFiles/propertyUsagesByRef.0.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/testData/findUsages/kotlin/unresolvedAnnotation")
|
@TestMetadata("idea/testData/findUsages/kotlin/unresolvedAnnotation")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
@@ -1315,4 +1336,25 @@ public class JetFindUsagesTestGenerated extends AbstractJetFindUsagesTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("idea/testData/findUsages/propertyFiles")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class PropertyFiles extends AbstractJetFindUsagesTest {
|
||||||
|
public void testAllFilesPresentInPropertyFiles() throws Exception {
|
||||||
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/findUsages/propertyFiles"), Pattern.compile("^(.+)\\.0\\.properties$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("propertyFileUsages.0.properties")
|
||||||
|
public void testPropertyFileUsages() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/propertyFiles/propertyFileUsages.0.properties");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("propertyUsages.0.properties")
|
||||||
|
public void testPropertyUsages() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/propertyFiles/propertyUsages.0.properties");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user