AP-8446 [devkit]: reference provider for FUS group and event IDs + missing description inspection

GitOrigin-RevId: 4f07dc713edd53dc2bc72ff291227a4853580e72
This commit is contained in:
Roman Shevchenko
2026-02-11 20:15:37 +00:00
committed by intellij-monorepo-bot
parent f0269e1da8
commit 6b7ecb38dc
10 changed files with 474 additions and 7 deletions
@@ -35,6 +35,7 @@ open class EventLogGroup {
val groupData: List<Pair<EventField<*>, FeatureUsageData.() -> Unit>>
@Deprecated("Descriptions are moved to a separate file; use another constructor", ReplaceWith("EventLogGroup(id, version, recorder, groupData)"))
@Suppress("EventLogDescription")
constructor(
@EventIdName id: String,
version: Int,
@@ -68,6 +69,7 @@ open class EventLogGroup {
}
@Deprecated("Descriptions are moved to a separate file; use another constructor", ReplaceWith("EventLogGroup(id, version, recorder)"))
@Suppress("EventLogDescription")
constructor(
@EventIdName id: String,
version: Int,
@@ -0,0 +1,6 @@
<html>
<body>
Reports missing FUS group or event descriptions in the corresponding recorder properties files (<code>build/event/*.properties</code>),
and warns when a group or event ID cannot be evaluated.
</body>
</html>
@@ -28,6 +28,7 @@
<gotoRelatedProvider implementation="org.jetbrains.idea.devkit.testAssistant.TestCaseAsRelatedFileProvider"/>
<gotoRelatedProvider implementation="org.jetbrains.idea.devkit.navigation.DescriptionInspectionGotoRelatedProvider"/>
<psi.referenceContributor language="UAST" implementation="org.jetbrains.idea.devkit.testAssistant.TestDataReferenceContributor"/>
<psi.referenceContributor language="UAST" implementation="org.jetbrains.idea.devkit.references.EventLogDescriptionReferenceContributor"/>
<automaticRenamerFactory implementation="org.jetbrains.idea.devkit.refactoring.InspectionAutomaticRenamerFactory"/>
<httpRequestHandler implementation="org.jetbrains.idea.devkit.requestHandlers.HttpDebugListener"/>
@@ -573,6 +574,10 @@
groupKey="inspections.group.code"
key="inspection.use.optimized.eel.functions.display.name"/>"
<localInspection language="UAST" projectType="INTELLIJ_PLUGIN" enabledByDefault="true" level="WARNING" shortName="EventLogDescription"
groupPathKey="inspections.group.path" groupKey="inspections.group.code" key="inspections.event.log.description.display.name"
implementationClass="org.jetbrains.idea.devkit.inspections.EventLogDescriptionInspection"/>
<moduleConfigurationEditorProvider implementation="org.jetbrains.idea.devkit.module.PluginModuleEditorsProvider"/>
<implicitUsageProvider implementation="org.jetbrains.idea.devkit.inspections.DevKitImplicitUsageProvider"/>
@@ -382,6 +382,17 @@ inspections.use.gray.awt.color.used.name='java.awt.Color' used for gray
inspections.use.gray.fix.convert.name=Convert to ''Gray._{0}''
inspections.use.gray.fix.convert.family.name=Convert to 'Gray'
inspections.event.log.description.display.name=Missing event log descriptions
inspections.event.log.recorder.not.evaluable=Cannot evaluate the recorder name; consider using a constant expression
inspections.event.log.recorder.unknown=Unknown recorder (''{0}'' is missing)
inspections.event.log.group.id.not.evaluable=Cannot evaluate the group ID; consider using a constant expression
inspections.event.log.group.description.missing=Group ''{0}'' description is missing from ''{1}''
inspections.event.log.group.description.empty=Group ''{0}'' description is empty
inspections.event.log.event.id.not.evaluable=Cannot evaluate the event ID; consider using a constant expression
inspections.event.log.event.group.not.evaluable=Cannot find the event group; consider using a constant expression
inspections.event.log.event.description.missing=Event ''{0}'' description is missing from ''{1}''
inspections.event.log.event.description.empty=Event ''{0}'' description is empty
line.marker.related.property.tooltip=Related property
line.marker.related.property.popup.title=Related Properties
line.marker.related.property.description=Related property
@@ -3,15 +3,13 @@ package org.jetbrains.idea.devkit;
import com.intellij.DynamicBundle;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.PropertyKey;
import java.util.function.Supplier;
public final class DevKitBundle {
public static final @NonNls String BUNDLE = "messages.DevKitBundle";
public static final String BUNDLE = "messages.DevKitBundle";
private static final DynamicBundle ourInstance = new DynamicBundle(DevKitBundle.class, BUNDLE);
@@ -19,8 +17,10 @@ public final class DevKitBundle {
return ourInstance.getMessage(key, params);
}
public static @NotNull Supplier<@Nls String> messagePointer(@NotNull @PropertyKey(resourceBundle = BUNDLE) String key,
Object @NotNull ... params) {
public static @NotNull Supplier<@Nls String> messagePointer(
@NotNull @PropertyKey(resourceBundle = BUNDLE) String key,
Object @NotNull ... params
) {
return ourInstance.getLazyMessage(key, params);
}
}
@@ -0,0 +1,105 @@
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.idea.devkit.inspections
import com.intellij.codeInspection.AbstractBaseUastLocalInspectionTool
import com.intellij.codeInspection.LocalInspectionToolSession
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.lang.properties.PropertiesFileType
import com.intellij.openapi.project.guessProjectDir
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.PsiManager
import com.intellij.uast.UastHintedVisitorAdapter
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.annotations.PropertyKey
import org.jetbrains.annotations.VisibleForTesting
import org.jetbrains.idea.devkit.DevKitBundle
import org.jetbrains.idea.devkit.references.EVENT_LOG_GROUP_FQN
import org.jetbrains.idea.devkit.references.EVENT_LOG_PROPERTIES_DIR
import org.jetbrains.idea.devkit.references.eventLogGroupCall
import org.jetbrains.idea.devkit.references.findEventLogPropertiesFile
import org.jetbrains.idea.devkit.references.findGroupIdAndRecorderName
import org.jetbrains.idea.devkit.references.findRecorderName
import org.jetbrains.uast.UCallExpression
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UastCallKind
import org.jetbrains.uast.evaluateString
import org.jetbrains.uast.visitor.AbstractUastNonRecursiveVisitor
@VisibleForTesting
@ApiStatus.Internal
class EventLogDescriptionInspection : AbstractBaseUastLocalInspectionTool() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
val hasFUS = JavaPsiFacade.getInstance(holder.project).findClass(EVENT_LOG_GROUP_FQN, holder.file.resolveScope) != null
if (!hasFUS)
return PsiElementVisitor.EMPTY_VISITOR
val hasDescriptions = holder.project.guessProjectDir()
?.findFileByRelativePath(EVENT_LOG_PROPERTIES_DIR)
?.let { PsiManager.getInstance(holder.project).findDirectory(it) }
?.let { it.files.any { file -> file.name.endsWith(PropertiesFileType.DOT_DEFAULT_EXTENSION) } } == true
if (!hasDescriptions)
return PsiElementVisitor.EMPTY_VISITOR
return UastHintedVisitorAdapter.create(
holder.file.language,
EventLogDescriptionInspectionVisitor(holder),
arrayOf(UCallExpression::class.java),
directOnly = true
)
}
}
private val EVENT_LOG_GROUP_CALL_PATTERN = eventLogGroupCall()
private class EventLogDescriptionInspectionVisitor(private val holder: ProblemsHolder) : AbstractUastNonRecursiveVisitor() {
override fun visitCallExpression(node: UCallExpression): Boolean {
val argument = node.getArgumentForParameter(0)
if (argument != null && EVENT_LOG_GROUP_CALL_PATTERN.accepts(node)) {
if (node.kind == UastCallKind.CONSTRUCTOR_CALL) {
val recorderArg = node.getArgumentForParameter(2)
val recorder = findRecorderName(node)
?: return warn(recorderArg ?: node, "inspections.event.log.recorder.not.evaluable")
val file = findEventLogPropertiesFile(holder.project, recorder)
?: return error(recorderArg ?: node, "inspections.event.log.recorder.unknown", "${EVENT_LOG_PROPERTIES_DIR}/${recorder}.properties")
val groupId = argument.evaluateString()?.takeIf { it.isNotBlank() }
?: return warn(argument, "inspections.event.log.group.id.not.evaluable")
val description = file.findPropertyByKey(groupId)?.value
?: return error(argument, "inspections.event.log.group.description.missing", groupId, file.name)
if (description.isBlank())
error(argument, "inspections.event.log.group.description.empty", groupId)
}
else {
val receiver = node.receiver
val (groupId, recorder) = receiver?.let { findGroupIdAndRecorderName(it) }
?: return warn(receiver ?: node, "inspections.event.log.event.group.not.evaluable")
val eventId = argument.evaluateString()?.takeIf { it.isNotBlank() }
?: return warn(argument, "inspections.event.log.event.id.not.evaluable")
findEventLogPropertiesFile(holder.project, recorder)?.let { file ->
val key = "${groupId}.${eventId}"
val description = file.findPropertyByKey(key)?.value
?: return error(argument, "inspections.event.log.event.description.missing", key, file.name)
if (description.isBlank())
error(argument, "inspections.event.log.event.description.empty", key)
}
}
}
return true
}
private fun warn(element: UElement, messageKey: @PropertyKey(resourceBundle = DevKitBundle.BUNDLE) String): Boolean {
element.sourcePsi?.let {
holder.registerProblem(it, DevKitBundle.message(messageKey), ProblemHighlightType.WARNING)
}
return true
}
private fun error(element: UElement, messageKey: @PropertyKey(resourceBundle = DevKitBundle.BUNDLE) String, vararg params: Any): Boolean {
element.sourcePsi?.let {
holder.registerProblem(it, DevKitBundle.message(messageKey, *params), ProblemHighlightType.GENERIC_ERROR)
}
return true
}
}
@@ -0,0 +1,59 @@
// Copyright 2000-2026 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.lang.properties.psi.PropertiesFile
import com.intellij.lang.properties.references.PropertyReferenceBase
import com.intellij.patterns.uast.injectionHostUExpression
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiLanguageInjectionHost
import com.intellij.psi.PsiReference
import com.intellij.psi.PsiReferenceContributor
import com.intellij.psi.PsiReferenceRegistrar
import com.intellij.psi.UastInjectionHostReferenceProvider
import com.intellij.psi.registerUastReferenceProvider
import com.intellij.util.ProcessingContext
import org.jetbrains.uast.UCallExpression
import org.jetbrains.uast.UExpression
import org.jetbrains.uast.UastCallKind
import org.jetbrains.uast.evaluateString
import org.jetbrains.uast.getParentOfType
internal class EventLogDescriptionReferenceContributor : PsiReferenceContributor() {
override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) {
registrar.registerUastReferenceProvider(
injectionHostUExpression().callParameter(0, eventLogGroupCall()),
EventLogDescriptionReferenceProvider(),
PsiReferenceRegistrar.DEFAULT_PRIORITY,
)
}
}
private class EventLogDescriptionReferenceProvider : UastInjectionHostReferenceProvider() {
override fun getReferencesForInjectionHost(
uExpression: UExpression,
host: PsiLanguageInjectionHost,
context: ProcessingContext,
): Array<PsiReference> {
val call = uExpression.getParentOfType(UCallExpression::class.java, true) ?: return PsiReference.EMPTY_ARRAY
if (call.kind == UastCallKind.CONSTRUCTOR_CALL) {
val groupId = uExpression.evaluateString() ?: return PsiReference.EMPTY_ARRAY
val recorder = findRecorderName(call) ?: return PsiReference.EMPTY_ARRAY
return arrayOf(EventLogDescriptionReference(groupId, host, recorder))
}
else {
val eventId = uExpression.evaluateString() ?: return PsiReference.EMPTY_ARRAY
val receiver = call.receiver ?: return PsiReference.EMPTY_ARRAY
val (groupId, recorder) = findGroupIdAndRecorderName(receiver) ?: return PsiReference.EMPTY_ARRAY
return arrayOf(EventLogDescriptionReference("${groupId}.${eventId}", host, recorder))
}
}
}
private class EventLogDescriptionReference(key: String, element: PsiElement, private val recorder: String)
: PropertyReferenceBase(key, /*soft =*/ true, element)
{
override fun getPropertiesFiles(): List<PropertiesFile?> {
val file = findEventLogPropertiesFile(this.element.project, recorder)
return if (file != null) listOf(file) else emptyList()
}
}
@@ -0,0 +1,65 @@
// Copyright 2000-2026 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.internal.statistic.eventLog.FUS_RECORDER
import com.intellij.lang.properties.psi.PropertiesFile
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.guessProjectDir
import com.intellij.patterns.ElementPattern
import com.intellij.patterns.PsiJavaPatterns.psiMethod
import com.intellij.patterns.uast.callExpression
import com.intellij.psi.PsiManager
import org.jetbrains.uast.UCallExpression
import org.jetbrains.uast.UExpression
import org.jetbrains.uast.UMethod
import org.jetbrains.uast.UQualifiedReferenceExpression
import org.jetbrains.uast.UResolvable
import org.jetbrains.uast.UVariable
import org.jetbrains.uast.UastCallKind
import org.jetbrains.uast.evaluateString
import org.jetbrains.uast.resolveToUElement
import org.jetbrains.uast.toUElementOfType
internal const val EVENT_LOG_GROUP_FQN = "com.intellij.internal.statistic.eventLog.EventLogGroup"
internal const val EVENT_LOG_PROPERTIES_DIR = "build/events"
private const val REGISTER_EVENT_NAME = "registerEvent"
private const val REGISTER_VARARG_EVENT_NAME = "registerVarargEvent"
internal fun eventLogGroupCall(): ElementPattern<UCallExpression> = callExpression().andOr(
callExpression().constructor(EVENT_LOG_GROUP_FQN),
callExpression().withAnyResolvedMethod(
psiMethod().withName(REGISTER_EVENT_NAME, REGISTER_VARARG_EVENT_NAME).definedInClass(EVENT_LOG_GROUP_FQN)
)
)
internal fun findRecorderName(call: UCallExpression): String? {
val recorderArg = call.getArgumentForParameter(2) ?: return FUS_RECORDER
return recorderArg.evaluateString()?.takeIf { it.isNotBlank() }
}
internal fun findGroupIdAndRecorderName(expression: UExpression): Pair<String, String>? = when (expression) {
is UCallExpression if (expression.kind == UastCallKind.CONSTRUCTOR_CALL) -> {
val groupId = expression.getArgumentForParameter(0)?.let(UExpression::evaluateString) ?: return null
val recorder = findRecorderName(expression) ?: return null
groupId to recorder
}
is UQualifiedReferenceExpression -> {
findGroupIdAndRecorderName(expression.selector)
}
else -> {
val variable = when (val resolved = (expression as? UResolvable)?.resolveToUElement()) {
is UVariable -> resolved
is UMethod -> resolved.sourcePsi.toUElementOfType<UVariable>() // Kotlin synthetic accessors
else -> null
} ?: return null
val initializer = variable.uastInitializer ?: return null
findGroupIdAndRecorderName(initializer)
}
}
internal fun findEventLogPropertiesFile(project: Project, recorder: String): PropertiesFile? {
val projectDir = project.guessProjectDir() ?: return null
val file = projectDir.findFileByRelativePath("${EVENT_LOG_PROPERTIES_DIR}/${recorder}.properties") ?: return null
return PsiManager.getInstance(project).findFile(file) as? PropertiesFile
}
@@ -12,8 +12,7 @@ import java.util.List;
import java.util.stream.Stream;
public class DevkitInspectionsRegistrationCheckTest extends BasePlatformTestCase {
private static final int EXPECTED_INSPECTIONS_NUMBER = 93;
private static final int EXPECTED_INSPECTIONS_NUMBER = 94;
/**
* Inspections that are finished and intentionally disabled.
@@ -0,0 +1,215 @@
// Copyright 2000-2026 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.lang.properties.psi.Property
import com.intellij.openapi.application.runReadAction
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase5
import org.jetbrains.idea.devkit.inspections.EventLogDescriptionInspection
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertNotEquals
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertInstanceOf
import org.junit.jupiter.api.assertNotNull
class EventLogDescriptionReferenceContributorTest : LightJavaCodeInsightFixtureTestCase5() {
@BeforeEach
fun setUp() {
fixture.addClass("""
package com.intellij.internal.statistic.eventLog;
public class EventLogGroup {
public EventLogGroup(String id, int version) {}
public EventLogGroup(String id, int version, String recorder) {}
public EventId registerEvent(String id) {}
public EventId registerVarargEvent(String id, Object... fields) {}
public static class EventId {}
}""".trimIndent()
)
fixture.addFileToProject("build/events/FUS.properties", """
my.group=FUS group
my.group.event=FUS event
my.group.var.event=FUS vararg event
empty.group=
my.group.empty.event=
""".trimIndent())
fixture.addFileToProject("build/events/ML.properties", "ml.group=ML group")
}
@Test
fun `group in default recorder - Java`() {
fixture.configureByText("Foo.java", """
import com.intellij.internal.statistic.eventLog.EventLogGroup;
class Foo {
private static final EventLogGroup GROUP = new EventLogGroup("my.group<caret>", 1);
}
""".trimIndent()
)
testResolve("FUS.properties", "FUS group")
}
@Test
fun `event in default recorder - Java`() {
fixture.configureByText("Foo.java", """
import com.intellij.internal.statistic.eventLog.EventLogGroup;
class Foo {
private static final EventLogGroup GROUP = new EventLogGroup("my.group", 1);
private static final EventLogGroup.EventId EVENT = GROUP.registerEvent("event<caret>");
}
""".trimIndent()
)
testResolve("FUS.properties", "FUS event")
}
@Test
fun `vararg event in default recorder - Java`() {
fixture.configureByText("Foo.java", """
import com.intellij.internal.statistic.eventLog.EventLogGroup;
class Foo {
private static final EventLogGroup GROUP = new EventLogGroup("my.group", 1);
private static final EventLogGroup.EventId EVENT = GROUP.registerVarargEvent("var.event<caret>", "whatever");
}
""".trimIndent()
)
testResolve("FUS.properties", "FUS vararg event")
}
@Test
fun `group in default recorder - Kotlin`() {
fixture.configureByText("Foo.kt", """
import com.intellij.internal.statistic.eventLog.EventLogGroup
object Foo {
private val GROUP = EventLogGroup("my.group<caret>", 1)
}
""".trimIndent()
)
testResolve("FUS.properties", "FUS group")
}
@Test
fun `event in default recorder - Kotlin`() {
fixture.configureByText("Foo.kt", """
import com.intellij.internal.statistic.eventLog.EventLogGroup
object Foo {
val GROUP = EventLogGroup("my.group", 1) // public, to verify the Kotlin property accessor way
val EVENT = GROUP.registerEvent("event<caret>")
}
""".trimIndent()
)
testResolve("FUS.properties", "FUS event")
}
@Test
fun `vararg event in default recorder - Kotlin`() {
fixture.configureByText("Foo.kt", """
import com.intellij.internal.statistic.eventLog.EventLogGroup
object Foo {
private val GROUP = EventLogGroup("my.group", 1)
private val EVENT = GROUP.registerVarargEvent("var.event<caret>", "whatever")
}
""".trimIndent()
)
testResolve("FUS.properties", "FUS vararg event")
}
@Test
fun `group in custom recorder`() {
fixture.configureByText("Foo.java", """
import com.intellij.internal.statistic.eventLog.EventLogGroup;
class Foo {
private static final String RECORDER = "ML";
private static final EventLogGroup GROUP = new EventLogGroup("ml.group<caret>", 1, RECORDER);
}""".trimIndent()
)
testResolve("ML.properties", "ML group")
}
@Test
fun `skipping navigation when recorder is non-evaluatable`() {
fixture.configureByText("Foo.java", """
import com.intellij.internal.statistic.eventLog.EventLogGroup;
class Foo {
private static String recorder() { return "ML"; }
private static final EventLogGroup GROUP = new EventLogGroup("ml.group<caret>", 1, recorder());
}""".trimIndent()
)
testNoResolve()
}
@Test
fun `problem highlighting - Java`() {
fixture.enableInspections(EventLogDescriptionInspection::class.java)
fixture.configureByText("Foo.java", """
import com.intellij.internal.statistic.eventLog.EventLogGroup;
class Foo {
// the good
private static final EventLogGroup GROUP = new EventLogGroup("my.group", 1);
private static final EventLogGroup.EventId EVENT = GROUP.registerEvent("event");
// the bad
private static final EventLogGroup G1 =
new EventLogGroup("-", 1, <warning descr="Cannot evaluate the recorder name; consider using a constant expression">System.getProperty("recorder")</warning>);
private static final EventLogGroup G2 =
new EventLogGroup("-", 1, <error descr="Unknown recorder ('build/events/WTF.properties' is missing)">"WTF"</error>);
private static final EventLogGroup G3 =
new EventLogGroup(<warning descr="Cannot evaluate the group ID; consider using a constant expression">System.getProperty("group")</warning>, 1, "FUS");
private static final EventLogGroup G4 =
new EventLogGroup(<error descr="Group 'missing.group' description is missing from 'FUS.properties'">"missing.group"</error>, 1);
private static final EventLogGroup G5 =
new EventLogGroup(<error descr="Group 'empty.group' description is empty">"empty.group"</error>, 1);
// the ugly
private static EventLogGroup group() { return new EventLogGroup("my.group", 1); }
private static final EventLogGroup.EventId E1 =
<warning descr="Cannot find the event group; consider using a constant expression">group()</warning>.registerEvent("-");
private static final EventLogGroup.EventId E2 =
GROUP.registerEvent(<warning descr="Cannot evaluate the event ID; consider using a constant expression">System.getProperty("event")</warning>);
private static final EventLogGroup.EventId E3 =
GROUP.registerEvent(<error descr="Event 'my.group.missing.event' description is missing from 'FUS.properties'">"missing.event"</error>);
private static final EventLogGroup.EventId E4 =
GROUP.registerEvent(<error descr="Event 'my.group.empty.event' description is empty">"empty.event"</error>);
}""".trimIndent()
)
fixture.checkHighlighting()
}
@Test
fun `problem highlighting - Kotlin`() {
fixture.enableInspections(EventLogDescriptionInspection::class.java)
fixture.configureByText("Foo.kt", """
import com.intellij.internal.statistic.eventLog.EventLogGroup
object Foo {
// the good
private val GROUP = EventLogGroup("my.group", 1)
private val EVENT = GROUP.registerEvent("event")
// the bad
private val G1 = EventLogGroup("-", 1, <warning descr="Cannot evaluate the recorder name; consider using a constant expression">System.getProperty("recorder")</warning>)
private val G2 = EventLogGroup("-", 1, <error descr="Unknown recorder ('build/events/WTF.properties' is missing)">"WTF"</error>)
private val G3 = EventLogGroup(<warning descr="Cannot evaluate the group ID; consider using a constant expression">System.getProperty("group")</warning>, 1, "FUS")
private val G4 = EventLogGroup(<error descr="Group 'missing.group' description is missing from 'FUS.properties'">"missing.group"</error>, 1)
private val G5 = EventLogGroup(<error descr="Group 'empty.group' description is empty">"empty.group"</error>, 1)
// the ugly
private fun group() = EventLogGroup("my.group", 1)
private val E1 = <warning descr="Cannot find the event group; consider using a constant expression">group()</warning>.registerEvent("-")
private val E2 = GROUP.registerEvent(<warning descr="Cannot evaluate the event ID; consider using a constant expression">System.getProperty("event")</warning>)
private val E3 = GROUP.registerEvent(<error descr="Event 'my.group.missing.event' description is missing from 'FUS.properties'">"missing.event"</error>)
private val E4 = GROUP.registerEvent(<error descr="Event 'my.group.empty.event' description is empty">"empty.event"</error>)
}""".trimIndent()
)
fixture.checkHighlighting()
}
private fun testResolve(expectedFile: String, expectedText: String) = runReadAction {
val reference = fixture.getReferenceAtCaretPosition()
assertNotNull(reference)
assertEquals("EventLogDescriptionReference", reference.javaClass.simpleName)
val property = assertInstanceOf<Property>(reference.resolve())
assertEquals(expectedFile, property.containingFile.name)
assertEquals(expectedText, property.value)
}
private fun testNoResolve() {
val reference = fixture.getReferenceAtCaretPosition()
if (reference != null) {
assertNotEquals("EventLogDescriptionReference", reference.javaClass.simpleName)
}
}
}