From d6a56f86c33d3766fa1fdb3d700586b5802fbc32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yann=20C=C3=A9bron?= Date: Wed, 12 Feb 2025 16:49:13 +0100 Subject: [PATCH] [devkit] Handle without 'id' correctly (IJPL-177709) GitOrigin-RevId: 012c879eb66e914667517359390dd884ac056705 --- .../resources/intellij.devkit.core.xml | 2 ++ .../devkit/devkit-core/src/dom/Action.java | 21 ++++++++++++ .../devkit-core/src/dom/ActionOrGroup.java | 24 ++++++++++++-- .../index/IdeaPluginRegistrationIndex.java | 6 ++-- .../src/dom/index/RegistrationIndexer.java | 15 ++++----- .../src/navigation/LineMarkerInfoHelper.java | 8 ++--- .../PluginDescriptorStructureUtil.java | 8 ++--- .../references/ActionOrGroupIdReference.java | 17 ++++++---- .../ActionWithoutIdReferencesQueryExecutor.kt | 33 +++++++++++++++++++ .../DevKitRelatedPropertiesProvider.java | 9 ++--- .../testData/codeInsight/ActionCompletion.xml | 1 + .../ActionCompletionBundle.properties | 2 ++ .../testData/navigation/structure/plugin.xml | 2 +- .../codeInsight/PluginXmlFunctionalTest.java | 3 +- .../PluginDescriptorStructureTest.java | 4 +-- .../codeInsight/KtActionReferenceTest.kt | 3 +- .../src/PluginXmlI18nInspection.java | 16 +++++---- .../MyBundle.properties | 3 ++ ...uginXmlCapitalization_ActionPluginName.xml | 2 ++ .../pluginXmlI18n/PluginXmlI18nInspection.xml | 5 ++- 20 files changed, 137 insertions(+), 47 deletions(-) create mode 100644 plugins/devkit/devkit-core/src/references/ActionWithoutIdReferencesQueryExecutor.kt diff --git a/plugins/devkit/devkit-core/resources/intellij.devkit.core.xml b/plugins/devkit/devkit-core/resources/intellij.devkit.core.xml index b2feb2adca54..6c164f19ad2f 100644 --- a/plugins/devkit/devkit-core/resources/intellij.devkit.core.xml +++ b/plugins/devkit/devkit-core/resources/intellij.devkit.core.xml @@ -510,6 +510,8 @@ + + getEffectiveIdAttribute() { + if (DomUtil.hasXml(getId())) { + return getId(); + } + + return getClazz(); + } + @NotNull @Attribute("class") @Required diff --git a/plugins/devkit/devkit-core/src/dom/ActionOrGroup.java b/plugins/devkit/devkit-core/src/dom/ActionOrGroup.java index 0fb8c41c4a26..6f497512af97 100644 --- a/plugins/devkit/devkit-core/src/dom/ActionOrGroup.java +++ b/plugins/devkit/devkit-core/src/dom/ActionOrGroup.java @@ -5,6 +5,7 @@ import com.intellij.psi.PsiClass; import com.intellij.util.xml.*; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.devkit.dom.impl.ActionOrGroupReferencingConverter; import java.util.List; @@ -12,6 +13,25 @@ import java.util.function.Function; public interface ActionOrGroup extends DomElement { + /** + * @return possibly fallback ID if {@link #getId()} is not specified + * @see #getEffectiveIdAttribute() + */ + @Nullable + default String getEffectiveId() { + return getId().getStringValue(); + } + + /** + * @return underlying attribute for {@link #getEffectiveId()}, used for navigation purposes + */ + default GenericAttributeValue getEffectiveIdAttribute() { + return getId(); + } + + /** + * @see #getEffectiveId() + */ @NotNull @NameValue @Stubbed @@ -96,12 +116,12 @@ public interface ActionOrGroup extends DomElement { } public String getMessageKey(ActionOrGroup actionOrGroup) { - return getMessageKeyPrefix(actionOrGroup) + actionOrGroup.getId().getStringValue() + + return getMessageKeyPrefix(actionOrGroup) + actionOrGroup.getEffectiveId() + myPropertyKeySuffix; } public String getMessageKey(ActionOrGroup actionOrGroup, @NotNull OverrideText overrideText) { - return getMessageKeyPrefix(actionOrGroup) + actionOrGroup.getId().getStringValue() + + return getMessageKeyPrefix(actionOrGroup) + actionOrGroup.getEffectiveId() + "." + overrideText.getPlace().getStringValue() + myPropertyKeySuffix; } diff --git a/plugins/devkit/devkit-core/src/dom/index/IdeaPluginRegistrationIndex.java b/plugins/devkit/devkit-core/src/dom/index/IdeaPluginRegistrationIndex.java index cc68b1345860..660cb855c88d 100644 --- a/plugins/devkit/devkit-core/src/dom/index/IdeaPluginRegistrationIndex.java +++ b/plugins/devkit/devkit-core/src/dom/index/IdeaPluginRegistrationIndex.java @@ -1,4 +1,4 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.idea.devkit.dom.index; import com.intellij.openapi.project.Project; @@ -40,7 +40,7 @@ import java.util.*; *
    *
  • Application/Project/Module-component class - {@link Component#getInterfaceClass()} / {@link Component#getImplementationClass()} / {@link Component#getHeadlessImplementationClass()}
  • *
  • Action/ActionGroup class - {@link Action#getClazz()}/{@link Group#getClazz()}
  • - *
  • Action/ActionGroup ID - {@link ActionOrGroup#getId()}
  • + *
  • Action/ActionGroup ID - {@link ActionOrGroup#getEffectiveId()}
  • *
  • Application/Project Listener class - {@link Listeners.Listener#getListenerClassName()}
  • *
  • Listener topic class - {@link Listeners.Listener#getTopicClassName()}
  • *
@@ -48,7 +48,7 @@ import java.util.*; @SuppressWarnings("UnusedReturnValue") public final class IdeaPluginRegistrationIndex extends PluginXmlIndexBase> { - private static final int INDEX_VERSION = 8; + private static final int INDEX_VERSION = 9; private static final ID> NAME = ID.create("IdeaPluginRegistrationIndex"); diff --git a/plugins/devkit/devkit-core/src/dom/index/RegistrationIndexer.java b/plugins/devkit/devkit-core/src/dom/index/RegistrationIndexer.java index e8141d835e9a..573f97f1771c 100644 --- a/plugins/devkit/devkit-core/src/dom/index/RegistrationIndexer.java +++ b/plugins/devkit/devkit-core/src/dom/index/RegistrationIndexer.java @@ -1,4 +1,4 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.idea.devkit.dom.index; import com.intellij.openapi.util.text.StringUtil; @@ -9,9 +9,9 @@ import com.intellij.util.SmartList; import com.intellij.util.containers.FactoryMap; import com.intellij.util.xml.DomElement; import com.intellij.util.xml.DomUtil; -import com.intellij.util.xml.GenericAttributeValue; import com.intellij.util.xml.GenericDomValue; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.devkit.dom.*; import java.util.List; @@ -106,25 +106,24 @@ class RegistrationIndexer { private void processActionContainer(ActionContainer actionContainer) { for (Action action : actionContainer.getActions()) { addEntry(action, action.getClazz(), RegistrationEntry.RegistrationType.ACTION); - addIdEntry(action, action.getId(), RegistrationEntry.RegistrationType.ACTION_ID); + addIdEntry(action, action.getEffectiveId(), RegistrationEntry.RegistrationType.ACTION_ID); } for (Group group : actionContainer.getGroups()) { addEntry(group, group.getClazz(), RegistrationEntry.RegistrationType.ACTION); - addIdEntry(group, group.getId(), RegistrationEntry.RegistrationType.ACTION_GROUP_ID); + addIdEntry(group, group.getEffectiveId(), RegistrationEntry.RegistrationType.ACTION_GROUP_ID); processActionContainer(group); } } private void addIdEntry(DomElement domElement, - GenericAttributeValue idValue, + @Nullable String idValue, RegistrationEntry.RegistrationType type) { + if (StringUtil.isEmptyOrSpaces(idValue)) return; if (!DomUtil.hasXml(domElement)) return; - String id = idValue.getStringValue(); - if (StringUtil.isEmptyOrSpaces(id)) return; - storeEntry(id, domElement, type); + storeEntry(idValue, domElement, type); } private void addEntry(DomElement domElement, diff --git a/plugins/devkit/devkit-core/src/navigation/LineMarkerInfoHelper.java b/plugins/devkit/devkit-core/src/navigation/LineMarkerInfoHelper.java index ccfbd903bc05..8d664aaed4cb 100644 --- a/plugins/devkit/devkit-core/src/navigation/LineMarkerInfoHelper.java +++ b/plugins/devkit/devkit-core/src/navigation/LineMarkerInfoHelper.java @@ -1,4 +1,4 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.idea.devkit.navigation; import com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo; @@ -80,15 +80,13 @@ final class LineMarkerInfoHelper { static RelatedItemLineMarkerInfo createActionLineMarkerInfo(List targets, PsiElement element) { return createPluginLineMarkerInfo(targets, element, DevKitBundle.message("gutter.related.navigation.choose.action"), - (NullableFunction)action -> - ObjectUtils.chooseNotNull(action.getId().getStringValue(), action.getClazz().getStringValue())); + (NullableFunction)action -> action.getEffectiveId()); } static RelatedItemLineMarkerInfo createActionGroupLineMarkerInfo(List targets, PsiElement element) { return createPluginLineMarkerInfo(targets, element, DevKitBundle.message("gutter.related.navigation.choose.action.group"), - (NullableFunction)group -> - ObjectUtils.chooseNotNull(group.getId().getStringValue(), group.getClazz().getStringValue())); + (NullableFunction)group -> group.getEffectiveId()); } static RelatedItemLineMarkerInfo createComponentLineMarkerInfo(List targets, PsiElement element) { diff --git a/plugins/devkit/devkit-core/src/navigation/structure/PluginDescriptorStructureUtil.java b/plugins/devkit/devkit-core/src/navigation/structure/PluginDescriptorStructureUtil.java index 7142200eff29..995f87250a92 100644 --- a/plugins/devkit/devkit-core/src/navigation/structure/PluginDescriptorStructureUtil.java +++ b/plugins/devkit/devkit-core/src/navigation/structure/PluginDescriptorStructureUtil.java @@ -1,4 +1,4 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.idea.devkit.navigation.structure; import com.intellij.icons.AllIcons; @@ -63,8 +63,8 @@ public final class PluginDescriptorStructureUtil { return safeGetTagDisplayText(tag); } - if (element instanceof Action) { - String actionId = ((Action)element).getId().getStringValue(); + if (element instanceof Action action) { + String actionId = action.getEffectiveId(); if (StringUtil.isNotEmpty(actionId)) { return actionId; } @@ -196,7 +196,7 @@ public final class PluginDescriptorStructureUtil { } private static @Nullable String getGroupLocation(ActionOrGroup element) { - return element.getId().getStringValue(); + return element.getEffectiveId(); } private static @Nullable String getAddToGroupLocation(AddToGroup element) { diff --git a/plugins/devkit/devkit-core/src/references/ActionOrGroupIdReference.java b/plugins/devkit/devkit-core/src/references/ActionOrGroupIdReference.java index db19d2245f35..a6bb16072b47 100644 --- a/plugins/devkit/devkit-core/src/references/ActionOrGroupIdReference.java +++ b/plugins/devkit/devkit-core/src/references/ActionOrGroupIdReference.java @@ -19,10 +19,7 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.ProjectIconsAccessor; import com.intellij.util.*; import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.xml.DomElement; -import com.intellij.util.xml.DomTarget; -import com.intellij.util.xml.ElementPresentationManager; -import com.intellij.util.xml.GenericAttributeValue; +import com.intellij.util.xml.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.devkit.DevKitBundle; @@ -101,7 +98,7 @@ public final class ActionOrGroupIdReference extends PsiPolyVariantReferenceBase< } final List psiElements = - ContainerUtil.mapNotNull(processor.getResults(), actionOrGroup -> getDomTargetPsi(actionOrGroup)); + ContainerUtil.mapNotNull(processor.getResults(), actionOrGroup -> getActionOrGroupDomTargetPsi(actionOrGroup)); return PsiElementResolveResult.createResults(psiElements); } @@ -172,8 +169,8 @@ public final class ActionOrGroupIdReference extends PsiPolyVariantReferenceBase< final GlobalSearchScope domSearchScope = PluginRelatedLocatorsUtils.getCandidatesScope(project); IdeaPluginRegistrationIndex.processAllActionOrGroup(project, domSearchScope, actionOrGroup -> { if (isRelevantForVariant(actionOrGroup)) { - PsiElement psiElement = getDomTargetPsi(actionOrGroup); - String name = StringUtil.notNullize(actionOrGroup.getId().getStringValue(), + PsiElement psiElement = getActionOrGroupDomTargetPsi(actionOrGroup); + String name = StringUtil.notNullize(actionOrGroup.getEffectiveId(), DevKitBundle.message("plugin.xml.convert.action.or.group.invalid.name")); LookupElementBuilder builder = LookupElementBuilder.create(psiElement, name) .withRenderer(ActionOrGroupLookupRenderer.INSTANCE); @@ -245,6 +242,12 @@ public final class ActionOrGroupIdReference extends PsiPolyVariantReferenceBase< }; } + private static PsiElement getActionOrGroupDomTargetPsi(ActionOrGroup actionOrGroup) { + DomTarget target = DomTarget.getTarget(actionOrGroup, actionOrGroup.getEffectiveIdAttribute()); + assert target != null; + return PomService.convertToPsi(target); + } + private static PsiElement getDomTargetPsi(DomElement domElement) { DomTarget target = DomTarget.getTarget(domElement); assert target != null; diff --git a/plugins/devkit/devkit-core/src/references/ActionWithoutIdReferencesQueryExecutor.kt b/plugins/devkit/devkit-core/src/references/ActionWithoutIdReferencesQueryExecutor.kt new file mode 100644 index 000000000000..fe0728475056 --- /dev/null +++ b/plugins/devkit/devkit-core/src/references/ActionWithoutIdReferencesQueryExecutor.kt @@ -0,0 +1,33 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.idea.devkit.references + +import com.intellij.openapi.application.QueryExecutorBase +import com.intellij.psi.PsiReference +import com.intellij.psi.search.searches.ReferencesSearch +import com.intellij.psi.xml.XmlAttributeValue +import com.intellij.util.Processor +import com.intellij.util.xml.DomUtil +import org.jetbrains.idea.devkit.dom.Action + +/** + * Search for implicit [Action] `id` if not specified. + * Reference for [Action.getEffectiveId] to [Action.getClazz] (short class name). + * + * @see DevKitRelatedPropertiesProvider + */ +internal class ActionWithoutIdReferencesQueryExecutor : QueryExecutorBase() { + + override fun processQuery(queryParameters: ReferencesSearch.SearchParameters, consumer: Processor) { + val elementToSearch = queryParameters.elementToSearch + + if (elementToSearch !is XmlAttributeValue) return + if (elementToSearch.hostName != "class") return + + val domElement = DomUtil.getDomElement(elementToSearch) ?: return + val action = DomUtil.getParentOfType(domElement, Action::class.java, true) ?: return + if (DomUtil.hasXml(action.id)) return + + val effectiveId = action.effectiveId ?: return + queryParameters.optimizer.searchWord(effectiveId, queryParameters.effectiveSearchScope, true, elementToSearch) + } +} \ No newline at end of file diff --git a/plugins/devkit/devkit-core/src/references/DevKitRelatedPropertiesProvider.java b/plugins/devkit/devkit-core/src/references/DevKitRelatedPropertiesProvider.java index 602680d86d60..5ab49d51cf5f 100644 --- a/plugins/devkit/devkit-core/src/references/DevKitRelatedPropertiesProvider.java +++ b/plugins/devkit/devkit-core/src/references/DevKitRelatedPropertiesProvider.java @@ -45,6 +45,7 @@ import java.util.Collections; *

* * @see MessageBundleReferenceContributor + * @see ActionWithoutIdReferencesQueryExecutor */ final class DevKitRelatedPropertiesProvider extends DevkitRelatedLineMarkerProviderBase { @@ -72,7 +73,7 @@ final class DevKitRelatedPropertiesProvider extends DevkitRelatedLineMarkerProvi DomElement domElement = DomUtil.getDomElement(leaf); if (domElement instanceof ActionOrGroup actionOrGroup) { - createLineMarker(leaf, result, domElement, actionOrGroup.getId()); + createLineMarker(leaf, result, domElement, actionOrGroup.getEffectiveIdAttribute()); } else if (domElement instanceof OverrideText overrideText) { createLineMarker(leaf, result, domElement, overrideText.getPlace()); @@ -90,10 +91,10 @@ final class DevKitRelatedPropertiesProvider extends DevkitRelatedLineMarkerProvi final XmlElement valueXmlElement = DomUtil.getValueElement(referenceElement); if (valueXmlElement == null) return; - PropertiesFile file = DescriptorI18nUtil.findBundlePropertiesFile(domElement); - if (file == null) return; + PropertiesFile propertiesFile = DescriptorI18nUtil.findBundlePropertiesFile(domElement); + if (propertiesFile == null) return; - final Query query = ReferencesSearch.search(valueXmlElement, new LocalSearchScope(file.getContainingFile())); + final Query query = ReferencesSearch.search(valueXmlElement, new LocalSearchScope(propertiesFile.getContainingFile())); if (query.findFirst() == null) return; result.add( diff --git a/plugins/devkit/devkit-java-tests/testData/codeInsight/ActionCompletion.xml b/plugins/devkit/devkit-java-tests/testData/codeInsight/ActionCompletion.xml index e3266777605b..51cab0c56de2 100644 --- a/plugins/devkit/devkit-java-tests/testData/codeInsight/ActionCompletion.xml +++ b/plugins/devkit/devkit-java-tests/testData/codeInsight/ActionCompletion.xml @@ -5,6 +5,7 @@ + diff --git a/plugins/devkit/devkit-java-tests/testData/codeInsight/ActionCompletionBundle.properties b/plugins/devkit/devkit-java-tests/testData/codeInsight/ActionCompletionBundle.properties index 1f958ba4e8a0..1a092002ac7e 100644 --- a/plugins/devkit/devkit-java-tests/testData/codeInsight/ActionCompletionBundle.properties +++ b/plugins/devkit/devkit-java-tests/testData/codeInsight/ActionCompletionBundle.properties @@ -1,2 +1,4 @@ action.actionId.localized.text=_Action Localized Text action.actionId.localized.description=Action localized description +action.BarAction.text=Action without ID Localized Text +action.BarAction.description=Action without ID localized description diff --git a/plugins/devkit/devkit-java-tests/testData/navigation/structure/plugin.xml b/plugins/devkit/devkit-java-tests/testData/navigation/structure/plugin.xml index bd397b1ec8d1..58a4f124fbe3 100644 --- a/plugins/devkit/devkit-java-tests/testData/navigation/structure/plugin.xml +++ b/plugins/devkit/devkit-java-tests/testData/navigation/structure/plugin.xml @@ -65,6 +65,6 @@ - + \ No newline at end of file diff --git a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/codeInsight/PluginXmlFunctionalTest.java b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/codeInsight/PluginXmlFunctionalTest.java index 7dc3d2d9fb45..c1718bb3ed46 100644 --- a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/codeInsight/PluginXmlFunctionalTest.java +++ b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/codeInsight/PluginXmlFunctionalTest.java @@ -1,4 +1,4 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.idea.devkit.codeInsight; import com.intellij.codeInsight.TargetElementUtil; @@ -748,6 +748,7 @@ public class PluginXmlFunctionalTest extends JavaCodeInsightFixtureTestCase { LookupElement[] lookupElements = myFixture.getLookupElements(); assertLookupElement(lookupElements, "actionId", " \"ActionId Text\"", "ActionId description"); assertLookupElement(lookupElements, "actionId.localized", " \"Action Localized Text\"", "Action localized description"); + assertLookupElement(lookupElements, "BarAction", " \"Action without ID Localized Text\"", "Action without ID localized description"); assertLookupElement(lookupElements, "actionId.missing.localized", null, null); } diff --git a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/navigation/structure/PluginDescriptorStructureTest.java b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/navigation/structure/PluginDescriptorStructureTest.java index 77f97f5d5d2b..7b40a35702c3 100644 --- a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/navigation/structure/PluginDescriptorStructureTest.java +++ b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/navigation/structure/PluginDescriptorStructureTest.java @@ -1,4 +1,4 @@ -// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.idea.devkit.navigation.structure; import com.intellij.icons.AllIcons; @@ -117,7 +117,7 @@ public class PluginDescriptorStructureTest extends JavaCodeInsightFixtureTestCas TreeElement groupNode = actionNodes[0]; assertEquals("Group", groupNode.getPresentation().getPresentableText()); assertEquals("MyPlugin.MyGroup", groupNode.getPresentation().getLocationString()); - assertEquals("SomeAction2", actionNodes[1].getPresentation().getPresentableText()); + assertEquals("SomeAction2Class", actionNodes[1].getPresentation().getPresentableText()); assertEquals("SomeAction2Class", actionNodes[1].getPresentation().getLocationString()); TreeElement[] inGroupNodes = groupNode.getChildren(); diff --git a/plugins/devkit/devkit-kotlin-tests/testSrc/org/jetbrains/idea/devkit/kotlin/codeInsight/KtActionReferenceTest.kt b/plugins/devkit/devkit-kotlin-tests/testSrc/org/jetbrains/idea/devkit/kotlin/codeInsight/KtActionReferenceTest.kt index 325eba4eb054..730e87bc2412 100644 --- a/plugins/devkit/devkit-kotlin-tests/testSrc/org/jetbrains/idea/devkit/kotlin/codeInsight/KtActionReferenceTest.kt +++ b/plugins/devkit/devkit-kotlin-tests/testSrc/org/jetbrains/idea/devkit/kotlin/codeInsight/KtActionReferenceTest.kt @@ -106,6 +106,7 @@ class KtActionReferenceTest : JavaCodeInsightFixtureTestCase() { myFixture.createFile("plugin.xml", pluginXmlActions(""" + """ )); myFixture.configureByText("Caller.kt", """ @@ -115,7 +116,7 @@ class KtActionReferenceTest : JavaCodeInsightFixtureTestCase() { } """.trimIndent()) - assertSameElements(myFixture.getCompletionVariants("Caller.kt").orEmpty(), "myAction", "myGroup") + assertSameElements(myFixture.getCompletionVariants("Caller.kt").orEmpty(), "myAction", "myGroup", "myActionWithoutExplicitId") } fun testActionReferenceHighlighting() { diff --git a/plugins/devkit/intellij.devkit.i18n/src/PluginXmlI18nInspection.java b/plugins/devkit/intellij.devkit.i18n/src/PluginXmlI18nInspection.java index d730bd727cf6..19d08b8570ae 100644 --- a/plugins/devkit/intellij.devkit.i18n/src/PluginXmlI18nInspection.java +++ b/plugins/devkit/intellij.devkit.i18n/src/PluginXmlI18nInspection.java @@ -1,4 +1,4 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.idea.devkit.i18n; import com.intellij.codeInsight.intention.impl.config.IntentionManagerImpl; @@ -180,9 +180,6 @@ final class PluginXmlI18nInspection extends DevKitPluginXmlInspectionBase { } private static void highlightActionOrGroup(@NotNull DomElementAnnotationHolder holder, @NotNull ActionOrGroup actionOrGroup) { - String id = actionOrGroup.getId().getStringValue(); - if (id == null) return; - String text = actionOrGroup.getText().getStringValue(); String desc = actionOrGroup.getDescription().getStringValue(); if (text == null && desc == null) return; @@ -540,6 +537,13 @@ final class PluginXmlI18nInspection extends DevKitPluginXmlInspectionBase { } } + @Nullable + private static String getEffectiveActionOrGroupId(@Nullable XmlTag tag) { + ActionOrGroup actionOrGroup = DomUtil.findDomElement(tag, ActionOrGroup.class); + assert actionOrGroup != null; + return actionOrGroup.getEffectiveId(); + } + private static void extractTextAndDescription(@NotNull Project project, Collection tags, PropertiesFile propertiesFile, @@ -552,10 +556,10 @@ final class PluginXmlI18nInspection extends DevKitPluginXmlInspectionBase { String id; if (tag.getName().equals("override-text")) { - id = Objects.requireNonNull(tag.getParentTag()).getAttributeValue("id") + "." + tag.getAttributeValue("place"); + id = getEffectiveActionOrGroupId(tag.getParentTag()) + "." + tag.getAttributeValue("place"); } else { - id = tag.getAttributeValue("id"); + id = getEffectiveActionOrGroupId(tag); } List propertiesFiles = Collections.singletonList(propertiesFile); diff --git a/plugins/devkit/intellij.devkit.i18n/testData/inspections/pluginXmlCapitalization/MyBundle.properties b/plugins/devkit/intellij.devkit.i18n/testData/inspections/pluginXmlCapitalization/MyBundle.properties index 9c215ee30267..6a9a1925b518 100644 --- a/plugins/devkit/intellij.devkit.i18n/testData/inspections/pluginXmlCapitalization/MyBundle.properties +++ b/plugins/devkit/intellij.devkit.i18n/testData/inspections/pluginXmlCapitalization/MyBundle.properties @@ -6,6 +6,9 @@ action.BundleActionWithoutDescription.text=My Text action.BundleActionWrongCasing.text=lower case text action.BundleActionWrongCasing.description=lower case description +action.MyActionWithoutId.text=action without id lower case text +action.MyActionWithoutId.description=action without id lower case description + group.BundleGroup.text=Bundle Group group.BundleGroup.description=Bundle group description diff --git a/plugins/devkit/intellij.devkit.i18n/testData/inspections/pluginXmlCapitalization/pluginXmlCapitalization_ActionPluginName.xml b/plugins/devkit/intellij.devkit.i18n/testData/inspections/pluginXmlCapitalization/pluginXmlCapitalization_ActionPluginName.xml index f839184b9e9a..d2cb1f971a33 100644 --- a/plugins/devkit/intellij.devkit.i18n/testData/inspections/pluginXmlCapitalization/pluginXmlCapitalization_ActionPluginName.xml +++ b/plugins/devkit/intellij.devkit.i18n/testData/inspections/pluginXmlCapitalization/pluginXmlCapitalization_ActionPluginName.xml @@ -32,6 +32,8 @@ <action id="BundleActionWrongCasing"/> + <action class="MyActionWithoutId"/> + diff --git a/plugins/devkit/intellij.devkit.i18n/testData/inspections/pluginXmlI18n/PluginXmlI18nInspection.xml b/plugins/devkit/intellij.devkit.i18n/testData/inspections/pluginXmlI18n/PluginXmlI18nInspection.xml index b53d57b6e931..0ac4e2dad05d 100644 --- a/plugins/devkit/intellij.devkit.i18n/testData/inspections/pluginXmlI18n/PluginXmlI18nInspection.xml +++ b/plugins/devkit/intellij.devkit.i18n/testData/inspections/pluginXmlI18n/PluginXmlI18nInspection.xml @@ -3,8 +3,7 @@ - - action description="Not localized" text="Not Localized" class="foo.bar.BarAction"/> @@ -23,7 +22,7 @@ - group description="Not localized" text="Not Localized"/>