scala.tools.nsc.doc.model.MemberLookup.scala Maven / Gradle / Ivy
The newest version!
/*
* Scala (https://www.scala-lang.org)
*
* Copyright EPFL and Lightbend, Inc.
*
* Licensed under Apache License 2.0
* (http://www.apache.org/licenses/LICENSE-2.0).
*
* See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*/
package scala.tools.nsc
package doc
package model
import java.nio.file.Paths
import base._
import scala.tools.nsc.io.AbstractFile
/** This trait extracts all required information for documentation from compilation units */
trait MemberLookup extends base.MemberLookupBase {
thisFactory: ModelFactory =>
import global._
import definitions.{ NothingClass, AnyClass, AnyValClass, AnyRefClass }
override def internalLink(sym: Symbol, site: Symbol): Option[LinkTo] =
findTemplateMaybe(sym) match {
case Some(tpl) => Some(LinkToTpl(tpl))
case None =>
findTemplateMaybe(site) flatMap { inTpl =>
inTpl.members find (_.asInstanceOf[EntityImpl].sym == sym) map (LinkToMember(_, inTpl))
}
}
override def chooseLink(links: List[LinkTo]): LinkTo = {
val mbrs = links.collect {
case lm@LinkToMember(mbr: MemberEntity, _) => (mbr, lm)
}
if (mbrs.isEmpty)
links.head
else
mbrs.min(Ordering[MemberEntity].on[(MemberEntity, LinkTo)](_._1))._2
}
override def toString(link: LinkTo) = link match {
case LinkToTpl(tpl: EntityImpl) => tpl.sym.toString
case LinkToMember(mbr: EntityImpl, inTpl: EntityImpl) =>
mbr.sym.signatureString + " in " + inTpl.sym.toString
case _ => link.toString
}
override def findExternalLink(sym: Symbol, name: String): Option[LinkTo] = {
val sym1 =
if (sym == AnyClass || sym == AnyRefClass || sym == AnyValClass || sym == NothingClass)
definitions.ScalaPackageClass.info.member(newTermName("package"))
else if (sym.hasPackageFlag)
/* Get package object which has associatedFile ne null */
sym.info.member(newTermName("package"))
else sym
classpathEntryFor(sym1) flatMap { path =>
if (isJDK(sym1)) {
Some(LinkToExternalTpl(name, jdkUrl(path), makeTemplate(sym)))
}
else {
settings.extUrlMapping get path map { url =>
LinkToExternalTpl(name, url, makeTemplate(sym))
}
}
}
}
private def classpathEntryFor(s: Symbol): Option[String] = {
Option(s.associatedFile).flatMap(_.underlyingSource).map { src =>
val path = src.canonicalPath
if(path.endsWith(".class")) { // Individual class file -> Classpath entry is root dir
val nesting = s.ownerChain.count(_.hasPackageFlag)
if(nesting > 0) {
val p = 0.until(nesting).foldLeft(src) {
case (null, _) => null
case (f, _) => f.container
}
if(p eq null) path else p.canonicalPath
} else path
} else path // JAR file (and fallback option)
}
}
/**
* Check if this file is a child of the given directory string. Can only be used
* on directories that actually exist in the file system.
*/
def isChildOf(f: AbstractFile, dir: String): Boolean = {
val parent = Paths.get(dir).toAbsolutePath().toString
f.canonicalPath.startsWith(parent)
}
private def isJDK(sym: Symbol) =
sym.associatedFile.underlyingSource.map(f => isChildOf(f, (sys.props("java.home")))).getOrElse(false)
def jdkUrl(path: String): String = {
if (path.endsWith(".jmod")) {
val tokens = path.split(java.io.File.separatorChar)
val module = tokens.last.stripSuffix(".jmod")
s"$jdkUrl/$module"
}
else {
jdkUrl
}
}
def jdkUrl: String = {
if (settings.jdkApiDocBase.isDefault)
defaultJdkUrl
else
settings.jdkApiDocBase.value
}
lazy val defaultJdkUrl = {
if (javaVersion < 11) {
s"https://docs.oracle.com/javase/$javaVersion/docs/api"
}
else {
s"https://docs.oracle.com/en/java/javase/$javaVersion/docs/api"
}
}
lazy val javaVersion: Int =
System.getProperty("java.specification.version").split('.').take(2).map(_.toIntOption) match {
case Array(Some(1), Some(n)) => n // example: 1.8.0_242
case Array(Some(n)) => n // example: 14
case Array(Some(n), _) => n // example: 11.0.7
case _ => 8 // shrug!
}
override def warnNoLink = !settings.docNoLinkWarnings.value
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy