Skip to content

Handle exports presenting in scala3doc #10504

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

Merged
merged 5 commits into from
Nov 30, 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
1 change: 1 addition & 0 deletions compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2436,6 +2436,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
def EmptyFlags = dotc.core.Flags.EmptyFlags
def Enum: Flags = dotc.core.Flags.Enum
def Erased: Flags = dotc.core.Flags.Erased
def Exported: Flags = dotc.core.Flags.Exported
def ExtensionMethod: Flags = dotc.core.Flags.ExtensionMethod
def FieldAccessor: Flags = dotc.core.Flags.Accessor
def Final: Flags = dotc.core.Flags.Final
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ object Extractors {
if (flags.is(Flags.Enum)) flagList += "Flags.Enum"
if (flags.is(Flags.Erased)) flagList += "Flags.Erased"
if (flags.is(Flags.ExtensionMethod)) flagList += "Flags.ExtensionMethod"
if (flags.is(Flags.Exported)) flagList += "Flags.Exported"
if (flags.is(Flags.FieldAccessor)) flagList += "Flags.FieldAccessor"
if (flags.is(Flags.Final)) flagList += "Flags.Final"
if (flags.is(Flags.HasDefault)) flagList += "Flags.HasDefault"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ object SourceCode {
if (flags.is(Flags.Enum)) flagList += "enum"
if (flags.is(Flags.Erased)) flagList += "erased"
if (flags.is(Flags.ExtensionMethod)) flagList += "extension"
if (flags.is(Flags.Exported)) flagList += "exported"
if (flags.is(Flags.FieldAccessor)) flagList += "accessor"
if (flags.is(Flags.Final)) flagList += "final"
if (flags.is(Flags.HasDefault)) flagList += "hasDefault"
Expand Down
3 changes: 3 additions & 0 deletions library/src/scala/quoted/Quotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3154,6 +3154,9 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
/** Is this symbol `erased` */
def Erased: Flags

/** Is this symbol exported from provided instance */
def Exported: Flags

/** Is this symbol a `def` defined in an `extension` */
def ExtensionMethod: Flags

Expand Down
23 changes: 23 additions & 0 deletions scala3doc-testcases/src/tests/exports.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package tests
package exports

class A:
def aDefInt: Int = 1
def aDef1: 1 = 1
val aValInt: Int = 1
val aVal1: 1 = 1
var aVarInt: Int = 1
var aVar1: 1 = 1

object X:
def xDefInt: Int = 1
def xDef1: 1 = 1
val xValInt: Int = 1
val xVal1: 1 = 1
var xVarInt: Int = 1
var xVar1: 1 = 1

class B:
val a = new A
export a._
export X._
2 changes: 2 additions & 0 deletions scala3doc/src/dotty/dokka/model/api/api.scala
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ enum Kind(val name: String){
case Constructor extends Kind("def")
case Var extends Kind("var")
case Val extends Kind("val")
case Exported extends Kind("export")
case Type(concreate: Boolean, opaque: Boolean) extends Kind("Type") // should we handle opaque as modifier?
case Given(as: Option[Signature], conversion: Option[ImplicitConversion]) extends Kind("Given") with ImplicitConversionProvider
case Implicit(kind: Kind, conversion: Option[ImplicitConversion]) extends Kind(kind.name) with ImplicitConversionProvider
Expand All @@ -73,6 +74,7 @@ enum Origin:
case InheritedFrom(name: String, dri: DRI)
case ImplicitlyAddedBy(name: String, dri: DRI)
case ExtensionFrom(name: String, dri: DRI)
case ExportedFrom(name: String, dri: Option[DRI])
case DefinedWithin

case class Annotation(val dri: DRI, val params: List[Annotation.AnnotationParameter])
Expand Down
20 changes: 20 additions & 0 deletions scala3doc/src/dotty/dokka/site/PartiallyRenderedContent.scala
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,23 @@ case class PartiallyRenderedContent(
}
}// forrach does not work here
document.outerHtml()


class A:
def defInt: Int = 1
def def1: 1 = 1
val valInt: Int = 1
val val1: 1 = 1
var varInt: Int = 1
var var1: 1 = 1

object X:
def x: Int = 1
val x2: 1 = 1
var x3: Int = 1

class B:
val a = new A
export a._
export X._

16 changes: 15 additions & 1 deletion scala3doc/src/dotty/dokka/tasty/ClassLikeSupport.scala
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,21 @@ trait ClassLikeSupport:
.map { _ =>
parseMethod(dd.symbol, kind = Kind.Given(getGivenInstance(dd).map(_.asSignature), None))
}

case dd: DefDef if !dd.symbol.isHiddenByVisibility && dd.symbol.isExported =>
val exportedTarget = dd.rhs.collect {
case a: Apply => a.fun.asInstanceOf[Select]
case s: Select => s
}
val functionName = exportedTarget.fold("function")(_.name)
val instanceName = exportedTarget.collect {
case Select(qualifier: Select, _) => qualifier.name
case Select(qualifier: Ident, _) => qualifier.tpe.typeSymbol.normalizedName
}.getOrElse("instance")
val dri = dd.rhs.collect {
case s: Select if s.symbol.isDefDef => s.symbol.dri
}.orElse(exportedTarget.map(_.qualifier.tpe.typeSymbol.dri))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will typeSymbol works with object? See comment above.

Copy link
Contributor Author

@BarkingBad BarkingBad Nov 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hard to tell. Could not produce anything breaking the generation.

EDIT: That was my misinterpretation

However, there is one interesting thing, for that code:

object X:
  def x: Int = 1
  val x2: Int = 1
  var x3: Int = 1

class B:
  val a = new A
  export a._
  export X._

we get following output:

obraz

I will have to check is it our bug, but it sees x2 as Int, not literal 1, which is odd, since that type is stable and safe to assume it's literal type (as it did with previous vals)

Some(parseMethod(dd.symbol, kind = Kind.Exported).withOrigin(Origin.ExportedFrom(s"$instanceName.$functionName", dri)))

case dd: DefDef if !dd.symbol.isHiddenByVisibility && !dd.symbol.isGiven && !dd.symbol.isSyntheticFunc && !dd.symbol.isExtensionMethod =>
Some(parseMethod(dd.symbol))
Expand Down Expand Up @@ -184,7 +199,6 @@ trait ClassLikeSupport:
case dd: DefDef if !dd.symbol.isClassConstructor && !(dd.symbol.isSuperBridgeMethod || dd.symbol.isDefaultHelperMethod) => dd
case other => other
}

c.membersToDocument.flatMap(parseMember) ++
inherited.flatMap(s => parseInheritedMember(s))
}
Expand Down
2 changes: 2 additions & 0 deletions scala3doc/src/dotty/dokka/tasty/SymOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ class SymOps[Q <: Quotes](val q: Q):

