IParameterSymbol.GetAttributes() 不 return 实际符号
IParameterSymbol.GetAttributes() does not return actual symbols
我正在编写 roslyn 分析器,它应该检查方法的参数是否在当前方法声明或接口之一中使用 [NotNull] 属性声明,并对其方法主体进行一些检查。我用 RegisterCodeBlockAction 注册了 CodeBlockAction,但是当我试图从 interfaces/base classes 中的参数声明中获取属性时,它有它,有时它是 returns 空数组。
我发现,如果 interface/base class 位于其他程序集,并且当 Intelisense 运行s 它时,实际上分析器工作正常,但有构建输出中没有 warnings\errors。我认为发生这种情况是因为引用程序集的语义分析没有完全完成(但有点奇怪)。
我写了一些日志
6/6/2019 13:59:47 Analize method symbol "ClassLibrary1.Program.Foo(string)" with 1 interfaces
6/6/2019 13:59:47 declaration ClassLibrary2.IFoo.Foo(string): [0 attributes] string s
6/6/2019 13:59:47 declaration ClassLibrary1.Program.Foo(string): [0 attributes] string s
6/6/2019 13:59:59 Analize method symbol "ClassLibrary1.Program.Foo(string)" with 1 interfaces
6/6/2019 13:59:59 declaration ClassLibrary2.IFoo.Foo(string): [1 attributes] string s
6/6/2019 13:59:59 declaration ClassLibrary1.Program.Foo(string): [0 attributes] string s
所以你可以看到,在 13:59:47 (msbuild 运行) 没有属性,但是在 13:59:59 (我在 Visual studio 中打开文档)有一个属性。
这是我获取接口和参数的方法:
var allMethodDeclarations = //some code using methodSymbol.ContainingType.Interfaces
for (var i = 0; i < methodSymbol.Parameters.Length; ++i)
{
var currentParameter = methodSymbol.Parameters[i];
//parameters can be renamed, the only way is to use the order
var hasNotNull = allMethodDeclarations
.Select(d => d.Parameters[i])
.SelectMany(p => p.GetAttributes())
.Any(a => a.AttributeClass.Name == nameof(NotNullAttribute));
if (hasNotNull)
{
//do something
}
}
重现错误的示例代码:
在程序集 1
public interface IFoo
{
void Foo([NotNull] string s);
}
在程序集 2 中,它引用了程序集 1
public class Program : IFoo
{
public void Foo(string s)
{
}
}
好的,我明白了。这是因为来自 Jetbrains.Annotations 的 NotNullAttribute 上的条件编译属性,所以编译器显示来自实际引用符号的数据(它跳过 [NotNull] 因为 JETBRAINS_ANNOTATIONS 未定义)和 Visual Studio从代码中提供真实的属性列表,条件编译不考虑这种方式。
它看起来不一致,但我必须在我的项目中定义 JETBRAINS_ANNOTATIONS 才能使分析器工作。
我正在编写 roslyn 分析器,它应该检查方法的参数是否在当前方法声明或接口之一中使用 [NotNull] 属性声明,并对其方法主体进行一些检查。我用 RegisterCodeBlockAction 注册了 CodeBlockAction,但是当我试图从 interfaces/base classes 中的参数声明中获取属性时,它有它,有时它是 returns 空数组。
我发现,如果 interface/base class 位于其他程序集,并且当 Intelisense 运行s 它时,实际上分析器工作正常,但有构建输出中没有 warnings\errors。我认为发生这种情况是因为引用程序集的语义分析没有完全完成(但有点奇怪)。
我写了一些日志
6/6/2019 13:59:47 Analize method symbol "ClassLibrary1.Program.Foo(string)" with 1 interfaces
6/6/2019 13:59:47 declaration ClassLibrary2.IFoo.Foo(string): [0 attributes] string s
6/6/2019 13:59:47 declaration ClassLibrary1.Program.Foo(string): [0 attributes] string s
6/6/2019 13:59:59 Analize method symbol "ClassLibrary1.Program.Foo(string)" with 1 interfaces
6/6/2019 13:59:59 declaration ClassLibrary2.IFoo.Foo(string): [1 attributes] string s
6/6/2019 13:59:59 declaration ClassLibrary1.Program.Foo(string): [0 attributes] string s
所以你可以看到,在 13:59:47 (msbuild 运行) 没有属性,但是在 13:59:59 (我在 Visual studio 中打开文档)有一个属性。
这是我获取接口和参数的方法:
var allMethodDeclarations = //some code using methodSymbol.ContainingType.Interfaces
for (var i = 0; i < methodSymbol.Parameters.Length; ++i)
{
var currentParameter = methodSymbol.Parameters[i];
//parameters can be renamed, the only way is to use the order
var hasNotNull = allMethodDeclarations
.Select(d => d.Parameters[i])
.SelectMany(p => p.GetAttributes())
.Any(a => a.AttributeClass.Name == nameof(NotNullAttribute));
if (hasNotNull)
{
//do something
}
}
重现错误的示例代码:
在程序集 1
public interface IFoo
{
void Foo([NotNull] string s);
}
在程序集 2 中,它引用了程序集 1
public class Program : IFoo
{
public void Foo(string s)
{
}
}
好的,我明白了。这是因为来自 Jetbrains.Annotations 的 NotNullAttribute 上的条件编译属性,所以编译器显示来自实际引用符号的数据(它跳过 [NotNull] 因为 JETBRAINS_ANNOTATIONS 未定义)和 Visual Studio从代码中提供真实的属性列表,条件编译不考虑这种方式。 它看起来不一致,但我必须在我的项目中定义 JETBRAINS_ANNOTATIONS 才能使分析器工作。