Improved finding references in library code.

This commit is contained in:
Rik van der Kleij 2019-03-17 15:57:23 +01:00
parent 427fe7e95e
commit bce9451c18
5 changed files with 61 additions and 52 deletions

View File

@ -125,8 +125,8 @@ private[component] object DefinitionLocationComponent {
if (libraryFile || key.importQualifier.isDefined || key.qualifiedNameElement.getQualifierName.isDefined) {
findLocationByImportedIdentifiers(project, key, name) match {
case Some(r) => r
case None => if (libraryFile) {
case r@Right(_) => r
case Left(_) => if (libraryFile) {
ProgressManager.checkCanceled()
HaskellComponentsManager.findNameInfo(key.qualifiedNameElement) match {
@ -135,7 +135,7 @@ private[component] object DefinitionLocationComponent {
ProgressManager.checkCanceled()
HaskellReference.findIdentifiersByNameInfo(info, key.qualifiedNameElement.getIdentifierElement, project) match {
case Right(nes) if nes.nonEmpty => nes.headOption.map(ne => Right(PackageModuleLocation(findModuleName(ne), ne, name))).getOrElse(Left(NoInfoAvailable(name, psiFile.getName)))
case Right((mn, ne)) => Right(PackageModuleLocation(findModuleName(ne), ne, name))
case Left(noInfo) =>
HaskellReference.findIdentifierInFileByName(psiFile, name).
map(ne => Right(PackageModuleLocation(findModuleName(ne), ne, name))).getOrElse(Left(noInfo))
@ -158,7 +158,7 @@ private[component] object DefinitionLocationComponent {
val withoutLastColumn = name.headOption.exists(_.isUpper)
findLocationByRepl(project, psiFile, moduleName, key, name, withoutLastColumn) match {
case r@Right(_) => r
case Left(_) => findLocationByImportedIdentifiers(project, key, name).getOrElse(Left(NoInfoAvailable(name, key.psiFile.getName)))
case Left(_) => findLocationByImportedIdentifiers(project, key, name)
}
}
}
@ -167,25 +167,24 @@ private[component] object DefinitionLocationComponent {
Option(namedElement.getContainingFile).flatMap(HaskellPsiUtil.findModuleName).getOrElse("-")
}
private def findLocationByImportedIdentifiers(project: Project, key: Key, name: String): Option[DefinitionLocationResult] = {
val psiFile = key.psiFile
val mids = FileModuleIdentifiers.findAvailableModuleIdentifiers(psiFile)
private def findLocationByImportedIdentifiers(project: Project, key: Key, name: String): Either[NoInfo, PackageModuleLocation] = {
ProgressManager.checkCanceled()
val psiFile = key.psiFile
val qNameName = key.qualifiedNameElement.getName
val qName = key.importQualifier match {
case None => qNameName
case Some(q) => q + "." + qNameName
}
for {
mid <- mids.find(_.name == qName)
} yield {
HaskellReference.findIdentifiersByModuleAndName(project, Seq(mid.moduleName), name) match {
case Right(nes) if nes.nonEmpty => nes.headOption.map(ne => Right(PackageModuleLocation(mid.moduleName, ne, name, Some(qName)))).getOrElse(Left(NoInfoAvailable(name, psiFile.getName)))
case _ => Left(NoInfoAvailable(name, psiFile.getName))
}
val moduleNames = FileModuleIdentifiers.findAvailableModuleIdentifiers(psiFile).filter(_.name == qName).map(_.moduleName).toSeq
ProgressManager.checkCanceled()
HaskellReference.findIdentifiersByModulesAndName(project, moduleNames, name) match {
case Right((mn, ne)) => Right(PackageModuleLocation(mn, ne, name))
case Left(noInfo) => Left(noInfo)
}
}
@ -268,11 +267,9 @@ sealed trait DefinitionLocation {
def namedElement: HaskellNamedElement
def originalName: String
def originalQualifiedName: Option[String]
}
case class PackageModuleLocation(moduleName: String, namedElement: HaskellNamedElement, originalName: String, originalQualifiedName: Option[String] = None) extends DefinitionLocation
case class PackageModuleLocation(moduleName: String, namedElement: HaskellNamedElement, originalName: String) extends DefinitionLocation
case class LocalModuleLocation(psiFile: PsiFile, namedElement: HaskellNamedElement, originalName: String, originalQualifiedName: Option[String] = None) extends DefinitionLocation
case class LocalModuleLocation(psiFile: PsiFile, namedElement: HaskellNamedElement, originalName: String) extends DefinitionLocation

View File

@ -128,8 +128,8 @@ object FileModuleIdentifiers {
}
}
private def getModuleIdentifiersFromFullImportedModules(impliciPrelueActive: Boolean, psiFile: PsiFile, importDeclarations: Iterable[HaskellImportDeclaration]): Future[Iterable[Option[Iterable[ModuleIdentifier]]]] = {
val importInfos = getFullImportedModules(impliciPrelueActive, psiFile, importDeclarations)
private def getModuleIdentifiersFromFullImportedModules(noImplicitPrelude: Boolean, psiFile: PsiFile, importDeclarations: Iterable[HaskellImportDeclaration]): Future[Iterable[Option[Iterable[ModuleIdentifier]]]] = {
val importInfos = getFullImportedModules(noImplicitPrelude, psiFile, importDeclarations)
Future.sequence(importInfos.map(importInfo => {
val allModuleIdentifiers = HaskellComponentsManager.findModuleIdentifiers(psiFile.getProject, importInfo.moduleName)
@ -173,14 +173,14 @@ object FileModuleIdentifiers {
info.isImplicitPreludeActive || ApplicationUtil.runReadAction(HaskellPsiUtil.findLanguageExtensions(psiFile)).exists(p => ApplicationUtil.runReadAction(p.getText).contains("NoImplicitPrelude"))
}
private def getFullImportedModules(implicitPreludeActive: Boolean, psiFile: PsiFile, importDeclarations: Iterable[HaskellImportDeclaration]): Iterable[ImportFull] = {
private def getFullImportedModules(noImplicitPrelude: Boolean, psiFile: PsiFile, importDeclarations: Iterable[HaskellImportDeclaration]): Iterable[ImportFull] = {
val moduleNames = for {
id <- importDeclarations
if Option(id.getImportSpec).isEmpty
mn <- ApplicationUtil.runReadAction(id.getModuleName)
} yield ImportFull(mn, Option(id.getImportQualified).isDefined, Option(id.getImportQualifiedAs).map(qa => ApplicationUtil.runReadAction(qa.getQualifier.getName)))
if (moduleNames.map(_.moduleName).toSeq.contains(HaskellProjectUtil.Prelude) || implicitPreludeActive) {
if (moduleNames.map(_.moduleName).toSeq.contains(HaskellProjectUtil.Prelude) || noImplicitPrelude) {
moduleNames
} else {
Iterable(ImportFull(HaskellProjectUtil.Prelude, qualified = false, None)) ++ moduleNames

View File

@ -68,8 +68,8 @@ object HoogleComponent {
None
case Right(info) =>
val moduleName = info match {
case PackageModuleLocation(mn, _, _, _) => Some(mn)
case LocalModuleLocation(pf, _, _, _) => HaskellPsiUtil.findModuleName(pf)
case PackageModuleLocation(mn, _, _) => Some(mn)
case LocalModuleLocation(pf, _, _) => HaskellPsiUtil.findModuleName(pf)
}
moduleName match {
case None =>

View File

@ -167,8 +167,8 @@ class HaskellReference(element: HaskellNamedElement, textRange: TextRange) exten
ProgressManager.checkCanceled()
HaskellComponentsManager.findDefinitionLocation(psiFile, qualifiedNameElement, importQualifier) match {
case Right(PackageModuleLocation(_, ne, _, _)) => Right(ne)
case Right(LocalModuleLocation(_, ne, _, _)) => Right(ne)
case Right(PackageModuleLocation(_, ne, _)) => Right(ne)
case Right(LocalModuleLocation(_, ne, _)) => Right(ne)
case Left(noInfo) => Left(noInfo)
}
}
@ -178,12 +178,10 @@ class HaskellReference(element: HaskellNamedElement, textRange: TextRange) exten
}
private def findHaskellFile(importDeclarations: Iterable[HaskellImportDeclaration], qualifierElement: HaskellNamedElement, project: Project): Either[NoInfo, Option[PsiFile]] = {
val result = for {
id <- importDeclarations.find(id => id.getModuleName.contains(qualifierElement.getName))
(for {
id <- importDeclarations.find(_.getModuleName.contains(qualifierElement.getName))
mn <- id.getModuleName
} yield HaskellModuleNameIndex.findFilesByModuleName(project, mn)
result match {
} yield HaskellModuleNameIndex.findFilesByModuleName(project, mn)) match {
case Some(Right(files)) => Right(files.headOption)
case Some(Left(noInfo)) => Left(noInfo)
case None => Right(None)
@ -199,34 +197,48 @@ object HaskellReference {
HaskellEditorUtil.showStatusBarBalloonMessage(project, "Navigating to instance declarations is not available at this moment")
Seq()
} else {
identifiers.flatMap(_.toOption).flatten
identifiers.flatMap(_.toOption.map(_._2))
}
}
def findIdentifiersByLibraryNameInfo(project: Project, libraryNameInfo: LibraryNameInfo, name: String): Either[NoInfo, Seq[HaskellNamedElement]] = {
findIdentifiersByModuleAndName(project, Seq(libraryNameInfo.moduleName), name)
def findIdentifiersByLibraryNameInfo(project: Project, libraryNameInfo: LibraryNameInfo, name: String): Either[NoInfo, (String, HaskellNamedElement)] = {
findIdentifiersByModuleAndName(project, libraryNameInfo.moduleName, name)
}
def findIdentifiersByModuleAndName(project: Project, moduleNames: Seq[String], name: String): Either[NoInfo, Seq[HaskellNamedElement]] = {
def findIdentifiersByModuleAndName(project: Project, moduleName: String, name: String): Either[NoInfo, (String, HaskellNamedElement)] = {
ProgressManager.checkCanceled()
moduleNames.map(mn => HaskellModuleNameIndex.findFilesByModuleName(project, mn)).find(_.isLeft) match {
case Some(Left(noInfo)) => Left(noInfo)
case _ =>
findIdentifiersByModulesAndName(project, Seq(moduleName), name)
}
def findIdentifiersByModulesAndName(project: Project, moduleNames: Seq[String], name: String): Either[NoInfo, (String, HaskellNamedElement)] = {
ProgressManager.checkCanceled()
findIdentifiersByModuleAndName2(project, moduleNames, name).headOption.map {
case (mn, nes) => nes.headOption.map(ne => Right((mn, ne))).getOrElse(Left(NoInfoAvailable(name, moduleNames.mkString(" | "))))
}.getOrElse(Left(ModuleNotAvailable(moduleNames.mkString(" | "))))
}
private def findIdentifiersByModuleAndName2(project: Project, moduleNames: Seq[String], name: String): Seq[(String, Seq[HaskellNamedElement])] = {
ProgressManager.checkCanceled()
moduleNames.distinct.flatMap(mn => HaskellModuleNameIndex.findFilesByModuleName(project, mn) match {
case Left(_) => Seq()
case Right(files) =>
ProgressManager.checkCanceled()
val identifiers = moduleNames.map(mn => HaskellModuleNameIndex.findFilesByModuleName(project, mn)).flatMap(_.toSeq.flatMap(_.flatMap(f => findIdentifierInFileByName(f, name))))
val identifiers = files.flatMap(f => findIdentifierInFileByName(f, name))
if (identifiers.isEmpty) {
val importedModuleNames = moduleNames.map(mn => HaskellModuleNameIndex.findFilesByModuleName(project, mn)).flatMap(_.toSeq.flatMap(_.flatMap(pf => HaskellPsiUtil.findImportDeclarations(pf).flatMap(_.getModuleName))))
val importedModuleNames = files.flatMap(f => FileModuleIdentifiers.findAvailableModuleIdentifiers(f).filter(_.name == name).map(_.moduleName))
if (importedModuleNames.isEmpty) {
Right(Seq())
Seq()
} else {
findIdentifiersByModuleAndName(project, importedModuleNames, name)
findIdentifiersByModuleAndName2(project, importedModuleNames, name)
}
} else {
Right(identifiers)
Seq((mn, identifiers))
}
}
})
}
def findIdentifierInFileByName(psifile: PsiFile, name: String): Option[HaskellNamedElement] = {
@ -291,7 +303,7 @@ object HaskellReference {
}
}
def findIdentifiersByNameInfo(nameInfo: NameInfo, namedElement: HaskellNamedElement, project: Project): Either[NoInfo, Seq[HaskellNamedElement]] = {
def findIdentifiersByNameInfo(nameInfo: NameInfo, namedElement: HaskellNamedElement, project: Project): Either[NoInfo, (Option[String], HaskellNamedElement)] = {
ProgressManager.checkCanceled()
val name = namedElement.getName
@ -300,11 +312,11 @@ object HaskellReference {
val (virtualFile, psiFile) = HaskellFileUtil.findFileInRead(project, pni.filePath)
ProgressManager.checkCanceled()
(virtualFile, psiFile) match {
case (Some(vf), Right(pf)) => findIdentifierByLocation(project, vf, pf, pni.lineNr, pni.columnNr, name).map(r => Right(Seq(r))).getOrElse(Left(NoInfoAvailable(name, "-")))
case (Some(vf), Right(pf)) => findIdentifierByLocation(project, vf, pf, pni.lineNr, pni.columnNr, name).map(r => Right(HaskellPsiUtil.findModuleName(pf), r)).getOrElse(Left(NoInfoAvailable(name, "-")))
case (_, Right(_)) => Left(NoInfoAvailable(name, "-"))
case (_, Left(noInfo)) => Left(noInfo)
}
case lni: LibraryNameInfo => findIdentifiersByLibraryNameInfo(project, lni, name)
case lni: LibraryNameInfo => findIdentifiersByLibraryNameInfo(project, lni, name).map({ case (mn, nes) => (Some(mn), nes) })
case _ => Left(NoInfoAvailable(name, "-"))
}
}

View File

@ -68,8 +68,8 @@ class HoogleByNameContributor extends ChooseByNameContributor {
val result = HaskellComponentsManager.findNameInfoByModuleName(project, moduleName, name)
ProgressManager.checkCanceled()
val navigationItemByNameInfo = result.toOption.flatMap(_.headOption) match {
case Some(lni: LibraryNameInfo) => HaskellReference.findIdentifiersByLibraryNameInfo(project, lni, name).toOption.getOrElse(Seq()).
flatMap(HaskellPsiUtil.findDeclarationElement).map(d => createLibraryNavigationItem(d, moduleName))
case Some(lni: LibraryNameInfo) => HaskellReference.findIdentifiersByLibraryNameInfo(project, lni, name).toOption.
flatMap(x => HaskellPsiUtil.findDeclarationElement(x._2)).map(d => createLibraryNavigationItem(d, moduleName)).toSeq
case Some(pni: ProjectNameInfo) =>
HaskellFileUtil.findFileInRead(project, pni.filePath) match {
case (Some(virtualFile), Right(psiFile)) => HaskellReference.findIdentifierByLocation(project, virtualFile, psiFile, pni.lineNr, pni.columnNr, name).flatMap(HaskellPsiUtil.findDeclarationElement).toSeq
@ -81,11 +81,11 @@ class HoogleByNameContributor extends ChooseByNameContributor {
if (navigationItemByNameInfo.nonEmpty) {
navigationItemByNameInfo
} else {
val identifiers = HaskellReference.findIdentifiersByModuleAndName(project, Seq(moduleName), name).toOption
val identifiers = HaskellReference.findIdentifiersByModuleAndName(project, moduleName, name).toOption.map(_._2).toSeq
if (identifiers.isEmpty) {
NotFoundResult(moduleName, declaration)
} else {
identifiers.getOrElse(Seq()).map(e => HaskellPsiUtil.findDeclarationElement(e).getOrElse(e))
identifiers.flatMap(e => HaskellPsiUtil.findDeclarationElement(e))
}
}
})