def isGiven: Boolean = sym.flags.is(Flags.Given)

def isExported: Boolean = sym.flags.is(Flags.Exported)

def isExtensionMethod: Boolean = sym.flags.is(Flags.ExtensionMethod)

def isLeftAssoc(d: Symbol): Boolean = !d.name.endsWith(":")
Expand Down
9 changes: 6 additions & 3 deletions scala3doc/src/dotty/dokka/tasty/TypesSupport.scala
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,12 @@ trait TypesSupport:
// case _ =>
// throw Exception("Match error in TypeRef. This should not happen, please open an issue. " + convertTypeOrBoundsToReference(reflect)(qual))
// }
case tr @ TermRef(qual, typeName) => qual match {
case _ => link(tr.termSymbol)
}
case tr @ TermRef(qual, typeName) =>
tr.termSymbol.tree match
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one here is a little bit tricky. The reason behind this is to extract ConstantType when one occurs

case vd: ValDef => inner(vd.tpt.tpe)
case _ => link(tr.termSymbol)


// convertTypeOrBoundsToReference(reflect)(qual) match {
// case TypeReference(label, link, xs, _) => TypeReference(typeName + "$", link + "/" + label, xs)
// case EmptyReference => TypeReference(typeName, "", Nil)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ object FilterAttributes:
case Origin.InheritedFrom(name, _) => Map("inherited" -> name)
case Origin.ImplicitlyAddedBy(name, _) => Map("implicitly" -> s"by $name")
case Origin.ExtensionFrom(name, _) => Map("extension" -> s"from $name")
case Origin.ExportedFrom(name, _) => Map("export" -> s"from $name")
case _ => Map.empty
case null =>
Map.empty
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,11 @@ class ScalaPageContentBuilder(
val originInfo = documentable.origin match {
case Origin.ImplicitlyAddedBy(name, dri) => Signature("Implicitly added by ", SLink(name, dri))
case Origin.ExtensionFrom(name, dri) => Signature("Extension method from ", SLink(name, dri))
case Origin.ExportedFrom(name, dri) =>
val signatureName: String | dotty.dokka.model.api.Link = dri match
case Some(dri: DRI) => SLink(name, dri)
case None => name
Signature("Exported from ", signatureName)
case _ => Nil
}

Expand Down
4 changes: 4 additions & 0 deletions scala3doc/src/dotty/dokka/translators/ScalaPageCreator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ class ScalaPageCreator(
val (definedTypes, inheritedTypes) = s.membersBy(_.kind.isInstanceOf[Kind.Type])
val (definedGivens, inheritedGives) = s.membersBy(_.kind.isInstanceOf[Kind.Given])
val (definedExtensions, inheritedExtensions) = s.membersBy(_.kind.isInstanceOf[Kind.Extension])
val exports = s.allMembers.filter(_.kind == Kind.Exported)
val (definedImplicits, inheritedImplicits) = s.membersBy(_.kind.isInstanceOf[Kind.Implicit])

b
Expand Down Expand Up @@ -381,6 +382,9 @@ class ScalaPageCreator(
DocumentableGroup(Some("Defined implicits"), definedImplicits),
DocumentableGroup(Some("Inherited implicits"), inheritedImplicits)
)
.documentableTab("Exports")(
DocumentableGroup(Some("Defined exports"), exports)
)


def contentForEnum(c: DClass) =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ object ScalaSignatureProvider:
extensionSignature(extension, builder)
case method: DFunction if method.kind.isInstanceOf[Kind.Given] =>
givenMethodSignature(method, builder)
case exprt: DFunction if exprt.kind == Kind.Exported =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need that case and exportedMethodSignature since we handle it as methodSignature anyway ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can delete, but thought it would be more reasonable to state that explicitly

exportedMethodSignature(exprt, builder)
case method: DFunction =>
methodSignature(method, builder)
case enumEntry: DClass if enumEntry.kind == Kind.EnumCase =>
Expand Down Expand Up @@ -138,14 +140,14 @@ object ScalaSignatureProvider:
} else {
extension.getParameters.asScala(0)
}
val withSinature = builder
val withSignature = builder
.modifiersAndVisibility(extension, "def")
.name(extension.getName, extension.getDri)
.generics(extension)
.functionParameters(extension)

if extension.isConstructor then withSinature
else withSinature.text(":").text(" ").typeSignature(extension.getType)
if extension.isConstructor then withSignature
else withSignature.text(":").text(" ").typeSignature(extension.getType)

private def givenMethodSignature(method: DFunction, builder: SignatureBuilder): SignatureBuilder = method.kind match
case Kind.Given(Some(instance), _) =>
Expand All @@ -156,6 +158,8 @@ object ScalaSignatureProvider:
case _ =>
builder.text("given ").name(method.getName, method.getDri)

private def exportedMethodSignature(method: DFunction, builder: SignatureBuilder): SignatureBuilder =
methodSignature(method, builder)

private def methodSignature(method: DFunction, builder: SignatureBuilder): SignatureBuilder =
val bdr = builder
Expand Down