From 98257b98a423ed3d7e7ccd4ec575153e6e044232 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bu=CC=80i=20Vie=CC=A3=CC=82t=20Tha=CC=80nh?= Date: Fri, 24 Apr 2020 15:05:22 +0700 Subject: [PATCH] fix #1104 Can't get symbol from TextDocument for arg of ApplyInfix which have parens around ref scalameta/scalameta#1083 --- .../util/EagerInMemorySemanticdbIndex.scala | 12 +-- .../internal/v0/LegacySemanticdbIndex.scala | 2 +- .../internal/v1/InternalSemanticDoc.scala | 3 +- .../scala/scalafix/internal/v1/TreePos.scala | 102 ++++++++++-------- .../v0/LegacyInMemorySemanticdbIndex.scala | 2 +- 5 files changed, 66 insertions(+), 55 deletions(-) diff --git a/scalafix-core/src/main/scala/scalafix/internal/util/EagerInMemorySemanticdbIndex.scala b/scalafix-core/src/main/scala/scalafix/internal/util/EagerInMemorySemanticdbIndex.scala index d0f662f5a..ef2374e87 100644 --- a/scalafix-core/src/main/scala/scalafix/internal/util/EagerInMemorySemanticdbIndex.scala +++ b/scalafix-core/src/main/scala/scalafix/internal/util/EagerInMemorySemanticdbIndex.scala @@ -5,6 +5,7 @@ import scala.meta._ import scala.meta.internal.symtab._ import scala.meta.internal.{semanticdb => s} import scalafix.internal.v0._ +import scalafix.internal.v1.TreePos import scalafix.util.SemanticdbIndex import scalafix.v0 import scalafix.v0._ @@ -50,16 +51,7 @@ case class EagerInMemorySemanticdbIndex( def symbol(position: Position): Option[Symbol] = _names.get(position).map(_.symbol) def symbol(tree: Tree): Option[Symbol] = tree match { - case name @ Name(_) => - val syntax = name.syntax - // workaround for https://github.com/scalameta/scalameta/issues/1083 - val pos = - if (syntax.startsWith("(") && - syntax.endsWith(")") && - syntax != name.value) - Position.Range(name.pos.input, name.pos.start + 1, name.pos.end - 1) - else name.pos - symbol(pos) + case name: Name => TreePos.symbol[Option[Symbol]](name, symbol, _.isEmpty) case Importee.Rename(name, _) => symbol(name) case Importee.Name(name) => symbol(name) case Term.Select(_, name @ Name(_)) => symbol(name) diff --git a/scalafix-core/src/main/scala/scalafix/internal/v0/LegacySemanticdbIndex.scala b/scalafix-core/src/main/scala/scalafix/internal/v0/LegacySemanticdbIndex.scala index d41b7cb81..88558fb51 100644 --- a/scalafix-core/src/main/scala/scalafix/internal/v0/LegacySemanticdbIndex.scala +++ b/scalafix-core/src/main/scala/scalafix/internal/v0/LegacySemanticdbIndex.scala @@ -71,7 +71,7 @@ final class LegacySemanticdbIndex(val doc: v1.SemanticDocument) case multi => Some(v0.Symbol.Multi(multi)) } override def symbol(tree: Tree): Option[v0.Symbol] = - symbol(TreePos.symbol(tree)) + TreePos.symbolImpl[Option[v0.Symbol]](tree)(symbol, _.isEmpty) override def denotation(symbol: v0.Symbol): Option[v0.Denotation] = { doc.internal.info(v1.Symbol(symbol.syntax)).map { info => diff --git a/scalafix-core/src/main/scala/scalafix/internal/v1/InternalSemanticDoc.scala b/scalafix-core/src/main/scala/scalafix/internal/v1/InternalSemanticDoc.scala index 240c14361..3ae3462a5 100644 --- a/scalafix-core/src/main/scala/scalafix/internal/v1/InternalSemanticDoc.scala +++ b/scalafix-core/src/main/scala/scalafix/internal/v1/InternalSemanticDoc.scala @@ -50,7 +50,8 @@ final class InternalSemanticDoc( def symbol(tree: Tree): Symbol = { def fromTextDocument() = { - val result = symbols(TreePos.symbol(tree)) + val result = + TreePos.symbolImpl[Iterator[Symbol]](tree)(symbols, _.isEmpty) if (result.hasNext) result.next() // Discard multi symbols else Symbol.None } diff --git a/scalafix-core/src/main/scala/scalafix/internal/v1/TreePos.scala b/scalafix-core/src/main/scala/scalafix/internal/v1/TreePos.scala index 78b8f7af1..1aec4a16b 100644 --- a/scalafix-core/src/main/scala/scalafix/internal/v1/TreePos.scala +++ b/scalafix-core/src/main/scala/scalafix/internal/v1/TreePos.scala @@ -4,49 +4,67 @@ import scala.annotation.tailrec import scala.meta._ object TreePos { - @tailrec def symbol(tree: Tree): Position = tree match { - case name @ Name(_) => - val syntax = name.syntax - // workaround for https://github.com/scalameta/scalameta/issues/1083 - if (syntax.startsWith("(") && - syntax.endsWith(")") && - syntax != name.value) { + private[scalafix] def symbol[T]( + name: Name, + f: Position => T, + isEmpty: T => Boolean + ): T = { + val syntax = name.syntax + // workaround for https://github.com/scalameta/scalameta/issues/1083 + if (syntax.startsWith("(") && + syntax.endsWith(")") && + syntax != name.value) { + val pos = Position.Range(name.pos.input, name.pos.start + 1, name.pos.end - 1) - } else { - name.pos - } - case m: Member => symbol(m.name) - case t: Term.Select => symbol(t.name) - case t: Term.Interpolate => symbol(t.prefix) - case t: Term.Apply => symbol(t.fun) - case t: Term.ApplyInfix => symbol(t.op) - case t: Term.ApplyUnary => symbol(t.op) - case t: Term.ApplyType => symbol(t.fun) - case t: Term.Assign => symbol(t.lhs) - case t: Term.Ascribe => symbol(t.expr) - case t: Term.Annotate => symbol(t.expr) - case t: Term.New => symbol(t.init) - case t: Type.Select => symbol(t.name) - case t: Type.Project => symbol(t.name) - case t: Type.Singleton => symbol(t.ref) - case t: Type.Apply => symbol(t.tpe) - case t: Type.ApplyInfix => symbol(t.op) - case t: Type.Annotate => symbol(t.tpe) - case t: Type.ByName => symbol(t.tpe) - case t: Type.Repeated => symbol(t.tpe) - case t: Pat.Bind => symbol(t.lhs) - case t: Pat.Extract => symbol(t.fun) - case t: Pat.ExtractInfix => symbol(t.op) - case t: Pat.Interpolate => symbol(t.prefix) - case Defn.Val(_, p :: Nil, _, _) => symbol(p) - case Decl.Val(_, p :: Nil, _) => symbol(p) - case Defn.Var(_, p :: Nil, _, _) => symbol(p) - case Decl.Var(_, p :: Nil, _) => symbol(p) - case t: Importee.Rename => symbol(t.name) - case t: Importee.Name => symbol(t.name) - case Importer(_, i :: Nil) => symbol(i) - case t: Init => symbol(t.tpe) - case t: Mod.Annot => symbol(t.init) + val t = f(pos) + if (isEmpty(t)) f(name.pos) + else t + } else { + f(name.pos) + } + } + + def symbol(tree: Tree): Position = + symbolImpl[Position](tree)(identity[Position], _ => false) + + // The implicit function must named `$conforms` to shadow `Predef.$conforms` + @tailrec + private[scalafix] def symbolImpl[T]( + tree: Tree + )(implicit $conforms: Position => T, isEmpty: T => Boolean): T = tree match { + case name: Name => symbol(name, $conforms, isEmpty) + case m: Member => symbolImpl(m.name) + case t: Term.Select => symbolImpl(t.name) + case t: Term.Interpolate => symbolImpl(t.prefix) + case t: Term.Apply => symbolImpl(t.fun) + case t: Term.ApplyInfix => symbolImpl(t.op) + case t: Term.ApplyUnary => symbolImpl(t.op) + case t: Term.ApplyType => symbolImpl(t.fun) + case t: Term.Assign => symbolImpl(t.lhs) + case t: Term.Ascribe => symbolImpl(t.expr) + case t: Term.Annotate => symbolImpl(t.expr) + case t: Term.New => symbolImpl(t.init) + case t: Type.Select => symbolImpl(t.name) + case t: Type.Project => symbolImpl(t.name) + case t: Type.Singleton => symbolImpl(t.ref) + case t: Type.Apply => symbolImpl(t.tpe) + case t: Type.ApplyInfix => symbolImpl(t.op) + case t: Type.Annotate => symbolImpl(t.tpe) + case t: Type.ByName => symbolImpl(t.tpe) + case t: Type.Repeated => symbolImpl(t.tpe) + case t: Pat.Bind => symbolImpl(t.lhs) + case t: Pat.Extract => symbolImpl(t.fun) + case t: Pat.ExtractInfix => symbolImpl(t.op) + case t: Pat.Interpolate => symbolImpl(t.prefix) + case Defn.Val(_, p :: Nil, _, _) => symbolImpl(p) + case Decl.Val(_, p :: Nil, _) => symbolImpl(p) + case Defn.Var(_, p :: Nil, _, _) => symbolImpl(p) + case Decl.Var(_, p :: Nil, _) => symbolImpl(p) + case t: Importee.Rename => symbolImpl(t.name) + case t: Importee.Name => symbolImpl(t.name) + case Importer(_, i :: Nil) => symbolImpl(i) + case t: Init => symbolImpl(t.tpe) + case t: Mod.Annot => symbolImpl(t.init) case _ => tree.pos } } diff --git a/scalafix-reflect/src/main/scala/scalafix/internal/v0/LegacyInMemorySemanticdbIndex.scala b/scalafix-reflect/src/main/scala/scalafix/internal/v0/LegacyInMemorySemanticdbIndex.scala index 3c1af0556..da6f175b6 100644 --- a/scalafix-reflect/src/main/scala/scalafix/internal/v0/LegacyInMemorySemanticdbIndex.scala +++ b/scalafix-reflect/src/main/scala/scalafix/internal/v0/LegacyInMemorySemanticdbIndex.scala @@ -41,7 +41,7 @@ case class LegacyInMemorySemanticdbIndex( } } override def symbol(tree: Tree): Option[v0.Symbol] = - symbol(TreePos.symbol(tree)) + TreePos.symbolImpl[Option[v0.Symbol]](tree)(symbol, _.isEmpty) override def denotation(symbol: v0.Symbol): Option[Denotation] = symbol match { case v0.Symbol.Local(id) =>