我需要分析一些扩展方法。例如Enumerable.ToList
。
要分析的代码示例:
var test = @"
using System.Linq;
namespace Test
{
public class TestType
{
void TestMethod()
{
var empty = new[] {0};
var test = empty.ToList();
}
}
}";
诊断:
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.InvocationExpression);
}
private static void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
{
var symbolInfo = context.SemanticModel.GetSymbolInfo(context.Node);
}
但是symbolInfo.Symbol
为null,并且没有任何候选者。如果我这样更改代码示例:
var test = @"
using System.Linq;
namespace Test
{
public class TestType
{
void TestMethod()
{
var empty = new[] {0};
var test = Enumerable.ToList(empty);
}
}
}";
然后symbolInfo
有一个候选人,但仍然没有符号。如何获取扩展方法调用的符号信息?
答案 0 :(得分:1)
如果您使用默认的单元测试帮助程序类,该类是从“带有代码修复的分析器”项目模板自动创建的,那么您应该了解以下内容。
GetSortedDiagnosticsFromDocuments
方法会尝试运行分析器,即使在处理作为输入提供的代码时出现编译错误。当然,当出现编译错误时,语义模型可能不完整或缺失。
您可以通过以下方式更改此方法:
// old version: no compilation errors detection
var compilationWithAnalyzers = project.GetCompilationAsync().Result.WithAnalyzers(ImmutableArray.Create(analyzer));
// new version: detect the compilation errors
var compilation = project.GetCompilationAsync().Result;
var compilerErrors = compilation.GetDiagnostics().Where(i => i.Severity == DiagnosticSeverity.Error);
if (compilerErrors.Any())
{
return compilerErrors.ToArray();
}
var compilationWithAnalyzers = compilation.WithAnalyzers(ImmutableArray.Create(analyzer));
如果您随后尝试使用此代码和输入字符串来运行单元测试,则会发现至少2个编译错误:
错误CS0012:类型'List <>'在未引用的程序集中定义。您必须添加对程序集'System.Collections,Version = 4.1.0.0,Culture = neutral,PublicKeyToken = b03f5f7f11d50a3a'的引用。
(版本号可能不同)
和
错误CS5001:程序不包含适用于入口点的静态“主”方法
您需要解决这些错误才能编译代码,以便可以访问有效的语义模型。
void TestMethod()
更改为static void Main()
。确实不是必须这样做,但是最好有一个没有编译器错误的有效代码。System.Collections
和System.Runtime
的引用。当您使用项目模板中的帮助程序代码时,在单元测试中没有方便的方法来执行此操作。但是要进行测试,您可以更改CreateProject
方法。 默认情况下,还配置了4个其他引用。添加缺少的参考:
var collectionsReference = MetadataReference.CreateFromFile(typeof(Stack<>).Assembly.Location);
var runtimeReference = MetadataReference.CreateFromFile(typeof(ISet<>).Assembly.Location);
var solution = new AdhocWorkspace()
.CurrentSolution
.AddProject(projectId, TestProjectName, TestProjectName, language)
.AddMetadataReference() //...
// ...extend the AddMetadataReference chain
.AddMetadataReference(projectId, collectionsReference)
.AddMetadataReference(projectId, runtimeReference);
然后,您应该能够在单元测试中编译代码并获得有效的语义模型。
您可能愿意实现该动态引用功能,例如通过将正在动态创建的项目对象暴露给单元测试调用者。