Skip to content

Commit bd2a665

Browse files
committed
Resolve dependency source
1 parent 96aa562 commit bd2a665

File tree

1 file changed

+54
-51
lines changed

1 file changed

+54
-51
lines changed

compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala

Lines changed: 54 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -55,17 +55,7 @@ class ExtractDependencies extends Phase {
5555
val dumpInc = ctx.settings.YdumpSbtInc.value
5656
val forceRun = dumpInc || ctx.settings.YforceSbtPhases.value
5757
if ((ctx.sbtCallback != null || forceRun) && !unit.isJava) {
58-
val sourceFile = unit.source.file
59-
val responsibleOfImports = firstClassOrModule(unit.tpdTree) match {
60-
case None =>
61-
ctx.warning("""|No class, trait or object is defined in the compilation unit.
62-
|The incremental compiler cannot record the dependency information in such case.
63-
|Some errors like unused import referring to a non-existent class might not be reported.
64-
|""".stripMargin, unit.tpdTree.pos)
65-
defn.RootClass
66-
case Some(sym) => sym
67-
}
68-
val extractDeps = new ExtractDependenciesCollector(responsibleOfImports)
58+
val extractDeps = new ExtractDependenciesCollector
6959
extractDeps.traverse(unit.tpdTree)
7060

7161
if (dumpInc) {
@@ -74,6 +64,7 @@ class ExtractDependencies extends Phase {
7464
Arrays.sort(names)
7565
Arrays.sort(deps)
7666

67+
val sourceFile = unit.source.file
7768
val pw = io.File(sourceFile.jpath).changeExtension("inc").toFile.printWriter()
7869
try {
7970
pw.println(s"// usedNames: ${names.mkString(",")}")
@@ -96,23 +87,6 @@ class ExtractDependencies extends Phase {
9687
}
9788
}
9889

99-
private def firstClassOrModule(tree: tpd.Tree)(implicit ctx: Context): Option[Symbol] = {
100-
import tpd._
101-
val acc = new TreeAccumulator[Option[Symbol]] {
102-
def apply(x: Option[Symbol], t: Tree)(implicit ctx: Context) =
103-
if (x.isDefined) x
104-
else t match {
105-
case moduleDef: Thicket =>
106-
Some(moduleDef.symbol)
107-
case typeDef: TypeDef =>
108-
Some(typeDef.symbol)
109-
case other =>
110-
foldOver(x, other)
111-
}
112-
}
113-
acc(None, tree)
114-
}
115-
11690
/*
11791
* Handles dependency on given symbol by trying to figure out if represents a term
11892
* that is coming from either source code (not necessarily compiled in this compilation
@@ -209,7 +183,7 @@ private final class UsedNamesInClass {
209183
* specially, see the subsection "Dependencies introduced by member reference and
210184
* inheritance" in the "Name hashing algorithm" section.
211185
*/
212-
private class ExtractDependenciesCollector(responsibleForImports: Symbol)(implicit val ctx: Context) extends tpd.TreeTraverser { thisTreeTraverser =>
186+
private class ExtractDependenciesCollector extends tpd.TreeTraverser { thisTreeTraverser =>
213187
import tpd._
214188
import ExtractDependencies._
215189

@@ -225,7 +199,50 @@ private class ExtractDependenciesCollector(responsibleForImports: Symbol)(implic
225199
*/
226200
def dependencies: Set[ClassDependency] = _dependencies
227201

228-
private def addUsedName(enclosingSym: Symbol, name: Name) = {
202+
/** Top level import dependencies are registered as coming from a first top level
203+
* class/trait/object declared in the compilation unit. If none exists, issue warning.
204+
*/
205+
private[this] var _responsibleForImports: Symbol = _
206+
private def responsibleForImports(implicit ctx: Context) = {
207+
def firstClassOrModule(tree: Tree) = {
208+
val acc = new TreeAccumulator[Symbol] {
209+
def apply(x: Symbol, t: Tree)(implicit ctx: Context) =
210+
t match {
211+
case typeDef: TypeDef =>
212+
typeDef.symbol
213+
case other =>
214+
foldOver(x, other)
215+
}
216+
}
217+
acc(NoSymbol, tree)
218+
}
219+
220+
if (_responsibleForImports == null) {
221+
val tree = ctx.compilationUnit.tpdTree
222+
_responsibleForImports = firstClassOrModule(tree)
223+
if (_responsibleForImports == NoSymbol)
224+
ctx.warning("""|No class, trait or object is defined in the compilation unit.
225+
|The incremental compiler cannot record the dependency information in such case.
226+
|Some errors like unused import referring to a non-existent class might not be reported.
227+
|""".stripMargin, tree.pos)
228+
}
229+
_responsibleForImports
230+
}
231+
232+
/**
233+
* Resolves dependency source (that is, the closest non-local enclosing
234+
* class from a given `currentOwner` set by the `Traverser`).
235+
*
236+
* TODO: cache and/or optimise?
237+
*/
238+
private def resolveDependencySource(implicit ctx: Context): Symbol = {
239+
def isNonLocalClass(sym: Symbol) = sym.isClass && !isLocal(sym)
240+
//val source = ctx.owner.ownersIterator.find(isNonLocalClass).get // Zinc
241+
val source = currentClass
242+
if (source.isEffectiveRoot) responsibleForImports else source
243+
}
244+
245+
private def addUsedName(enclosingSym: Symbol, name: Name)(implicit ctx: Context) = {
229246
val enclosingName =
230247
if (enclosingSym == defn.RootClass) classNameAsString(responsibleForImports)
231248
else classNameAsString(enclosingSym)
@@ -236,40 +253,26 @@ private class ExtractDependenciesCollector(responsibleForImports: Symbol)(implic
236253
private def addDependency(sym: Symbol)(implicit ctx: Context): Unit =
237254
if (!ignoreDependency(sym)) {
238255
val tlClass = sym.topLevelClass
256+
val from = resolveDependencySource
239257
if (tlClass.ne(NoSymbol)) {
240-
if (currentClass == defn.RootClass) {
241-
_dependencies += ClassDependency(responsibleForImports, tlClass, DependencyByMemberRef)
242-
} else {
243-
// Some synthetic type aliases like AnyRef do not belong to any class
244-
_dependencies += ClassDependency(currentClass, tlClass, DependencyByMemberRef)
245-
}
258+
_dependencies += ClassDependency(from, tlClass, DependencyByMemberRef)
246259
}
247-
addUsedName(nonLocalEnclosingClass(ctx.owner), sym.name.stripModuleClassSuffix)
248-
}
249-
250-
private def nonLocalEnclosingClass(sym: Symbol)(implicit ctx: Context): Symbol =
251-
sym.enclosingClass match {
252-
case NoSymbol => NoSymbol
253-
case csym =>
254-
if (isLocal(csym))
255-
nonLocalEnclosingClass(csym.owner)
256-
else
257-
csym
260+
addUsedName(from, sym.name.stripModuleClassSuffix)
258261
}
259262

260-
private def ignoreDependency(sym: Symbol) =
263+
private def ignoreDependency(sym: Symbol)(implicit ctx: Context) =
261264
sym.eq(NoSymbol) ||
262265
sym.isEffectiveRoot ||
263266
sym.isAnonymousFunction ||
264267
sym.isAnonymousClass
265268

266269
private def addInheritanceDependency(parent: Symbol)(implicit ctx: Context): Unit =
267-
_dependencies += ClassDependency(currentClass, parent.topLevelClass, DependencyByInheritance)
270+
_dependencies += ClassDependency(resolveDependencySource, parent.topLevelClass, DependencyByInheritance)
268271

269272
private class PatMatDependencyTraverser(ctx0: Context) extends ExtractTypesCollector(ctx0) {
270273
override protected def addDependency(symbol: Symbol)(implicit ctx: Context): Unit = {
271274
if (!ignoreDependency(symbol) && symbol.is(Sealed)) {
272-
val encName = nonLocalEnclosingClass(ctx.owner).fullName.stripModuleClassSuffix.toString
275+
val encName = classNameAsString(resolveDependencySource)
273276
val nameUsed = _usedNames.getOrElseUpdate(encName, new UsedNamesInClass)
274277

275278
nameUsed.update(symbol.name, UseScope.Default)
@@ -299,7 +302,7 @@ private class ExtractDependenciesCollector(responsibleForImports: Symbol)(implic
299302
case Thicket(Ident(name) :: Ident(rename) :: Nil) =>
300303
addImported(name)
301304
if (rename ne nme.WILDCARD) {
302-
addUsedName(nonLocalEnclosingClass(ctx.owner), rename)
305+
addUsedName(resolveDependencySource, rename)
303306
}
304307
case _ =>
305308
}

0 commit comments

Comments
 (0)