summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/doc/DocFactory.scala
blob: 02b69034ef6d98f2111982365244273cf65eaa5a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/* NSC -- new Scala compiler
 * Copyright 2007-2012 LAMP/EPFL
 * @author  David Bernard, Manohar Jonnalagedda
 */

package scala.tools.nsc
package doc

import scala.util.control.ControlThrowable
import reporters.Reporter
import scala.reflect.internal.util.{ NoPosition, BatchSourceFile}
import io.{ File, Directory }
import DocParser.Parsed

/** A documentation processor controls the process of generating Scala
  * documentation, which is as follows.
  *
  * * A simplified compiler instance (with only the front-end phases enabled)
  * * is created, and additional ''sourceless'' comments are registered.
  * * Documentable files are compiled, thereby filling the compiler's symbol table.
  * * A documentation model is extracted from the post-compilation symbol table.
  * * A generator is used to transform the model into the correct final format (HTML).
  *
  * A processor contains a single compiler instantiated from the processor's
  * `settings`. Each call to `document` uses the same compiler instance with
  * the same symbol table. In particular, this implies that the scaladoc site
  * obtained from a call to `run` will contain documentation about files compiled
  * during previous calls to the same processor's `run` method.
  *
  * @param reporter The reporter to which both documentation and compilation errors will be reported.
  * @param settings The settings to be used by the documenter and compiler for generating documentation.
  *
  * @author Gilles Dubochet */
class DocFactory(val reporter: Reporter, val settings: doc.Settings) { processor =>
  /** The unique compiler instance used by this processor and constructed from its `settings`. */
  object compiler extends Global(settings, reporter) with interactive.RangePositions {
    override protected def computeInternalPhases() {
      phasesSet += syntaxAnalyzer
      phasesSet += analyzer.namerFactory
      phasesSet += analyzer.packageObjects
      phasesSet += analyzer.typerFactory
      phasesSet += superAccessors
      phasesSet += pickler
      phasesSet += refChecks
    }
    override def forScaladoc = true
  }

  /** Creates a scaladoc site for all symbols defined in this call's `source`,
    * as well as those defined in `sources` of previous calls to the same processor.
    * @param source The list of paths (relative to the compiler's source path,
    *        or absolute) of files to document or the source code. */
  def makeUniverse(source: Either[List[String], String]): Option[Universe] = {
    assert(settings.docformat.value == "html")
    source match {
      case Left(files) =>
        new compiler.Run() compile files
      case Right(sourceCode) =>
        new compiler.Run() compileSources List(new BatchSourceFile("newSource", sourceCode))
    }

    if (reporter.hasErrors)
      return None

    val extraTemplatesToDocument: Set[compiler.Symbol] = {
      if (settings.docUncompilable.isDefault) Set()
      else {
        val uncompilable = new {
          val global: compiler.type = compiler
          val settings = processor.settings
        } with Uncompilable { }

        compiler.docComments ++= uncompilable.comments
        docdbg("" + uncompilable)

        uncompilable.templates
      }
    }

    val modelFactory = (
      new { override val global: compiler.type = compiler }
        with model.ModelFactory(compiler, settings)
        with model.ModelFactoryImplicitSupport
        with model.ModelFactoryTypeSupport
        with model.diagram.DiagramFactory
        with model.comment.CommentFactory
        with model.TreeFactory
        with model.MemberLookup {
          override def templateShouldDocument(sym: compiler.Symbol, inTpl: DocTemplateImpl) =
            extraTemplatesToDocument(sym) || super.templateShouldDocument(sym, inTpl)
        }
    )

    modelFactory.makeModel match {
      case Some(madeModel) =>
        if (!settings.scaladocQuietRun)
          println("model contains " + modelFactory.templatesCount + " documentable templates")
        Some(madeModel)
      case None =>
        if (!settings.scaladocQuietRun)
          println("no documentable class found in compilation units")
        None
    }
  }

  object NoCompilerRunException extends ControlThrowable { }

  val documentError: PartialFunction[Throwable, Unit] = {
    case NoCompilerRunException =>
      reporter.info(null, "No documentation generated with unsucessful compiler run", false)
    case _: ClassNotFoundException =>
      ()
  }

  /** Generate document(s) for all `files` containing scaladoc documenataion.
    * @param files The list of paths (relative to the compiler's source path, or absolute) of files to document. */
  def document(files: List[String]) {
    def generate() = {
      import doclet._
      val docletClass    = Class.forName(settings.docgenerator.value) // default is html.Doclet
      val docletInstance = docletClass.newInstance().asInstanceOf[Generator]

      docletInstance match {
        case universer: Universer =>
          val universe = makeUniverse(Left(files)) getOrElse { throw NoCompilerRunException }
          universer setUniverse universe

          docletInstance match {
            case indexer: Indexer => indexer setIndex model.IndexModelFactory.makeIndex(universe)
            case _                => ()
          }
        case _ => ()
      }
      docletInstance.generate
    }

    try generate()
    catch documentError
  }

  private[doc] def docdbg(msg: String) {
    if (settings.Ydocdebug.value)
      println(msg)
  }
}