Skip to content

Instantly share code, notes, and snippets.

@dubik
Created September 5, 2014 09:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dubik/a9bb09efa5b6d6f211c7 to your computer and use it in GitHub Desktop.
Save dubik/a9bb09efa5b6d6f211c7 to your computer and use it in GitHub Desktop.
package org.dubikdev.rpp.lang.psi
import com.intellij.psi.{PsiFile, PsiElement, PsiReferenceBase}
import com.intellij.openapi.util.TextRange
import scala.collection.JavaConverters._
import scala.reflect.ClassTag
class RppReferenceImpl(element: RppId, textRange: TextRange)
extends PsiReferenceBase(element, textRange) {
override def resolve(): PsiElement = {
val identifier = element.getPlainid
recResolveIdentifier(element.getParent, identifier)
}
private def getValOrNull[T](func: () => T): Option[T] = {
try {
val v = func()
if (v != null)
Some(v)
else
None
} catch {
case i: NullPointerException => None
case t: Throwable => throw new Exception
}
}
private def searchInBlockStat(blockStat: RppBlockStat, identifier: PsiElement): Option[PsiElement] = {
// Block can have 'var' or 'val'
val rppPatDefOpt = getValOrNull(() => blockStat.getDef.getPatVarDef.getValDef) match {
case Some(x) => Some(x.getPatDef)
case None => getValOrNull(() => blockStat.getDef.getPatVarDef.getVarDef) match {
case Some(x) => Some(x.getPatDef)
case None => None
}
}
rppPatDefOpt match {
case Some(x) => x.getPattern2List.asScala.find(_.getPlainid.getText == identifier.getText)
case None => None
}
}
private def searchInAndUp(element: PsiElement, identifier: PsiElement): PsiElement = {
var found: Option[PsiElement] = None
var foundElement: PsiElement = null
var current = element
while (current != null) {
found = current match {
case rppBlockStat: RppBlockStat => searchInBlockStat(rppBlockStat, identifier)
case rppFun: RppFunDef => rppFun.getFunSig.getParamClauses.getParamClause.getParams.getParamList.asScala.find(_.getPlainid.getText == identifier.getText)
case rppClass: RppClassDef => None
case psiFile: PsiFile => return null
case _ => None
}
found match {
case None => if (current.getPrevSibling == null) {
current = current.getParent
} else {
current = current.getPrevSibling
}
case Some(x) => current = null // Exit from loop
foundElement = x
}
}
foundElement
}
private def recResolveIdentifier(element: PsiElement, identifier: PsiElement): PsiElement = {
findEnclosingElement[RppBlockStat](identifier) match {
case Some(x) => searchInAndUp(x, identifier)
case None => findEnclosingElement[RppExpr](identifier) match {
case Some(x) => searchInAndUp(x, identifier)
case None => null
}
}
}
private def findEnclosingElement[E <: PsiElement : ClassTag](element: PsiElement): Option[E] = {
element match {
case null => None
case parentElement: E if parentElement.isInstanceOf[E] => Some(parentElement)
case _: PsiElement => findEnclosingElement(element.getParent)
}
}
override def getVariants: Array[AnyRef] = {
Array()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment