三.使用Roslyn分析代碼
[九.發(fā)布Visual Studio 擴展]
三.使用Roslyn分析代碼
?上一節(jié)我們實現(xiàn)了一個右擊的上下文命令苦囱,并獲取了用戶選的的位置和內(nèi)容,這一節(jié)我們來看一下如何通過Roslyn來實現(xiàn)代碼分析脾猛。
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/)的內(nèi)容可以選擇版本和語言(并沒有選擇)。想要得到特點的接口猛拴,方法羹铅,屬性的Url我們需要組合后面的字符。根據(jù)后面的字符串愉昆,我們需要得到當(dāng)前選擇內(nèi)容的類型职员,是方法屬性還是一個接口,然后獲取到這個接口的命名空間跛溉。
痛苦的是我們無法簡單的根據(jù)一個選擇的字符來的到他的類型信息和命名空間焊切,幸運的是.Net 為我們提供Rosly工具來分析源代碼。
3.2 通過Roslyn解析語義信息
對于接口的話芳室,我們只需要獲取這個接口的命名空間即可专肪,但對于屬性和方法,我們還需要獲取這個屬性或方法所屬的接口或者類渤愁。為了獲取這些信息牵祟,首先我們需要對代碼進行語法分析深夯,從而得到選擇區(qū)域在語法樹上的節(jié)點抖格;
其次,拿到的節(jié)點信息Node咕晋,就要對建立代碼的編譯模型雹拄,從預(yù)編譯模型中獲取語義信息(ISymblo接口);有了語義信息掌呜,我們遍可以解析當(dāng)前節(jié)點的類型滓玖,命名空間等等。
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 解決方案的語義模型质蕉,再獲取當(dāng)前選擇的節(jié)點
2. 獲取語義信息
public ISymbol GetSymbolInfo(SyntaxNode node, SemanticModel Model)
{
var symbolInfo = Model.GetSymbolInfo(node);
return symbolInfo.Symbol;
}
3.通過構(gòu)造類來構(gòu)造SolidWorks Api Help的Url鏈接
uRLContructor = new Du.Core.SolidWorksURLContructor(symbolInfo.Symbol);
if (uRLContructor.Result == Du.Core.SolidWorksURLContructor.SolidWorksURLResult.Exist)
{
SetApiBrowser(uRLContructor, symbolInfo.Symbol);
}
通過一個類來構(gòu)造Ur
public class SolidWorksURLContructor
{
#region 靜態(tài)字段
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 構(gòu)造函數(shù)
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>
/// 屬性或者方法構(gòu)造器
/// </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構(gòu)造器
/// </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
}
}