From 41f07be2477568f6b1a91719a4e5f5b029f64805 Mon Sep 17 00:00:00 2001 From: Martin Duhem Date: Fri, 3 Oct 2014 22:01:49 +0200 Subject: [PATCH] Port fix for #1544 from Dependency to ExtractUsedNames The fix for sbt/sbt#1237 was unfortunately not completely correct, and infinite loops could still occur during the extraction of used names. In sbt/sbt#1544, a fix that was robuster and easier to understand was applied to `/compile/interface/src/main/scala/xsbt/Dependency.scala` in a similar situation (cyclic chains of original trees in macro expansions). This commit ports this fix to `ExtractUsedNames.scala`. Closes sbt/sbt#1640, sbt/sbt#1610. --- .../main/scala/xsbt/ExtractUsedNames.scala | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/compile/interface/src/main/scala/xsbt/ExtractUsedNames.scala b/compile/interface/src/main/scala/xsbt/ExtractUsedNames.scala index 4d69f0d9b..56f67f3e8 100644 --- a/compile/interface/src/main/scala/xsbt/ExtractUsedNames.scala +++ b/compile/interface/src/main/scala/xsbt/ExtractUsedNames.scala @@ -49,6 +49,16 @@ class ExtractUsedNames[GlobalType <: CallbackGlobal](val global: GlobalType) ext private def extractByTreeWalk(tree: Tree): Set[String] = { val namesBuffer = collection.mutable.ListBuffer.empty[String] + + /* + * Some macros appear to contain themselves as original tree. + * We must check that we don't inspect the same tree over and over. + * See https://issues.scala-lang.org/browse/SI-8486 + * https://github.com/sbt/sbt/issues/1237 + * https://github.com/sbt/sbt/issues/1544 + */ + val inspectedOriginalTrees = collection.mutable.Set.empty[Tree] + def addSymbol(symbol: Symbol): Unit = { val symbolNameAsString = symbol.name.decode.trim namesBuffer += symbolNameAsString @@ -56,12 +66,7 @@ class ExtractUsedNames[GlobalType <: CallbackGlobal](val global: GlobalType) ext def handleTreeNode(node: Tree): Unit = { def handleMacroExpansion(original: Tree): Unit = { - // Some macros seem to be their own orignal tree, or appear in the children of their - // original tree. To prevent infinite loops, we need to filter out nodes that we already - // handled. - // This is only relevant for Scala 2.10.4 - // See https://issues.scala-lang.org/browse/SI-8486 - original.filter(_ ne node).foreach(handleTreeNode) + original.foreach(handleTreeNode) } def handleClassicTreeNode(node: Tree): Unit = node match { @@ -90,7 +95,7 @@ class ExtractUsedNames[GlobalType <: CallbackGlobal](val global: GlobalType) ext } node match { - case MacroExpansionOf(original) => + case MacroExpansionOf(original) if inspectedOriginalTrees.add(original) => handleClassicTreeNode(node) handleMacroExpansion(original) case _ =>