diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index dc7d268..a48f3bc 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -96,10 +96,10 @@ jobs:
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- - name: Verify plugin binany compatibility
+ - name: Verify plugin binary compatibility
run: ./gradlew :plugin:runPluginVerifier
- # This job is successful if all depend jobs are successful. To be able to merge the PR, this job must be successful
+ # This job is successful if all dependent jobs are successful. To be able to merge the PR, this job must be successful
all-checks:
needs: [build, check-license, check-gradle-wrapper, verify]
runs-on: ubuntu-latest
diff --git a/build.gradle.kts b/build.gradle.kts
index c3ccb20..e5fd262 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -42,6 +42,11 @@ idea {
}
}
+intellij {
+ version.set("2022.2.5")
+ plugins.set(listOf("com.intellij.java"))
+}
+
plugins {
idea
kotlin("jvm") version "1.8.10"
diff --git a/plugin/src/main/resources/META-INF/plugin.xml b/plugin/src/main/resources/META-INF/plugin.xml
index 376c7c3..466d2c3 100644
--- a/plugin/src/main/resources/META-INF/plugin.xml
+++ b/plugin/src/main/resources/META-INF/plugin.xml
@@ -33,6 +33,8 @@
+
\ No newline at end of file
diff --git a/src/main/grammar/Rego.bnf b/src/main/grammar/Rego.bnf
index 0b8434d..5028535 100644
--- a/src/main/grammar/Rego.bnf
+++ b/src/main/grammar/Rego.bnf
@@ -12,6 +12,7 @@
psiImplClassSuffix="Impl"
psiPackage= "org.openpolicyagent.ideaplugin.lang.psi"
psiImplPackage="org.openpolicyagent.ideaplugin.lang.psi.impl"
+ psiImplUtilClass="org.openpolicyagent.ideaplugin.lang.psi.ruleelements.RegoPsiImplUtil"
elementTypeHolderClass="org.openpolicyagent.ideaplugin.lang.psi.RegoTypes"
elementTypeClass="org.openpolicyagent.ideaplugin.lang.psi.RegoElementType"
@@ -67,6 +68,10 @@ module ::= package (import| rule)*
package ::= "package" ref
import ::= "import" ref ( "as" var )?
rule ::= "default"? rule-head rule-body*
+{
+ mixin="org.openpolicyagent.ideaplugin.lang.psi.ruleelements.RegoRuleElementImpl"
+ implements="org.openpolicyagent.ideaplugin.lang.psi.ruleelements.RegoRuleElement"
+}
rule-head ::= var ( "(" rule-args? ")" )? ("[" term "]" )? ( ( ":=" | "=" ) expr )?
rule-args ::= term ( "," term )*
rule-body ::= else-expr | query-block
diff --git a/src/main/kotlin/org/openpolicyagent/ideaplugin/ide/highlight/RegoHighlighterAnnotator.kt b/src/main/kotlin/org/openpolicyagent/ideaplugin/ide/highlight/RegoHighlighterAnnotator.kt
index ef1bc0a..52f91c4 100644
--- a/src/main/kotlin/org/openpolicyagent/ideaplugin/ide/highlight/RegoHighlighterAnnotator.kt
+++ b/src/main/kotlin/org/openpolicyagent/ideaplugin/ide/highlight/RegoHighlighterAnnotator.kt
@@ -6,7 +6,6 @@
package org.openpolicyagent.ideaplugin.ide.highlight
import com.intellij.lang.annotation.AnnotationHolder
-import com.intellij.lang.annotation.Annotator
import com.intellij.lang.annotation.HighlightSeverity
import com.intellij.psi.PsiElement
import org.openpolicyagent.ideaplugin.ide.colors.RegoColor
diff --git a/src/main/kotlin/org/openpolicyagent/ideaplugin/ide/reference/RegoReferenceContributor.kt b/src/main/kotlin/org/openpolicyagent/ideaplugin/ide/reference/RegoReferenceContributor.kt
new file mode 100644
index 0000000..7197df7
--- /dev/null
+++ b/src/main/kotlin/org/openpolicyagent/ideaplugin/ide/reference/RegoReferenceContributor.kt
@@ -0,0 +1,33 @@
+/*
+ * Use of this source code is governed by the MIT license that can be
+ * found in the LICENSE file.
+ */
+
+package org.openpolicyagent.ideaplugin.ide.reference
+
+import com.intellij.openapi.util.TextRange
+import com.intellij.patterns.PlatformPatterns
+import com.intellij.psi.*
+import com.intellij.util.ProcessingContext
+import org.openpolicyagent.ideaplugin.lang.psi.RegoReference
+
+class RegoReferenceContributor : PsiReferenceContributor() {
+ override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) {
+ registrar.registerReferenceProvider(
+ PlatformPatterns.psiElement(PsiLiteralExpression::class.java),
+ object : PsiReferenceProvider() {
+ override fun getReferencesByElement(
+ element: PsiElement,
+ context: ProcessingContext
+ ): Array {
+ val literalExpression = element as PsiLiteralExpression
+ val value = if (literalExpression.value is String) literalExpression.value as String else null
+ if (value != null && value.matches(Regex(".+\\{"))) {
+ val rule = TextRange(0, value.indexOf("{"))
+ return arrayOf(RegoReference(element, rule))
+ }
+ return PsiReference.EMPTY_ARRAY
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/org/openpolicyagent/ideaplugin/lang/RegoUtil.kt b/src/main/kotlin/org/openpolicyagent/ideaplugin/lang/RegoUtil.kt
new file mode 100644
index 0000000..3d80d1c
--- /dev/null
+++ b/src/main/kotlin/org/openpolicyagent/ideaplugin/lang/RegoUtil.kt
@@ -0,0 +1,57 @@
+/*
+ * Use of this source code is governed by the MIT license that can be
+ * found in the LICENSE file.
+ */
+
+package org.openpolicyagent.ideaplugin.lang
+
+import com.intellij.openapi.project.Project
+import com.intellij.psi.PsiManager
+import com.intellij.psi.search.FileTypeIndex
+import com.intellij.psi.search.GlobalSearchScope
+import com.intellij.psi.util.PsiTreeUtil
+import org.openpolicyagent.ideaplugin.lang.psi.RegoFile
+import org.openpolicyagent.ideaplugin.lang.psi.RegoRule
+
+object RegoUtil {
+ /**
+ * Searches the entire project for Rego language files with instances of the Rego-Rule with the given key.
+ *
+ * @param project current project
+ * @param ruleName to check
+ * @return matching properties
+ */
+ fun findRules(project: Project, ruleName: String): List {
+ val result = mutableListOf()
+ val virtualFiles = FileTypeIndex.getFiles(RegoFileType, GlobalSearchScope.allScope(project))
+ for (virtualFile in virtualFiles) {
+ val simpleFile = PsiManager.getInstance(project).findFile(virtualFile!!) as RegoFile?
+ if (simpleFile != null) {
+ val rules = PsiTreeUtil.getChildrenOfType(simpleFile, RegoRule::class.java)
+ if (rules != null) {
+ for (rule in rules) {
+ if (ruleName == rule.name) {
+ result.add(rule)
+ }
+ }
+ }
+ }
+ }
+ return result
+ }
+
+ fun findRules(project: Project?): List {
+ val result = mutableListOf()
+ val virtualFiles = FileTypeIndex.getFiles(RegoFileType, GlobalSearchScope.allScope(project!!))
+ for (virtualFile in virtualFiles) {
+ val regoFile = PsiManager.getInstance(project).findFile(virtualFile!!) as RegoFile?
+ if (regoFile != null) {
+ val rules = PsiTreeUtil.getChildrenOfType(regoFile, RegoRule::class.java)
+ if (rules != null) {
+ result.addAll(rules)
+ }
+ }
+ }
+ return result
+ }
+}
diff --git a/src/main/kotlin/org/openpolicyagent/ideaplugin/lang/psi/RegoElementFactory.kt b/src/main/kotlin/org/openpolicyagent/ideaplugin/lang/psi/RegoElementFactory.kt
new file mode 100644
index 0000000..b08b7ed
--- /dev/null
+++ b/src/main/kotlin/org/openpolicyagent/ideaplugin/lang/psi/RegoElementFactory.kt
@@ -0,0 +1,23 @@
+/*
+ * Use of this source code is governed by the MIT license that can be
+ * found in the LICENSE file.
+ */
+
+package org.openpolicyagent.ideaplugin.lang.psi
+
+import com.intellij.openapi.project.Project
+import com.intellij.psi.PsiFileFactory
+import org.openpolicyagent.ideaplugin.lang.RegoFileType
+
+
+object RegoElementFactory {
+ fun createRule(project: Project?, name: String): RegoRule {
+ val file = createFile(project, name)
+ return file.firstChild as RegoRule
+ }
+
+ fun createFile(project: Project?, text: String): RegoFile {
+ val name = "dummy.rego"
+ return PsiFileFactory.getInstance(project).createFileFromText(name, RegoFileType, text) as RegoFile
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/org/openpolicyagent/ideaplugin/lang/psi/RegoReference.kt b/src/main/kotlin/org/openpolicyagent/ideaplugin/lang/psi/RegoReference.kt
new file mode 100644
index 0000000..1d7ac49
--- /dev/null
+++ b/src/main/kotlin/org/openpolicyagent/ideaplugin/lang/psi/RegoReference.kt
@@ -0,0 +1,55 @@
+/*
+ * Use of this source code is governed by the MIT license that can be
+ * found in the LICENSE file.
+ */
+
+package org.openpolicyagent.ideaplugin.lang.psi
+
+import com.intellij.codeInsight.lookup.LookupElement
+import com.intellij.codeInsight.lookup.LookupElementBuilder
+import com.intellij.openapi.util.TextRange
+import com.intellij.psi.*
+import org.openpolicyagent.ideaplugin.lang.RegoIcons
+import org.openpolicyagent.ideaplugin.lang.RegoUtil
+
+
+class RegoReference(element: PsiElement, textRange: TextRange) : PsiReferenceBase(element, textRange),
+ PsiPolyVariantReference {
+ private val key: String
+
+ init {
+ key = element.text.substring(textRange.startOffset, textRange.endOffset)
+ }
+
+ override fun multiResolve(incompleteCode: Boolean): Array {
+ val project = myElement!!.project
+ val rules = RegoUtil.findRules(project, key)
+ val results = mutableListOf()
+ for (rule in rules) {
+ results.add(PsiElementResolveResult(rule))
+ }
+ return results.toTypedArray()
+ }
+
+ override fun resolve(): PsiElement? {
+ val resolveResults = multiResolve(false)
+ return if (resolveResults.size == 1) resolveResults[0].element else null
+ }
+
+ override fun getVariants(): Array {
+ val project = myElement!!.project
+ val rules = RegoUtil.findRules(project)
+ val variants = mutableListOf()
+ for (rule in rules) {
+ if (rule.name != null && rule.name!!.isNotEmpty()) {
+ variants.add(
+ LookupElementBuilder
+ .create(rule)
+ .withIcon(RegoIcons.OPA)
+ .withTypeText(rule.containingFile.name)
+ )
+ }
+ }
+ return variants.toTypedArray()
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/org/openpolicyagent/ideaplugin/lang/psi/ruleelements/RegoPsiImplUtil.kt b/src/main/kotlin/org/openpolicyagent/ideaplugin/lang/psi/ruleelements/RegoPsiImplUtil.kt
new file mode 100644
index 0000000..a07ec0b
--- /dev/null
+++ b/src/main/kotlin/org/openpolicyagent/ideaplugin/lang/psi/ruleelements/RegoPsiImplUtil.kt
@@ -0,0 +1,45 @@
+/*
+ * Use of this source code is governed by the MIT license that can be
+ * found in the LICENSE file.
+ */
+
+package org.openpolicyagent.ideaplugin.lang.psi.ruleelements
+
+import com.intellij.psi.PsiElement
+import org.openpolicyagent.ideaplugin.lang.psi.RegoElementFactory
+import org.openpolicyagent.ideaplugin.lang.psi.RegoRule
+import org.openpolicyagent.ideaplugin.lang.psi.RegoTypes
+
+
+class RegoPsiImplUtil {
+ companion object {
+
+ @JvmStatic
+ fun getRuleHead(element: RegoRule): String? {
+ val keyNode = element.node.findChildByType(RegoTypes.RULE_HEAD)
+ return keyNode?.text
+ }
+
+ @JvmStatic
+ fun getName(element: RegoRule): String? {
+ return getRuleHead(element)
+ }
+
+ @JvmStatic
+ fun setName(element: RegoRule, newName: String): PsiElement {
+ val keyNode = element.node.findChildByType(RegoTypes.RULE_HEAD)
+ if (keyNode != null) {
+ val property = RegoElementFactory.createRule(element.project, newName)
+ val newKeyNode = property.firstChild.node
+ element.node.replaceChild(keyNode, newKeyNode)
+ }
+ return element
+ }
+
+ @JvmStatic
+ fun getNameIdentifier(element: RegoRule): PsiElement? {
+ val keyNode = element.node.findChildByType(RegoTypes.RULE_HEAD)
+ return keyNode?.psi
+ }
+ }
+}
diff --git a/src/main/kotlin/org/openpolicyagent/ideaplugin/lang/psi/ruleelements/RegoRuleElement.kt b/src/main/kotlin/org/openpolicyagent/ideaplugin/lang/psi/ruleelements/RegoRuleElement.kt
new file mode 100644
index 0000000..54d0ac9
--- /dev/null
+++ b/src/main/kotlin/org/openpolicyagent/ideaplugin/lang/psi/ruleelements/RegoRuleElement.kt
@@ -0,0 +1,10 @@
+/*
+ * Use of this source code is governed by the MIT license that can be
+ * found in the LICENSE file.
+ */
+
+package org.openpolicyagent.ideaplugin.lang.psi.ruleelements
+
+import com.intellij.psi.PsiNameIdentifierOwner
+
+interface RegoRuleElement : PsiNameIdentifierOwner
\ No newline at end of file
diff --git a/src/main/kotlin/org/openpolicyagent/ideaplugin/lang/psi/ruleelements/RegoRuleElementImpl.kt b/src/main/kotlin/org/openpolicyagent/ideaplugin/lang/psi/ruleelements/RegoRuleElementImpl.kt
new file mode 100644
index 0000000..42c9b9b
--- /dev/null
+++ b/src/main/kotlin/org/openpolicyagent/ideaplugin/lang/psi/ruleelements/RegoRuleElementImpl.kt
@@ -0,0 +1,28 @@
+/*
+ * Use of this source code is governed by the MIT license that can be
+ * found in the LICENSE file.
+ */
+
+package org.openpolicyagent.ideaplugin.lang.psi.ruleelements
+
+import com.intellij.extapi.psi.ASTWrapperPsiElement
+import com.intellij.lang.ASTNode
+import com.intellij.psi.PsiElement
+import org.openpolicyagent.ideaplugin.lang.psi.RegoRule
+import org.openpolicyagent.ideaplugin.lang.psi.ruleelements.RegoPsiImplUtil.Companion.getName
+import org.openpolicyagent.ideaplugin.lang.psi.ruleelements.RegoPsiImplUtil.Companion.getNameIdentifier
+import org.openpolicyagent.ideaplugin.lang.psi.ruleelements.RegoPsiImplUtil.Companion.setName
+
+abstract class RegoRuleElementImpl(node: ASTNode) : ASTWrapperPsiElement(node), RegoRuleElement {
+ override fun getName(): String? {
+ return getName(this as RegoRule)
+ }
+
+ override fun setName(newName: String): PsiElement {
+ return setName(this as RegoRule, newName)
+ }
+
+ override fun getNameIdentifier(): PsiElement? {
+ return getNameIdentifier(this as RegoRule)
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/META-INF/opa-core.xml b/src/main/resources/META-INF/opa-core.xml
index 44f6955..8378c03 100644
--- a/src/main/resources/META-INF/opa-core.xml
+++ b/src/main/resources/META-INF/opa-core.xml
@@ -49,8 +49,7 @@
-
-
+