1
1
using System . Collections . Immutable ;
2
2
using System . Text ;
3
3
using Microsoft . CodeAnalysis ;
4
+ using Microsoft . CodeAnalysis . CSharp ;
4
5
using Microsoft . CodeAnalysis . CSharp . Syntax ;
5
6
using Microsoft . CodeAnalysis . Text ;
6
7
7
8
namespace Monologue . SourceGenerator ;
8
9
9
- internal record LogData ( string ? PreComputed , string ? GetOperation , string ? Path , string ? Type ) ;
10
+ internal enum DeclarationType
11
+ {
12
+ Logged ,
13
+ Struct ,
14
+ Protobuf ,
15
+ Other
16
+ }
17
+
18
+
19
+ internal record LogAttributeInfo ( string Path , string LogLevel , string LogType , bool UseProtobuf ) ;
20
+
21
+ internal record LogData ( string GetOperation , string ? Type , DeclarationType DecelType , LogAttributeInfo AttributeInfo ) ;
10
22
11
23
internal record ClassData ( ImmutableArray < LogData > LoggedItems , string Name , string ClassDeclaration , string ? Namespace ) ;
12
24
@@ -48,20 +60,49 @@ public class LogGenerator : IIncrementalGenerator
48
60
if ( attributeClass . ToDisplayString ( ) == "Monologue.LogAttribute" )
49
61
{
50
62
token . ThrowIfCancellationRequested ( ) ;
63
+
64
+ string path = member . Name ;
65
+ bool useProtobuf = false ;
66
+ string logTypeEnum = "Monologue.LogType.Nt | Monologue.LogType.File" ;
67
+ string logLevel = "Monologue.LogLevel.Default" ;
68
+
69
+ // Get the log attribute
70
+ foreach ( var named in attribute . NamedArguments )
71
+ {
72
+ if ( named . Key == "Key" )
73
+ {
74
+ if ( ! named . Value . IsNull )
75
+ {
76
+ path = SymbolDisplay . FormatPrimitive ( named . Value . Value ! , false , false ) ;
77
+ }
78
+ }
79
+ else if ( named . Key == "LogLevel" )
80
+ {
81
+ logLevel = named . Value . ToCSharpString ( ) ;
82
+ }
83
+ else if ( named . Key == "LogType" )
84
+ {
85
+ logTypeEnum = named . Value . ToCSharpString ( ) ;
86
+ }
87
+ else if ( named . Key == "UseProtobuf" )
88
+ {
89
+ useProtobuf = ( bool ) named . Value . Value ! ;
90
+ }
91
+ }
92
+
93
+ var attributeInfo = new LogAttributeInfo ( path , logLevel , logTypeEnum , useProtobuf ) ;
94
+
51
95
string getOperation ;
52
- string defaultPathName ;
53
96
ITypeSymbol logType ;
54
97
// This is ours
55
98
if ( member is IFieldSymbol field )
56
99
{
57
100
getOperation = field . Name ;
58
- defaultPathName = field . Name ;
59
101
logType = field . Type ;
60
102
}
61
103
else if ( member is IPropertySymbol property )
62
104
{
63
105
getOperation = property . Name ;
64
- defaultPathName = property . Name ;
65
106
logType = property . Type ;
66
107
}
67
108
else if ( member is IMethodSymbol method )
@@ -76,15 +117,14 @@ public class LogGenerator : IIncrementalGenerator
76
117
}
77
118
78
119
getOperation = $ "{ method . Name } ()";
79
- defaultPathName = method . Name ;
80
120
logType = method . ReturnType ;
81
121
}
82
122
else
83
123
{
84
124
throw new InvalidOperationException ( "Field is not loggable" ) ;
85
125
}
86
126
87
- var fullOperation = ComputeOperation ( logType , getOperation , defaultPathName ) ;
127
+ var fullOperation = ComputeOperation ( logType , getOperation , attributeInfo ) ;
88
128
token . ThrowIfCancellationRequested ( ) ;
89
129
loggableMembers . Add ( fullOperation ) ;
90
130
break ;
@@ -98,36 +138,41 @@ public class LogGenerator : IIncrementalGenerator
98
138
return new ClassData ( loggableMembers . ToImmutable ( ) , $ "{ classSymbol . ContainingNamespace } { classSymbol . ToDisplayString ( fmt ) } { classSymbol . MetadataName } ", typeBuilder . ToString ( ) , ns ) ;
99
139
}
100
140
101
- private static LogData ComputeOperation ( ITypeSymbol logType , string getOp , string path )
141
+ private static LogData ComputeOperation ( ITypeSymbol logType , string getOp , LogAttributeInfo attributeInfo )
102
142
{
103
143
if ( logType . GetAttributes ( ) . Where ( x => x . AttributeClass ? . ToDisplayString ( ) == "Monologue.GenerateLogAttribute" ) . Any ( ) )
104
144
{
105
- return new ( $ " { getOp } .UpdateMonologue($ \" {{path}}/ { path } \" , logger);" , null , null , null ) ;
145
+ return new LogData ( getOp , null , DeclarationType . Logged , attributeInfo ) ;
106
146
}
107
147
if ( logType . AllInterfaces . Where ( x => x . ToDisplayString ( ) == "Monologue.ILogged" ) . Any ( ) )
108
148
{
109
- return new ( $ "{ getOp } .UpdateMonologue($\" {{path}}/{ path } \" , logger);", null , null , null ) ;
110
- //return $"{getOp}.UpdateMonologue($\"{{path}}/{path}\", logger);";
149
+ return new LogData ( getOp , null , DeclarationType . Logged , attributeInfo ) ;
111
150
}
112
151
var fmt = new SymbolDisplayFormat ( typeQualificationStyle : SymbolDisplayTypeQualificationStyle . NameAndContainingTypesAndNamespaces , genericsOptions : SymbolDisplayGenericsOptions . IncludeTypeParameters ) ;
113
- var fullName = logType . ToDisplayString ( fmt ) ;
114
- var structName = $ "WPIUtil.Serialization.Struct.IStructSerializable<{ fullName } >";
115
- var protobufName = $ "WPIUtil.Serialization.Protobuf.IProtobufSerializable<{ fullName } >";
152
+ var fullTypeName = logType . ToDisplayString ( fmt ) ;
153
+ var structName = $ "WPIUtil.Serialization.Struct.IStructSerializable<{ fullTypeName } >";
154
+ var protobufName = $ "WPIUtil.Serialization.Protobuf.IProtobufSerializable<{ fullTypeName } >";
155
+
116
156
foreach ( var inf in logType . AllInterfaces )
117
157
{
118
158
var interfaceName = inf . ToDisplayString ( ) ;
119
- // For now prefer struct
120
159
if ( interfaceName == structName )
121
160
{
122
- return new ( $ "logger.LogStruct($\" {{path}}/{ path } \" , LogType.Nt, { getOp } );", null , null , null ) ;
161
+ if ( ! attributeInfo . UseProtobuf )
162
+ {
163
+ return new LogData ( getOp , null , DeclarationType . Struct , attributeInfo ) ;
164
+ }
123
165
}
124
166
else if ( interfaceName == protobufName )
125
167
{
126
- return new ( $ "logger.LogProto($\" {{path}}/{ path } \" , LogType.Nt, { getOp } );", null , null , null ) ;
168
+ if ( attributeInfo . UseProtobuf )
169
+ {
170
+ return new LogData ( getOp , null , DeclarationType . Protobuf , attributeInfo ) ;
171
+ }
127
172
}
128
173
}
129
174
130
- return new ( null , getOp , path , fullName ) ;
175
+ return new LogData ( getOp , fullTypeName , DeclarationType . Other , attributeInfo ) ;
131
176
}
132
177
133
178
public void Initialize ( IncrementalGeneratorInitializationContext context )
@@ -145,14 +190,22 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
145
190
146
191
static void ConstructCall ( LogData data , StringBuilder builder )
147
192
{
148
- if ( data . PreComputed is not null )
149
- {
193
+ builder . Append ( " " ) ;
150
194
151
- builder . AppendLine ( $ " { data . PreComputed } ") ;
152
- return ;
195
+ switch ( data . DecelType )
196
+ {
197
+ case DeclarationType . Logged :
198
+ builder . AppendLine ( $ "{ data . GetOperation } ?.UpdateMonologue($\" {{path}}/{ data . AttributeInfo . Path } \" , logger);") ;
199
+ return ;
200
+ case DeclarationType . Struct :
201
+ builder . AppendLine ( $ "logger.LogStruct($\" {{path}}/{ data . AttributeInfo . Path } \" , { data . AttributeInfo . LogType } , { data . GetOperation } );") ;
202
+ return ;
203
+ case DeclarationType . Protobuf :
204
+ builder . AppendLine ( $ "logger.LogProto($\" {{path}}/{ data . AttributeInfo . Path } \" , { data . AttributeInfo . LogType } , { data . GetOperation } );") ;
205
+ return ;
153
206
}
154
207
155
- var ret = data . Type switch
208
+ ( string ? LogMethod , string Cast , string Conversion ) ret = data . Type switch
156
209
{
157
210
"System.Single" => ( "LogFloat" , "" , "" ) ,
158
211
"System.Double" => ( "LogDouble" , "" , "" ) ,
@@ -189,7 +242,7 @@ static void ConstructCall(LogData data, StringBuilder builder)
189
242
_ => ( data . Type , "" , "" )
190
243
} ;
191
244
192
- builder . AppendLine ( $ " logger.{ ret . Item1 } ($\" {{path}}/{ data . Path } \" , LogType.Nt , { ret . Item2 } { data . GetOperation } { ret . Item3 } );") ;
245
+ builder . AppendLine ( $ "logger.{ ret . LogMethod } ($\" {{path}}/{ data . AttributeInfo . Path } \" , { data . AttributeInfo . LogType } , { ret . Cast } { data . GetOperation } { ret . Conversion } );") ;
193
246
}
194
247
195
248
static void Execute ( ClassData ? classData , SourceProductionContext context )
0 commit comments