49. クリックした位置を取得 dte.ActiveDocument
var csFile = Path.Combine(dte.ActiveDocument.Path, dte.ActiveDocument.Name);
//ファイルを読む
var csLines = File.ReadAllLines(csFile);
//選択位置取得
var sel = dte.ActiveDocument.Selection as TextSelection;
var pos = GetPos(csLines, sel.CurrentLine - 1, sel.CurrentColumn - 1);
static int GetPos(string[] lines, int currentLine, int currentCol)
{
int charCount = 0;
for (int i = 0; i < lines.Length; i++)
{
if (i == currentLine)
{
return charCount + currentCol;
}
charCount += lines[i].Length;
charCount += Environment.NewLine.Length;
}
return -1;
}
dte.ActiveDocumentを使う
55. 型情報を得る
アセンブリのパスを取得
もっといい方法があるかも
var proj = dte.ActiveDocument.ProjectItem.ContainingProject.FileName;
var solutionBuild = dte.Solution.SolutionBuild;
//選択されているビルドのモード(Debug)
var buildConfig = solutionBuild.ActiveConfiguration.Name;
//選択されているプラットフォーム
var platform = solutionBuild.ActiveConfiguration.
SolutionContexts.Cast<SolutionContext>().FirstOrDefault().PlatformName;
//CSファイル解析は端折ります・・・ XML解析です。
//出力フォルダ取得
var output = CSProjAnalyzer.GetOutputDirectory(proj, buildConfig, platform);
//拡張子
var ext = CSProjAnalyzer.GetTargetFileExtension(proj);
//バイナリパス
var assembly = Path.Combine(output, CSProjAnalyzer.GetAssemblyName(proj) + "." + ext);
56. 型情報を得る Mono.Cecil
//アセンブリ情報取得
var asm = AssemblyDefinition.ReadAssembly(assemblyPath);
//タイプ
var type = asm.Modules.SelectMany(e => e.Types).
Where(e => e.FullName == typeFullName).FirstOrDefault();
//完全なマッチロジックにはならないが、実用上問題ないレベルではある・・・
var methodInfo = type.Methods.Where(e => e.Name == methodName).
Where(e => IsMatchMethod(e, methodName, argumentTypes)).FirstOrDefault();
割り切った
57. private static bool IsMatchMethod(MethodDefinition methodInfo, string methodName, List<string> argumentTypes)
{
if (methodInfo.Name != methodName) return false;
if (methodInfo.Parameters.Count != argumentTypes.Count) return false;
for (int i = 0; i < methodInfo.Parameters.Count; i++)
{
if (!IsMatchType(methodInfo.Parameters[i].ParameterType, argumentTypes[i])) return false;
}
return true;
}
static bool IsMatchType(TypeReference type, string typeName)
{
var types1 = GetAllTypes(type);
var types2 = GetAllTypes(typeName);
if (types1.Length != types2.Length) return false;
for (int i = 0; i < types1.Length; i++)
{
if (!types1[i].Contains(types2[i])) return false;
}
return true;
}
static string[] GetAllTypes(string type)
{
return type.Replace(">", "").Split(new[] { "<", "," }, System.StringSplitOptions.RemoveEmptyEntries).Select(e => AdjustTypeName(e)).ToArray();
}
static string[] GetAllTypes(TypeReference type)
{
var types = new List<string>();
if (type.IsGenericInstance)
{
types.AddRange(GetAllTypes(type.GetElementType()));
foreach (var e in ((dynamic)type).GenericArguments)
{
types.AddRange(GetAllTypes(e));
}
}
else
{
//Innerクラスの表現が違うので合わせる
types.Add(type.FullName.Replace("/", "+"));
}
return types.ToArray();
}
static string AdjustTypeName(string type)
{
type = type.Trim();
var arrayCount = GetArrayCount(type);
type = type.Replace("[]", string.Empty);
switch (type)
{
case "byte": type = typeof(byte).FullName; break;
case "char": type = typeof(char).FullName; break;
case "short": type = typeof(short).FullName; break;
case "ushort": type = typeof(ushort).FullName; break;
case "int": type = typeof(int).FullName; break;
case "uint": type = typeof(uint).FullName; break;
case "long": type = typeof(long).FullName; break;
case "ulong": type = typeof(ulong).FullName; break;
case "float": type = typeof(float).FullName; break;
case "double": type = typeof(double).FullName; break;
case "decimal": type = typeof(decimal).FullName; break;
case "string": type = typeof(string).FullName; break;
}
return type + string.Join("", Enumerable.Range(0, arrayCount).Select(e => "[]"));
}
static int GetArrayCount(string type)
{
int count = 0;
while (true)
{
int index = type.IndexOf("[]");
if (index == -1) break;
count++;
type = type.Substring(index + "[]".Length);
}
return count;
}
IsMatchMethodは関数名と引数から、
(だいたい)マッチしてるか判別するロジックです。