mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[kotlin] fix common uast properties ref contributor to get rid of dedicated kotlin one
^ KTIJ-22356 also enables search for properties bundle/properties key for k2 (part of KTIJ-21662) GitOrigin-RevId: e3ec5803a2de593e1b3fd742f3ed7ae97a3e6d42
This commit is contained in:
committed by
intellij-monorepo-bot
parent
5ab4f3c510
commit
ddb2d075d9
+15
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInspection.restriction;
|
||||
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
@@ -112,6 +112,8 @@ public final class AnnotationContext {
|
||||
if (context != EMPTY) return context;
|
||||
context = fromArgument(expression);
|
||||
if (context != EMPTY) return context;
|
||||
context = fromInfixMethod(expression);
|
||||
if (context != EMPTY) return context;
|
||||
return fromInitializer(expression);
|
||||
}
|
||||
|
||||
@@ -223,6 +225,18 @@ public final class AnnotationContext {
|
||||
return fromModifierListOwner(parameter).withType(parameterType);
|
||||
}
|
||||
|
||||
private static @NotNull AnnotationContext fromInfixMethod(@NotNull UExpression expression) {
|
||||
UBinaryExpression parent = ObjectUtils.tryCast(expression.getUastParent(), UBinaryExpression.class);
|
||||
PsiMethod method = parent != null ? parent.resolveOperator() : null;
|
||||
if (method == null) return EMPTY;
|
||||
PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
if (parameters.length != 2) return EMPTY;
|
||||
PsiParameter parameter = UastUtils.isPsiAncestor(expression, parent.getRightOperand()) ? parameters[1] : parameters[0];
|
||||
if (parameter == null) return EMPTY;
|
||||
PsiType parameterType = parameter.getType();
|
||||
return fromModifierListOwner(parameter).withType(parameterType);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static AnnotationContext fromInitializer(UExpression expression) {
|
||||
UElement parent = expression.getUastParent();
|
||||
|
||||
+19
-36
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.lang.properties;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
@@ -20,11 +6,11 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.LocalSearchScope;
|
||||
import com.intellij.psi.search.searches.AnnotatedElementsSearch;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.uast.UElement;
|
||||
import org.jetbrains.uast.UExpression;
|
||||
import org.jetbrains.uast.UField;
|
||||
import org.jetbrains.uast.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -63,37 +49,34 @@ public class PropertiesUastReferenceContributor extends PsiReferenceContributor
|
||||
if (!(parent instanceof UField)) {
|
||||
return PsiReference.EMPTY_ARRAY;
|
||||
}
|
||||
PsiElement elementSource = uExpression.getSourcePsi();
|
||||
if (elementSource == null) return PsiReference.EMPTY_ARRAY;
|
||||
final UField field = (UField)parent;
|
||||
UExpression initializer = field.getUastInitializer();
|
||||
if (initializer == null) return PsiReference.EMPTY_ARRAY;
|
||||
PsiElement initializerSource = initializer.getSourcePsi();
|
||||
if (initializerSource == null) return PsiReference.EMPTY_ARRAY;
|
||||
PsiElement elementSource = uExpression.getSourcePsi();
|
||||
if (initializerSource != elementSource ||
|
||||
!field.isFinal() ||
|
||||
if (!field.isFinal() ||
|
||||
!field.getType().equalsToText(CommonClassNames.JAVA_LANG_STRING)) {
|
||||
return PsiReference.EMPTY_ARRAY;
|
||||
}
|
||||
List<PsiReference> references = new ArrayList<>();
|
||||
final PsiClass propertyKeyAnnotation =
|
||||
JavaPsiFacade.getInstance(initializerSource.getProject())
|
||||
JavaPsiFacade.getInstance(elementSource.getProject())
|
||||
.findClass(AnnotationUtil.PROPERTY_KEY, elementSource.getResolveScope());
|
||||
if (propertyKeyAnnotation != null) {
|
||||
LOG.assertTrue(propertyKeyAnnotation.isAnnotationType());
|
||||
AnnotatedElementsSearch.searchPsiParameters(propertyKeyAnnotation, new LocalSearchScope(elementSource.getContainingFile()))
|
||||
.forEach(parameter -> {
|
||||
final PsiModifierList list = parameter.getModifierList();
|
||||
LOG.assertTrue(list != null);
|
||||
final PsiAnnotation annotation = list.findAnnotation(AnnotationUtil.PROPERTY_KEY);
|
||||
LOG.assertTrue(annotation != null);
|
||||
for (PsiNameValuePair pair : annotation.getParameterList().getAttributes()) {
|
||||
if (AnnotationUtil.PROPERTY_KEY_RESOURCE_BUNDLE_PARAMETER.equals(pair.getName())) {
|
||||
final PsiAnnotationMemberValue value = pair.getValue();
|
||||
if (value instanceof PsiReferenceExpression && ((PsiReferenceExpression)value).resolve() == field.getSourcePsi()) {
|
||||
Collections.addAll(references, myUnderlying.getReferencesForInjectionHost(uExpression, host, context));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
UParameter uParameter = ObjectUtils.tryCast(UastContextKt.toUElement(parameter), UParameter.class);
|
||||
if (uParameter == null) return true;
|
||||
List<UAnnotation> annotations = uParameter.getUAnnotations();
|
||||
UAnnotation uAnnotation =
|
||||
ContainerUtil.find(annotations, anno -> AnnotationUtil.PROPERTY_KEY.equals(anno.getQualifiedName()));
|
||||
if (uAnnotation == null) return true;
|
||||
UExpression attributeValue = uAnnotation.findAttributeValue(AnnotationUtil.PROPERTY_KEY_RESOURCE_BUNDLE_PARAMETER);
|
||||
if (attributeValue instanceof UResolvable &&
|
||||
field.equals(UastContextKt.toUElement(((UResolvable)attributeValue).resolve()))) {
|
||||
Collections.addAll(references, myUnderlying.getReferencesForInjectionHost(uExpression, host, context));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
+9
-11
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.lang.properties;
|
||||
|
||||
import com.intellij.codeInspection.i18n.JavaI18nUtil;
|
||||
@@ -13,10 +13,7 @@ import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.UastInjectionHostReferenceProvider;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.uast.UElement;
|
||||
import org.jetbrains.uast.UExpression;
|
||||
import org.jetbrains.uast.UPolyadicExpression;
|
||||
import org.jetbrains.uast.UastBinaryOperator;
|
||||
import org.jetbrains.uast.*;
|
||||
|
||||
class UastPropertiesReferenceProvider extends UastInjectionHostReferenceProvider {
|
||||
|
||||
@@ -37,7 +34,10 @@ class UastPropertiesReferenceProvider extends UastInjectionHostReferenceProvider
|
||||
@NotNull PsiLanguageInjectionHost host,
|
||||
@NotNull ProcessingContext context) {
|
||||
UExpression parent = StringFlowUtil.goUp(element, false, NlsInfo.factory());
|
||||
if (!canBePropertyKeyRef(parent)) {
|
||||
UElement gParent = parent.getUastParent();
|
||||
if (gParent instanceof UPolyadicExpression &&
|
||||
((UPolyadicExpression)gParent).getOperator() != UastBinaryOperator.ASSIGN &&
|
||||
(!(gParent instanceof UBinaryExpression) || ((UBinaryExpression)gParent).resolveOperator() == null)) {
|
||||
return PsiReference.EMPTY_ARRAY;
|
||||
}
|
||||
Object value = element.evaluate();
|
||||
@@ -63,15 +63,13 @@ class UastPropertiesReferenceProvider extends UastInjectionHostReferenceProvider
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (gParent instanceof UBinaryExpression) {
|
||||
return PsiReference.EMPTY_ARRAY;
|
||||
}
|
||||
soft = myDefaultSoft;
|
||||
bundleName = null;
|
||||
}
|
||||
PsiReference reference = new PropertyReference(text, host, bundleName, soft);
|
||||
return new PsiReference[]{reference};
|
||||
}
|
||||
|
||||
private static boolean canBePropertyKeyRef(@NotNull UExpression element) {
|
||||
UElement parent = element.getUastParent();
|
||||
return !(parent instanceof UPolyadicExpression) || ((UPolyadicExpression)parent).getOperator() == UastBinaryOperator.ASSIGN;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
</dependencies>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<psi.referenceContributor language="kotlin" implementation="org.jetbrains.kotlin.idea.i18n.KotlinPropertiesReferenceContributor"/>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.i18n.KotlinInvalidBundleOrPropertyInspection"
|
||||
groupBundle="messages.KotlinBundle" groupKey="group.names.kotlin"
|
||||
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
|
||||
package org.jetbrains.kotlin.idea.i18n
|
||||
|
||||
import com.intellij.patterns.PlatformPatterns
|
||||
import com.intellij.psi.*
|
||||
import org.jetbrains.kotlin.psi.KtStringTemplateExpression
|
||||
|
||||
class KotlinPropertiesReferenceContributor : PsiReferenceContributor() {
|
||||
override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) {
|
||||
registrar.registerReferenceProvider(
|
||||
PlatformPatterns.psiElement(KtStringTemplateExpression::class.java),
|
||||
KotlinPropertyKeyReferenceProvider
|
||||
)
|
||||
|
||||
registrar.registerReferenceProvider(
|
||||
PlatformPatterns.psiElement(KtStringTemplateExpression::class.java),
|
||||
KotlinResourceBundleNameReferenceProvider
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
|
||||
package org.jetbrains.kotlin.idea.i18n
|
||||
|
||||
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.annotations.PropertyKey
|
||||
import org.jetbrains.kotlin.base.fe10.analysis.findAnnotation
|
||||
import org.jetbrains.kotlin.base.fe10.analysis.getStringValue
|
||||
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotated
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.safeAnalyzeNonSourceRootCode
|
||||
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.util.getParentResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.util.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 Annotated.getBundleNameByAnnotation(): String? {
|
||||
return findAnnotation<PropertyKey>()?.getStringValue(PropertyKey::resourceBundle)
|
||||
}
|
||||
|
||||
private fun KtExpression.getBundleNameByContext(): String? {
|
||||
val expression = KtPsiUtil.safeDeparenthesize(this)
|
||||
val parent = expression.parent
|
||||
|
||||
if (parent is KtProperty) {
|
||||
return parent.resolveToDescriptorIfAny()?.getBundleNameByAnnotation()
|
||||
}
|
||||
|
||||
val bindingContext = expression.safeAnalyzeNonSourceRootCode(BodyResolveMode.PARTIAL)
|
||||
val resolvedCall = if (parent is KtQualifiedExpression && expression == parent.receiverExpression) {
|
||||
parent.selectorExpression.getResolvedCall(bindingContext)
|
||||
} else {
|
||||
expression.getParentResolvedCall(bindingContext)
|
||||
} ?: return null
|
||||
val callable = resolvedCall.resultingDescriptor
|
||||
|
||||
if ((resolvedCall.extensionReceiver as? ExpressionReceiver)?.expression == expression) {
|
||||
return callable.extensionReceiverParameter?.getBundleNameByAnnotation()
|
||||
}
|
||||
|
||||
return resolvedCall.valueArguments.entries
|
||||
.singleOrNull { it.value.arguments.any { it.getArgumentExpression() == expression } }
|
||||
?.key
|
||||
?.getBundleNameByAnnotation()
|
||||
}
|
||||
|
||||
private fun KtAnnotationEntry.getPropertyKeyResolvedCall(): ResolvedCall<*>? {
|
||||
val resolvedCall = resolveToCall() ?: return null
|
||||
val klass = (resolvedCall.resultingDescriptor as? ClassConstructorDescriptor)?.containingDeclaration ?: return null
|
||||
if (klass.kind != ClassKind.ANNOTATION_CLASS || klass.importableFqName != PROPERTY_KEY) return null
|
||||
return resolvedCall
|
||||
}
|
||||
|
||||
private fun KtStringTemplateExpression.isBundleName(): Boolean {
|
||||
when (val parent = KtPsiUtil.safeDeparenthesize(this).parent) {
|
||||
is KtValueArgument -> {
|
||||
val resolvedCall = parent.getStrictParentOfType<KtAnnotationEntry>()?.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 KtProperty -> {
|
||||
val contexts = (parent.useScope as? LocalSearchScope)?.scope ?: arrayOf(parent.containingFile)
|
||||
return contexts.any {
|
||||
it.anyDescendantOfType<KtAnnotationEntry> 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 KtSimpleNameExpression && bundleNameExpression.mainReference.resolve() == parent
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
object KotlinPropertyKeyReferenceProvider : PsiReferenceProvider() {
|
||||
override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array<out PsiReference> {
|
||||
if (!(element is KtStringTemplateExpression && element.isPlain())) return PsiReference.EMPTY_ARRAY
|
||||
val bundleName = element.getBundleNameByContext() ?: return PsiReference.EMPTY_ARRAY
|
||||
return arrayOf(PropertyReference(ElementManipulators.getValueText(element), element, bundleName, false))
|
||||
}
|
||||
}
|
||||
|
||||
object KotlinResourceBundleNameReferenceProvider : PsiReferenceProvider() {
|
||||
override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array<out PsiReference> {
|
||||
if (!(element is KtStringTemplateExpression && element.isPlain() && element.isBundleName())) return PsiReference.EMPTY_ARRAY
|
||||
return arrayOf(ResourceBundleReference(element))
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -1,2 +1,4 @@
|
||||
## FIND_FILE_USAGES
|
||||
foo.bar=test
|
||||
foo.bar=test
|
||||
|
||||
// FIR_COMPARISON
|
||||
+3
-1
@@ -1 +1,3 @@
|
||||
foo<caret>.bar=test
|
||||
foo<caret>.bar=test
|
||||
|
||||
// FIR_COMPARISON
|
||||
-8
@@ -102,12 +102,4 @@
|
||||
<offset>15</offset>
|
||||
<length>5</length>
|
||||
</problem>
|
||||
<problem>
|
||||
<file>unresolvedBundleReference.kt</file>
|
||||
<line>5</line>
|
||||
<module>testInvalidBundleOrProperty_InvalidBundleOrProperty</module>
|
||||
<entry_point TYPE="method" FQNAME="UnresolvedBundleReferenceKt java.lang.String message(java.lang.String key, java.lang.Object... args)"/>
|
||||
<problem_class severity="ERROR" attribute_key="WRONG_REFERENCES_ATTRIBUTES">Invalid property key</problem_class>
|
||||
<description>Invalid resource bundle reference 'TestBundle2'</description>
|
||||
</problem>
|
||||
</problems>
|
||||
|
||||
+1
@@ -182,6 +182,7 @@ internal class KotlinK2SearchUsagesSupport : KotlinSearchUsagesSupport {
|
||||
|
||||
override fun forceResolveReferences(file: KtFile, elements: List<KtElement>) {
|
||||
|
||||
val i = 0;
|
||||
}
|
||||
|
||||
override fun scriptDefinitionExists(file: PsiFile): Boolean {
|
||||
|
||||
Reference in New Issue
Block a user