Skip to content

Commit

Permalink
Merge pull request #1487 from kpbochenek/goto-parent-method-right
Browse files Browse the repository at this point in the history
Goto super method in hierarchy of inheritance
  • Loading branch information
tgodzik authored Mar 24, 2020
2 parents 1081b85 + 55838e6 commit 39fa3cc
Show file tree
Hide file tree
Showing 26 changed files with 1,626 additions and 228 deletions.
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ inThisBuild(
List(
version ~= { dynVer =>
if (isCI) dynVer
else localSnapshotVersion // only for local publishng
else localSnapshotVersion // only for local publishing
},
scalaVersion := V.scala212,
crossScalaVersions := List(V.scala212),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package scala.meta.internal.implementation

import scala.meta.internal.semanticdb.SymbolInformation

final case class ClassHierarchyItem(
symbolInformation: SymbolInformation,
asSeenFrom: Map[String, String]
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ package scala.meta.internal.implementation

import org.eclipse.lsp4j.Location
import org.eclipse.lsp4j.TextDocumentPositionParams
import scala.meta.internal.mtags.GlobalSymbolIndex
import scala.meta.internal.mtags.Mtags
import scala.meta.internal.mtags.Semanticdbs
import scala.meta.internal.mtags.SymbolDefinition
import scala.meta.internal.mtags.{Symbol => MSymbol}
import scala.meta.internal.metals.MetalsEnrichments._
import scala.meta.io.AbsolutePath
Expand All @@ -16,7 +19,6 @@ import java.util.concurrent.ConcurrentHashMap
import java.nio.file.Path
import scala.meta.internal.semanticdb.SymbolInformation
import scala.meta.internal.semanticdb.MethodSignature
import scala.meta.internal.mtags.GlobalSymbolIndex
import scala.meta.internal.metals.BuildTargets
import scala.meta.internal.metals.Buffers
import scala.meta.internal.metals.DefinitionProvider
Expand All @@ -26,7 +28,6 @@ import scala.meta.internal.semanticdb.TypeSignature
import scala.collection.mutable
import scala.meta.internal.symtab.GlobalSymbolTable
import scala.util.control.NonFatal
import scala.meta.internal.mtags.Mtags
import java.util.concurrent.ConcurrentLinkedQueue

final class ImplementationProvider(
Expand Down Expand Up @@ -80,30 +81,47 @@ final class ImplementationProvider(
}
}

def defaultSymbolSearch(
textDocumentWithPath: TextDocumentWithPath
): String => Option[SymbolInformation] =
defaultSymbolSearch(
textDocumentWithPath.filePath,
textDocumentWithPath.textDocument
)

def defaultSymbolSearch(
anyWorkspacePath: AbsolutePath,
textDocument: TextDocument
): String => Option[SymbolInformation] = {
lazy val global =
new GlobalClassTable(buildTargets).globalSymbolTableFor(anyWorkspacePath)
symbol => {
textDocument.symbols
.find(_.symbol == symbol)
.orElse(findSymbolInformation(symbol))
.orElse(global.flatMap(_.safeInfo(symbol)))
}
}

def implementations(
params: TextDocumentPositionParams
): List[Location] = {
val source = params.getTextDocument.getUri.toAbsolutePath
lazy val global = globalTable.globalSymbolTableFor(source)
val locations = for {
(symbolOccurrence, currentDocument) <- definitionProvider
.symbolOccurence(
.symbolOccurrence(
source,
params
params.getPosition
)
.toIterable
} yield {
// 1. Search locally for symbol
// 2. Search inside workspace
// 3. Search classpath via GlobalSymbolTable
def symbolSearch(symbol: String): Option[SymbolInformation] = {
findSymbol(currentDocument, symbol)
.orElse(findSymbolDef(symbol))
.orElse(global.flatMap(_.safeInfo(symbol)))
}
val symbolSearch = defaultSymbolSearch(source, currentDocument)
val sym = symbolOccurrence.symbol
val dealiased =
if (sym.desc.isType) dealiasClass(sym, symbolSearch _) else sym
if (sym.desc.isType) dealiasClass(sym, symbolSearch) else sym

val definitionDocument =
if (currentDocument.definesSymbol(dealiased)) {
Expand Down Expand Up @@ -147,20 +165,19 @@ final class ImplementationProvider(
if (owner.nonEmpty) {
findSymbol(textDocument, owner)
} else {
textDocument.symbols.find {
case sym =>
sym.signature match {
case sig: ClassSignature =>
sig.declarations.exists(_.symlinks.contains(symbol))
case _ => false
}
textDocument.symbols.find { sym =>
sym.signature match {
case sig: ClassSignature =>
sig.declarations.exists(_.symlinks.contains(symbol))
case _ => false
}
}
}
}

val results = for {
currentInfo <- findSymbol(textDocument, symbol)
if (!isClassLike(currentInfo))
if !isClassLike(currentInfo)
classInfo <- findClassInfo(symbol.owner)
} yield {
classInfo.signature match {
Expand Down Expand Up @@ -266,18 +283,13 @@ final class ImplementationProvider(
if (isClassLike(parentSymbolInfo))
Some(implReal.symbol)
else {
lazy val global = globalTable.globalSymbolTableFor(source)
def localSearch(symbol: String): Option[SymbolInformation] = {
findSymbol(implDocument, symbol)
.orElse(findSymbolDef(symbol))
.orElse(global.flatMap(_.safeInfo(symbol)))
}
val symbolSearch = defaultSymbolSearch(source, implDocument)
MethodImplementation.findInherited(
parentSymbolInfo,
symbolClass,
classContext,
implReal,
localSearch
symbolSearch
)
}
}
Expand Down Expand Up @@ -331,10 +343,10 @@ final class ImplementationProvider(
loc =>
// we are not interested in local symbols from outside the workspace
(loc.symbol.isLocal && loc.file.isEmpty) ||
// local symbols ineheritance should only be picked up in the same file
// local symbols inheritance should only be picked up in the same file
(loc.symbol.isLocal && loc.file != currentPath)
}
directImplementations.toSet ++ directImplementations
directImplementations ++ directImplementations
.flatMap { loc =>
val allPossible = loop(loc.symbol, loc.file)
allPossible.map(_.translateAsSeenFrom(loc))
Expand All @@ -348,13 +360,28 @@ final class ImplementationProvider(
}
}

private def findSymbolDef(symbol: String): Option[SymbolInformation] = {
private def findSymbolInformation(
symbol: String
): Option[SymbolInformation] = {
findSemanticDbForSymbol(symbol).flatMap(findSymbol(_, symbol))
}

def findSemanticDbWithPathForSymbol(
symbol: String
): Option[TextDocumentWithPath] = {
for {
symbolDefinition <- findSymbolDefinition(symbol)
document <- findSemanticdb(symbolDefinition.path)
} yield TextDocumentWithPath(document, symbolDefinition.path)
}

private def findSymbolDefinition(symbol: String): Option[SymbolDefinition] = {
index.definition(MSymbol(symbol))
}

private def findSemanticDbForSymbol(symbol: String): Option[TextDocument] = {
for {
symbolDefinition <- index.definition(MSymbol(symbol))
symbolDefinition <- findSymbolDefinition(symbol)
document <- findSemanticdb(symbolDefinition.path)
} yield {
document
Expand Down Expand Up @@ -422,7 +449,7 @@ object ImplementationProvider {
}
}

def findSymbol(
private def findSymbol(
semanticDb: TextDocument,
symbol: String
): Option[SymbolInformation] = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ object MethodImplementation {
findSymbol,
asSeenFrom
)
if isOverridenMethod(
if isOverriddenMethod(
methodSymbolInfo,
bottomSymbolInformation,
findParent = true
Expand Down Expand Up @@ -88,12 +88,12 @@ object MethodImplementation {
inheritanceContext.findSymbol,
asSeenFrom
)
if isOverridenMethod(methodSymbolInfo, parentSymbol)(context)
if isOverriddenMethod(methodSymbolInfo, parentSymbol)(context)
} yield methodSymbol
validMethods.headOption
}

private def isOverridenMethod(
private def isOverriddenMethod(
methodSymbolInfo: SymbolInformation,
otherSymbol: SymbolInformation,
findParent: Boolean = false
Expand Down Expand Up @@ -202,22 +202,35 @@ object MethodImplementation {
}
}

def checkSignaturesEqual(
parentSignature: MethodSignature,
childSignature: MethodSignature,
asSeenFrom: Map[String, String],
findSymbol: String => Option[SymbolInformation]
): Boolean = {
val context = Context(findSymbol, findSymbol, asSeenFrom)
signaturesEqual(parentSignature, childSignature)(context)
}

private def signaturesEqual(
parentSig: Signature,
sig: Signature
parentSignature: Signature,
childSignature: Signature
)(implicit context: Context): Boolean = {
(parentSig, sig) match {
case (sig1: MethodSignature, sig2: MethodSignature) =>
(parentSignature, childSignature) match {
case (
methodParentSignature: MethodSignature,
methodChildSignature: MethodSignature
) =>
val newContext = context.addAsSeenFrom(
typeMappingFromMethodScope(
sig1.typeParameters,
sig2.typeParameters
methodParentSignature.typeParameters,
methodChildSignature.typeParameters
)
)
lazy val enrichedSig1 =
addParameterSignatures(sig1, context.findSymbol)
addParameterSignatures(methodParentSignature, context.findSymbol)
lazy val enrichedSig2 =
addParameterSignatures(sig2, context.findSymbol)
addParameterSignatures(methodChildSignature, context.findSymbol)
paramsAreEqual(
enrichedSig1.parameterLists,
enrichedSig2.parameterLists
Expand Down
Loading

0 comments on commit 39fa3cc

Please sign in to comment.