alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Scala example source code file (ModelFactoryTypeSupport.scala)

This example Scala source code file (ModelFactoryTypeSupport.scala) is included in my "Source Code Warehouse" project. The intent of this project is to help you more easily find Scala source code examples by using tags.

All credit for the original source code belongs to scala-lang.org; I'm just trying to make examples easier to find. (For my Scala work, see my Scala examples and tutorials.)

Scala tags/keywords

collection, compiler, modelfactorytypesupport, nil, nsc, objectclass, polytype, some, tooltip, type, typeentity, typeref, unit

The ModelFactoryTypeSupport.scala Scala example source code

/* NSC -- new Scala compiler -- Copyright 2007-2013 LAMP/EPFL */

package scala.tools.nsc
package doc
package model

import base._
import diagram._

import scala.collection._

/** This trait extracts all required information for documentation from compilation units */
trait ModelFactoryTypeSupport {
  thisFactory: ModelFactory
               with ModelFactoryImplicitSupport
               with ModelFactoryTypeSupport
               with DiagramFactory
               with CommentFactory
               with TreeFactory
               with MemberLookup =>

  import global._
  import definitions.{ ObjectClass, NothingClass, AnyClass, AnyValClass, AnyRefClass }

  protected val typeCache = new mutable.LinkedHashMap[Type, TypeEntity]

