三.使用Roslyn分析代码
[九.发布Visual Studio 扩展]
三.使用Roslyn分析代码
上一节我们实现了一个右击的上下文命令,并获取了用户选的的位置和内容,这一节我们来看一下如何通过Roslyn来实现代码分析。
3.1 分析SolidWroks在线Api的Url格式
方法 ModelDoc2的GetTiltle()方法 http://help.solidworks.com/2018/english/api/sldworksapi/SolidWorks.Interop.sldworks~SolidWorks.Interop.sldworks.IModelDoc2~GetTitle.html
属性 ModelDoc2的Visible属性 http://help.solidworks.com/2018/english/api/sldworksapi/SolidWorks.Interop.sldworks~SolidWorks.Interop.sldworks.IModelDoc2~Visible.html
通过分析Url我们可以判断出我们要得到的信息,通过控制前缀(http://help.solidworks.com/2018/english/api/sldworksapi/)的内容可以选择版本和语言(并没有选择)。想要得到特点的接口,方法,属性的Url我们需要组合后面的字符。根据后面的字符串,我们需要得到当前选择内容的类型,是方法属性还是一个接口,然后获取到这个接口的命名空间。
痛苦的是我们无法简单的根据一个选择的字符来的到他的类型信息和命名空间,幸运的是.Net 为我们提供Rosly工具来分析源代码。
3.2 通过Roslyn解析语义信息
对于接口的话,我们只需要获取这个接口的命名空间即可,但对于属性和方法,我们还需要获取这个属性或方法所属的接口或者类。为了获取这些信息,首先我们需要对代码进行语法分析,从而得到选择区域在语法树上的节点;
其次,拿到的节点信息Node,就要对建立代码的编译模型,从预编译模型中获取语义信息(ISymblo接口);有了语义信息,我们遍可以解析当前节点的类型,命名空间等等。
1.语法分析
public ISymbol GetDocPostionSymobl(string ActiveDocPath,int StartPosition,int Length)
{
foreach (var project in DuSolidWorksToolsPackage.myVSWorkspace.CurrentSolution.Projects)
{
foreach (var doc in project.Documents)
{
if (doc.FilePath == ActiveDocPath)
{
var Model = doc.GetSemanticModelAsync().GetAwaiter().GetResult();
if (Model == null)
{
return null;
}
var root = Model.SyntaxTree.GetRoot();
CSharpCompilation CsharpComp = Model.Compilation as CSharpCompilation;
var node = root.FindNode(new Microsoft.CodeAnalysis.Text.TextSpan(StartPosition, Length));
if (node != null)
{
var mySymbol = GetSymbolInfo(node, Model);
return mySymbol;
}
break;
}
}
}
return null;
}
通过Visual Studio WorkSpace 获取Visual Stuio 解决方案的语义模型,再获取当前选择的节点
2. 获取语义信息
public ISymbol GetSymbolInfo(SyntaxNode node, SemanticModel Model)
{
var symbolInfo = Model.GetSymbolInfo(node);
return symbolInfo.Symbol;
}
3.通过构造类来构造SolidWorks Api Help的Url链接
uRLContructor = new Du.Core.SolidWorksURLContructor(symbolInfo.Symbol);
if (uRLContructor.Result == Du.Core.SolidWorksURLContructor.SolidWorksURLResult.Exist)
{
SetApiBrowser(uRLContructor, symbolInfo.Symbol);
}
通过一个类来构造Ur
public class SolidWorksURLContructor
{
#region 静态字段
public static int NowVersion = 2018;
public static string NowApiWelcomeUrl {
get {
return "http://help.solidworks.com/" + NowVersion.ToString() + "/english/api/sldworksapiprogguide/Welcome.htm";
}
}
#endregion
#region 私有字段
private ISymbol mySymbol;
#endregion
#region 公共属性
public SolidWorksURLResult Result { get; set; }
public SolidWorksURLSourse Sourse = SolidWorksURLSourse.Web;
public string URL { get; set; }
/// <summary>
/// api欢迎页面
/// </summary>
public string ApiWelcomeUrl
{
get
{
switch (Sourse)
{
case SolidWorksURLSourse.Local:
break;
case SolidWorksURLSourse.Web:
return "http://help.solidworks.com/" + Version.ToString() + "/english/api/sldworksapiprogguide/Welcome.htm";
}
return "http://help.solidworks.com/" + Version.ToString() + "/english/api/sldworksapiprogguide/Welcome.htm";
}
}
public int Version {
get { return SolidWorksURLContructor.NowVersion; }
set {
SolidWorksURLContructor.NowVersion = value;
URL = GetUrl();
}
}
#endregion
/// <summary>
/// 定向URL
/// </summary>
private string SolidWorksApiInitUrl
{
get
{
return "http://help.solidworks.com/" + Version.ToString() + "/english/api/sldworksapi/";
}
}
#region 构造函数
public SolidWorksURLContructor(Microsoft.CodeAnalysis.ISymbol symbol)
{
mySymbol = symbol;
URL = GetUrl();
}
#endregion
#region 私有方法
private string GetUrl()
{
string Url = string.Empty;
switch (mySymbol.Kind)
{
case SymbolKind.Alias:
break;
case SymbolKind.ArrayType:
break;
case SymbolKind.Assembly:
break;
case SymbolKind.DynamicType:
break;
case SymbolKind.ErrorType:
break;
case SymbolKind.Event:
break;
//字段
case SymbolKind.Field:
break;
case SymbolKind.Label:
break;
case SymbolKind.Local:
break;
//方法
case SymbolKind.Method:
Url = PropertyOrMethodURLContructor(mySymbol.ContainingAssembly.Identity.Name,mySymbol.ContainingType.Name,mySymbol.OriginalDefinition.Name);
break;
case SymbolKind.NetModule:
break;
//类名
case SymbolKind.NamedType:
Url = NameTypeURLContructor(mySymbol.ContainingAssembly.Identity.Name, mySymbol.Name);
break;
//命名空间
case SymbolKind.Namespace:
Url = NameSpaceURLCon(mySymbol.ContainingAssembly.Identity.Name);
break;
case SymbolKind.Parameter:
break;
case SymbolKind.PointerType:
break;
//属性
case SymbolKind.Property:
Url = PropertyOrMethodURLContructor(mySymbol.ContainingAssembly.Identity.Name, mySymbol.ContainingType.Name, mySymbol.OriginalDefinition.Name);
break;
case SymbolKind.RangeVariable:
break;
case SymbolKind.TypeParameter:
break;
case SymbolKind.Preprocessing:
break;
case SymbolKind.Discard:
break;
}
if (string.IsNullOrEmpty(Url))
{
Result = SolidWorksURLResult.None;
}
else
{
Result = SolidWorksURLResult.Exist;
}
return Url;
}
private string NameSpaceURLCon(string name)
{
return "";
}
/// <summary>
/// 属性或者方法构造器
/// </summary>
/// <param name="NameSpace"></param>
/// <param name="originalDefinition"></param>
/// <returns></returns>
private string PropertyOrMethodURLContructor(string NameSpace,string TypeName,string originalDefinition)
{
//http://help.solidworks.com/2018/english/api/sldworksapi/SolidWorks.Interop.sldworks~SolidWorks.Interop.sldworks.IModelDoc2~CustomInfo2.html
switch (Sourse)
{
case SolidWorksURLSourse.Local:
break;
case SolidWorksURLSourse.Web:
return (SolidWorksApiInitUrl + NameSpace + "~"+NameSpace+"."+TypeName+"~"+ originalDefinition + ".html");
}
return "";
}
/// <summary>
/// 类名的帮助URL构造器
/// </summary>
/// <param name="NameSpace"></param>
/// <param name="ClassName"></param>
/// <returns></returns>
private string NameTypeURLContructor(string NameSpace, string ClassName)
{
string FullName = string.Empty;
if (ClassName.ToCharArray()[0] == 'I' )
{
FullName = NameSpace + ClassName + "_members.html";
}
else
{
FullName = NameSpace + ".I" + ClassName + "_members.html";
}
//string FullName = NameSpace + ".I" + ClassName + " members.html";
//http://help.solidworks.com/2018/english/api/sldworksapi/SolidWorks.Interop.sldworks~SolidWorks.Interop.sldworks.IModelDoc2_members.html
switch (Sourse)
{
case SolidWorksURLSourse.Local:
break;
case SolidWorksURLSourse.Web:
return (SolidWorksApiInitUrl + NameSpace + "~" + FullName);
}
return "";
}
#endregion
public enum SolidWorksURLResult
{
Exist,
None
}
public enum SolidWorksURLSourse {
Local,
Web
}
}