Skip to content

Commit

Permalink
Implement References - wip (open-policy-agent#113)
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrea Canonica committed Apr 6, 2023
1 parent 4f21821 commit 1995360
Show file tree
Hide file tree
Showing 15 changed files with 284 additions and 30 deletions.
18 changes: 10 additions & 8 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@ jobs:

steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v1
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: 11
java-version: 17
distribution: corretto

# Cache gradle dependencies
- uses: actions/cache@v2
Expand Down Expand Up @@ -71,10 +72,11 @@ jobs:

steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v1
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: 11
java-version: 17
distribution: corretto

# Cache gradle dependencies
- uses: actions/cache@v2
Expand All @@ -94,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
Expand Down
20 changes: 8 additions & 12 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,15 @@ idea {
}
}

intellij {
version.set("2022.2.5")
plugins.set(listOf("com.intellij.java"))
}

plugins {
idea
kotlin("jvm") version "1.7.21"
id("org.jetbrains.intellij") version "1.11.0"
kotlin("jvm") version "1.8.10"
id("org.jetbrains.intellij") version "1.13.3"
id("org.jetbrains.grammarkit") version "2021.2.2"
}

Expand Down Expand Up @@ -89,7 +94,7 @@ allprojects {

// Set the JVM language level used to build project. Use Java 11 for 2020.3+, and Java 17 for 2022.2+.
kotlin {
jvmToolchain(11)
jvmToolchain(17)
}

sourceSets {
Expand All @@ -99,15 +104,6 @@ allprojects {
}

tasks {
// There is a bug in gradle and tests are not detected. This is a workaround until gradle 7.5 is released.
// More information at https://youtrack.jetbrains.com/issue/IDEA-278926#focus=Comments-27-5561012.0-0 and
// https://github.com/gradle/gradle/pull/20123
val test by getting(Test::class) {
setScanForTestClasses(false)
// Only run tests from classes that end with "Test"
include("**/*Test.class")
}

withType<org.jetbrains.intellij.tasks.PatchPluginXmlTask> {
sinceBuild.set(prop("sinceBuild"))
untilBuild.set(prop("untilBuild"))
Expand Down
12 changes: 6 additions & 6 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ kotlin.code.style=official
baseIDE=idea

# if you change the version of ide, also change psiViewerPluginVersion accordingly (cf https://plugins.jetbrains.com/plugin/227-psiviewer/versions)
ideaVersion=IC-2022.1
pycharmCommunityVersion=PC-2022.1
psiViewerPluginVersion=221-SNAPSHOT
ideaVersion=IC-2022.2
pycharmCommunityVersion=PC-2022.2
psiViewerPluginVersion=222-SNAPSHOT

# see https://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/build_number_ranges.html for more information
sinceBuild=221
untilBuild=223.*
sinceBuild=222
untilBuild=231.*

# these two variables will be overwrite by the release process (ie the github action) thanks to the env variables:
# these two variables will be overwritten by the release process (i.e. the GitHub action) thanks to the env variables:
# - ORG_GRADLE_PROJECT_publishToken
# - ORG_GRADLE_PROJECT_publishChannel
# - ORG_GRADLE_PROJECT_pluginVersion
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
2 changes: 2 additions & 0 deletions plugin/src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
<!-- although Rego module type is only created by IDEA, we need it in other IDEs as well
to be able to open a project created in IDEA without errors -->
<moduleType id="REGO_MODULE" implementationClass="org.openpolicyagent.ideaplugin.ide.extensions.RegoModuleType"/>
<psi.referenceContributor language="kotlin"
implementation="org.openpolicyagent.ideaplugin.ide.reference.RegoReferenceContributor"/>
</extensions>

</idea-plugin>
5 changes: 5 additions & 0 deletions src/main/grammar/Rego.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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<out PsiReference> {
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<PsiReference>(RegoReference(element, rule))
}
return PsiReference.EMPTY_ARRAY
}
})
}
}
57 changes: 57 additions & 0 deletions src/main/kotlin/org/openpolicyagent/ideaplugin/lang/RegoUtil.kt
Original file line number Diff line number Diff line change
@@ -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<RegoRule> {
val result = mutableListOf<RegoRule>()
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<RegoRule> {
val result = mutableListOf<RegoRule>()
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
}
}
Original file line number Diff line number Diff line change
@@ -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
}
}
Original file line number Diff line number Diff line change
@@ -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<PsiElement>(element, textRange),
PsiPolyVariantReference {
private val key: String

init {
key = element.text.substring(textRange.startOffset, textRange.endOffset)
}

override fun multiResolve(incompleteCode: Boolean): Array<out ResolveResult> {
val project = myElement!!.project
val rules = RegoUtil.findRules(project, key)
val results = mutableListOf<ResolveResult>()
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<out Any> {
val project = myElement!!.project
val rules = RegoUtil.findRules(project)
val variants = mutableListOf<LookupElement>()
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()
}
}
Original file line number Diff line number Diff line change
@@ -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
}
}
}
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit 1995360

Please sign in to comment.