@@ -55,17 +55,7 @@ class ExtractDependencies extends Phase {
55
55
val dumpInc = ctx.settings.YdumpSbtInc .value
56
56
val forceRun = dumpInc || ctx.settings.YforceSbtPhases .value
57
57
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
69
59
extractDeps.traverse(unit.tpdTree)
70
60
71
61
if (dumpInc) {
@@ -74,6 +64,7 @@ class ExtractDependencies extends Phase {
74
64
Arrays .sort(names)
75
65
Arrays .sort(deps)
76
66
67
+ val sourceFile = unit.source.file
77
68
val pw = io.File (sourceFile.jpath).changeExtension(" inc" ).toFile.printWriter()
78
69
try {
79
70
pw.println(s " // usedNames: ${names.mkString(" ," )}" )
@@ -96,23 +87,6 @@ class ExtractDependencies extends Phase {
96
87
}
97
88
}
98
89
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
-
116
90
/*
117
91
* Handles dependency on given symbol by trying to figure out if represents a term
118
92
* that is coming from either source code (not necessarily compiled in this compilation
@@ -209,7 +183,7 @@ private final class UsedNamesInClass {
209
183
* specially, see the subsection "Dependencies introduced by member reference and
210
184
* inheritance" in the "Name hashing algorithm" section.
211
185
*/
212
- private class ExtractDependenciesCollector ( responsibleForImports : Symbol )( implicit val ctx : Context ) extends tpd.TreeTraverser { thisTreeTraverser =>
186
+ private class ExtractDependenciesCollector extends tpd.TreeTraverser { thisTreeTraverser =>
213
187
import tpd ._
214
188
import ExtractDependencies ._
215
189
@@ -225,7 +199,50 @@ private class ExtractDependenciesCollector(responsibleForImports: Symbol)(implic
225
199
*/
226
200
def dependencies : Set [ClassDependency ] = _dependencies
227
201
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 ) = {
229
246
val enclosingName =
230
247
if (enclosingSym == defn.RootClass ) classNameAsString(responsibleForImports)
231
248
else classNameAsString(enclosingSym)
@@ -236,40 +253,26 @@ private class ExtractDependenciesCollector(responsibleForImports: Symbol)(implic
236
253
private def addDependency (sym : Symbol )(implicit ctx : Context ): Unit =
237
254
if (! ignoreDependency(sym)) {
238
255
val tlClass = sym.topLevelClass
256
+ val from = resolveDependencySource
239
257
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 )
246
259
}
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)
258
261
}
259
262
260
- private def ignoreDependency (sym : Symbol ) =
263
+ private def ignoreDependency (sym : Symbol )( implicit ctx : Context ) =
261
264
sym.eq(NoSymbol ) ||
262
265
sym.isEffectiveRoot ||
263
266
sym.isAnonymousFunction ||
264
267
sym.isAnonymousClass
265
268
266
269
private def addInheritanceDependency (parent : Symbol )(implicit ctx : Context ): Unit =
267
- _dependencies += ClassDependency (currentClass , parent.topLevelClass, DependencyByInheritance )
270
+ _dependencies += ClassDependency (resolveDependencySource , parent.topLevelClass, DependencyByInheritance )
268
271
269
272
private class PatMatDependencyTraverser (ctx0 : Context ) extends ExtractTypesCollector (ctx0) {
270
273
override protected def addDependency (symbol : Symbol )(implicit ctx : Context ): Unit = {
271
274
if (! ignoreDependency(symbol) && symbol.is(Sealed )) {
272
- val encName = nonLocalEnclosingClass(ctx.owner).fullName.stripModuleClassSuffix.toString
275
+ val encName = classNameAsString(resolveDependencySource)
273
276
val nameUsed = _usedNames.getOrElseUpdate(encName, new UsedNamesInClass )
274
277
275
278
nameUsed.update(symbol.name, UseScope .Default )
@@ -299,7 +302,7 @@ private class ExtractDependenciesCollector(responsibleForImports: Symbol)(implic
299
302
case Thicket (Ident (name) :: Ident (rename) :: Nil ) =>
300
303
addImported(name)
301
304
if (rename ne nme.WILDCARD ) {
302
- addUsedName(nonLocalEnclosingClass(ctx.owner) , rename)
305
+ addUsedName(resolveDependencySource , rename)
303
306
}
304
307
case _ =>
305
308
}
0 commit comments