Skip to content

Commit 4ab2acc

Browse files
authored
Support partial methods (#4)
1 parent b72ec2d commit 4ab2acc

2 files changed

Lines changed: 54 additions & 27 deletions

File tree

src/libraries/Microsoft.Extensions.Logging/gen/LoggingGenerator.Parser.cs

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public Parser(GeneratorExecutionContext context)
110110
/// <summary>
111111
/// Gets the set of logging classes that should be generated based on the discovered annotated interfaces.
112112
/// </summary>
113-
public IEnumerable<LoggerClass> GetLogClasses(List<InterfaceDeclarationSyntax> interfaces)
113+
public IEnumerable<LoggerClass> GetLogClasses(List<TypeDeclarationSyntax> types)
114114
{
115115
var logExtensionsAttribute = _compilation.GetTypeByMetadataName("Microsoft.Extensions.Logging.LoggerExtensionsAttribute");
116116
if (logExtensionsAttribute is null)
@@ -140,9 +140,9 @@ public IEnumerable<LoggerClass> GetLogClasses(List<InterfaceDeclarationSyntax> i
140140
yield break;
141141
}
142142

143-
foreach (var iface in interfaces)
143+
foreach (var typeDef in types)
144144
{
145-
foreach (var al in iface.AttributeLists)
145+
foreach (var al in typeDef.AttributeLists)
146146
{
147147
foreach (var a in al.Attributes)
148148
{
@@ -153,13 +153,13 @@ public IEnumerable<LoggerClass> GetLogClasses(List<InterfaceDeclarationSyntax> i
153153
{
154154
// determine the namespace the interface is declared in, if any
155155
NamespaceDeclarationSyntax? ns = null;
156-
if (iface.Parent != null)
156+
if (typeDef.Parent != null)
157157
{
158-
ns = iface.Parent as NamespaceDeclarationSyntax;
159-
if (ns == null && iface.Parent is not CompilationUnitSyntax)
158+
ns = typeDef.Parent as NamespaceDeclarationSyntax;
159+
if (ns == null && typeDef.Parent is not CompilationUnitSyntax)
160160
{
161161
// since this generator doesn't know how to generate a nested type...
162-
Diag(ErrorNestedType, iface.Identifier.GetLocation());
162+
Diag(ErrorNestedType, typeDef.Identifier.GetLocation());
163163
}
164164
}
165165

@@ -173,42 +173,48 @@ public IEnumerable<LoggerClass> GetLogClasses(List<InterfaceDeclarationSyntax> i
173173
}
174174

175175
// if no name was specified, try to derive it from the interface name
176-
var ifaceName = iface.Identifier.ToString();
176+
var ifaceName = typeDef.Identifier.ToString();
177177
if (name == null)
178178
{
179-
if (ifaceName[0] == 'I')
179+
if (typeDef is InterfaceDeclarationSyntax iface)
180180
{
181-
// strip the leading I
182-
name = ifaceName.Substring(1);
181+
if (ifaceName[0] == 'I' && ifaceName.Length > 1)
182+
{
183+
name = ifaceName.Substring(1);
184+
}
185+
else
186+
{
187+
name = ifaceName + "Extensions";
188+
}
183189
}
184190
else
185191
{
186-
// fail
187-
name = string.Empty;
192+
name = typeDef.Identifier.ToString();
188193
}
189194
}
190195

191196
var lc = new LoggerClass
192197
{
193198
Namespace = ns?.Name.ToString(),
194199
Name = name,
195-
OriginalInterfaceName = iface.Identifier.ToString(),
196-
AccessModifiers = iface.Modifiers.ToString(),
197-
Documentation = GetDocs(iface),
200+
OriginalInterfaceName = typeDef.Identifier.ToString(),
201+
AccessModifiers = typeDef.Modifiers.ToString(),
202+
Documentation = GetDocs(typeDef),
203+
IsInterface = typeDef is InterfaceDeclarationSyntax
198204
};
199205

200206
if (string.IsNullOrWhiteSpace(lc.Name))
201207
{
202208
Diag(ErrorInvalidTypeName, a.GetLocation(), ifaceName);
203209
}
204210

205-
if (iface.Arity > 0)
211+
if (typeDef.Arity > 0)
206212
{
207-
Diag(ErrorInterfaceGeneric, iface.GetLocation());
213+
Diag(ErrorInterfaceGeneric, typeDef.GetLocation());
208214
}
209215

210216
var ids = new HashSet<string>();
211-
foreach (var method in iface.Members.Where(m => m.IsKind(SyntaxKind.MethodDeclaration)).OfType<MethodDeclarationSyntax>())
217+
foreach (var method in typeDef.Members.Where(m => m.IsKind(SyntaxKind.MethodDeclaration)).OfType<MethodDeclarationSyntax>())
212218
{
213219
foreach (var mal in method.AttributeLists)
214220
{
@@ -289,6 +295,12 @@ public IEnumerable<LoggerClass> GetLogClasses(List<InterfaceDeclarationSyntax> i
289295
Type = p.Type!.ToString(),
290296
IsExceptionType = IsBaseOrIdentity(pSymbol, exSymbol),
291297
};
298+
299+
if (lp.Type.EndsWith("ILogger", StringComparison.Ordinal))
300+
{
301+
continue;
302+
}
303+
292304
lm.Parameters.Add(lp);
293305

294306
if (lp.Name.StartsWith("__", StringComparison.Ordinal))
@@ -394,6 +406,7 @@ private class LoggerClass
394406
public string AccessModifiers = string.Empty;
395407
public List<LoggerMethod> Methods = new();
396408
public string Documentation = string.Empty;
409+
public bool IsInterface { get; set; }
397410
}
398411

399412
// A log method in a logging class

src/libraries/Microsoft.Extensions.Logging/gen/LoggingGenerator.cs

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ namespace Microsoft.Extensions.Logging.Generators
66
using System.Collections.Generic;
77
using System.Text;
88
using Microsoft.CodeAnalysis;
9+
using Microsoft.CodeAnalysis.CSharp;
910
using Microsoft.CodeAnalysis.CSharp.Syntax;
1011
using Microsoft.CodeAnalysis.Text;
1112

@@ -30,7 +31,7 @@ public void Execute(GeneratorExecutionContext context)
3031
var p = new Parser(context);
3132

3233
var types = new StringBuilder();
33-
foreach (var lc in p.GetLogClasses(receiver.InterfaceDeclarations))
34+
foreach (var lc in p.GetLogClasses(receiver.TypeDeclarations))
3435
{
3536
types.Append(GenType(lc));
3637
}
@@ -53,7 +54,7 @@ private static string GenType(LoggerClass lc)
5354
{
5455
methods.Append(GenStruct(lm));
5556
methods.Append(GenEventId(lm));
56-
methods.Append(GenExtensionLogMethod(lm));
57+
methods.Append(GenExtensionLogMethod(lc, lm));
5758
}
5859

5960
var namespaceStart = string.Empty;
@@ -68,10 +69,9 @@ private static string GenType(LoggerClass lc)
6869
return $@"
6970
{namespaceStart}
7071
{lc.Documentation}
71-
{lc.AccessModifiers} static class {lc.Name}
72+
{lc.AccessModifiers} {(lc.IsInterface ? "static" : "")} class {lc.Name}
7273
{{
7374
{methods}
74-
public static {lc.OriginalInterfaceName} Wrap(this ILogger logger) => new __Wrapper__(logger);
7575
{GenWrapper(lc)}
7676
}}
7777
{namespaceEnd}
@@ -80,13 +80,19 @@ private static string GenType(LoggerClass lc)
8080

8181
private static string GenWrapper(LoggerClass lc)
8282
{
83+
if (!lc.IsInterface)
84+
{
85+
return "";
86+
}
8387
var methods = new StringBuilder();
8488
foreach (var lm in lc.Methods)
8589
{
8690
methods.Append(GenInstanceLogMethod(lm));
8791
}
8892

8993
return $@"
94+
public static {lc.OriginalInterfaceName} Wrap(this ILogger logger) => new __Wrapper__(logger);
95+
9096
private sealed class __Wrapper__ : {lc.OriginalInterfaceName}
9197
{{
9298
private readonly ILogger __logger;
@@ -162,7 +168,7 @@ private static string GenInstanceLogMethod(LoggerMethod lm)
162168
";
163169
}
164170

165-
private static string GenExtensionLogMethod(LoggerMethod lm)
171+
private static string GenExtensionLogMethod(LoggerClass lc, LoggerMethod lm)
166172
{
167173
string exceptionArg = "null";
168174
foreach (var p in lm.Parameters)
@@ -174,9 +180,11 @@ private static string GenExtensionLogMethod(LoggerMethod lm)
174180
}
175181
}
176182

183+
var loggerArg = lc.IsInterface ? "this ILogger logger" : "ILogger logger";
184+
177185
return $@"
178186
{lm.Documentation}
179-
public static void {lm.Name}(this ILogger logger{(lm.Parameters.Count > 0 ? ", " : string.Empty)}{GenParameters(lm)})
187+
public static {(lc.IsInterface ? "" : "partial")} void {lm.Name}({loggerArg}{(lm.Parameters.Count > 0 ? ", " : string.Empty)}{GenParameters(lm)})
180188
{{
181189
if (logger.IsEnabled((LogLevel){lm.Level}))
182190
{{
@@ -299,13 +307,19 @@ private static string GenCases(LoggerMethod lm)
299307

300308
private sealed class SyntaxReceiver : ISyntaxReceiver
301309
{
302-
public List<InterfaceDeclarationSyntax> InterfaceDeclarations { get; } = new();
310+
public List<TypeDeclarationSyntax> TypeDeclarations { get; } = new();
303311

304312
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
305313
{
306314
if (syntaxNode is InterfaceDeclarationSyntax interfaceSyntax && interfaceSyntax.AttributeLists.Count > 0)
307315
{
308-
InterfaceDeclarations.Add(interfaceSyntax);
316+
TypeDeclarations.Add(interfaceSyntax);
317+
}
318+
319+
// Any partial class
320+
if (syntaxNode is ClassDeclarationSyntax { Modifiers: { Count: > 0 } modifiers } classSyntax && modifiers.Any(SyntaxKind.StaticKeyword) && modifiers.Any(SyntaxKind.PartialKeyword))
321+
{
322+
TypeDeclarations.Add(classSyntax);
309323
}
310324
}
311325
}

0 commit comments

Comments
 (0)