如果我有以下类型
Defn.Var(mods, pats, decltpe, rhs) 在scalameta中,可能会出现如下所示的变量将decltype设置为None:
var x = 10我仍然想知道Scala在没有亲自检查赋值表达式的类型的情况下推断出的变量x的确切类型。我知道我只能得到10是一个Int文本的信息,但对于更复杂的表达式,为该类型提供一些辅助函数可能会有所帮助。scalameta中有没有给出推断类型的函数?
发布于 2019-07-22 06:10:59
libraryDependencies += "org.scalameta" %% "scalameta" % "4.2.0"主要是在编译前处理源代码(将其解析为树,转换树),即当没有任何关于符号和类型的信息时。要获得有关符号和类型的信息,应该启动编译器(其中之一)。
这正是SemanticDB的作用所在。如果您打开semanticdb-scalac编译器插件
addCompilerPlugin("org.scalameta" % "semanticdb-scalac" % "4.1.0" cross CrossVersion.full)
scalacOptions ++= Seq(
"-Yrangepos",
"-P:semanticdb:synthetics:on",
)然后,在编译时,它将在.class文件附近生成.semanticdb文件。关于符号和类型的信息将在那里。这些文件可以使用semanticdb进行解析
libraryDependencies += "org.scalameta" %% "semanticdb" % "4.1.0"例如,如果您有App1.scala
object App1 {
var x = 10
}然后
import java.nio.file.Paths
import scala.meta.internal.semanticdb.Locator
Locator(
Paths.get("./target/scala-2.12/classes/META-INF/semanticdb/src/main/scala/App1.scala.semanticdb")
)((path, textDocuments) =>
println(textDocuments)
)产生
TextDocuments(Vector(TextDocument(SEMANTICDB4,src/main/scala/App1.scala,,29E9BFD566BEFD436FBE59679524E53D,SCALA,Vector(SymbolInformation(_empty_/App1.`x_=`().,SCALA,METHOD,2048,x_=,MethodSignature(Some(Scope(Vector(),Vector())),Vector(Scope(Vector(_empty_/App1.`x_=`().(x$1)),Vector())),TypeRef(Empty,scala/Unit#,Vector())),Vector(),PublicAccess()), SymbolInformation(_empty_/App1.,SCALA,OBJECT,8,App1,ClassSignature(Some(Scope(Vector(),Vector())),Vector(TypeRef(Empty,scala/AnyRef#,Vector())),Empty,Some(Scope(Vector(_empty_/App1.x()., _empty_/App1.`x_=`().),Vector()))),Vector(),PublicAccess()), SymbolInformation(_empty_/App1.`x_=`().(x$1),SCALA,PARAMETER,0,x$1,ValueSignature(TypeRef(Empty,scala/Int#,Vector())),Vector(),Empty), SymbolInformation(_empty_/App1.x().,SCALA,METHOD,2048,x,MethodSignature(Some(Scope(Vector(),Vector())),Vector(),TypeRef(Empty,scala/Int#,Vector())),Vector(),PublicAccess())),Vector(SymbolOccurrence(Some(Range(1,6,1,7)),_empty_/App1.x().,DEFINITION), SymbolOccurrence(Some(Range(0,7,0,11)),_empty_/App1.,DEFINITION)),Vector(),Vector())))您可以使用Metap漂亮地打印此文件
import scala.meta.cli.Metap
Metap.main(Array("target/scala-2.12/classes/META-INF/semanticdb/src/main/scala/App1.scala.semanticdb"))输出
src/main/scala/App1.scala
-------------------------
Summary:
Schema => SemanticDB v4
Uri => src/main/scala/App1.scala
Text => empty
Language => Scala
Symbols => 4 entries
Occurrences => 2 entries
Symbols:
_empty_/App1. => final object App1 extends AnyRef { +2 decls }
_empty_/App1.`x_=`(). => var method x_=(x$1: Int): Unit
_empty_/App1.`x_=`().(x$1) => param x$1: Int
_empty_/App1.x(). => var method x: Int
Occurrences:
[0:7..0:11) <= _empty_/App1.
[1:6..1:7) <= _empty_/App1.x().和
import scala.meta.internal.semanticdb.TypeRef
import scala.meta.internal.semanticdb.SignatureMessage.SealedValue.{ClassSignature, MethodSignature, TypeSignature, ValueSignature, Empty}
Locator(
Paths.get("./target/scala-2.12/classes/META-INF/semanticdb/src/main/scala/App1.scala.semanticdb")
)((path, textDocuments) =>
for {
document <- textDocuments.documents
symbol <- document.symbols
} println(s"symbol=${symbol.displayName}, ${symbol.signature.asMessage.sealedValue match {
case v: ValueSignature => s"ValueSignature, type=${v.value.tpe match { case t: TypeRef => t.symbol}}"
case m: MethodSignature => s"MethodSignature, returnType=${m.value.returnType match { case t: TypeRef => t.symbol}}"
case c: ClassSignature => "ClassSignature"
case t: TypeSignature => "TypeSignature"
case Empty => "Empty"
}}")
)产生
symbol=x_=, MethodSignature, returnType=scala/Unit#
symbol=App1, ClassSignature
symbol=x$1, ValueSignature, type=scala/Int#
symbol=x, MethodSignature, returnType=scala/Int#方案是here。
你也可以试试Scalafix
sbt new scalacenter/scalafix.g8 --repo="scalafixdemo"
cd scalafix
sbt ~tests/test如果你用input/src/main/scala/fix/Scalafixdemo.scala编写
package fix
object Scalafixdemo {
var x = 10
}在rules/src/main/scala/fix/Scalafixdemo.scala中
package fix
import scalafix.v1._
import scala.meta._
class Scalafixdemo extends SemanticRule("Scalafixdemo") {
override def fix(implicit doc: SemanticDocument): Patch = {
// println("Tree.syntax: " + doc.tree.syntax)
// println("Tree.structure: " + doc.tree.structure)
// println("Tree.structureLabeled: " + doc.tree.structureLabeled)
doc.tree.traverse {
case t@q"..$mods var ..$patsnel: $tpeopt = $expropt" =>
println(t.symbol.info.get.signature)
}
Patch.empty
}
}然后它将打印: Int
https://stackoverflow.com/questions/57132249
复制相似问题