@@ -2,23 +2,19 @@ package com.example.ide.psi
22
33
44import com.example.ide.completion.findReferenceStyleFile
5- import com.intellij.lang.ecmascript6.psi.ES6ImportedBinding
65import com.intellij.lang.javascript.JSTokenTypes
76import com.intellij.lang.javascript.psi.JSFile
87import com.intellij.lang.javascript.psi.JSIndexedPropertyAccessExpression
98import com.intellij.lang.javascript.psi.JSLiteralExpression
10- import com.intellij.lang.javascript.psi.JSReferenceExpression
119import com.intellij.patterns.PlatformPatterns
1210import com.intellij.psi.*
13- import com.intellij.psi.css.StylesheetFile
14- import com.intellij.psi.filters.ElementFilter
15- import com.intellij.psi.filters.position.FilterPattern
1611import com.intellij.util.ProcessingContext
1712import org.jetbrains.annotations.NotNull
1813
1914
2015/* *
21- * Reference provider for styles["className"] syntax
16+ * Reference provider for styles["className"] syntax.
17+ * All validation logic is centralized here to avoid duplicate PSI resolution.
2218 */
2319class CssModuleIndexedReferenceProvider : PsiReferenceProvider () {
2420
@@ -27,8 +23,21 @@ class CssModuleIndexedReferenceProvider : PsiReferenceProvider() {
2723 context : ProcessingContext
2824 ): Array <PsiReference > {
2925 if (element !is JSLiteralExpression ) return PsiReference .EMPTY_ARRAY
26+
27+ // Fast check: must be a string literal token
28+ if (element.node.firstChildNode?.elementType != JSTokenTypes .STRING_LITERAL ) {
29+ return PsiReference .EMPTY_ARRAY
30+ }
31+
32+ // Fast check: must be inside indexed property access (styles["xxx"])
33+ if (element.parent !is JSIndexedPropertyAccessExpression ) {
34+ return PsiReference .EMPTY_ARRAY
35+ }
36+
3037 val name = element.stringValue?.trim().orEmpty()
3138 if (name.isBlank()) return PsiReference .EMPTY_ARRAY
39+
40+ // Expensive check: resolve to style file (done only once here)
3241 val styleFile = findReferenceStyleFile(element) ? : return PsiReference .EMPTY_ARRAY
3342
3443 // Always return a dynamic reference that resolves fresh each time
@@ -37,54 +46,13 @@ class CssModuleIndexedReferenceProvider : PsiReferenceProvider() {
3746}
3847
3948/* *
40- * Reference provider for styles.className syntax
49+ * Simplified filter - only does basic type matching.
50+ * Expensive PSI resolution is deferred to the provider.
4151 */
42- class CssModuleDotReferenceProvider : PsiReferenceProvider () {
43-
44- override fun getReferencesByElement (
45- element : PsiElement ,
46- context : ProcessingContext
47- ): Array <PsiReference > {
48- if (element !is JSReferenceExpression ) return PsiReference .EMPTY_ARRAY
49-
50- // Get the qualifier (the part before the dot, e.g., "styles" in "styles.app")
51- val qualifier = element.qualifier
52- if (qualifier !is JSReferenceExpression ) return PsiReference .EMPTY_ARRAY
53-
54- // Resolve the qualifier to check if it's a CSS module import
55- val resolved = qualifier.reference?.resolve()
56- if (resolved !is ES6ImportedBinding ) return PsiReference .EMPTY_ARRAY
57-
58- val referencedElements = resolved.findReferencedElements()
59- if (referencedElements.isEmpty()) return PsiReference .EMPTY_ARRAY
60-
61- val styleFile = referencedElements.first() as ? StylesheetFile ? : return PsiReference .EMPTY_ARRAY
62-
63- // Get the property name (the part after the dot)
64- val propertyName = element.referenceName ? : return PsiReference .EMPTY_ARRAY
65-
66- return arrayOf(CssModuleClassReference (element, styleFile, propertyName))
67- }
68- }
69-
70- // Filter for styles["className"] syntax
71- private val INDEXED_ACCESS_FILTER = PlatformPatterns .psiElement(JSLiteralExpression ::class .java).and (
72- FilterPattern (
73- object : ElementFilter {
74- override fun isAcceptable (element : Any? , context : PsiElement ? ): Boolean {
75- return element is JSLiteralExpression
76- && element.parent is JSIndexedPropertyAccessExpression
77- && context != null
78- && context.containingFile is JSFile
79- && isStyleIndex(element)
80- && element.node.firstChildNode?.elementType == JSTokenTypes .STRING_LITERAL
81- }
82-
83- override fun isClassAcceptable (hintClass : Class <* >? ): Boolean {
84- return JSLiteralExpression ::class .java.isAssignableFrom(hintClass!! )
85- }
86- }
87- ))
52+ private val INDEXED_ACCESS_FILTER = PlatformPatterns
53+ .psiElement(JSLiteralExpression ::class .java)
54+ .withParent(JSIndexedPropertyAccessExpression ::class .java)
55+ .inFile(PlatformPatterns .psiFile(JSFile ::class .java))
8856
8957
9058class CssModulesIndexedStylesVarPsiReferenceContributor : PsiReferenceContributor () {
@@ -96,4 +64,8 @@ class CssModulesIndexedStylesVarPsiReferenceContributor : PsiReferenceContributo
9664 }
9765}
9866
99- fun isStyleIndex (element : JSLiteralExpression ): Boolean = findReferenceStyleFile(element) != = null
67+ /* *
68+ * Check if the element is a style index expression (styles["className"]).
69+ * This function is used by other parts of the codebase (e.g., annotator).
70+ */
71+ fun isStyleIndex (element : JSLiteralExpression ): Boolean = findReferenceStyleFile(element) != null
0 commit comments