Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #1104 #1105

Merged
merged 3 commits into from
May 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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._
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
102 changes: 60 additions & 42 deletions scalafix-core/src/main/scala/scalafix/internal/v1/TreePos.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
2 changes: 0 additions & 2 deletions scalafix-docs/src/main/scala/scalafix/docs/PatchDocs.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package scalafix.docs

import java.nio.file.Paths
import java.io.File
import org.typelevel.paiges.Doc
import scala.meta.inputs.Input
import scala.meta.interactive.InteractiveSemanticdb
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import scala.meta.internal.pc.ScalafixGlobal
import scalafix.internal.v1.LazyValue
import scala.util.control.NonFatal
import scala.util.Properties
import metaconfig.Conf
import scalafix.internal.compat.CompilerCompat._

final class ExplicitResultTypes(
Expand Down
5 changes: 5 additions & 0 deletions scalafix-tests/shared/src/main/scala/test/SymbolTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,8 @@ object a {
object d
}
}
trait SymbolTest {
def shouldBe(right: Any)
def arg = 1
this shouldBe (arg)
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
package scalafix.tests.v1

import org.scalatest.FunSuite
import scala.meta.Import
import scala.meta.Importer
import scala.meta._
import scalafix.tests.core.BaseSemanticSuite
import scalafix.v1._

class SymbolSuite extends FunSuite {
class SymbolSuite extends munit.FunSuite {
implicit val doc = BaseSemanticSuite.loadDoc("SymbolTest.scala")

test("normalized") {
val ref :: Nil = doc.tree.collect {
case Import(Importer(ref, _) :: Nil) => ref
}

import scalafix.v1._
assert(ref.symbol.normalized.owner.value == "test.a.")
assertEquals(ref.symbol.normalized.owner.value, "test.a.")
}

test("fromTextDocument") {
val arg :: Nil = doc.tree.collect {
case Term.ApplyInfix(_, Term.Name("shouldBe"), _, arg :: Nil) => arg
}

assertNotEquals(arg.symbol, Symbol.None)
}
}