首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如果decltpe为空,如何使用scalameta获取变量的类型?

如果decltpe为空,如何使用scalameta获取变量的类型?
EN

Stack Overflow用户
提问于 2019-07-21 18:23:34
回答 1查看 350关注 0票数 1

如果我有以下类型

代码语言:javascript
复制
Defn.Var(mods, pats, decltpe, rhs) 

在scalameta中,可能会出现如下所示的变量将decltype设置为None

代码语言:javascript
复制
var x = 10

我仍然想知道Scala在没有亲自检查赋值表达式的类型的情况下推断出的变量x的确切类型。我知道我只能得到10是一个Int文本的信息,但对于更复杂的表达式,为该类型提供一些辅助函数可能会有所帮助。scalameta中有没有给出推断类型的函数?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-07-22 06:10:59

Scalameta

代码语言:javascript
复制
libraryDependencies += "org.scalameta" %% "scalameta" % "4.2.0"

主要是在编译前处理源代码(将其解析为树,转换树),即当没有任何关于符号和类型的信息时。要获得有关符号和类型的信息,应该启动编译器(其中之一)。

这正是SemanticDB的作用所在。如果您打开semanticdb-scalac编译器插件

代码语言:javascript
复制
addCompilerPlugin("org.scalameta" % "semanticdb-scalac" % "4.1.0" cross CrossVersion.full)
scalacOptions ++= Seq(
  "-Yrangepos",
  "-P:semanticdb:synthetics:on",
)

然后,在编译时,它将在.class文件附近生成.semanticdb文件。关于符号和类型的信息将在那里。这些文件可以使用semanticdb进行解析

代码语言:javascript
复制
libraryDependencies += "org.scalameta" %% "semanticdb" % "4.1.0"

例如,如果您有App1.scala

代码语言:javascript
复制
object App1 {
  var x = 10
}

然后

代码语言:javascript
复制
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)
)

产生

代码语言:javascript
复制
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漂亮地打印此文件

代码语言:javascript
复制
import scala.meta.cli.Metap
Metap.main(Array("target/scala-2.12/classes/META-INF/semanticdb/src/main/scala/App1.scala.semanticdb"))

输出

代码语言:javascript
复制
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().

代码语言:javascript
复制
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"
  }}")
)

产生

代码语言:javascript
复制
symbol=x_=, MethodSignature, returnType=scala/Unit#
symbol=App1, ClassSignature
symbol=x$1, ValueSignature, type=scala/Int#
symbol=x, MethodSignature, returnType=scala/Int#

方案是here

你也可以试试Scalafix

代码语言:javascript
复制
sbt new scalacenter/scalafix.g8 --repo="scalafixdemo"
cd scalafix
sbt ~tests/test

如果你用input/src/main/scala/fix/Scalafixdemo.scala编写

代码语言:javascript
复制
package fix

object Scalafixdemo {
  var x = 10
}

rules/src/main/scala/fix/Scalafixdemo.scala

代码语言:javascript
复制
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://github.com/DmytroMitin/scalafix-codegen

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57132249

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档