{
string? loggerField = null;
- foreach (MemberDeclarationSyntax m in classDec.Members)
+ INamedTypeSymbol? classType = sm.GetDeclaredSymbol(classDec, _cancellationToken);
+
+ bool onMostDerivedType = true;
+
+ while (classType is { SpecialType: not SpecialType.System_Object })
{
- if (m is FieldDeclarationSyntax fds)
+ foreach (IFieldSymbol fs in classType.GetMembers().OfType<IFieldSymbol>())
{
- foreach (VariableDeclaratorSyntax v in fds.Declaration.Variables)
+ if (!onMostDerivedType && fs.DeclaredAccessibility == Accessibility.Private)
+ {
+ continue;
+ }
+ if (IsBaseOrIdentity(fs.Type, loggerSymbol))
{
- var fs = sm.GetDeclaredSymbol(v, _cancellationToken) as IFieldSymbol;
- if (fs != null)
+ if (loggerField == null)
{
- if (IsBaseOrIdentity(fs.Type, loggerSymbol))
- {
- if (loggerField == null)
- {
- loggerField = v.Identifier.Text;
- }
- else
- {
- return (null, true);
- }
- }
+ loggerField = fs.Name;
+ }
+ else
+ {
+ return (null, true);
}
}
}
+
+ onMostDerivedType = false;
+ classType = classType.BaseType;
}
return (loggerField, false);
public class LoggerMessageGeneratedCodeTests
{
[Fact]
+ public void FindsLoggerFieldInBaseClass()
+ {
+ var logger = new MockLogger();
+
+ logger.Reset();
+
+ new DerivedClass(logger).Test();
+ Assert.Equal("Test.", logger.LastFormattedString);
+ }
+
+ [Fact]
+ public void FindsLoggerFieldInAnotherParialClass()
+ {
+ var logger = new MockLogger();
+
+ logger.Reset();
+
+ new PartialClassWithLoggerField(logger).Test();
+ Assert.Equal("Test.", logger.LastFormattedString);
+ }
+
+ [Fact]
public void BasicTests()
{
var logger = new MockLogger();
using Microsoft.Extensions.Logging;
+// No explicit tests use the following two types, but the fact
+// that they are here means we exercise a constraint that we
+// exclude private fields of base types.
+// If that logic ever changes, then just by having these two classes
+// will mean that compilation fails with:
+// error SYSLIB1020: Found multiple fields of type Microsoft.Extensions.Logging.ILogger in class DerivedClass_with_private_logger
+public class BaseClassWithPrivateLogger
+{
+ private ILogger _logger;
+
+ public BaseClassWithPrivateLogger(ILogger logger) => _logger = logger;
+}
+
+public partial class DerivedClassWithPrivateLogger : BaseClassWithPrivateLogger
+{
+ private ILogger _logger;
+
+ public DerivedClassWithPrivateLogger(ILogger logger) : base(logger)
+ {
+ _logger = logger;
+ }
+
+ [LoggerMessage(0, LogLevel.Debug, "Test.")]
+ public partial void Test();
+}
+
+public class BaseClass
+{
+ protected ILogger _logger;
+
+ public BaseClass(ILogger logger) => _logger = logger;
+}
+
+public partial class DerivedClass : BaseClass
+{
+ public DerivedClass(ILogger logger) : base(logger) { }
+
+ [LoggerMessage(0, LogLevel.Debug, "Test.")]
+ public partial void Test();
+}
+
+public partial class PartialClassWithLoggerField
+{
+ private ILogger _logger;
+
+ public PartialClassWithLoggerField(ILogger logger) => _logger = logger;
+}
+
+public partial class PartialClassWithLoggerField
+{
+ [LoggerMessage(0, LogLevel.Debug, "Test.")]
+ public partial void Test();
+}
+
// Used to test use outside of a namespace
internal static partial class NoNamespace
{