diff options
author | Adriaan Moors <adriaan@lightbend.com> | 2016-08-13 08:32:41 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-08-13 08:32:41 -0700 |
commit | d6f601d53e53be6f8071c0646c19b68faac69ec0 (patch) | |
tree | 8d8aec4c13199596a8cf04991380fed4fb3b902b /src | |
parent | 69c6500b5f25e1b4a66d3a62cf40d23877a9023f (diff) | |
parent | 36732d7a14ab246d9ab6b011a0eafe4115978f19 (diff) | |
download | scala-d6f601d53e53be6f8071c0646c19b68faac69ec0.tar.gz scala-d6f601d53e53be6f8071c0646c19b68faac69ec0.tar.bz2 scala-d6f601d53e53be6f8071c0646c19b68faac69ec0.zip |
Merge pull request #5332 from retronym/review/5304
Fixes to Java source support in Scaladoc
Diffstat (limited to 'src')
9 files changed, 77 insertions, 35 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala index 689e6405d0..b78c5acc4f 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala @@ -97,4 +97,12 @@ abstract class TreeInfo extends scala.reflect.internal.TreeInfo { case DocDef(_, definition) => isPureDef(definition) case _ => super.isPureDef(tree) } + + override def firstConstructor(stats: List[Tree]): Tree = { + def unwrap(stat: Tree): Tree = stat match { + case DocDef(_, defn) => unwrap(defn) + case tree => tree + } + super.firstConstructor(stats map unwrap) + } } diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index 01ca8033ac..e4bc055da4 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -117,11 +117,8 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { atPos(pkg.pos) { PackageDef(pkg, stats) } def makeTemplate(parents: List[Tree], stats: List[Tree]) = - Template( - parents, - noSelfType, - if (treeInfo.firstConstructor(stats) == EmptyTree) makeConstructor(List()) :: stats - else stats) + Template(parents, noSelfType, if (treeInfo.firstConstructor(stats) == EmptyTree) + makeConstructor(Nil) :: stats else stats) def makeSyntheticParam(count: Int, tpt: Tree): ValDef = makeParam(nme.syntheticParamName(count), tpt) @@ -586,7 +583,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { case CLASS | ENUM | INTERFACE | AT => typeDecl(if (definesInterface(parentToken)) mods | Flags.STATIC else mods) case _ => - joinComment(termDecl(mods, parentToken)) + termDecl(mods, parentToken) } def makeCompanionObject(cdef: ClassDef, statics: List[Tree]): Tree = @@ -600,26 +597,8 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { Import(Ident(cdef.name.toTermName), ImportSelector.wildList) } - // Importing the companion object members cannot be done uncritically: see - // ticket #2377 wherein a class contains two static inner classes, each of which - // has a static inner class called "Builder" - this results in an ambiguity error - // when each performs the import in the enclosing class's scope. - // - // To address this I moved the import Companion._ inside the class, as the first - // statement. This should work without compromising the enclosing scope, but may (?) - // end up suffering from the same issues it does in scala - specifically that this - // leaves auxiliary constructors unable to access members of the companion object - // as unqualified identifiers. - def addCompanionObject(statics: List[Tree], cdef: ClassDef): List[Tree] = { - def implWithImport(importStmt: Tree) = deriveTemplate(cdef.impl)(importStmt :: _) - // if there are no statics we can use the original cdef, but we always - // create the companion so import A._ is not an error (see ticket #1700) - val cdefNew = - if (statics.isEmpty) cdef - else deriveClassDef(cdef)(_ => implWithImport(importCompanionObject(cdef))) - - List(makeCompanionObject(cdefNew, statics), cdefNew) - } + def addCompanionObject(statics: List[Tree], cdef: ClassDef): List[Tree] = + List(makeCompanionObject(cdef, statics), cdef) def importDecl(): List[Tree] = { accept(IMPORT) @@ -726,8 +705,15 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { in.nextToken() } else { if (in.token == ENUM || definesInterface(in.token)) mods |= Flags.STATIC - val decls = memberDecl(mods, parentToken) - (if (mods.hasStaticFlag || inInterface && !(decls exists (_.isInstanceOf[DefDef]))) + val decls = joinComment(memberDecl(mods, parentToken)) + + def isDefDef(tree: Tree): Boolean = tree match { + case _: DefDef => true + case DocDef(_, defn) => isDefDef(defn) + case _ => false + } + + (if (mods.hasStaticFlag || inInterface && !(decls exists isDefDef)) statics else members) ++= decls diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 16ef75c863..c73ea54c3d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -1016,7 +1016,16 @@ trait Contexts { self: Analyzer => || unit.exists && s.sourceFile != unit.source.file ) ) - def lookupInPrefix(name: Name) = pre member name filter qualifies + def lookupInPrefix(name: Name) = { + val sym = pre.member(name).filter(qualifies) + def isNonPackageNoModuleClass(sym: Symbol) = + sym.isClass && !sym.isModuleClass && !sym.isPackageClass + if (!sym.exists && unit.isJava && isNonPackageNoModuleClass(pre.typeSymbol)) { + // TODO factor out duplication with Typer::inCompanionForJavaStatic + val pre1 = companionSymbolOf(pre.typeSymbol, this).typeOfThis + pre1.member(name).filter(qualifies).andAlso(_ => pre = pre1) + } else sym + } def accessibleInPrefix(s: Symbol) = isAccessible(s, pre, superAccess = false) def searchPrefix = { diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala index ea323d0fba..99ef4ed373 100644 --- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala +++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala @@ -201,7 +201,7 @@ trait MethodSynthesis { import AnnotationInfo.{mkFilter => annotationFilter} def addDerivedTrees(typer: Typer, stat: Tree): List[Tree] = stat match { - case vd @ ValDef(mods, name, tpt, rhs) if deriveAccessors(vd) && !vd.symbol.isModuleVar => + case vd @ ValDef(mods, name, tpt, rhs) if deriveAccessors(vd) && !vd.symbol.isModuleVar && !vd.symbol.isJava => stat.symbol.initialize // needed! val getter = Getter(vd) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index d412b5ef33..7c176c8047 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -4719,6 +4719,16 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper if (isStableContext(tree, mode, pt)) tree setType clazz.thisType else tree } + + // For Java, instance and static members are in the same scope, but we put the static ones in the companion object + // so, when we can't find a member in the class scope, check the companion + def inCompanionForJavaStatic(pre: Type, cls: Symbol, name: Name): Symbol = + if (!(context.unit.isJava && cls.isClass && !cls.isModuleClass)) NoSymbol else { + val companion = companionSymbolOf(cls, context) + if (!companion.exists) NoSymbol + else member(gen.mkAttributedRef(pre, companion), name) // assert(res.isStatic, s"inCompanionJavaStatic($pre, $cls, $name) = $res ${res.debugFlagString}") + } + /* Attribute a selection where `tree` is `qual.name`. * `qual` is already attributed. */ @@ -4745,7 +4755,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper dyna.wrapErrors(t, (_.typed1(t, mode, pt))) } - val sym = tree.symbol orElse member(qual, name) orElse { + val sym = tree.symbol orElse member(qual, name) orElse inCompanionForJavaStatic(qual.tpe.prefix, qual.symbol, name) orElse { // symbol not found? --> try to convert implicitly to a type that does have the required // member. Added `| PATTERNmode` to allow enrichment in patterns (so we can add e.g., an // xml member to StringContext, which in turn has an unapply[Seq] method) diff --git a/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala b/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala index 2152ce234a..d8ec7b18fd 100644 --- a/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala +++ b/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala @@ -216,11 +216,16 @@ abstract class ScaladocSyntaxAnalyzer[G <: Global](val global: G) extends Syntax class ScaladocJavaUnitScanner(unit: CompilationUnit) extends JavaUnitScanner(unit) { - private val docBuffer: StringBuilder = new StringBuilder + private var docBuffer: StringBuilder = _ private var inDocComment = false private var docStart: Int = 0 private var lastDoc: DocComment = null + override def init() = { + docBuffer = new StringBuilder + super.init() + } + // get last doc comment def flushDoc(): DocComment = try lastDoc finally lastDoc = null diff --git a/src/scaladoc/scala/tools/nsc/doc/ScaladocGlobal.scala b/src/scaladoc/scala/tools/nsc/doc/ScaladocGlobal.scala index 625d074df5..10d8286528 100644 --- a/src/scaladoc/scala/tools/nsc/doc/ScaladocGlobal.scala +++ b/src/scaladoc/scala/tools/nsc/doc/ScaladocGlobal.scala @@ -13,7 +13,11 @@ trait ScaladocGlobalTrait extends Global { override val useOffsetPositions = false override def newUnitParser(unit: CompilationUnit) = new syntaxAnalyzer.ScaladocUnitParser(unit, Nil) - override def newJavaUnitParser(unit: CompilationUnit) = new syntaxAnalyzer.ScaladocJavaUnitParser(unit) + override def newJavaUnitParser(unit: CompilationUnit) = if (createJavadoc) { + new syntaxAnalyzer.ScaladocJavaUnitParser(unit) + } else { + super.newJavaUnitParser(unit) + } override lazy val syntaxAnalyzer = new ScaladocSyntaxAnalyzer[outer.type](outer) { val runsAfter = List[String]() @@ -41,7 +45,7 @@ class ScaladocGlobal(settings: doc.Settings, reporter: Reporter) extends Global( phasesSet += analyzer.typerFactory } override def forScaladoc = true - override def createJavadoc = true + override def createJavadoc = if (settings.docNoJavaComments.value) false else true override lazy val analyzer = new { val global: ScaladocGlobal.this.type = ScaladocGlobal.this diff --git a/src/scaladoc/scala/tools/nsc/doc/Settings.scala b/src/scaladoc/scala/tools/nsc/doc/Settings.scala index 59380dd782..063a949323 100644 --- a/src/scaladoc/scala/tools/nsc/doc/Settings.scala +++ b/src/scaladoc/scala/tools/nsc/doc/Settings.scala @@ -213,6 +213,11 @@ class Settings(error: String => Unit, val printMsg: String => Unit = println(_)) "Group similar functions together (based on the @group annotation)" ) + val docNoJavaComments = BooleanSetting ( + "-no-java-comments", + "Prevents parsing and inclusion of comments from java sources." + ) + // For improved help output. def scaladocSpecific = Set[Settings#Setting]( docformat, doctitle, docfooter, docversion, docUncompilable, docsourceurl, docgenerator, docRootContent, useStupidTypes, @@ -222,7 +227,7 @@ class Settings(error: String => Unit, val printMsg: String => Unit = println(_)) docImplicits, docImplicitsDebug, docImplicitsShowAll, docImplicitsHide, docImplicitsSoundShadowing, docDiagramsMaxNormalClasses, docDiagramsMaxImplicitClasses, docNoPrefixes, docNoLinkWarnings, docRawOutput, docSkipPackages, - docExpandAllTypes, docGroups + docExpandAllTypes, docGroups, docNoJavaComments ) val isScaladocSpecific: String => Boolean = scaladocSpecific map (_.name) diff --git a/src/scaladoc/scala/tools/partest/ScaladocJavaModelTest.scala b/src/scaladoc/scala/tools/partest/ScaladocJavaModelTest.scala new file mode 100644 index 0000000000..1008be5b87 --- /dev/null +++ b/src/scaladoc/scala/tools/partest/ScaladocJavaModelTest.scala @@ -0,0 +1,15 @@ +package scala.tools.partest + +import scala.tools.nsc.doc.Universe + +/** A class for testing scaladoc model generation on java sources. */ +abstract class ScaladocJavaModelTest extends ScaladocModelTest { + + // overridden to pass explicit files to newDocFactory.makeUniverse (rather than code strings) + // since the .java file extension is required + override def model: Option[Universe] = { + val path = resourcePath + "/" + resourceFile + newDocFactory.makeUniverse(Left(List(path))) + } + +} |