diff --git a/ReflectionAnalyzers.Tests/REFL016UseNameofTests/Valid.cs b/ReflectionAnalyzers.Tests/REFL016UseNameofTests/Valid.cs index 1349d683..d56b7ab3 100644 --- a/ReflectionAnalyzers.Tests/REFL016UseNameofTests/Valid.cs +++ b/ReflectionAnalyzers.Tests/REFL016UseNameofTests/Valid.cs @@ -586,5 +586,38 @@ class C : Control RoslynAssert.Valid(Analyzer, Descriptor, code); } + + [TestCase("GetMethod(\"M1\")")] + [TestCase("GetMethod(\"M1\", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[0], null)")] + public static void InNestedTypeInheritance(string expression) + { + var @base = @" +namespace N +{ + class Base + { + protected void M1() { } + } +}"; + + var code = @" +namespace N +{ + using System; + using System.Reflection; + + class C : Base + { + class Nested + { + void M2() + { + typeof(Base).GetMethod(""M1""); + } + } + } +}".AssertReplace("GetMethod(\"M1\")", expression); + RoslynAssert.Valid(Analyzer, Descriptor, @base, code); + } } } diff --git a/ReflectionAnalyzers/Helpers/NameOf.cs b/ReflectionAnalyzers/Helpers/NameOf.cs index 2ebb6950..3c22869e 100644 --- a/ReflectionAnalyzers/Helpers/NameOf.cs +++ b/ReflectionAnalyzers/Helpers/NameOf.cs @@ -17,7 +17,7 @@ internal static bool TryGetExpressionText(ReflectedMember member, SyntaxNodeAnal targetName = null; if (member.Symbol is null || !member.Symbol.CanBeReferencedByName || - !context.SemanticModel.IsAccessible(context.Node.SpanStart, member.Symbol) || + !IsAccessible() || member.Symbol is INamedTypeSymbol { IsGenericType: true } || (member.Symbol is IMethodSymbol method && method.MethodKind != MethodKind.Ordinary)) { @@ -60,6 +60,27 @@ member.Symbol is ITypeSymbol || targetName = $"{TypeOfString(member.Symbol.ContainingType)}.{member.Symbol.Name}"; return true; + bool IsAccessible() + { + // Working around https://github.com/dotnet/roslyn/issues/43696 + if (context.SemanticModel.IsAccessible(context.Node.SpanStart, member.Symbol)) + { + if (member.Symbol.DeclaredAccessibility.IsEither(Accessibility.Public, Accessibility.Internal)) + { + return true; + } + + if (context.Node.FirstAncestor() is { } containingType) + { + return containingType.Identifier.ValueText == member.Symbol.ContainingType.MetadataName; + } + + return true; + } + + return false; + } + string TypeOfString(ITypeSymbol t) { if (t is INamedTypeSymbol { TupleUnderlyingType: { } utt } namedType &&