Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Goto super method in hierarchy of inheritance #1487

Merged
merged 19 commits into from
Mar 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
kpbochenek marked this conversation as resolved.
Show resolved Hide resolved
}

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