  /** */
  def makeType(aType: Type, inTpl: TemplateImpl): TypeEntity = {
    def createTypeEntity = new TypeEntity {
      private var nameBuffer = new StringBuilder
      private var refBuffer = new immutable.TreeMap[Int, (LinkTo, Int)]
      private def appendTypes0(types: List[Type], sep: String): Unit = types match {
        case Nil =>
        case tp :: Nil =>
          appendType0(tp)
        case tp :: tps =>
          appendType0(tp)
          nameBuffer append sep
          appendTypes0(tps, sep)
      }

      private def appendType0(tpe: Type): Unit = tpe match {
        /* Type refs */
        case tp: TypeRef if definitions.isFunctionTypeDirect(tp) =>
          val args = tp.typeArgs
          nameBuffer append '('
          appendTypes0(args.init, ", ")
          nameBuffer append ") ⇒ "
          appendType0(args.last)
        case tp: TypeRef if definitions.isScalaRepeatedParamType(tp) =>
          appendType0(tp.args.head)
          nameBuffer append '*'
        case tp: TypeRef if definitions.isByNameParamType(tp) =>
          nameBuffer append "⇒ "
          appendType0(tp.args.head)
        case tp: TypeRef if definitions.isTupleTypeDirect(tp) =>
          val args = tp.typeArgs
          nameBuffer append '('
          appendTypes0(args, ", ")
          nameBuffer append ')'
        case TypeRef(pre, aSym, targs) =>
          val preSym = pre.widen.typeSymbol

          // SI-3314/SI-4888: Classes, Traits and Types can be inherited from a template to another:
          // class Enum { abstract class Value }
          // class Day extends Enum { object Mon extends Value /*...*/ }
          // ===> in such cases we have two options:
          // (0) if there's no inheritance taking place (Enum#Value) we can link to the template directly
          // (1) if we generate the doc template for Day, we can link to the correct member
          // (2) If the symbol comes from an external library for which we know the documentation URL, point to it.
          // (3) if we don't generate the doc template, we should at least indicate the correct prefix in the tooltip
          val bSym = normalizeTemplate(aSym)
          val owner =
            if ((preSym != NoSymbol) &&                  /* it needs a prefix */
                (preSym != bSym.owner) &&                /* prefix is different from owner */
                (aSym == bSym))                          /* normalization doesn't play tricks on us */
              preSym
            else
              bSym.owner

          val link =
            findTemplateMaybe(bSym) match {
              case Some(bTpl) if owner == bSym.owner =>
                // (0) the owner's class is linked AND has a template - lovely
                bTpl match {
                  case dtpl: DocTemplateEntity => new LinkToTpl(dtpl)
                  case _ => new Tooltip(bTpl.qualifiedName)
                }
              case _ =>
                val oTpl = findTemplateMaybe(owner)
                (oTpl, oTpl flatMap (findMember(bSym, _))) match {
                  case (Some(oTpl), Some(bMbr)) =>
                    // (1) the owner's class
                    LinkToMember(bMbr, oTpl)
                  case _ =>
                    val name = makeQualifiedName(bSym)
                    if (!bSym.owner.isPackage)
                      Tooltip(name)
                    else
                      findExternalLink(bSym, name).getOrElse (
                        // (3) if we couldn't find neither the owner nor external URL to link to, show a tooltip with the qualified name
                        Tooltip(name)
                      )
                }
            }

          // SI-4360 Showing prefixes when necessary
          // We check whether there's any directly accessible type with the same name in the current template OR if the
          // type is inherited from one template to another. There may be multiple symbols with the same name in scope,
          // but we won't show the prefix if our symbol is among them, only if *it's not* -- that's equal to showing
          // the prefix only for ambiguous references, not for overloaded ones.
          def needsPrefix: Boolean = {
            if ((owner != bSym.owner || preSym.isRefinementClass) && (normalizeTemplate(owner) != inTpl.sym))
              return true
            // don't get tricked into prefixng method type params and existentials:
            // I tried several tricks BUT adding the method for which I'm creating the type => that simply won't scale,
            // as ValueParams are independent of their parent member, and I really don't want to add this information to
            // all terms, as we're already over the allowed memory footprint
            if (aSym.isTypeParameterOrSkolem || aSym.isExistentiallyBound /* existential or existential skolem */)
              return false

            for (tpl <- inTpl.sym.ownerChain) {
              tpl.info.member(bSym.name) match {
                case NoSymbol =>
                  // No syms with that name, look further inside the owner chain
                case sym =>
                  // Symbol found -- either the correct symbol, another one OR an overloaded alternative
                  if (sym == bSym)
                    return false
                  else sym.info match {
                    case OverloadedType(owner, alternatives) =>
                      return alternatives.contains(bSym)
                    case _ =>
                      return true
                  }
              }
            }
            // if it's not found in the owner chain, we can safely leave out the prefix
            false
          }

          val prefix =
            if (!settings.docNoPrefixes && needsPrefix && (bSym != AnyRefClass /* which we normalize */)) {
              if (!owner.isRefinementClass) {
                val qName = makeQualifiedName(owner, Some(inTpl.sym))
                if (qName != "") qName + "." else ""
              }
              else {
                nameBuffer append "("
                appendType0(pre)
                nameBuffer append ")#"
                "" // we already appended the prefix
              }
            } else ""

          //DEBUGGING:
          //if (makeQualifiedName(bSym) == "pack1.A") println("needsPrefix(" + bSym + ", " + owner + ", " + inTpl.qualifiedName + ") => " + needsPrefix + "  and prefix=" + prefix)

          val name = prefix + bSym.nameString
          val pos0 = nameBuffer.length
          refBuffer += pos0 -> ((link, name.length))
          nameBuffer append name

          if (!targs.isEmpty) {
            nameBuffer append '['
            appendTypes0(targs, ", ")
            nameBuffer append ']'
          }
        /* Refined types */
        case RefinedType(parents, defs) =>
          val ignoreParents = Set[Symbol](AnyClass, ObjectClass)
          val filtParents = parents filterNot (x => ignoreParents(x.typeSymbol)) match {
            case Nil    => parents
            case ps     => ps
          }
          appendTypes0(filtParents, " with ")
          // XXX Still todo: properly printing refinements.
          // Since I didn't know how to go about displaying a multi-line type, I went with
          // printing single method refinements (which should be the most common) and printing
          // the number of members if there are more.
          defs.toList match {
            case Nil      => ()
            case x :: Nil => nameBuffer append (" { " + x.defString + " }")
            case xs       => nameBuffer append (" { ... /* %d definitions in type refinement */ }" format xs.size)
          }
        /* Eval-by-name types */
        case NullaryMethodType(result) =>
          nameBuffer append '⇒'
          appendType0(result)

        /* Polymorphic types */
        case PolyType(tparams, result) => assert(tparams.nonEmpty)
          def typeParamsToString(tps: List[Symbol]): String = if (tps.isEmpty) "" else
            tps.map{tparam =>
              tparam.varianceString + tparam.name + typeParamsToString(tparam.typeParams)
            }.mkString("[", ", ", "]")
          nameBuffer append typeParamsToString(tparams)
          appendType0(result)

        case et@ExistentialType(quantified, underlying) =>

          def appendInfoStringReduced(sym: Symbol, tp: Type): Unit = {
            if (sym.isType && !sym.isAliasType && !sym.isClass) {
                tp match {
                  case PolyType(tparams, _) =>
                    nameBuffer append "["
                    appendTypes0(tparams.map(_.tpe), ", ")
                    nameBuffer append "]"
                  case _ =>
                }
                tp.resultType match {
                  case rt @ TypeBounds(_, _) =>
                    appendType0(rt)
                  case rt                    =>
                    nameBuffer append " <: "
                    appendType0(rt)
                }
            } else {
              // fallback to the Symbol infoString
              nameBuffer append sym.infoString(tp)
            }
          }

          def appendClauses = {
            nameBuffer append " forSome {"
            var first = true
            for (sym <- quantified) {
              if (!first) { nameBuffer append ", " } else first = false
              if (sym.isSingletonExistential) {
                nameBuffer append "val "
                nameBuffer append tpnme.dropSingletonName(sym.name)
                nameBuffer append ": "
                appendType0(dropSingletonType(sym.info.bounds.hi))
              } else {
                if (sym.flagString != "") nameBuffer append (sym.flagString + " ")
                if (sym.keyString != "") nameBuffer append (sym.keyString + " ")
                nameBuffer append sym.varianceString
                nameBuffer append sym.nameString
                appendInfoStringReduced(sym, sym.info)
              }
            }
            nameBuffer append "}"
          }

          underlying match {
            case TypeRef(pre, sym, args) if et.isRepresentableWithWildcards =>
              appendType0(typeRef(pre, sym, Nil))
              nameBuffer append "["
              var first = true
              val qset = quantified.toSet
              for (arg <- args) {
                if (!first) { nameBuffer append ", " } else first = false
                arg match {
                  case TypeRef(_, sym, _) if (qset contains sym) =>
                    nameBuffer append "_"
                    appendInfoStringReduced(sym, sym.info)
                  case arg =>
                    appendType0(arg)
                }
              }
              nameBuffer append "]"
            case MethodType(_, _) | NullaryMethodType(_) | PolyType(_, _) =>
              nameBuffer append "("
              appendType0(underlying)
              nameBuffer append ")"
              appendClauses
            case _ =>
              appendType0(underlying)
              appendClauses
          }

        case tb@TypeBounds(lo, hi) =>
          if (tb.lo != TypeBounds.empty.lo) {
            nameBuffer append " >: "
            appendType0(lo)
          }
          if (tb.hi != TypeBounds.empty.hi) {
            nameBuffer append " <: "
            appendType0(hi)
          }
        // case tpen: ThisType | SingleType | SuperType =>
        //   if (tpen.isInstanceOf[ThisType] && tpen.asInstanceOf[ThisType].sym.isEffectiveRoot) {
        //     appendType0 typeRef(NoPrefix, sym, Nil)
        //   } else {
        //     val underlying =
        //     val pre = underlying.typeSymbol.skipPackageObject
        //     if (pre.isOmittablePrefix) pre.fullName + ".type"
        //     else prefixString + "type"
        case tpen@ThisType(sym) =>
          appendType0(typeRef(NoPrefix, sym, Nil))
          nameBuffer append ".this"
          if (!tpen.underlying.typeSymbol.skipPackageObject.isOmittablePrefix) nameBuffer append ".type"
        case tpen@SuperType(thistpe, supertpe) =>
          nameBuffer append "super["
          appendType0(supertpe)
          nameBuffer append "]"
        case tpen@SingleType(pre, sym) =>
          appendType0(typeRef(pre, sym, Nil))
          if (!tpen.underlying.typeSymbol.skipPackageObject.isOmittablePrefix) nameBuffer append ".type"
        case tpen =>
          nameBuffer append tpen.toString
      }
      appendType0(aType)
      val refEntity = refBuffer
      val name = optimize(nameBuffer.toString)
      nameBuffer = null
    }

    // SI-4360: Entity caching depends on both the type AND the template it's in, as the prefixes might change for the
    // same type based on the template the type is shown in.
    if (settings.docNoPrefixes)
      typeCache.getOrElseUpdate(aType, createTypeEntity)
    else createTypeEntity
  }
}

Other Scala source code examples

Here is a short list of links related to this Scala ModelFactoryTypeSupport.scala source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.