Skip to content

Commit

Permalink
Consume inits part of package object within the inner scope (#16282)
Browse files Browse the repository at this point in the history
package objects `inits` (the constructor + any extends)` should be in the scope of the package object vs other scala templates (class, object) that are in the package scope.

This PR fixes that, by calling the apply on the inits within the package object scope.

Fixes #16259
  • Loading branch information
somdoron authored Jul 26, 2022
1 parent 897a8aa commit 7371aa4
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,16 @@ object Analysis {
case class ProvidedSymbol(name: String, recursive: Boolean)
}

case class ProvidedSymbol(sawClass: Boolean, sawTrait: Boolean, sawObject: Boolean, recursive: Boolean)
case class ProvidedSymbol(
sawClass: Boolean,
sawTrait: Boolean,
sawObject: Boolean,
recursive: Boolean
)

class SourceAnalysisTraverser extends Traverser {
val nameParts = ArrayBuffer[String]()
var skipProvidedNames = false
var skipProvidedNames = false

val providedSymbolsByScope = HashMap[String, HashMap[String, ProvidedSymbol]]()
val importsByScope = HashMap[String, ArrayBuffer[AnImport]]()
Expand All @@ -56,7 +61,7 @@ class SourceAnalysisTraverser extends Traverser {
case (None, None) => None
}

def maybeExtractName(tree: Tree): Option[String] =
def maybeExtractName(tree: Tree): Option[String] =
tree match {
case Term.Select(qual, name) => extractNameSelect(qual, name)
case Type.Select(qual, name) => extractNameSelect(qual, name)
Expand Down Expand Up @@ -192,9 +197,9 @@ class SourceAnalysisTraverser extends Traverser {

def visitMods(mods: List[Mod]): Unit = {
mods.foreach({
case Mod.Annot(init) =>
apply(init) // rely on `Init` extraction in main parsing match code
case _ => ()
case Mod.Annot(init) =>
apply(init) // rely on `Init` extraction in main parsing match code
case _ => ()
})
}

Expand All @@ -209,8 +214,25 @@ class SourceAnalysisTraverser extends Traverser {
visitMods(mods)
val name = extractName(nameNode)
recordScope(name)
recordProvidedName(name, sawObject = true)
visitTemplate(templ, name)

// TODO: should object already be recursive?
// an object is recursive if extends another type because we cannot figure out the provided types
// in the parents, we just mark the object as recursive (which is indicated by non-empty inits)
val recursive = !templ.inits.isEmpty
recordProvidedName(name, sawObject = true, recursive = recursive)

// visitTemplate visits the inits part of the template in the outer scope,
// however for a package object the inits part can actually be found both in the inner scope as well (package inner).
// therefore we are not calling visitTemplate, calling all the apply methods in the inner scope.
// issue https://github.com/pantsbuild/pants/issues/16259
withNamePart(
name,
() => {
templ.inits.foreach(init => apply(init))
apply(templ.early)
apply(templ.stats)
}
)
}

case Defn.Class(mods, nameNode, _tparams, ctor, templ) => {
Expand Down Expand Up @@ -238,7 +260,7 @@ class SourceAnalysisTraverser extends Traverser {
// in the parents, we just mark the object as recursive (which is indicated by non-empty inits)
val recursive = !templ.inits.isEmpty
recordProvidedName(name, sawObject = true, recursive = recursive)

// If the object is recursive, no need to provide the symbols inside
if (recursive)
withSuppressProvidedNames(() => visitTemplate(templ, name))
Expand Down Expand Up @@ -333,7 +355,7 @@ class SourceAnalysisTraverser extends Traverser {
}

case Init(tpe, _name, argss) => {
extractNamesFromTypeTree(tpe).foreach(recordConsumedSymbol(_))
extractNamesFromTypeTree(tpe).foreach(recordConsumedSymbol(_))
argss.foreach(_.foreach(apply))
}

Expand Down Expand Up @@ -376,7 +398,9 @@ class SourceAnalysisTraverser extends Traverser {
def gatherProvidedSymbols(): Vector[Analysis.ProvidedSymbol] = {
providedSymbolsByScope
.flatMap({ case (scopeName, symbolsForScope) =>
symbolsForScope.map { case(symbolName, symbol) => Analysis.ProvidedSymbol(s"${scopeName}.${symbolName}", symbol.recursive)}.toVector
symbolsForScope.map { case (symbolName, symbol) =>
Analysis.ProvidedSymbol(s"${scopeName}.${symbolName}", symbol.recursive)
}.toVector
})
.toVector
}
Expand All @@ -387,10 +411,14 @@ class SourceAnalysisTraverser extends Traverser {
val encodedSymbolsForScope = symbolsForScope.flatMap({
case (symbolName, symbol) => {
val encodedSymbolName = NameTransformer.encode(symbolName)
val result = ArrayBuffer[Analysis.ProvidedSymbol](Analysis.ProvidedSymbol(encodedSymbolName, symbol.recursive))
val result = ArrayBuffer[Analysis.ProvidedSymbol](
Analysis.ProvidedSymbol(encodedSymbolName, symbol.recursive)
)
if (symbol.sawObject) {
result.append(Analysis.ProvidedSymbol(encodedSymbolName + "$", symbol.recursive))
result.append(Analysis.ProvidedSymbol(encodedSymbolName + "$.MODULE$", symbol.recursive))
result.append(
Analysis.ProvidedSymbol(encodedSymbolName + "$.MODULE$", symbol.recursive)
)
}
result.toVector
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -577,3 +577,19 @@ def test_object_extends_ctor(rule_runner: RuleRunner) -> None:
"foo.Bar",
"foo.hello",
]


def test_package_object_extends_trait(rule_runner: RuleRunner) -> None:
analysis = _analyze(
rule_runner,
textwrap.dedent(
"""
package foo
package object bar extends Trait {
}
"""
),
)

assert sorted(analysis.fully_qualified_consumed_symbols()) == ["foo.Trait", "foo.bar.Trait"]

0 comments on commit 7371aa4

Please sign in to comment.