public AutoInterfaceTemplateAttribute(AutoInterfaceTargets targets) { this.Targets = targets; }
public PartialTemplate(AutoInterfaceTargets memberTargets, Regex?memberFilter, TemplateDefinition template) { this.MemberTargets = memberTargets; this.MemberFilter = memberFilter; this.Template = template; }
private static List <AutoInterfaceRecord> CollectRecords(GeneratorExecutionContext context, ISymbol symbol, ITypeSymbol receiverType, INamedTypeSymbol autoInterfaceAttributeSymbol, INamedTypeSymbol autoInterfaceTemplateAttributeSymbol) { List <PartialTemplate> templateParts = new(); Dictionary <ISymbol, HashSet <INamedTypeSymbol> > danglingInterfaceTypesBySymbols = new(SymbolEqualityComparer.Default); foreach (AttributeData attribute in symbol.GetAttributes()) { if (attribute.AttributeClass != null && attribute.AttributeClass.Equals(autoInterfaceTemplateAttributeSymbol, SymbolEqualityComparer.Default)) { ITypeSymbol?type = receiverType.WithNullableAnnotation(NullableAnnotation.NotAnnotated); AutoInterfaceTargets memberTargets = (AutoInterfaceTargets)Convert.ToInt32(attribute.ConstructorArguments[0].Value); if (type.TypeKind == TypeKind.Interface) { if (type is INamedTypeSymbol interfaceType) { if (receiverType.IsMatchByTypeOrImplementsInterface(type)) { string?templateBody = null; string?templateFileName = null; string?templateLanguage = null; string?memberFilter = null; #region collect named arguments [only one argument for now] foreach (KeyValuePair <string, TypedConstant> arg in attribute.NamedArguments) { switch (arg.Key) { case "FileName": { if (arg.Value.Value is string s) { templateFileName = s; } } break; case "Body": { if (arg.Value.Value is string s) { templateBody = s; } } break; case "Language": { if (arg.Value.Value is string s) { templateLanguage = s; } } break; case "Filter": { if (arg.Value.Value is string s) { memberFilter = s; } } break; } } #endregion if (templateBody != null && templateBody.Trim().Length > 0) { if (templateFileName != null && templateFileName.Trim().Length > 0) { Helpers.ReportDiagnostic(context, "BK-AG12", nameof(AutoInterfaceResource.AG12_title), nameof(AutoInterfaceResource.AG12_message), nameof(AutoInterfaceResource.AG12_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax() ); continue; } Regex?rxMemberFilter = null; if (memberFilter != null && memberFilter.Length > 0) { try { rxMemberFilter = new Regex(memberFilter, RegexOptions.Singleline | RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture); } catch { Helpers.ReportDiagnostic(context, "BK-AG15", nameof(AutoInterfaceResource.AG15_title), nameof(AutoInterfaceResource.AG15_message), nameof(AutoInterfaceResource.AG15_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), memberFilter); continue; } } templateParts.Add(new PartialTemplate(memberTargets, rxMemberFilter, new TemplateDefinition(templateLanguage ?? "scriban", templateBody.Trim()))); if (danglingInterfaceTypesBySymbols.TryGetValue(symbol, out HashSet <INamedTypeSymbol> interfaceTypes) == false) { danglingInterfaceTypesBySymbols[symbol] = interfaceTypes = new HashSet <INamedTypeSymbol>(SymbolEqualityComparer.Default); } interfaceTypes.Add(interfaceType); } else if (templateFileName != null && templateFileName.Trim().Length > 0) { string?content = null; AdditionalText?file = context.AdditionalFiles.FirstOrDefault(i => i.Path.EndsWith(templateFileName)); if (file != null) { content = file.GetText()?.ToString()?.Trim(); if (content == null) { content = ""; } } else { Helpers.ReportDiagnostic(context, "BK-AG11", nameof(AutoInterfaceResource.AG11_title), nameof(AutoInterfaceResource.AG11_message), nameof(AutoInterfaceResource.AG11_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), templateFileName); continue; } if (string.IsNullOrEmpty(templateLanguage)) { string extension = Path.GetExtension(templateFileName).ToLowerInvariant(); if (extension.StartsWith(".")) { extension = extension.Substring(1); } templateLanguage = extension; } Regex?rxMemberFilter = null; if (memberFilter != null && memberFilter.Length > 0) { try { rxMemberFilter = new Regex(memberFilter, RegexOptions.Singleline | RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture); } catch { Helpers.ReportDiagnostic(context, "BK-AG15", nameof(AutoInterfaceResource.AG15_title), nameof(AutoInterfaceResource.AG15_message), nameof(AutoInterfaceResource.AG15_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), memberFilter); continue; } } templateParts.Add(new PartialTemplate(memberTargets, rxMemberFilter, new TemplateDefinition(templateLanguage ?? "scriban", content))); if (danglingInterfaceTypesBySymbols.TryGetValue(symbol, out HashSet <INamedTypeSymbol> interfaceTypes) == false) { danglingInterfaceTypesBySymbols[symbol] = interfaceTypes = new HashSet <INamedTypeSymbol>(SymbolEqualityComparer.Default); } interfaceTypes.Add(interfaceType); } else { Helpers.ReportDiagnostic(context, "BK-AG14", nameof(AutoInterfaceResource.AG14_title), nameof(AutoInterfaceResource.AG14_message), nameof(AutoInterfaceResource.AG14_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax() ); continue; } } else { Helpers.ReportDiagnostic(context, "BK-AG04", nameof(AutoInterfaceResource.AG04_title), nameof(AutoInterfaceResource.AG04_message), nameof(AutoInterfaceResource.AG04_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), receiverType.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat), type.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat)); continue; } } else { Helpers.ReportDiagnostic(context, "BK-AG09", nameof(AutoInterfaceResource.AG09_title), nameof(AutoInterfaceResource.AG09_message), nameof(AutoInterfaceResource.AG09_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), 157834); continue; } } else { Helpers.ReportDiagnostic(context, "BK-AG03", nameof(AutoInterfaceResource.AG03_title), nameof(AutoInterfaceResource.AG03_message), nameof(AutoInterfaceResource.AG03_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), type.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat)); continue; } } } List <AutoInterfaceRecord> records = new(); foreach (AttributeData attribute in symbol.GetAttributes()) { if (attribute.AttributeClass != null && attribute.AttributeClass.Equals(autoInterfaceAttributeSymbol, SymbolEqualityComparer.Default)) { ITypeSymbol?type = null; bool? includeBaseInterfaces = null; bool? preferCoalesce = null; if (attribute.ConstructorArguments.Length == 0) { type = receiverType.WithNullableAnnotation(NullableAnnotation.NotAnnotated); } else { if (attribute.ConstructorArguments[0].Value is ITypeSymbol targetType) { type = targetType; } } if (type == null) { Helpers.ReportDiagnostic(context, "BK-AG07", nameof(AutoInterfaceResource.AG07_title), nameof(AutoInterfaceResource.AG07_message), nameof(AutoInterfaceResource.AG07_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax()); continue; } else if (type.TypeKind == TypeKind.Interface) { if (type is INamedTypeSymbol interfaceType) { string?templateBody = null; string?templateFileName = null; string?templateLanguage = null; #region collect named arguments foreach (KeyValuePair <string, TypedConstant> arg in attribute.NamedArguments) { switch (arg.Key) { case "TemplateFileName": { if (arg.Value.Value is string s) { templateFileName = s; } } break; case "TemplateBody": { if (arg.Value.Value is string s) { templateBody = s; } } break; case "TemplateLanguage": { if (arg.Value.Value is string s) { templateLanguage = s; } } break; case "IncludeBaseInterfaces": { if (arg.Value.Value is bool b) { includeBaseInterfaces = b; } } break; case "PreferCoalesce": { if (arg.Value.Value is bool b) { preferCoalesce = b; } } break; } } #endregion TemplateDefinition?template = null; if (templateBody != null && templateBody.Trim().Length > 0) { if (templateFileName != null && templateFileName.Trim().Length > 0) { Helpers.ReportDiagnostic(context, "BK-AG12", nameof(AutoInterfaceResource.AG12_title), nameof(AutoInterfaceResource.AG12_message), nameof(AutoInterfaceResource.AG12_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax() ); continue; } template = new TemplateDefinition(templateLanguage ?? "scriban", templateBody.Trim()); } else if (templateFileName != null && templateFileName.Trim().Length > 0) { string?content = null; AdditionalText?file = context.AdditionalFiles.FirstOrDefault(i => i.Path.EndsWith(templateFileName)); if (file != null) { content = file.GetText()?.ToString()?.Trim(); if (content == null) { content = ""; } } else { Helpers.ReportDiagnostic(context, "BK-AG11", nameof(AutoInterfaceResource.AG11_title), nameof(AutoInterfaceResource.AG11_message), nameof(AutoInterfaceResource.AG11_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), templateFileName); continue; } if (string.IsNullOrEmpty(templateLanguage)) { string extension = Path.GetExtension(templateFileName).ToLowerInvariant(); if (extension.StartsWith(".")) { extension = extension.Substring(1); } templateLanguage = extension; } if (templateParts.Count > 0) { Helpers.ReportDiagnostic(context, "BK-AG13", nameof(AutoInterfaceResource.AG13_title), nameof(AutoInterfaceResource.AG13_message), nameof(AutoInterfaceResource.AG13_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax() ); continue; } template = new TemplateDefinition(templateLanguage ?? "scriban", content); } if (includeBaseInterfaces == null) { includeBaseInterfaces = false; } if (preferCoalesce == null) { preferCoalesce = true; } if (receiverType.IsMatchByTypeOrImplementsInterface(type)) { danglingInterfaceTypesBySymbols.Remove(symbol); records.Add(new AutoInterfaceRecord(symbol, receiverType, interfaceType, template, templateParts, false, preferCoalesce.Value)); if (includeBaseInterfaces.Value) { foreach (INamedTypeSymbol baseInterfaceType in interfaceType.AllInterfaces) { records.Add(new AutoInterfaceRecord(symbol, receiverType, baseInterfaceType, template, templateParts, false, preferCoalesce.Value)); } } } else if (receiverType.IsAllInterfaceMembersImplementedBySignature(type) && (includeBaseInterfaces.Value == false || interfaceType.AllInterfaces.All(i => receiverType.IsMatchByTypeOrImplementsInterface(i) || receiverType.IsAllInterfaceMembersImplementedBySignature(i)))) { danglingInterfaceTypesBySymbols.Remove(symbol); records.Add(new AutoInterfaceRecord(symbol, receiverType, interfaceType, template, templateParts, true, preferCoalesce.Value)); if (includeBaseInterfaces.Value) { foreach (INamedTypeSymbol baseInterfaceType in interfaceType.AllInterfaces) { bool byType = receiverType.IsMatchByTypeOrImplementsInterface(baseInterfaceType); records.Add(new AutoInterfaceRecord(symbol, receiverType, baseInterfaceType, template, templateParts, !byType, preferCoalesce.Value)); } } } else { Helpers.ReportDiagnostic(context, "BK-AG04", nameof(AutoInterfaceResource.AG04_title), nameof(AutoInterfaceResource.AG04_message), nameof(AutoInterfaceResource.AG04_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), receiverType.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat), type.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat)); continue; } } else { Helpers.ReportDiagnostic(context, "BK-AG09", nameof(AutoInterfaceResource.AG09_title), nameof(AutoInterfaceResource.AG09_message), nameof(AutoInterfaceResource.AG09_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), 157834); continue; } } else { Helpers.ReportDiagnostic(context, "BK-AG03", nameof(AutoInterfaceResource.AG03_title), nameof(AutoInterfaceResource.AG03_message), nameof(AutoInterfaceResource.AG03_description), DiagnosticSeverity.Error, attribute.ApplicationSyntaxReference?.GetSyntax(), type.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat)); continue; } } } foreach (KeyValuePair <ISymbol, HashSet <INamedTypeSymbol> > danglingInterfaceTypes in danglingInterfaceTypesBySymbols) { foreach (INamedTypeSymbol interfaceType in danglingInterfaceTypes.Value) { records.Add(new AutoInterfaceRecord(danglingInterfaceTypes.Key, receiverType, interfaceType, null, templateParts, false, false)); } } return(records); }