如何使用Resharper SDK从IClrDeclaredElement获取IDeclaredType

Geo*_*rge 2 c# resharper-sdk

我正在为Resharper编写一个导航插件,我的情况是我有一个IDeclaredElement我从中获得的列表

var declaredElements = context.GetData(DataConstants.DECLARED_ELEMENTS)
Run Code Online (Sandbox Code Playgroud)

此元素是用户将鼠标光标放在其上的元素.

我想做的是获取IDeclaredType声明的元素,包括它可能具有的任何类型参数,如果它是泛型类型的话.

当涉及到类型系统时,resharper SDK文档很轻松,并没有真正解释各种类型之间的关系.

我已经在其他插件周围寻找试图找到这个的例子,但是空洞了.我已经检查了每个Util和Extension类,看看是否有某个方法可以提供我想要的东西,但是没有.

关于我发现的唯一的事情是:

declaredElements.First().GetSuperTypes()
Run Code Online (Sandbox Code Playgroud)

返回类型层次结构,不包括当前类型.有用,但不是我想要的.

有没有人有这个API的经验或了解它是如何工作的?我喜欢一个解释类型之间关系的答案.

我对它的理解,简而言之:

  • 名称中带有Declared的类型(IDeclaredElement, IDeclaredType) 似乎是指物理代码元素.
  • IType似乎是所有类型的顶级接口,与物理代码元素不对应
  • 我不清楚名称中带有Element的类型的含义(ITypeElement, IDeclaredElement),也许它指的是AST元素.

我很喜欢这方面的一些澄清.

cit*_*att 9

我在文档中添加了一个问题来更新:https://github.com/JetBrains/resharper-devguide/issues/4

我会尝试在这里提供一个盆栽的解释.

ITreeNode类型层次定义代码的抽象语法树.这提供了大量信息,但是非常低级 - 它直接映射到代码的原始文本.它也错过了一些更高级别的信息.例如,如果我想获取类声明的所有类型成员,我可以为类运行AST,并收集所有适当的树节点,但是我还必须处理部分类,并且AST不提供任何信息用于定位班级的其他部分.同样,如果我看到类声明public class Foo : Bar,我将不得不手动解析Bar基类型.

IDeclaredElement类型层次结构在本质上是语法树的语义视图.在最简单的层面上,声明的元素是"具有声明的东西".这可以是类声明,或方法声明,或甚至与代码无关的东西 - HTML元素,CSS类甚至颜色和文件系统路径(这就是它被称为"元素"的原因 - 它需要一个可以应用于的名称很多不同的事情).

例如,CLR类型用ITypeElement接口表示,接口派生自IDeclaredElement.它提供了获取目标类型的方法,属性,构造函数等声明元素的方法和属性.因此,(几乎)可以仅根据声明的元素提供CLR源项目的语义视图.几乎,但不完全.

声明的元素具有GetDeclarations提供IDeclaration语法树节点的方法,该语法树节点是声明的元素的声明.类似地,IDeclaration节点提供的DeclaredElement属性能够从节点获取声明的元素.

此外,ReSharper有一个非常强大的机制叫做引用,允许树节点有一个传出的引用,它将解析为一个声明的元素(它也可能无法解析,这是一个错误,比如使用一个尚未解决的方法写入,或者它可以解析为多个元素,例如使用方法而不限定它的重载次数).这些引用可以应用到任何节点,诸如变量名返回参考变量声明,或Barpublic class Foo : Bar具有到所声明的元素的引用Bar(从它有可能得到IDeclaration和的源代码Bar).

这提供了一组令人印象深刻的功能 - 代码文件的语法视图,代码声明的语义视图以及将所有内容连接在一起的引用,但这并未涵盖所有内容.声明的元素提供声明的东西的语义视图,但不是为了表示所有使用场景.

具体来说(查看CLR类型),它不能将类型的用法表示为数组,指针或封闭泛型类型.ITypeElement可以提供类的语义视图FooBar<T>,但它不能代表Foo[],或Bar<Quux>.

声明的元素需要能够将这些使用场景建模为基类,方法签名等.为此,派生的声明元素(例如ITypeElement)使用附加的接口层次结构来表示此"类型系统"信息.此层次结构取决于所分析的语言.对于CLR类型,它是IType层次结构,对于JavaScript,它是IJavaScriptType.

IType是附加信息,而不是声明元素的语义视图的替代.该IType可返回所有类型成员的符号表,但不提供在以同样的方式存取ITypeElement一样.相反,(并且取决于被建模的东西)a IType本质上是声明元素和实例的包装器ISubstitution,它为泛型类型参数提供替换(数组表示为System.Array类型,具有底层元素类型,它本身是一个IType,因为它可能是一个封闭的通用,或另一个数组).替换也可以是空替换,它不替代任何东西,允许表示为开放泛型的类型,或者根本不是通用的类型.该IDeclaredType接口是一个IType引用声明的元件.

除此之外:解析引用实际上解析为声明的元素,并且ISubstitution再次解析为泛型.在解析方法声明签名的引用时,您需要知道它是一个IList<T>,什么T是.

为了获得一个IType实例,您需要从现有的声明元素(方法签名,基类等)中获取一个实例,或者通过创建它来获取实例TypeFactory.CreateType.ISubstitution如果它是泛型类型,你很可能也需要指定一个.您还可以通过以下方式获得一组常见的"预定义"类型:

var type = psiModule.GetPredefinedType(context).String; 
Run Code Online (Sandbox Code Playgroud)

您可以使用这些类型传递给其中一个TypeFactory.CreateType方法,作为ITypeElement您传入的类型参数.

所以,结果是,我们在源中声明了一个类,这给了我们ITreeNode,IDeclarationITypeDeclaration.我们可以使用IDeclaration或解析引用来获取此声明的语义视图IDeclaredElement,ITypeElement作为表示类的派生接口.基于CLR的声明元素用于IType表示类型用法,例如基类,可能需要是封闭的泛型,或者可能是开放式泛型或数组的方法参数.IDeclaredType是一种类型用法,可以让我们回到声明的元素.并且类型通常在内部用声明的元素表示ISubstitution,并且可以填充任何通用参数,或者在没有泛型参数时作为ID替换.最后,您可以IType使用TypeFactory.CreateType或使用属性PredefinedType.

  • 不完全是复制粘贴,但它现在在文档中.[简介](http://jetbrains.github.io/resharper-devguide/Architecture/PSI.html),[语法树](http://jetbrains.github.io/resharper-devguide/PSI/SyntaxTrees.html) ,[声明的元素](http://jetbrains.github.io/resharper-devguide/PSI/DeclaredElements.html),[参考文献](http://jetbrains.github.io/resharper-devguide/PSI/References.html )和[Type Systems](http://jetbrains.github.io/resharper-devguide/PSI/TypeSystems2.html) (2认同)