PSI引用(References)

走着路睡觉大约 5 分钟

PSI引用(References)

本文档主要讲2点:

  1. 如何查找变量方法等在哪里被使用了,
  2. 使用的变量在哪里声明的

PSI引用(References):从使用了变量的位置链接到声明变量的位置。

解析引用(Resolving a reference): 从声明变量的位置链接到使用该变量的位置。

编程语言定义了引用类型。例如:定义一个JAVA方法

public void hello(String message) {
    System.out.println(message);
}

上述方法包含了5个引用(References)

  • String: 引用了JDK中的 java.lang.String
  • System: 引用了JDK中的 java.lang.System
  • out: 引用了java.lang.System 类的成员变量 out
  • println: 引用了java.lang.System 类的 println() 方法
  • messageprintln(message)引用了hello(String message) 中的message参数

提示

注意: hello(String message) 中的message参数不是引用,不能被 resolve。因为此处是声明了一个变量,并没有引用其它变量

引用(Reference) 实例都是 PsiReferenceopen in new window 接口的子类 。引用(Reference)PSI元素 不同,PsiElement.getReferences() 方法会返回引用该PSI元素 的所有 ReferencesPsiReference.getElement() 能获取该 References 使用到的 PSI元素

解析引用(Resolving reference) - PsiReference.resolve() 方法可以定位到该元素在哪里声明的。 PsiReference.getElement()PsiReference.resolve() 的不同的地方在于:PsiReference.getElement() 返回的是引用的元素,PsiReference.resolve() 返回引用的声明。例如上面示例中的第5个引用 messagegetElement() 方法会返回第2行的message元素标识符 ,resolve() 返回第1行(message参数)中的message标识符

解析引用(Resolving reference) 的过程与解析代码不同,它们不是同时执行的。解析引用(resolving references)有时可能会失败,如果当前在 IDE 中打开的代码没有编译,或者在其他异常情况下,PsiReference.resolve() 可能会返回 null ,所以使用引用(references)的代码必须处理返回null这种情况。

提示

了解更多,可以参考 PSI性能 文档中的 缓存 部分

Contributed References

IDE 能识别编程语言定义的引用,也能识别代码中API和框架定义的引用,如下面的示例:

File f = new File("foo.txt");

如上:在JAVA的语法中,"foo.txt" 只是一个字符串,没有特殊含义。但是,在IntelliJ IDEA输入上述代码,并在"foo.txt"上Ctrl + Click,如果在当前目录中有一个foo.txt文件,这时IntelliJ IDEA 会解析它的语法并提供定位到该文件上的引用(Reference)

通常,如果一个元素没有定义好的引用(Reference)(例如,字符串和注释),IDE将会提供引用。IDE也会为非代码文件(例如xml或json)提供引用。

Contributing references 经常用来扩展编辑语言的引用(Reference)。例如:Java PSI 是intellij platform的一部分,在您的插件中并没有定义它,但是你的插件可以给JAVA提供额外引用,参考下面示例:

<extensions defaultExtensionNs="com.intellij">
<!--   language 指定编辑语言的ID,表示该Contributor 是扩展的哪个编辑语言-->
    <psi.referenceContributor  language="JAVA" implementation=""></psi.referenceContributor>
</extensions>

The exact places to contribute references to are then specified using Element Patterns in calls to PsiReferenceRegistrar.registerReferenceProvider() .

更多内容可以文档 Reference Contributor tutorialopen in new window.

References with Optional or Multiple Resolve Results

通常情况下,PsiReference.resolve() 只会定位到一个元素, 如果 resolve 失败了,IDE 需要高亮显示代码异常的错误提示。但发生下面的特殊情况时,可以不用高亮显示异常:

  • soft references :如上面的示例中 File("foo.txt") ,如果IDE找不到 foo.txt文件,这并不代表是代码异常,可能是因为这个文件只会在程序运行的时候有效。所以如果 PsiReference.isSoft() 返回 True ,则可以忽略它的 resolve 异常。

  • polyvariant references :例如在 JavaScript 中,由于它是 动态类型语言,所以 resolve 时 IDE 就不能准确地确定哪个方法被调用了,这时 resolve 可能会定位到多个可能的元素,这样的 Reference 需要实现 PsiPolyVariantReferenceopen in new window 接口

resolve PsiPolyVariantReference 时,应该使用 multiResolve() 方法,会返回 ResolveResult[]open in new window ,每一个 ResolveResult 对象都对应一个 PSI元素,并指定了该 PSI元素是否有效。例如:在JAVA中,一个方法拥有多个重载方法,你调用该方法时,指定的参数不能匹配到任意一个重载方法,这时调用multiResolve() 方法 你会得到 ResolveResult[] ,其中每一个ResolveResult 都关联了一个重载方法,但是isValidResult() 方法返回结果都是 false

搜索References

Resolving reference 是从使用了变量的位置链接到声明变量的位置。

references search 是从声明的位置搜索使用了该声明的位置

ReferencesSearch.search()open in new window 执行搜索功能,传入要查找的元素(也可以传入可选参数:Scope-查找的范围)。返回的 Queryopen in new window 对象包含所有的使用位置。可以迭代 Query 对象,找到需要的引用(Reference) 时,可以停止迭代。

实现References

可以查看自定义编辑语言支持 中的相关文档 :guideopen in new windowtutorialopen in new window

上次编辑于:
贡献者: zhaojingbo
Loading...