diff --git a/docs/project/list-of-diagnostics.md b/docs/project/list-of-diagnostics.md index 41d5a78f3f1..76e734dea86 100644 --- a/docs/project/list-of-diagnostics.md +++ b/docs/project/list-of-diagnostics.md @@ -145,7 +145,7 @@ The diagnostic id values reserved for .NET Libraries analyzer warnings are `SYSL | __`SYSLIB1024`__ | Argument is using the unsupported out parameter modifier | | __`SYSLIB1025`__ | Multiple logging methods cannot use the same event name within a class | | __`SYSLIB1026`__ | C# language version not supported by the logging source generator. | -| __`SYSLIB1027`__ | _`SYSLIB1001`-`SYSLIB1029` reserved for logging._ | +| __`SYSLIB1027`__ | Primary constructor parameter of type Microsoft.Extensions.Logging.ILogger is hidden by a field | | __`SYSLIB1028`__ | _`SYSLIB1001`-`SYSLIB1029` reserved for logging._ | | __`SYSLIB1029`__ | _`SYSLIB1001`-`SYSLIB1029` reserved for logging._ | | __`SYSLIB1030`__ | JsonSourceGenerator did not generate serialization metadata for type | diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.Abstractions.sln b/src/libraries/Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.Abstractions.sln index 4064dd66cbf..27d405dd7a6 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.Abstractions.sln +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/Microsoft.Extensions.Logging.Abstractions.sln @@ -23,6 +23,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Loggin EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Logging.Generators.Roslyn4.0.Tests", "tests\Microsoft.Extensions.Logging.Generators.Tests\Microsoft.Extensions.Logging.Generators.Roslyn4.0.Tests.csproj", "{1CB869A7-2EEC-4A53-9C33-DF9E0C75825B}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Logging.Generators.Roslyn4.8.Tests", "tests\Microsoft.Extensions.Logging.Generators.Tests\Microsoft.Extensions.Logging.Generators.Roslyn4.8.Tests.csproj", "{D6167506-0671-46A3-94E5-7A98032DCEC6}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibraryImportGenerator", "..\System.Runtime.InteropServices\gen\LibraryImportGenerator\LibraryImportGenerator.csproj", "{852D4E16-58C3-47C2-A6BC-A5B12B37209F}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Interop.SourceGeneration", "..\System.Runtime.InteropServices\gen\Microsoft.Interop.SourceGeneration\Microsoft.Interop.SourceGeneration.csproj", "{6645D0C4-83D1-4426-B9CD-67096CB7A60F}" @@ -135,6 +137,10 @@ Global {F3186815-B9A5-455F-B0DF-E39D4235C24F}.Debug|Any CPU.Build.0 = Debug|Any CPU {F3186815-B9A5-455F-B0DF-E39D4235C24F}.Release|Any CPU.ActiveCfg = Release|Any CPU {F3186815-B9A5-455F-B0DF-E39D4235C24F}.Release|Any CPU.Build.0 = Release|Any CPU + {D6167506-0671-46A3-94E5-7A98032DCEC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D6167506-0671-46A3-94E5-7A98032DCEC6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D6167506-0671-46A3-94E5-7A98032DCEC6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D6167506-0671-46A3-94E5-7A98032DCEC6}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -162,6 +168,7 @@ Global {8215F79E-510B-4CA1-B775-50C47BB58360} = {58760833-B4F5-429D-9ABD-15FDF83E25CD} {F3186815-B9A5-455F-B0DF-E39D4235C24F} = {14DFA192-3C7E-4F10-B5FD-3953BC82A6B1} {14DFA192-3C7E-4F10-B5FD-3953BC82A6B1} = {58760833-B4F5-429D-9ABD-15FDF83E25CD} + {D6167506-0671-46A3-94E5-7A98032DCEC6} = {4DE63935-DCA9-4D63-9C1F-AAE79C89CA8B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {450DA749-CBDC-4BDC-950F-8A491CF59D49} diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/DiagnosticDescriptors.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/DiagnosticDescriptors.cs index 409ab6de3f5..a8f2af18072 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/DiagnosticDescriptors.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/DiagnosticDescriptors.cs @@ -208,5 +208,13 @@ namespace Microsoft.Extensions.Logging.Generators category: "LoggingGenerator", defaultSeverity: DiagnosticSeverity.Error, isEnabledByDefault: true); + + public static DiagnosticDescriptor PrimaryConstructorParameterLoggerHidden { get; } = DiagnosticDescriptorHelper.Create( + id: "SYSLIB1027", + title: new LocalizableResourceString(nameof(SR.PrimaryConstructorParameterLoggerHiddenTitle), SR.ResourceManager, typeof(FxResources.Microsoft.Extensions.Logging.Generators.SR)), + messageFormat: new LocalizableResourceString(nameof(SR.PrimaryConstructorParameterLoggerHiddenMessage), SR.ResourceManager, typeof(FxResources.Microsoft.Extensions.Logging.Generators.SR)), + category: "LoggingGenerator", + DiagnosticSeverity.Info, + isEnabledByDefault: true); } } diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Parser.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Parser.cs index 1604b8689d9..b474c5ea54a 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Parser.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Parser.cs @@ -630,11 +630,23 @@ namespace Microsoft.Extensions.Logging.Generators INamedTypeSymbol? classType = sm.GetDeclaredSymbol(classDec, _cancellationToken); + INamedTypeSymbol? currentClassType = classType; bool onMostDerivedType = true; - while (classType is { SpecialType: not SpecialType.System_Object }) + // We keep track of the names of all non-logger fields, since they prevent referring to logger + // primary constructor parameters with the same name. Example: + // partial class C(ILogger logger) + // { + // private readonly object logger = logger; + // + // [LoggerMessage(EventId = 0, Level = LogLevel.Debug, Message = ""M1"")] + // public partial void M1(); // The ILogger primary constructor parameter cannot be used here. + // } + HashSet shadowedNames = new(StringComparer.Ordinal); + + while (currentClassType is { SpecialType: not SpecialType.System_Object }) { - foreach (IFieldSymbol fs in classType.GetMembers().OfType()) + foreach (IFieldSymbol fs in currentClassType.GetMembers().OfType()) { if (!onMostDerivedType && fs.DeclaredAccessibility == Accessibility.Private) { @@ -651,10 +663,52 @@ namespace Microsoft.Extensions.Logging.Generators return (null, true); } } + else + { + shadowedNames.Add(fs.Name); + } } onMostDerivedType = false; - classType = classType.BaseType; + currentClassType = currentClassType.BaseType; + } + + // We prioritize fields over primary constructor parameters and avoid warnings if both exist. + if (loggerField is not null) + { + return (loggerField, false); + } + + IEnumerable primaryConstructors = classType.InstanceConstructors + .Where(ic => ic.DeclaringSyntaxReferences + .Any(ds => ds.GetSyntax() is ClassDeclarationSyntax)); + + foreach (IMethodSymbol primaryConstructor in primaryConstructors) + { + foreach (IParameterSymbol parameter in primaryConstructor.Parameters) + { + if (IsBaseOrIdentity(parameter.Type, loggerSymbol)) + { + if (shadowedNames.Contains(parameter.Name)) + { + // Accessible fields always shadow primary constructor parameters, + // so we can't use the primary constructor parameter, + // even if the field is not a valid logger. + Diag(DiagnosticDescriptors.PrimaryConstructorParameterLoggerHidden, parameter.Locations[0], classDec.Identifier.Text); + + continue; + } + + if (loggerField == null) + { + loggerField = parameter.Name; + } + else + { + return (null, true); + } + } + } } return (loggerField, false); diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Roslyn4.0.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Roslyn4.0.cs index 7dd80ba2926..74cc8e13fcf 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Roslyn4.0.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Roslyn4.0.cs @@ -45,7 +45,7 @@ namespace Microsoft.Extensions.Logging.Generators return; } - IEnumerable distinctClasses = classes.Distinct(); + ImmutableHashSet distinctClasses = classes.ToImmutableHashSet(); var p = new Parser(compilation, context.ReportDiagnostic, context.CancellationToken); IReadOnlyList logClasses = p.GetLogClasses(distinctClasses); diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/Strings.resx b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/Strings.resx index 602e6f4730d..cca9ce4ef6c 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/Strings.resx +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/Strings.resx @@ -1,17 +1,17 @@ - @@ -237,4 +237,12 @@ The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + + Class '{0}' has a primary constructor parameter of type Microsoft.Extensions.Logging.ILogger that is hidden by a field in the class or a base class, preventing its use + {Locked="Microsoft.Extensions.Logging.ILogger"} + + + Primary constructor parameter of type Microsoft.Extensions.Logging.ILogger is hidden by a field + {Locked="Microsoft.Extensions.Logging.ILogger"} + \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.cs.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.cs.xlf index 6f3218ac6dd..eb8dd19b8c7 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.cs.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.cs.xlf @@ -132,6 +132,16 @@ Našlo se několik polí typu Microsoft.Extensions.Logging.ILogger {Locked="Microsoft.Extensions.Logging.ILogger"} + + Class '{0}' has a primary constructor parameter of type Microsoft.Extensions.Logging.ILogger that is hidden by a field in the class or a base class, preventing its use + Class '{0}' has a primary constructor parameter of type Microsoft.Extensions.Logging.ILogger that is hidden by a field in the class or a base class, preventing its use + {Locked="Microsoft.Extensions.Logging.ILogger"} + + + Primary constructor parameter of type Microsoft.Extensions.Logging.ILogger is hidden by a field + Primary constructor parameter of type Microsoft.Extensions.Logging.ILogger is hidden by a field + {Locked="Microsoft.Extensions.Logging.ILogger"} + Remove redundant qualifier (Info:, Warning:, Error:, etc) from the logging message since it is implicit in the specified log level. Odeberte redundantní kvalifikátor (Informace:, Upozornění:, Chyba: atd.) ze zprávy o protokolování, protože je na zadané úrovni protokolu implicitní. diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.de.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.de.xlf index b838765022a..b508628ac5e 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.de.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.de.xlf @@ -132,6 +132,16 @@ Mehrere Felder vom Typ "Microsoft.Extensions.Logging.ILogger" gefunden {Locked="Microsoft.Extensions.Logging.ILogger"} + + Class '{0}' has a primary constructor parameter of type Microsoft.Extensions.Logging.ILogger that is hidden by a field in the class or a base class, preventing its use + Class '{0}' has a primary constructor parameter of type Microsoft.Extensions.Logging.ILogger that is hidden by a field in the class or a base class, preventing its use + {Locked="Microsoft.Extensions.Logging.ILogger"} + + + Primary constructor parameter of type Microsoft.Extensions.Logging.ILogger is hidden by a field + Primary constructor parameter of type Microsoft.Extensions.Logging.ILogger is hidden by a field + {Locked="Microsoft.Extensions.Logging.ILogger"} + Remove redundant qualifier (Info:, Warning:, Error:, etc) from the logging message since it is implicit in the specified log level. Entfernen Sie den redundanten Qualifizierer (z. B. "Info:", "Warnung:" oder "Fehler:") aus der Protokollierungsmeldung, weil er auf der angegebenen Protokollebene implizit enthalten ist. diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.es.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.es.xlf index 30000484775..fd199f459d9 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.es.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.es.xlf @@ -132,6 +132,16 @@ Se encontraron varios campos de tipo Microsoft.Extensions.Logging.ILogger {Locked="Microsoft.Extensions.Logging.ILogger"} + + Class '{0}' has a primary constructor parameter of type Microsoft.Extensions.Logging.ILogger that is hidden by a field in the class or a base class, preventing its use + Class '{0}' has a primary constructor parameter of type Microsoft.Extensions.Logging.ILogger that is hidden by a field in the class or a base class, preventing its use + {Locked="Microsoft.Extensions.Logging.ILogger"} + + + Primary constructor parameter of type Microsoft.Extensions.Logging.ILogger is hidden by a field + Primary constructor parameter of type Microsoft.Extensions.Logging.ILogger is hidden by a field + {Locked="Microsoft.Extensions.Logging.ILogger"} + Remove redundant qualifier (Info:, Warning:, Error:, etc) from the logging message since it is implicit in the specified log level. Quitar calificadores redundantes (Información:, Advertencia:, Error:, etc.) del mensaje de registro, ya que está implícito en el nivel de registro especificado. diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.fr.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.fr.xlf index 04ccccc8536..ac019c9dabf 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.fr.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.fr.xlf @@ -132,6 +132,16 @@ Plusieurs champs de type Microsoft.Extensions.Logging.ILogger ont été trouvés {Locked="Microsoft.Extensions.Logging.ILogger"} + + Class '{0}' has a primary constructor parameter of type Microsoft.Extensions.Logging.ILogger that is hidden by a field in the class or a base class, preventing its use + Class '{0}' has a primary constructor parameter of type Microsoft.Extensions.Logging.ILogger that is hidden by a field in the class or a base class, preventing its use + {Locked="Microsoft.Extensions.Logging.ILogger"} + + + Primary constructor parameter of type Microsoft.Extensions.Logging.ILogger is hidden by a field + Primary constructor parameter of type Microsoft.Extensions.Logging.ILogger is hidden by a field + {Locked="Microsoft.Extensions.Logging.ILogger"} + Remove redundant qualifier (Info:, Warning:, Error:, etc) from the logging message since it is implicit in the specified log level. Supprimez le qualificateur redondant (Info:, Warning:, Error:, etc.) du message de journalisation, car il est implicite dans le niveau de journalisation spécifié. diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.it.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.it.xlf index 0c007fdce54..dc2f02184e1 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.it.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.it.xlf @@ -132,6 +132,16 @@ Sono stati trovati più campi di tipo Microsoft.Extensions.Logging.ILogger {Locked="Microsoft.Extensions.Logging.ILogger"} + + Class '{0}' has a primary constructor parameter of type Microsoft.Extensions.Logging.ILogger that is hidden by a field in the class or a base class, preventing its use + Class '{0}' has a primary constructor parameter of type Microsoft.Extensions.Logging.ILogger that is hidden by a field in the class or a base class, preventing its use + {Locked="Microsoft.Extensions.Logging.ILogger"} + + + Primary constructor parameter of type Microsoft.Extensions.Logging.ILogger is hidden by a field + Primary constructor parameter of type Microsoft.Extensions.Logging.ILogger is hidden by a field + {Locked="Microsoft.Extensions.Logging.ILogger"} + Remove redundant qualifier (Info:, Warning:, Error:, etc) from the logging message since it is implicit in the specified log level. Rimuovere il qualificatore ridondante (Informazioni:, Avviso:, Errore: e così via) dal messaggio di registrazione perché è implicito nel livello di log specificato. diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ja.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ja.xlf index 36f5b1baad5..3f012705018 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ja.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ja.xlf @@ -132,6 +132,16 @@ Microsoft.Extensions.Logging.ILogger という種類の複数のフィールドが見つかりました {Locked="Microsoft.Extensions.Logging.ILogger"} + + Class '{0}' has a primary constructor parameter of type Microsoft.Extensions.Logging.ILogger that is hidden by a field in the class or a base class, preventing its use + Class '{0}' has a primary constructor parameter of type Microsoft.Extensions.Logging.ILogger that is hidden by a field in the class or a base class, preventing its use + {Locked="Microsoft.Extensions.Logging.ILogger"} + + + Primary constructor parameter of type Microsoft.Extensions.Logging.ILogger is hidden by a field + Primary constructor parameter of type Microsoft.Extensions.Logging.ILogger is hidden by a field + {Locked="Microsoft.Extensions.Logging.ILogger"} + Remove redundant qualifier (Info:, Warning:, Error:, etc) from the logging message since it is implicit in the specified log level. 指定されたログ レベルでは暗黙的であるため、冗長な修飾子 (Info:、Warning:、Error: など) をログ メッセージから削除します。 diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ko.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ko.xlf index 547c49b3e33..5bb9507b859 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ko.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ko.xlf @@ -132,6 +132,16 @@ Microsoft.Extensions.Logging.ILogger 형식의 필드가 여러 개 있음 {Locked="Microsoft.Extensions.Logging.ILogger"} + + Class '{0}' has a primary constructor parameter of type Microsoft.Extensions.Logging.ILogger that is hidden by a field in the class or a base class, preventing its use + Class '{0}' has a primary constructor parameter of type Microsoft.Extensions.Logging.ILogger that is hidden by a field in the class or a base class, preventing its use + {Locked="Microsoft.Extensions.Logging.ILogger"} + + + Primary constructor parameter of type Microsoft.Extensions.Logging.ILogger is hidden by a field + Primary constructor parameter of type Microsoft.Extensions.Logging.ILogger is hidden by a field + {Locked="Microsoft.Extensions.Logging.ILogger"} + Remove redundant qualifier (Info:, Warning:, Error:, etc) from the logging message since it is implicit in the specified log level. 중복 한정자(정보:, 경고:, 오류: 등)가 지정된 로그 수준에서 암시적이기 때문에 로깅 메시지에서 제거합니다. diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.pl.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.pl.xlf index a40b72d24ff..0c014dd5317 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.pl.xlf @@ -132,6 +132,16 @@ Znaleziono wiele pól typu Microsoft.Extensions.Logging.ILogger {Locked="Microsoft.Extensions.Logging.ILogger"} + + Class '{0}' has a primary constructor parameter of type Microsoft.Extensions.Logging.ILogger that is hidden by a field in the class or a base class, preventing its use + Class '{0}' has a primary constructor parameter of type Microsoft.Extensions.Logging.ILogger that is hidden by a field in the class or a base class, preventing its use + {Locked="Microsoft.Extensions.Logging.ILogger"} + + + Primary constructor parameter of type Microsoft.Extensions.Logging.ILogger is hidden by a field + Primary constructor parameter of type Microsoft.Extensions.Logging.ILogger is hidden by a field + {Locked="Microsoft.Extensions.Logging.ILogger"} + Remove redundant qualifier (Info:, Warning:, Error:, etc) from the logging message since it is implicit in the specified log level. Usuń nadmiarowy kwalifikator (Info:, Warning:, Error: itp.) z komunikatu rejestrowania, ponieważ jest on domyślny na określonym poziomie dziennika. diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.pt-BR.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.pt-BR.xlf index 0560fb6b590..6a4a35d1acc 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.pt-BR.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.pt-BR.xlf @@ -132,6 +132,16 @@ Múltiplos campos encontrados do tipo Microsoft.Extensions.Logging.ILogger {Locked="Microsoft.Extensions.Logging.ILogger"} + + Class '{0}' has a primary constructor parameter of type Microsoft.Extensions.Logging.ILogger that is hidden by a field in the class or a base class, preventing its use + Class '{0}' has a primary constructor parameter of type Microsoft.Extensions.Logging.ILogger that is hidden by a field in the class or a base class, preventing its use + {Locked="Microsoft.Extensions.Logging.ILogger"} + + + Primary constructor parameter of type Microsoft.Extensions.Logging.ILogger is hidden by a field + Primary constructor parameter of type Microsoft.Extensions.Logging.ILogger is hidden by a field + {Locked="Microsoft.Extensions.Logging.ILogger"} + Remove redundant qualifier (Info:, Warning:, Error:, etc) from the logging message since it is implicit in the specified log level. Remova o qualificador redundante (Info:, Aviso:, Erro:, etc) da mensagem de log, pois está implícito no nível de log especificado. diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ru.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ru.xlf index 589635d5721..053970d8886 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ru.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ru.xlf @@ -132,6 +132,16 @@ Обнаружено несколько полей типа Microsoft.Extensions.Logging.ILogger {Locked="Microsoft.Extensions.Logging.ILogger"} + + Class '{0}' has a primary constructor parameter of type Microsoft.Extensions.Logging.ILogger that is hidden by a field in the class or a base class, preventing its use + Class '{0}' has a primary constructor parameter of type Microsoft.Extensions.Logging.ILogger that is hidden by a field in the class or a base class, preventing its use + {Locked="Microsoft.Extensions.Logging.ILogger"} + + + Primary constructor parameter of type Microsoft.Extensions.Logging.ILogger is hidden by a field + Primary constructor parameter of type Microsoft.Extensions.Logging.ILogger is hidden by a field + {Locked="Microsoft.Extensions.Logging.ILogger"} + Remove redundant qualifier (Info:, Warning:, Error:, etc) from the logging message since it is implicit in the specified log level. Удалите избыточный квалификатор (Info:, Warning:, Error:, и т. п.) из сообщения журнала, поскольку квалификатор подразумевается на указанном уровне ведения журнала. diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.tr.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.tr.xlf index c40d99aa460..03f094a1607 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.tr.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.tr.xlf @@ -132,6 +132,16 @@ Microsoft.Extensions.Logging.ILogger türünde birden çok alan bulundu {Locked="Microsoft.Extensions.Logging.ILogger"} + + Class '{0}' has a primary constructor parameter of type Microsoft.Extensions.Logging.ILogger that is hidden by a field in the class or a base class, preventing its use + Class '{0}' has a primary constructor parameter of type Microsoft.Extensions.Logging.ILogger that is hidden by a field in the class or a base class, preventing its use + {Locked="Microsoft.Extensions.Logging.ILogger"} + + + Primary constructor parameter of type Microsoft.Extensions.Logging.ILogger is hidden by a field + Primary constructor parameter of type Microsoft.Extensions.Logging.ILogger is hidden by a field + {Locked="Microsoft.Extensions.Logging.ILogger"} + Remove redundant qualifier (Info:, Warning:, Error:, etc) from the logging message since it is implicit in the specified log level. Belirtilen günlük düzeyinde örtük olduğundan gereksiz niteleyiciyi (Bilgi:, Uyarı:, Hata: vb.) günlüğe kaydetme iletisinden kaldırın. diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.zh-Hans.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.zh-Hans.xlf index 04c39c8843a..2217d0a4cc9 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.zh-Hans.xlf @@ -132,6 +132,16 @@ 找到 Microsoft.Extensions.Logging.ILogger 类型的多个字段 {Locked="Microsoft.Extensions.Logging.ILogger"} + + Class '{0}' has a primary constructor parameter of type Microsoft.Extensions.Logging.ILogger that is hidden by a field in the class or a base class, preventing its use + Class '{0}' has a primary constructor parameter of type Microsoft.Extensions.Logging.ILogger that is hidden by a field in the class or a base class, preventing its use + {Locked="Microsoft.Extensions.Logging.ILogger"} + + + Primary constructor parameter of type Microsoft.Extensions.Logging.ILogger is hidden by a field + Primary constructor parameter of type Microsoft.Extensions.Logging.ILogger is hidden by a field + {Locked="Microsoft.Extensions.Logging.ILogger"} + Remove redundant qualifier (Info:, Warning:, Error:, etc) from the logging message since it is implicit in the specified log level. 从日志记录消息中删除冗余限定符(信息:、警告:、错误: 等),因为其在指定的日志级别中为隐式内容。 diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.zh-Hant.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.zh-Hant.xlf index af008cf098f..6044c601d92 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.zh-Hant.xlf @@ -132,6 +132,16 @@ 找到多個 Microsoft.Extensions.Logging.ILogger 類型的欄位 {Locked="Microsoft.Extensions.Logging.ILogger"} + + Class '{0}' has a primary constructor parameter of type Microsoft.Extensions.Logging.ILogger that is hidden by a field in the class or a base class, preventing its use + Class '{0}' has a primary constructor parameter of type Microsoft.Extensions.Logging.ILogger that is hidden by a field in the class or a base class, preventing its use + {Locked="Microsoft.Extensions.Logging.ILogger"} + + + Primary constructor parameter of type Microsoft.Extensions.Logging.ILogger is hidden by a field + Primary constructor parameter of type Microsoft.Extensions.Logging.ILogger is hidden by a field + {Locked="Microsoft.Extensions.Logging.ILogger"} + Remove redundant qualifier (Info:, Warning:, Error:, etc) from the logging message since it is implicit in the specified log level. 從記錄訊息中移除備援限定詞 (資訊:、警告:、錯誤: 等等),因為它在指定的記錄層級中為隱含。 diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/Baselines/TestWithLoggerFromPrimaryConstructor.generated.txt b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/Baselines/TestWithLoggerFromPrimaryConstructor.generated.txt new file mode 100644 index 00000000000..ba6b0d865e6 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/Baselines/TestWithLoggerFromPrimaryConstructor.generated.txt @@ -0,0 +1,21 @@ +// +#nullable enable + +namespace Microsoft.Extensions.Logging.Generators.Tests.TestClasses +{ + partial class TestWithLoggerFromPrimaryConstructor + { + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "%VERSION%")] + private static readonly global::System.Action __M0Callback = + global::Microsoft.Extensions.Logging.LoggerMessage.Define(global::Microsoft.Extensions.Logging.LogLevel.Debug, new global::Microsoft.Extensions.Logging.EventId(0, nameof(M0)), "M0", new global::Microsoft.Extensions.Logging.LogDefineOptions() { SkipEnabledCheck = true }); + + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "%VERSION%")] + public partial void M0() + { + if (logger.IsEnabled(global::Microsoft.Extensions.Logging.LogLevel.Debug)) + { + __M0Callback(logger, null); + } + } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/Baselines/TestWithLoggerInFieldAndFromPrimaryConstructor.generated.txt b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/Baselines/TestWithLoggerInFieldAndFromPrimaryConstructor.generated.txt new file mode 100644 index 00000000000..acfd43a0d28 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/Baselines/TestWithLoggerInFieldAndFromPrimaryConstructor.generated.txt @@ -0,0 +1,21 @@ +// +#nullable enable + +namespace Microsoft.Extensions.Logging.Generators.Tests.TestClasses +{ + partial class TestWithLoggerFromPrimaryConstructor + { + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "%VERSION%")] + private static readonly global::System.Action __M0Callback = + global::Microsoft.Extensions.Logging.LoggerMessage.Define(global::Microsoft.Extensions.Logging.LogLevel.Debug, new global::Microsoft.Extensions.Logging.EventId(0, nameof(M0)), "M0", new global::Microsoft.Extensions.Logging.LogDefineOptions() { SkipEnabledCheck = true }); + + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "%VERSION%")] + public partial void M0() + { + if (_logger.IsEnabled(global::Microsoft.Extensions.Logging.LogLevel.Debug)) + { + __M0Callback(_logger, null); + } + } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratedCodeTests.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratedCodeTests.cs index 7688e26ad00..1013af8ae36 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratedCodeTests.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratedCodeTests.cs @@ -26,7 +26,7 @@ namespace Microsoft.Extensions.Logging.Generators.Tests } [Fact] - public void FindsLoggerFieldInAnotherParialClass() + public void FindsLoggerFieldInAnotherPartialClass() { var logger = new MockLogger(); @@ -36,6 +36,41 @@ namespace Microsoft.Extensions.Logging.Generators.Tests Assert.Equal("Test.", logger.LastFormattedString); } +#if ROSLYN4_8_OR_GREATER + [Fact] + public void FindsLoggerInPrimaryConstructorParameter() + { + var logger = new MockLogger(); + + logger.Reset(); + + new ClassWithPrimaryConstructor(logger).Test(); + Assert.Equal("Test.", logger.LastFormattedString); + } + + [Fact] + public void FindsLoggerInPrimaryConstructorParameterInDifferentPartialDeclaration() + { + var logger = new MockLogger(); + + logger.Reset(); + + new ClassWithPrimaryConstructorInDifferentPartialDeclaration(logger).Test(); + Assert.Equal("Test.", logger.LastFormattedString); + } + + [Fact] + public void FindsLoggerInFieldInitializedFromPrimaryConstructorParameter() + { + var logger = new MockLogger(); + + logger.Reset(); + + new ClassWithPrimaryConstructor(logger).Test(); + Assert.Equal("Test.", logger.LastFormattedString); + } +#endif + [Fact] public void BasicTests() { diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorEmitterTests.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorEmitterTests.cs index 30cf036fdd8..0952f66a8ad 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorEmitterTests.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorEmitterTests.cs @@ -187,6 +187,40 @@ namespace Microsoft.Extensions.Logging.Generators.Tests.TestClasses await VerifyAgainstBaselineUsingFile("TestWithNestedClassWithGenericTypesWithAttributes.generated.txt", testSourceCode); } +#if ROSLYN4_8_OR_GREATER + [Fact] + public async Task TestBaseline_TestWithLoggerFromPrimaryConstructor_Success() + { + string testSourceCode = @" +namespace Microsoft.Extensions.Logging.Generators.Tests.TestClasses +{ + internal partial class TestWithLoggerFromPrimaryConstructor(ILogger logger) + { + [LoggerMessage(EventId = 0, Level = LogLevel.Debug, Message = ""M0"")] + public partial void M0(); + } +}"; + await VerifyAgainstBaselineUsingFile("TestWithLoggerFromPrimaryConstructor.generated.txt", testSourceCode); + } + + [Fact] + public async Task TestBaseline_TestWithLoggerInFieldAndFromPrimaryConstructor_UsesField() + { + string testSourceCode = @" +namespace Microsoft.Extensions.Logging.Generators.Tests.TestClasses +{ + internal partial class TestWithLoggerFromPrimaryConstructor(ILogger logger) + { + private readonly ILogger _logger = logger; + + [LoggerMessage(EventId = 0, Level = LogLevel.Debug, Message = ""M0"")] + public partial void M0(); + } +}"; + await VerifyAgainstBaselineUsingFile("TestWithLoggerInFieldAndFromPrimaryConstructor.generated.txt", testSourceCode); + } +#endif + [Fact] public void GenericTypeParameterAttributesAreRetained() { diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs index d0d5fc30af5..15a4f965074 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs @@ -417,6 +417,142 @@ namespace Microsoft.Extensions.Logging.Generators.Tests } #endif + [Fact] + public async Task FieldOnOtherPartialDeclarationOK() + { + IReadOnlyList diagnostics = await RunGenerator(@" + partial class C + { + private ILogger _logger; + + public C(ILogger logger) + { + _logger = logger; + } + } + + partial class C + { + [LoggerMessage(EventId = 0, Level = LogLevel.Debug, Message = ""M1"")] + public partial void M1(); + } + "); + + Assert.Empty(diagnostics); + } + +#if ROSLYN4_8_OR_GREATER + [Fact] + public async Task PrimaryConstructorOK() + { + IReadOnlyList diagnostics = await RunGenerator(@" + partial class C(ILogger logger) + { + [LoggerMessage(EventId = 0, Level = LogLevel.Debug, Message = ""M1"")] + public partial void M1(); + } + "); + + Assert.Empty(diagnostics); + } + + [Fact] + public async Task PrimaryConstructorOnOtherPartialDeclarationOK() + { + IReadOnlyList diagnostics = await RunGenerator(@" + partial class C(ILogger logger); + + partial class C + { + [LoggerMessage(EventId = 0, Level = LogLevel.Debug, Message = ""M1"")] + public partial void M1(); + } + "); + + Assert.Empty(diagnostics); + } + + [Fact] + public async Task PrimaryConstructorWithDifferentNameLoggerFieldOK() + { + IReadOnlyList diagnostics = await RunGenerator(@" + partial class C(ILogger logger) + { + private readonly ILogger _logger = logger; + + [LoggerMessage(EventId = 0, Level = LogLevel.Debug, Message = ""M1"")] + public partial void M1(); + } + "); + + Assert.Empty(diagnostics); + } + + [Fact] + public async Task PrimaryConstructorWithSameNameLoggerFieldOK() + { + IReadOnlyList diagnostics = await RunGenerator(@" + partial class C(ILogger logger) + { + private readonly ILogger logger = logger; + + [LoggerMessage(EventId = 0, Level = LogLevel.Debug, Message = ""M1"")] + public partial void M1(); + } + "); + + Assert.Empty(diagnostics); + } + + [Fact] + public async Task PrimaryConstructorLoggerShadowedByField() + { + IReadOnlyList diagnostics = await RunGenerator(@" + partial class C(ILogger logger) + { + private readonly object logger = logger; + + [LoggerMessage(EventId = 0, Level = LogLevel.Debug, Message = ""M1"")] + public partial void M1(); + } + "); + + Assert.Equal(2, diagnostics.Count); + + Assert.Equal(DiagnosticDescriptors.PrimaryConstructorParameterLoggerHidden.Id, diagnostics[0].Id); + var lineSpan = diagnostics[0].Location.GetLineSpan(); + Assert.Equal(4, lineSpan.StartLinePosition.Line); + Assert.Equal(40, lineSpan.StartLinePosition.Character); + + Assert.Equal(DiagnosticDescriptors.MissingLoggerField.Id, diagnostics[1].Id); + } + + [Fact] + public async Task PrimaryConstructorLoggerShadowedByBaseClass() + { + IReadOnlyList diagnostics = await RunGenerator(@" + class Base(object logger) { + protected readonly object logger = logger; + } + + partial class Derived(ILogger logger) : Base(logger) + { + [LoggerMessage(EventId = 0, Level = LogLevel.Debug, Message = ""M1"")] + public partial void M1(); + } + "); + + Assert.Equal(2, diagnostics.Count); + + Assert.Equal(DiagnosticDescriptors.PrimaryConstructorParameterLoggerHidden.Id, diagnostics[0].Id); + var lineSpan = diagnostics[0].Location.GetLineSpan(); + Assert.Equal(8, lineSpan.StartLinePosition.Line); + Assert.Equal(46, lineSpan.StartLinePosition.Character); + + Assert.Equal(DiagnosticDescriptors.MissingLoggerField.Id, diagnostics[1].Id); + } +#endif + [Theory] [InlineData("false")] [InlineData("true")] diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/Microsoft.Extensions.Logging.Generators.Roslyn4.8.Tests.csproj b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/Microsoft.Extensions.Logging.Generators.Roslyn4.8.Tests.csproj new file mode 100644 index 00000000000..e480e542b15 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/Microsoft.Extensions.Logging.Generators.Roslyn4.8.Tests.csproj @@ -0,0 +1,22 @@ + + + + $(MicrosoftCodeAnalysisVersion_4_8) + $(DefineConstants);ROSLYN4_0_OR_GREATER;ROSLYN4_8_OR_GREATER + true + -O1 + + false + + + + + + + + + + + + + diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/TestClasses/MiscTestExtensions.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/TestClasses/MiscTestExtensions.cs index 05984d67570..5f4fec36ac7 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/TestClasses/MiscTestExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/TestClasses/MiscTestExtensions.cs @@ -57,6 +57,30 @@ public partial class PartialClassWithLoggerField public partial void Test(); } +#if ROSLYN4_8_OR_GREATER +public partial class ClassWithPrimaryConstructor(ILogger logger) +{ + [LoggerMessage(0, LogLevel.Debug, "Test.")] + public partial void Test(); +} + +public partial class ClassWithPrimaryConstructorInDifferentPartialDeclaration(ILogger logger); + +public partial class ClassWithPrimaryConstructorInDifferentPartialDeclaration +{ + [LoggerMessage(0, LogLevel.Debug, "Test.")] + public partial void Test(); +} + +public partial class ClassWithPrimaryConstructorAndField(ILogger logger) +{ + private readonly ILogger _logger = logger; + + [LoggerMessage(0, LogLevel.Debug, "Test.")] + public partial void Test(); +} +#endif + // Used to test use outside of a namespace internal static partial class NoNamespace {