internal static void DebugWarning(this GeneratorExecutionContext context, string message) => context.ReportDiagnostic( Diagnostic.Create( "IXDEBUGDEBUG", "Debug", message, DiagnosticSeverity.Warning, DiagnosticSeverity.Warning, true, 4));
public static void ReportMissingDependency( GeneratorExecutionContext context, string packageName) => context.ReportDiagnostic(_missingDependency, packageName);
public void Execute(GeneratorExecutionContext context) { // If this isn't working, run 'dotnet build-server shutdown' first. if (Environment .GetEnvironmentVariable($"Debug{nameof(GodotOnReadySourceGenerator)}") == "true") { Debugger.Launch(); } var receiver = context.SyntaxReceiver as OnReadyReceiver ?? throw new Exception(); INamedTypeSymbol GetSymbolByName(string fullName) => context.Compilation.GetTypeByMetadataName(fullName) ?? throw new Exception($"Can't find {fullName}"); var onReadyGetSymbol = GetSymbolByName("GodotOnReady.Attributes.OnReadyGetAttribute"); var onReadySymbol = GetSymbolByName("GodotOnReady.Attributes.OnReadyAttribute"); var generateDataSelectorEnumSymbol = GetSymbolByName("GodotOnReady.Attributes.GenerateDataSelectorEnumAttribute"); var resourceSymbol = GetSymbolByName("Godot.Resource"); var nodeSymbol = GetSymbolByName("Godot.Node"); List <PartialClassAddition> additions = new(); var classSymbols = receiver.AllClasses .Select(classDecl => { INamedTypeSymbol?classSymbol = context.Compilation .GetSemanticModel(classDecl.SyntaxTree) .GetDeclaredSymbol(classDecl); if (classSymbol is null) { context.ReportDiagnostic( Diagnostic.Create( new DiagnosticDescriptor( "GORSG0001", "Inspection", $"Unable to find declared symbol for {classDecl}. Skipping.", "GORSG.Parsing", DiagnosticSeverity.Warning, true ), classDecl.GetLocation() ) ); } return(classSymbol); }) .Distinct(SymbolEqualityComparer.Default) .OfType <INamedTypeSymbol>(); foreach (var classSymbol in classSymbols) { foreach (var attribute in classSymbol.GetAttributes() .Where(a => Equal(a.AttributeClass, generateDataSelectorEnumSymbol))) { var fields = classSymbol.GetMembers() .OfType <IFieldSymbol>() .Where(f => f.IsReadOnly && f.IsStatic) .ToArray(); additions.Add(new DataSelectorEnumAddition( fields, new AttributeSite(classSymbol, attribute))); } var members = Enumerable .Concat( classSymbol.GetMembers().OfType <IPropertySymbol>().Select(MemberSymbol.Create), classSymbol.GetMembers().OfType <IFieldSymbol>().Select(MemberSymbol.Create)) .ToArray(); foreach (var member in members) { foreach (var attribute in member.Symbol .GetAttributes() .Where(a => Equal(a.AttributeClass, onReadyGetSymbol))) { var site = new MemberAttributeSite( member, new AttributeSite(classSymbol, attribute)); if (site.AttributeSite.Attribute.NamedArguments.Any( a => a.Key == "Property" && a.Value.Value is string { Length: > 0 }))
/// <inheritdoc/> public void Execute(GeneratorExecutionContext context) { if (context.Compilation is not CSharpCompilation compilation) { return; } GeneratorOptions options; AdditionalText? nativeMethodsJsonFile = context.AdditionalFiles .FirstOrDefault(af => string.Equals(Path.GetFileName(af.Path), NativeMethodsJsonAdditionalFileName, StringComparison.OrdinalIgnoreCase)); if (nativeMethodsJsonFile is object) { string optionsJson = nativeMethodsJsonFile.GetText(context.CancellationToken) !.ToString(); try { options = JsonSerializer.Deserialize <GeneratorOptions>(optionsJson, new JsonSerializerOptions { AllowTrailingCommas = true, ReadCommentHandling = JsonCommentHandling.Skip, PropertyNamingPolicy = JsonNamingPolicy.CamelCase, }); } catch (JsonException ex) { context.ReportDiagnostic(Diagnostic.Create(OptionsParsingError, location: null, nativeMethodsJsonFile.Path, ex.Message)); return; } } else { options = new GeneratorOptions(); } AdditionalText?nativeMethodsTxtFile = context.AdditionalFiles .FirstOrDefault(af => string.Equals(Path.GetFileName(af.Path), NativeMethodsTxtAdditionalFileName, StringComparison.OrdinalIgnoreCase)); if (nativeMethodsTxtFile is null) { return; } var parseOptions = (CSharpParseOptions)context.ParseOptions; if (!compilation.Options.AllowUnsafe) { context.ReportDiagnostic(Diagnostic.Create(UnsafeCodeRequired, location: null)); } Docs?docs = ParseDocs(context); IReadOnlyList <Generator> generators = CollectMetadataPaths(context).Select(path => new Generator(path, docs, options, compilation, parseOptions)).ToList(); try { SuperGenerator.Combine(generators); SourceText?nativeMethodsTxt = nativeMethodsTxtFile.GetText(context.CancellationToken); if (nativeMethodsTxt is null) { return; } foreach (TextLine line in nativeMethodsTxt.Lines) { context.CancellationToken.ThrowIfCancellationRequested(); string name = line.ToString(); if (string.IsNullOrWhiteSpace(name) || name.StartsWith("//", StringComparison.InvariantCulture)) { continue; } name = name.Trim(); var location = Location.Create(nativeMethodsTxtFile.Path, line.Span, nativeMethodsTxt.Lines.GetLinePositionSpan(line.Span)); try { if (Generator.GetBannedAPIs(options).TryGetValue(name, out string?reason)) { context.ReportDiagnostic(Diagnostic.Create(BannedApi, location, reason)); continue; } if (name.EndsWith(".*", StringComparison.Ordinal)) { string?moduleName = name.Substring(0, name.Length - 2); int matches = 0; foreach (Generator generator in generators) { if (generator.TryGenerateAllExternMethods(moduleName, context.CancellationToken)) { matches++; } } switch (matches) { case 0: context.ReportDiagnostic(Diagnostic.Create(NoMethodsForModule, location, moduleName)); break; case > 1: context.ReportDiagnostic(Diagnostic.Create(AmbiguousMatchError, location, moduleName)); break; } continue; } List <string> matchingApis = new(); foreach (Generator generator in generators) { if (generator.TryGenerate(name, out IReadOnlyList <string> preciseApi, context.CancellationToken)) { matchingApis.AddRange(preciseApi); continue; } matchingApis.AddRange(preciseApi); if (generator.TryGetEnumName(name, out string?declaringEnum)) { context.ReportDiagnostic(Diagnostic.Create(UseEnumValueDeclaringType, location, declaringEnum)); generator.TryGenerate(declaringEnum, out preciseApi, context.CancellationToken); matchingApis.AddRange(preciseApi); } } switch (matchingApis.Count) { case 0: ReportNoMatch(location, name); break; case > 1: context.ReportDiagnostic(Diagnostic.Create(AmbiguousMatchErrorWithSuggestions, location, name, ConcatSuggestions(matchingApis))); break; } } catch (GenerationFailedException ex) { if (Generator.IsPlatformCompatibleException(ex)) { context.ReportDiagnostic(Diagnostic.Create(CpuArchitectureIncompatibility, location)); } else { // Build up a complete error message. context.ReportDiagnostic(Diagnostic.Create(InternalError, location, AssembleFullExceptionMessage(ex))); } } } foreach (Generator generator in generators) { IOrderedEnumerable <KeyValuePair <string, CodeAnalysis.CSharp.Syntax.CompilationUnitSyntax> >?compilationUnits = generator.GetCompilationUnits(context.CancellationToken) .OrderBy(pair => pair.Key, StringComparer.OrdinalIgnoreCase) .ThenBy(pair => pair.Key, StringComparer.Ordinal); foreach (KeyValuePair <string, CodeAnalysis.CSharp.Syntax.CompilationUnitSyntax> unit in compilationUnits) { context.AddSource($"{generator.InputAssemblyName}.{unit.Key}", unit.Value.ToFullString()); } } string ConcatSuggestions(IReadOnlyList <string> suggestions) { var suggestionBuilder = new StringBuilder(); for (int i = 0; i < suggestions.Count; i++) { if (i > 0) { suggestionBuilder.Append(i < suggestions.Count - 1 ? ", " : " or "); } suggestionBuilder.Append('"'); suggestionBuilder.Append(suggestions[i]); suggestionBuilder.Append('"'); } return(suggestionBuilder.ToString()); } void ReportNoMatch(Location?location, string failedAttempt) { List <string> suggestions = new(); foreach (Generator generator in generators) { suggestions.AddRange(generator.GetSuggestions(failedAttempt).Take(4)); } if (suggestions.Count > 0) { context.ReportDiagnostic(Diagnostic.Create(NoMatchingMethodOrTypeWithSuggestions, location, failedAttempt, ConcatSuggestions(suggestions))); } else { context.ReportDiagnostic(Diagnostic.Create( Generator.ContainsIllegalCharactersForAPIName(failedAttempt) ? NoMatchingMethodOrTypeWithBadCharacters : NoMatchingMethodOrType, location, failedAttempt)); } } } finally { foreach (Generator generator in generators) { generator.Dispose(); } } }
/// <summary> /// Generates source for for ElementFactory class. /// </summary> /// <param name="context">The context object.</param> /// <param name="compilation">The compilation object.</param> /// <param name="elementFactorySymbol">The ElementFactory type object.</param> /// <param name="svgElementSymbols">The SvgElement type symbols.</param> /// <param name="svgElementBaseSymbol">The base class for SvgElement type symbols.</param> private static void ProcessClass(GeneratorExecutionContext context, Compilation compilation, INamedTypeSymbol elementFactorySymbol, List <INamedTypeSymbol> svgElementSymbols, INamedTypeSymbol svgElementBaseSymbol) { // Get the containing namespace for ElementFactory class. if (!elementFactorySymbol.ContainingSymbol.Equals(elementFactorySymbol.ContainingNamespace, SymbolEqualityComparer.Default)) { context.ReportDiagnostic(Diagnostic.Create(ErrorDescriptor, Location.None, "Invalid ElementFactory symbol namespace.")); return; } // Get SvgElementAttribute symbol using for later attribute retrieval. var svgElementAttribute = compilation.GetTypeByMetadataName("Svg.SvgElementAttribute"); if (svgElementAttribute is null) { context.ReportDiagnostic(Diagnostic.Create(ErrorDescriptor, Location.None, "Could not get Svg.SvgElementAttribute metadata.")); return; } // Get SvgAttributeAttribute symbol using for later attribute retrieval. var svgAttributeAttribute = compilation.GetTypeByMetadataName("Svg.SvgAttributeAttribute"); if (svgAttributeAttribute is null) { context.ReportDiagnostic(Diagnostic.Create(ErrorDescriptor, Location.None, "Could not get Svg.SvgAttributeAttribute metadata.")); return; } // Convert symbol to proper display string. string namespaceElementFactory = elementFactorySymbol.ContainingNamespace.ToDisplayString(); // Format symbols to support generic types and namespaces. var format = new SymbolDisplayFormat( typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeTypeConstraints | SymbolDisplayGenericsOptions.IncludeVariance ); // Format symbols to support generic types without namespaces. var formatClass = new SymbolDisplayFormat( typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypes, genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeTypeConstraints | SymbolDisplayGenericsOptions.IncludeVariance ); string classElementFactory = elementFactorySymbol.ToDisplayString(formatClass); // Key: ElementName SortedDictionary <string, Element> items = new(); // Include all element even without SvgElementAttribute set (e.g. SvgDocument). List <Element> elements = new(); // Get all classes with SvgElementAttribute attribute set. foreach (var svgElementSymbol in svgElementSymbols) { string classNameSvgElement = svgElementSymbol.ToDisplayString(format); var elementName = default(string); var attributes = svgElementSymbol.GetAttributes(); if (attributes.Length > 0) { // Find SvgElementAttribute attribute data. The SvgElementAttribute has constructor with one argument of type string. var attributeData = attributes.FirstOrDefault(ad => ad?.AttributeClass?.Equals(svgElementAttribute, SymbolEqualityComparer.Default) ?? false); if (attributeData is not null && attributeData.ConstructorArguments.Length == 1) { // The ElementName is set in attribute by providing constructor argument. elementName = (string?)attributeData.ConstructorArguments[0].Value; } } if (string.Empty.Equals(elementName)) { continue; } if (elementName is not null && items.TryGetValue(elementName, out var element)) { element.ClassNames.Add(classNameSvgElement); }
private string ProcessClassDeclaration ( ClassDeclarationSyntax classDeclaration, GeneratorExecutionContext sourceContext, INamedTypeSymbol nativeApiAttributeSymbol, MarshalBuilder rootMarshalBuilder, ref List <ITypeSymbol> processedSymbols, INamedTypeSymbol excludeFromOverrideAttribute ) { var stopwatch = Stopwatch.StartNew(); var compilation = sourceContext.Compilation; if (!classDeclaration.Modifiers.Any(x => x.IsKind(SyntaxKind.PartialKeyword))) { return(null); } if (!classDeclaration.Parent.IsKind(SyntaxKind.NamespaceDeclaration)) { return(null); } var namespaceDeclaration = (NamespaceDeclarationSyntax)classDeclaration.Parent; if (!namespaceDeclaration.Parent.IsKind(SyntaxKind.CompilationUnit)) { return(null); } var compilationUnit = (CompilationUnitSyntax)namespaceDeclaration.Parent; var classSymbol = ModelExtensions.GetDeclaredSymbol (compilation.GetSemanticModel(classDeclaration.SyntaxTree), classDeclaration) as ITypeSymbol; if (!compilation.HasImplicitConversion (classSymbol, compilation.GetTypeByMetadataName("Silk.NET.Core.Native.NativeApiContainer"))) { return(null); } var classIsSealed = classDeclaration.Modifiers.Any(x => x.Text == "sealed"); var generateSeal = false; if (sourceContext.AnalyzerConfigOptions.GetOptions (classDeclaration.SyntaxTree) .TryGetValue("silk_touch_sealed_vtable_creation", out var generateSealstr)) { if (bool.TryParse(generateSealstr, out var v)) { generateSeal = v; } } var generateVTable = false; if (sourceContext.AnalyzerConfigOptions.GetOptions (classDeclaration.SyntaxTree) .TryGetValue("silk_touch_vtable_generate", out var genvtablestr)) { if (bool.TryParse(genvtablestr, out var v)) { generateVTable = v; } } var preloadVTable = false; if (sourceContext.AnalyzerConfigOptions.GetOptions (classDeclaration.SyntaxTree) .TryGetValue("silk_touch_vtable_preload", out var vtablepreloadstr)) { if (bool.TryParse(vtablepreloadstr, out var v)) { preloadVTable = v; } } var emitAssert = false; if (sourceContext.AnalyzerConfigOptions.GetOptions (classDeclaration.SyntaxTree) .TryGetValue("silk_touch_vtable_tree_emit_assert", out var emitAssertStr)) { if (bool.TryParse(emitAssertStr, out var v)) { emitAssert = v; } } var classAttribute = classSymbol.GetAttributes() .FirstOrDefault(x => SymbolEqualityComparer.Default.Equals(x.AttributeClass, nativeApiAttributeSymbol)); var classNativeApiAttribute = classAttribute == default ? new NativeApiAttribute() : ToNativeApiAttribute(classAttribute); var newMembers = new List <MemberDeclarationSyntax>(); int slotCount = 0; int gcCount = 0; var generatedVTableName = NameGenerator.Name("GeneratedVTable"); Dictionary <int, string> entryPoints = new Dictionary <int, string>(); var processedEntrypoints = new List <EntryPoint>(); foreach (var(declaration, symbol, entryPoint, callingConvention) in from declaration in from member in classDeclaration.Members where member.IsKind(SyntaxKind.MethodDeclaration) select(MethodDeclarationSyntax) member let symbol = compilation.GetSemanticModel(declaration.SyntaxTree).GetDeclaredSymbol(declaration) where symbol is not null let attribute = ToNativeApiAttribute ( symbol.GetAttributes() .FirstOrDefault (att => SymbolEqualityComparer.Default.Equals(att.AttributeClass, nativeApiAttributeSymbol)) ) where declaration.Modifiers.Any (modifier => modifier.IsKind(SyntaxKind.PartialKeyword)) && symbol.PartialImplementationPart is null let entryPoint = NativeApiAttribute.GetEntryPoint(attribute, classNativeApiAttribute, symbol.Name) let callingConvention = NativeApiAttribute.GetCallingConvention(attribute, classNativeApiAttribute) select(declaration, symbol, entryPoint, callingConvention)) { var slot = slotCount++; // even though technically that somehow makes slots defined behavior, THEY ARE NOT // SLOTS ARE UNDEFINED BEHAVIOR ProcessMethod ( sourceContext, rootMarshalBuilder, callingConvention, entryPoints, entryPoint, classIsSealed, generateSeal, generateVTable, slot, compilation, symbol, declaration, newMembers, ref gcCount, processedEntrypoints, generatedVTableName ); } if (slotCount > 0) { if (!processedSymbols.Contains(classSymbol)) { newMembers.Add ( MethodDeclaration ( List <AttributeListSyntax>(), TokenList(Token(SyntaxKind.ProtectedKeyword), Token(SyntaxKind.OverrideKeyword)), PredefinedType(Token(SyntaxKind.IntKeyword)), null, Identifier("CoreGetSlotCount"), null, ParameterList(), List <TypeParameterConstraintClauseSyntax>(), null, ArrowExpressionClause ( BinaryExpression ( SyntaxKind.AddExpression, LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(slotCount)), InvocationExpression ( MemberAccessExpression ( SyntaxKind.SimpleMemberAccessExpression, BaseExpression(), IdentifierName("CoreGetSlotCount") ) ) ) ), Token(SyntaxKind.SemicolonToken) ) ); newMembers.Add ( MethodDeclaration ( List <AttributeListSyntax>(), TokenList(Token(SyntaxKind.ProtectedKeyword), Token(SyntaxKind.OverrideKeyword)), PredefinedType(Token(SyntaxKind.IntKeyword)), null, Identifier("CoreGcSlotCount"), null, ParameterList(), List <TypeParameterConstraintClauseSyntax>(), null, ArrowExpressionClause ( BinaryExpression ( SyntaxKind.AddExpression, LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(gcCount)), InvocationExpression ( MemberAccessExpression ( SyntaxKind.SimpleMemberAccessExpression, BaseExpression(), IdentifierName("CoreGcSlotCount") ) ) ) ), Token(SyntaxKind.SemicolonToken) ) ); } processedSymbols.Add(classSymbol); } if (newMembers.Count == 0) { return(null); } if (generateVTable && entryPoints.Count > 0) { newMembers.Add ( GenerateVTable ( preloadVTable, entryPoints, emitAssert, sourceContext.ParseOptions.PreprocessorSymbolNames.Any (x => x == "NETCOREAPP" || x == "NET5" /* SEE INativeContext.cs in Core */), generatedVTableName ) ); newMembers.Add ( MethodDeclaration(IdentifierName("IVTable"), Identifier("CreateVTable")) .WithModifiers ( TokenList ( generateSeal ? new[] { Token(SyntaxKind.ProtectedKeyword), Token(SyntaxKind.SealedKeyword), Token(SyntaxKind.OverrideKeyword) } : new[] { Token(SyntaxKind.ProtectedKeyword), Token(SyntaxKind.OverrideKeyword) } ) ) .WithExpressionBody ( ArrowExpressionClause ( ObjectCreationExpression (IdentifierName(generatedVTableName)) .WithArgumentList(ArgumentList()) ) ) .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)) ); } ProcessNativeContextOverrides(processedEntrypoints.ToArray(), ref newMembers, classSymbol, classDeclaration, sourceContext.Compilation, excludeFromOverrideAttribute); var newNamespace = namespaceDeclaration.WithMembers ( List ( new MemberDeclarationSyntax[] { classDeclaration.WithMembers (List(newMembers)) .WithAttributeLists(List <AttributeListSyntax>()) } ) ) .WithUsings(compilationUnit.Usings); var result = newNamespace.NormalizeWhitespace().ToFullString(); stopwatch.Stop(); var reportTelemetry = true; #if !DEBUG reportTelemetry = sourceContext.AnalyzerConfigOptions.GlobalOptions.TryGetValue ("silk_touch_telemetry", out var telstr) && bool.Parse(telstr); #endif if (reportTelemetry) { sourceContext.ReportDiagnostic ( Diagnostic.Create ( Diagnostics.BuildInfo, classDeclaration.GetLocation(), slotCount, gcCount, stopwatch.ElapsedMilliseconds + "ms" ) ); } return(result); }
/// <inheritdoc/> public void Execute(GeneratorExecutionContext context) { if (!(context.Compilation is CSharpCompilation)) { return; } if (!context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.MicrosoftWindowsSdkWin32MetadataBasePath", out string?metadataPath) || string.IsNullOrWhiteSpace(metadataPath)) { return; } GeneratorOptions?options = null; AdditionalText? nativeMethodsJsonFile = context.AdditionalFiles .FirstOrDefault(af => string.Equals(Path.GetFileName(af.Path), NativeMethodsJsonAdditionalFileName, StringComparison.OrdinalIgnoreCase)); if (nativeMethodsJsonFile is object) { string optionsJson = nativeMethodsJsonFile.GetText(context.CancellationToken) !.ToString(); options = JsonSerializer.Deserialize <GeneratorOptions>(optionsJson, new JsonSerializerOptions { AllowTrailingCommas = true, ReadCommentHandling = JsonCommentHandling.Skip, PropertyNamingPolicy = JsonNamingPolicy.CamelCase, }); } AdditionalText?nativeMethodsTxtFile = context.AdditionalFiles .FirstOrDefault(af => string.Equals(Path.GetFileName(af.Path), NativeMethodsTxtAdditionalFileName, StringComparison.OrdinalIgnoreCase)); if (nativeMethodsTxtFile is null) { return; } using var metadataStream = File.OpenRead(Path.Combine(metadataPath, "Windows.Win32.winmd")); var compilation = (CSharpCompilation)context.Compilation; var parseOptions = (CSharpParseOptions)context.ParseOptions; if (!compilation.Options.AllowUnsafe) { context.ReportDiagnostic(Diagnostic.Create(UnsafeCodeRequired, location: null)); } using var generator = new Generator(metadataStream, options, compilation, parseOptions); SourceText?nativeMethodsTxt = nativeMethodsTxtFile.GetText(context.CancellationToken); if (nativeMethodsTxt is null) { return; } foreach (TextLine line in nativeMethodsTxt.Lines) { context.CancellationToken.ThrowIfCancellationRequested(); string name = line.ToString(); if (string.IsNullOrWhiteSpace(name) || name.StartsWith("//", StringComparison.InvariantCulture)) { continue; } name = name.Trim(); var location = Location.Create(nativeMethodsTxtFile.Path, line.Span, nativeMethodsTxt.Lines.GetLinePositionSpan(line.Span)); if (generator.BannedAPIs.TryGetValue(name, out string?reason)) { context.ReportDiagnostic(Diagnostic.Create(BannedApi, location, reason)); } else if (name.EndsWith(".*", StringComparison.Ordinal)) { var moduleName = name.Substring(0, name.Length - 2); if (!generator.TryGenerateAllExternMethods(moduleName, context.CancellationToken)) { context.ReportDiagnostic(Diagnostic.Create(NoMethodsForModule, location, moduleName)); } } else if (!generator.TryGenerate(name, context.CancellationToken)) { if (generator.TryGetEnumName(name, out string?declaringEnum)) { context.ReportDiagnostic(Diagnostic.Create(UseEnumValueDeclaringType, location, declaringEnum)); if (!generator.TryGenerate(declaringEnum, context.CancellationToken)) { ReportNoMatch(location, declaringEnum); } } else { ReportNoMatch(location, name); } } } var compilationUnits = generator.GetCompilationUnits(context.CancellationToken); foreach (var unit in compilationUnits) { context.AddSource(unit.Key, unit.Value.ToFullString()); } void ReportNoMatch(Location?location, string failedAttempt) { var suggestions = generator.GetSuggestions(failedAttempt).Take(4).ToList(); if (suggestions.Count > 0) { var suggestionBuilder = new StringBuilder(); for (int i = 0; i < suggestions.Count; i++) { if (i > 0) { suggestionBuilder.Append(i < suggestions.Count - 1 ? ", " : " or "); } suggestionBuilder.Append('"'); suggestionBuilder.Append(suggestions[i]); suggestionBuilder.Append('"'); } context.ReportDiagnostic(Diagnostic.Create(NoMatchingMethodOrTypeWithSuggestions, location, failedAttempt, suggestionBuilder)); } else { context.ReportDiagnostic(Diagnostic.Create(NoMatchingMethodOrType, location, failedAttempt)); } } }
public void Execute(GeneratorExecutionContext context) { try { var diagnosticReporter = new DiagnosticReporter( context ); var needToStoreGeneratedSources = context.AnalyzerConfigOptions.GlobalOptions.TryGetValue( $"build_property.Dpdt_Generator_GeneratedSourceFolder", out var generatedSourceFolder ); var generatedSourceFolderFullPath = Path.GetFullPath( generatedSourceFolder ?? "Dpdt.Pregenerated" ); var typeInfoContainer = new GeneratorTypeInfoContainer( ref context, needToStoreGeneratedSources, generatedSourceFolderFullPath ); var internalGenerator = new DpdtInternalGenerator( diagnosticReporter ); if (needToStoreGeneratedSources) { if (Directory.Exists(generatedSourceFolderFullPath)) { Directory.Delete(generatedSourceFolderFullPath, true); } Directory.CreateDirectory(generatedSourceFolderFullPath); } internalGenerator.Execute( typeInfoContainer, null ); diagnosticReporter.ReportWarning( "Dpdt generator successfully finished its work", $"Dpdt generator successfully finished its work, {typeInfoContainer.UnitsGenerated} compilation unit(s) generated." ); } catch (Exception excp) { context.ReportDiagnostic( Diagnostic.Create( new DiagnosticDescriptor( id: "DPDTINJECT100", title: "Couldn't generate a binding boilerplate code", messageFormat: "Couldn't generate a binding boilerplate code '{0}' {1}", category: "DpDtInject", DiagnosticSeverity.Error, isEnabledByDefault: true ), Location.None, excp.Message, excp.StackTrace ) ); } }
public void Execute(GeneratorExecutionContext context) { context.AddSource("MapperAttribute", SourceText.From(MappingAttributeText, Encoding.UTF8)); //Create a new compilation that contains the attribute var options = (context.Compilation as CSharpCompilation).SyntaxTrees[0].Options as CSharpParseOptions; var compilation = context.Compilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(SourceText.From(MappingAttributeText, Encoding.UTF8), options)); var allNodes = compilation.SyntaxTrees.SelectMany(s => s.GetRoot().DescendantNodes()); var allAttributes = allNodes.Where((d) => d.IsKind(SyntaxKind.Attribute)).OfType <AttributeSyntax>(); var attributes = allAttributes.Where(d => d.Name.ToString() == "Mapping" || d.Name.ToString() == "Mapper.Mapping").ToImmutableArray(); var allClasses = compilation.SyntaxTrees. SelectMany(x => x.GetRoot().DescendantNodes().OfType <ClassDeclarationSyntax>()); var sourceBuilder = new StringBuilder(@" //<auto-generated> namespace MapperGenerator { public static class Mapper {"); foreach (AttributeSyntax attr in attributes) { if (attr.ArgumentList is null) { throw new Exception("Can't be null here"); } #region Get Mapping Source Class Info //todo: add diagnostic when ArgumentList is null //get type of mapping target from constructor argument var mappedTypeArgSyntax = attr.ArgumentList.Arguments.First(); var mappedTypeArgSyntaxExpr = mappedTypeArgSyntax.Expression.NormalizeWhitespace().ToFullString(); var sourceClassName = GetContentInParentheses(mappedTypeArgSyntaxExpr); var sourceClassSyntax = allClasses.First(x => x.Identifier.ToString() == sourceClassName); var sourceClassModel = compilation.GetSemanticModel(sourceClassSyntax.SyntaxTree); var sourceClassNamedTypeSymbol = ModelExtensions.GetDeclaredSymbol(sourceClassModel, sourceClassSyntax); var sourceClassFullName = sourceClassNamedTypeSymbol.OriginalDefinition.ToString(); var sourceClassProperties = sourceClassSyntax.GetProperties(sourceClassModel); #endregion #region Get Mapping Target Class Info var targetClassSyntax = attr.SyntaxTree.GetRoot().DescendantNodes().OfType <ClassDeclarationSyntax>().Last(); var targetClassModel = compilation.GetSemanticModel(attr.SyntaxTree); var targetClassNamedTypeSymbol = ModelExtensions.GetDeclaredSymbol(targetClassModel, targetClassSyntax); var targetClassFullName = targetClassNamedTypeSymbol.OriginalDefinition.ToString(); var targetClassName = targetClassFullName.Split('.').Last(); var targetClassProperties = targetClassSyntax.GetProperties(targetClassModel); #endregion #region Create diagnostic erroes if any property of target doesn't match to source properties. //source class properties should match all of target class properties //should use same name and type of property var targetPropertiesMatchedResult = targetClassProperties.Select(target => new { TargetPropertyName = target.propertyName, TargetPropertySyntax = target.propertySyntax, IsMatched = sourceClassProperties.Any(source => source.propertyName == target.propertyName && source.propertyType == target.propertyType) }); if (targetPropertiesMatchedResult.Any(x => x.IsMatched == false)) { foreach (var target in targetPropertiesMatchedResult.Where(x => x.IsMatched == false)) { var diagnosticDescriptor = new DiagnosticDescriptor("MPERR001", "Property mapping error", $"{targetClassName}.{target.TargetPropertyName} couldn't match to {sourceClassName}, please check if the name and type of properties are the same.", "source generator", DiagnosticSeverity.Error, true); var diagnostic = Diagnostic.Create(diagnosticDescriptor, target.TargetPropertySyntax.GetLocation()); context.ReportDiagnostic(diagnostic); } break; } #endregion #region Build mapper method sourceBuilder.Append(@$ "
public void Execute(GeneratorExecutionContext context) { if (!(context.SyntaxReceiver is DuckSyntaxInterfaceReceiver receiver)) { return; } var duckableTypes = receiver.DuckableTypes; foreach (var duckedTypeDeclaration in duckableTypes) { var semanticModel = context.Compilation.GetSemanticModel(duckedTypeDeclaration.SyntaxTree); var duckedType = semanticModel.GetDeclaredSymbol(duckedTypeDeclaration, context.CancellationToken); var uniqueName = $"D{duckedType.Name}.cs"; var fields = CreateSourceForFields(context, duckedType); var fullMethods = duckedType .GetAllMembers() .GetPublicMethods() .Select(method => { var returnType = method.ReturnType; if (returnType.IsRefLikeType) { context.ReportDiagnostic(Diagnostic.Create(DuckCantHandleRefStructs, duckedTypeDeclaration.GetLocation(), DiagnosticSeverity.Error)); return(""); } var parameters = method.Parameters; if (parameters.Any(o => o.Type.IsRefLikeType)) { context.ReportDiagnostic(Diagnostic.Create(DuckCantHandleRefStructs, duckedTypeDeclaration.GetLocation(), DiagnosticSeverity.Error)); return(""); } return ($@" [System.Diagnostics.DebuggerStepThrough] public {returnType.ToGlobalName()} {method.Name}({parameters.Select(o => $"{o.Type.ToGlobalName()} {o.Name}").Join()}) {{ {(returnType.SpecialType == SpecialType.System_Void ? "" : "return ")}_{method.Name}({parameters.Select(o => o.Name).Join()}); }} "); }); var properties = duckedType .GetAllMembers() .OfType <IPropertySymbol>() .Select(property => { var returnType = property.Type; if (returnType.IsRefLikeType) { context.ReportDiagnostic(Diagnostic.Create(DuckCantHandleRefStructs, duckedTypeDeclaration.GetLocation(), DiagnosticSeverity.Error)); return(""); } return ($@" public {returnType.ToGlobalName()} {property.Name} {{ {(property.GetMethod != null ? $" [System.Diagnostics.DebuggerStepThrough] get {{ return _{property.Name}Getter(); }}" : string.Empty)} {(property.SetMethod != null ? $" [System.Diagnostics.DebuggerStepThrough] set {{ _{property.Name}Setter(value); }}" : string.Empty)} }} "); }); var source = $@" using System; namespace {duckedType.ContainingNamespace.ToDisplayString(new SymbolDisplayFormat(typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces))} {{ public partial class D{duckedType.Name} : {duckedType.Name} {{ {fields.JoinWithNewLine()} {properties.JoinWithNewLine()} {fullMethods.JoinWithNewLine()} }} }} "; context.AddSource(uniqueName, source.ToSourceText()); } }
public static void ReportDiagnostic(this GeneratorExecutionContext context, ISymbol symbol, string id, string message) { context.ReportDiagnostic(Diagnostic.Create(id, "Generators", message, DiagnosticSeverity.Warning, DiagnosticSeverity.Warning, true, 4, location: GetLocation(symbol))); }
public void Execute(GeneratorExecutionContext context) { try { if (!(context.SyntaxReceiver is ClusterCandidateSyntaxReceiver receiver)) { return; } var doBeautify = true; var beautifyExists = context.AnalyzerConfigOptions.GlobalOptions.TryGetValue( $"build_property.Dpdt_Generator_Beautify", out var beautify ); if (beautifyExists) { if (bool.TryParse(beautify?.ToLower() ?? "false", out var parsed)) { doBeautify = parsed; } } var diagnosticReporter = new DiagnosticReporter( context ); var sw = Stopwatch.StartNew(); var typeInfoContainer = new GeneratorTypeInfoContainer( ref context, receiver.CandidateClasses ); var internalGenerator = new DpdtInternalGenerator( diagnosticReporter, doBeautify ); internalGenerator.Execute( typeInfoContainer ); diagnosticReporter.ReportWarning( "Dpdt generator successfully finished its work", $"Dpdt generator successfully finished its work, {typeInfoContainer.UnitsGenerated} compilation unit(s) generated, taken {sw.Elapsed}." ); } catch (Exception excp) { Logging.LogGen(excp); context.ReportDiagnostic( Diagnostic.Create( new DiagnosticDescriptor( id: "DPDTINJECT100", title: "Couldn't generate a binding boilerplate code", messageFormat: "Couldn't generate a binding boilerplate code '{0}' {1}", category: "DpDtInject", DiagnosticSeverity.Error, isEnabledByDefault: true ), Location.None, excp.Message, excp.StackTrace ) ); } }
public static void ReportDiagnostic(this GeneratorExecutionContext context, DiagnosticSeverity severity, string text, SyntaxNode target) { context.ReportDiagnostic(severity, text, target.GetLocation()); }
public static void ReportDiagnostic(this GeneratorExecutionContext context, DiagnosticDescriptor descriptor, Location?location = null) { var diagnostic = Diagnostic.Create(descriptor, location ?? Location.None); context.ReportDiagnostic(diagnostic); }
private void HandleNode(GeneratorExecutionContext context, AttributeSyntax attributeNode, Compilation compilation, INamedTypeSymbol attributeSymbol) { var semanticModel = compilation.GetSemanticModel(attributeNode.SyntaxTree); var currentAttributeSymbol = semanticModel.GetSymbol <IMethodSymbol>(attributeNode, context.CancellationToken)?.ContainingType; if (!SymbolEqualityComparer.Default.Equals(attributeSymbol, currentAttributeSymbol)) { return; } var typeNode = attributeNode.Parent?.Parent as TypeDeclarationSyntax; if (typeNode is not RecordDeclarationSyntax && typeNode is not ClassDeclarationSyntax && typeNode is not StructDeclarationSyntax) { context.ReportDiagnostic(Diagnostic.Create( "YOUSEI01", "Generation", "Attribute must be applied to class, record or struct type.", DiagnosticSeverity.Error, DiagnosticSeverity.Error, true, 0, false, location: attributeNode.GetLocation())); return; } if (!typeNode.Modifiers.Any(SyntaxKind.PartialKeyword)) { context.ReportDiagnostic(Diagnostic.Create( "YOUSEI02", "Generation", "Type must be partial.", DiagnosticSeverity.Error, DiagnosticSeverity.Error, true, 0, false, location: typeNode.GetLocation())); return; } var type = semanticModel.GetDeclaredSymbol(typeNode); if (type is null) { context.ReportDiagnostic(Diagnostic.Create( "YOUSEI04", "Generation", "Type not resolvable.", DiagnosticSeverity.Error, DiagnosticSeverity.Error, true, 0, false, location: typeNode.GetLocation())); return; } var attributeData = type .GetAttributes() .First(o => SymbolEqualityComparer.Default.Equals(o.AttributeClass, attributeSymbol)); if (attributeData.ConstructorArguments.Length != 1) { context.ReportDiagnostic(Diagnostic.Create( "YOUSEI03", "Generation", "Wrong argument count.", DiagnosticSeverity.Error, DiagnosticSeverity.Error, true, 0, false, location: attributeNode.GetLocation())); return; } var targetType = attributeData.ConstructorArguments[0].Value as INamedTypeSymbol; if (targetType is null) { context.ReportDiagnostic(Diagnostic.Create( "YOUSEI04", "Generation", "No target type given.", DiagnosticSeverity.Error, DiagnosticSeverity.Error, true, 0, false, location: attributeNode.GetLocation())); return; } var properties = targetType.GetMembers() .OfType <IPropertySymbol>(); var typeKind = typeNode switch { ClassDeclarationSyntax => "class", RecordDeclarationSyntax => "record", StructDeclarationSyntax => "struct", _ => throw new NotSupportedException(), }; var sb = new StringBuilder(); sb.AppendLine($"namespace {type.ContainingNamespace} {{"); sb.AppendLine($" partial {typeKind} {type.Name} {{"); foreach (var prop in properties) { sb.AppendLine($" public Yousei.Shared.IParameter<{prop.Type}> {prop.Name} {{ get; init; }}"); } sb.AppendLine($" public async System.Threading.Tasks.Task<global::{targetType}> Resolve(Yousei.Shared.IFlowContext context)"); sb.AppendLine($" => new() {{"); foreach (var prop in properties) { sb.AppendLine($" {prop.Name} = await Resolve({prop.Name}, context),"); } sb.AppendLine($" }};"); sb.AppendLine($" private async System.Threading.Tasks.Task<T> Resolve<T>(Yousei.Shared.IParameter<T> parameter, Yousei.Shared.IFlowContext context) {{"); sb.AppendLine($" if(parameter is null)"); sb.AppendLine($" return default;"); sb.AppendLine($" return await parameter.Resolve(context);"); sb.AppendLine($" }}"); sb.AppendLine($" }}"); sb.AppendLine($"}}"); var source = SourceText.From(sb.ToString(), Encoding.UTF8); context.AddSource($"{type}.g.cs", source); }
/// <summary> /// Called to perform source generation. A generator can use the context to add source files via the AddSource(String, SourceText) method. /// </summary> /// <param name="context">The context which provides access to the current compilation and allows manipulation of the output.</param> public void Execute(GeneratorExecutionContext context) { try { context.LogInfo($"Starting source generation for Assembly=[{context.Compilation.Assembly.Name}]"); var stopwatch = Stopwatch.StartNew(); // Scan through the assembly and gather all types which should have property bags generated. var containerTypeSymbols = ContainerTypeUtility.GetPropertyContainerTypes(context.Compilation.Assembly); var propertyBags = containerTypeSymbols.Select(containerTypeSymbol => new PropertyBagDefinition(containerTypeSymbol)).ToList(); if (propertyBags.Count != 0) { var namespaceDeclarationSyntax = SyntaxFactory.NamespaceDeclaration(SyntaxFactory.ParseName("Unity.Properties.Generated")); var usingSystemReflectionSyntax = SyntaxFactory.UsingDirective(SyntaxFactory.ParseName("System.Reflection")) .WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia($"#if !{Defines.NET_DOTS}")) .WithTrailingTrivia(SyntaxFactory.ParseTrailingTrivia("#endif")); foreach (var propertyBag in propertyBags) { if (!propertyBag.IsValidPropertyBag) { var rule = new DiagnosticDescriptor( "SGP002", "Unable to generate PropertyBag", $"Unable to generate PropertyBag for Type=[{propertyBag.ContainerType}]. The type is inaccessible due to its protection level. The type must be flagged as 'public' or 'internal.", "Source Generator", DiagnosticSeverity.Warning, true, string.Empty); context.ReportDiagnostic(Diagnostic.Create(rule, propertyBag.ContainerType.GetSyntaxLocation())); continue; } foreach (var property in propertyBag.GetPropertyMembers().Where(p => !p.IsValidProperty)) { var rule = new DiagnosticDescriptor( "SGP003", "Unable to generate Property", $"Unable to generate Property=[{property.PropertyName}] with Type=[{property.MemberType}] for Container=[{propertyBag.ContainerType}]. The member type is inaccessible due to its protection level. The member type must be flagged as 'public' or 'internal.", "Source Generator", DiagnosticSeverity.Warning, true, string.Empty); context.ReportDiagnostic(Diagnostic.Create(rule, propertyBag.ContainerType.GetSyntaxLocation())); } var propertyBagDeclarationSyntax = PropertyBagFactory.CreatePropertyBagClassDeclarationSyntax(propertyBag); var propertyBagCompilationUnitSyntax = SyntaxFactory.CompilationUnit(); if (propertyBag.UsesReflection) { propertyBagCompilationUnitSyntax = propertyBagCompilationUnitSyntax.AddUsings(usingSystemReflectionSyntax); } propertyBagCompilationUnitSyntax = propertyBagCompilationUnitSyntax.AddMembers(namespaceDeclarationSyntax.AddMembers(propertyBagDeclarationSyntax)); propertyBagCompilationUnitSyntax = propertyBagCompilationUnitSyntax.NormalizeWhitespace(); var propertyBagHint = propertyBag.PropertyBagClassName; var propertyBagPath = context.GetGeneratedDebugSourcePath(propertyBagHint); var propertyBagSourceText = propertyBagCompilationUnitSyntax.GetTextUtf8(); File.WriteAllText(propertyBagPath, propertyBagSourceText); context.AddSource(propertyBagHint, propertyBagSourceText); } var registryDeclarationSyntax = PropertyBagRegistryFactory.CreatePropertyBagRegistryClassDeclarationSyntax(propertyBags); var registryCompilationUnitSyntax = SyntaxFactory.CompilationUnit(); registryCompilationUnitSyntax = registryCompilationUnitSyntax.AddMembers(namespaceDeclarationSyntax.AddMembers(registryDeclarationSyntax)); registryCompilationUnitSyntax = registryCompilationUnitSyntax.NormalizeWhitespace(); var propertyBagRegistryHint = "PropertyBagRegistry"; var propertyBagRegistryPath = context.GetGeneratedDebugSourcePath(propertyBagRegistryHint); var propertyBagRegistrySourceText = registryCompilationUnitSyntax.GetTextUtf8(); File.WriteAllText(propertyBagRegistryPath, propertyBagRegistrySourceText); context.AddSource(propertyBagRegistryHint, propertyBagRegistrySourceText); } context.LogInfo($"Finished source generation for Assembly=[{context.Compilation.Assembly.Name}] with {propertyBags.Count} property bags in {stopwatch.ElapsedMilliseconds}ms"); } catch (Exception exception) { var rule = new DiagnosticDescriptor( "SGP001", "Unknown Exception", exception.ToString(), "Source Generator", DiagnosticSeverity.Error, true, string.Empty); context.ReportDiagnostic(Diagnostic.Create(rule, context.Compilation.SyntaxTrees.First().GetRoot().GetLocation())); } }
private static Dictionary <string, BuilderToGenerate> DetermineBuildersToGenerate(GeneratorExecutionContext context, INamedTypeSymbol generateDataBuilderAttributeType) { var builders = new Dictionary <string, BuilderToGenerate>(); foreach (var inputDocument in context.Compilation.SyntaxTrees) { context.CancellationToken.ThrowIfCancellationRequested(); var typeNodes = inputDocument.GetRoot() .DescendantNodesAndSelf(n => n is CompilationUnitSyntax || n is NamespaceDeclarationSyntax || n is TypeDeclarationSyntax) .OfType <TypeDeclarationSyntax>(); var semanticModel = context.Compilation.GetSemanticModel(inputDocument); foreach (var typeNode in typeNodes) { if (!typeNode.AttributeLists.ContainsAttributeType(semanticModel, generateDataBuilderAttributeType, exactMatch: true)) { continue; } var typeSymbol = semanticModel.GetDeclaredSymbol(typeNode); if (typeSymbol == null) { continue; } var generationBlocked = false; if (typeSymbol.IsAbstract) { context.ReportDiagnostic(Diagnostic.Create(GeneratorOnAbstractDiagnostic, typeSymbol.Locations.First(), typeSymbol.Name)); generationBlocked = true; } if (typeNode.Modifiers.Any(m => m.Kind() == SyntaxKind.PartialKeyword)) { context.ReportDiagnostic(Diagnostic.Create(GeneratorOnPartialDiagnostic, typeNode.GetLocation(), typeSymbol.Name)); generationBlocked = true; } if (generationBlocked) { continue; } string typeFullMetadataName = typeSymbol.GetFullMetadataName(); if (!builders.TryGetValue(typeFullMetadataName, out var builder)) { builder = new BuilderToGenerate( typeSymbol.ContainingNamespace?.GetFullMetadataName(), typeSymbol.Name, typeNode, typeSymbol.DeclaredAccessibility); IMethodSymbol?constructorToUse = null; foreach (var typeSymbolConstructor in typeSymbol.Constructors) { if (typeSymbolConstructor.IsStatic) { continue; } if (typeSymbolConstructor.Parameters.Length > (constructorToUse?.Parameters.Length ?? 0)) { constructorToUse = typeSymbolConstructor; } } builder.ConstructorToUse = constructorToUse; builders.Add(typeFullMetadataName, builder); } builder.Properties.AddRange( typeSymbol .GetMembers() .Concat(typeSymbol.GetBaseTypes().SelectMany(t => t.GetMembers())) .OfType <IPropertySymbol>() .Where(m => m.DeclaredAccessibility == Accessibility.Public && !m.IsReadOnly && !m.IsIndexer && !m.IsStatic) .Select(property => new PropertyToGenerate( $"_{property.Name.Substring(0, 1).ToLower()}{property.Name.Substring(1)}", property.Name, property.Type, DetermineNullability(semanticModel, property))) ); } } return(builders); }
public void Execute(GeneratorExecutionContext context) { if (context.SyntaxReceiver is not ConfigurationTemplateInterfaceSyntaxReceiver receiver) { return; } var compilation = context.Compilation; var types = new ConfigurationTypes(compilation); if (!types.CheckContext(context)) { return; } foreach (var ifaceSyntax in receiver.CandidateInterfaces) { var model = compilation.GetSemanticModel(ifaceSyntax.SyntaxTree); var ifaceSymbol = model.GetDeclaredSymbol(ifaceSyntax, context.CancellationToken); if (ifaceSymbol == null) { continue; } if (!ifaceSymbol.GetAttributes() .Any(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, types.InputConfigurationAttribute))) { continue; } var diagnostics = Analyzers.AsParallel() .SelectMany(a => a.Analyze(context.Compilation, model, ifaceSyntax, context.CancellationToken)) .ToList(); foreach (var diag in diagnostics) { context.ReportDiagnostic(diag); } if (diagnostics.Any()) { return; } var configProperties = new List <(INamedTypeSymbol, IPropertySymbol)>(); var inputProperties = new List <(INamedTypeSymbol, IPropertySymbol)>(); foreach (var childIface in ifaceSymbol.AllInterfaces.Reverse().Concat(new[] { ifaceSymbol })) { // No need to check if child interfaces are partial because we only add to the root interface. foreach (var member in childIface.GetMembers()) { if (member is IMethodSymbol accessor && accessor.AssociatedSymbol is IPropertySymbol) { continue; } bool isConfigOption = member.GetAttributes() .Where(attr => attr?.AttributeClass? .Equals(types.ConfigurationOptionAttribute, SymbolEqualityComparer.Default) == true) .Any(); bool isInputOption = member.GetAttributes() .Where(attr => attr?.AttributeClass? .Equals(types.InputOptionAttribute, SymbolEqualityComparer.Default) == true) .Any(); // case where neither/both handled by analyzer guards above. if (isConfigOption && member is IPropertySymbol optionProperty) { configProperties.Add((childIface, optionProperty)); } else if (isInputOption && member is IPropertySymbol inputProperty) { inputProperties.Add((childIface, inputProperty)); } } } string classSource = GenerateSource(ifaceSymbol, configProperties, inputProperties, types); context.AddSource($"{ifaceSymbol.Name}_InputConfigurationSection.g.cs", SourceText.From(classSource, Encoding.UTF8)); } }
internal void Generate(GeneratorExecutionContext context) { try { var validPlatform = PlatformHelper.IsValidPlatform(context); var isDesignTime = DesignTimeHelper.IsDesignTime(context); var isApplication = PlatformHelper.IsApplication(context); if (validPlatform && !isDesignTime) { if (isApplication) { _cancellationToken = context.CancellationToken; _projectFullPath = context.GetMSBuildPropertyValue("MSBuildProjectFullPath"); _projectDirectory = Path.GetDirectoryName(_projectFullPath) ?? throw new InvalidOperationException($"MSBuild property MSBuildProjectFullPath value {_projectFullPath} is not valid"); // Defaults to 'false' _ = bool.TryParse(context.GetMSBuildPropertyValue("UnoXamlResourcesTrimming"), out _xamlResourcesTrimming); _baseIntermediateOutputPath = context.GetMSBuildPropertyValue("BaseIntermediateOutputPath"); _intermediatePath = Path.Combine( _projectDirectory, _baseIntermediateOutputPath ); _assemblyName = context.GetMSBuildPropertyValue("AssemblyName"); _defaultNamespace = context.GetMSBuildPropertyValue("RootNamespace"); _namedSymbolsLookup = context.Compilation.GetSymbolNameLookup(); _bindableAttributeSymbol = FindBindableAttributes(); _dependencyPropertySymbol = context.Compilation.GetTypeByMetadataName(XamlConstants.Types.DependencyProperty); _dependencyObjectSymbol = context.Compilation.GetTypeByMetadataName(XamlConstants.Types.DependencyObject); _javaObjectSymbol = context.Compilation.GetTypeByMetadataName("Java.Lang.Object"); _nsObjectSymbol = context.Compilation.GetTypeByMetadataName("Foundation.NSObject"); _nonBindableSymbol = context.Compilation.GetTypeByMetadataName("Windows.UI.Xaml.Data.NonBindableAttribute"); _resourceDictionarySymbol = context.Compilation.GetTypeByMetadataName("Windows.UI.Xaml.ResourceDictionary"); _currentModule = context.Compilation.SourceModule; var modules = from ext in context.Compilation.ExternalReferences let sym = context.Compilation.GetAssemblyOrModuleSymbol(ext) as IAssemblySymbol where sym != null from module in sym.Modules select module; modules = modules.Concat(context.Compilation.SourceModule); context.AddSource("BindableMetadata", GenerateTypeProviders(modules)); GenerateLinkerSubstitutionDefinition(); } else { context.AddSource("BindableMetadata", $"// validPlatform: {validPlatform} designTime:{isDesignTime} isApplication:{isApplication}"); } } } catch (OperationCanceledException) { throw; } catch (Exception e) { string?message = e.Message + e.StackTrace; if (e is AggregateException) { message = (e as AggregateException)?.InnerExceptions.Select(ex => ex.Message + e.StackTrace).JoinBy("\r\n"); } #if NETSTANDARD var diagnostic = Diagnostic.Create( XamlCodeGenerationDiagnostics.GenericXamlErrorRule, null, $"Failed to generate type providers. ({e.Message})"); context.ReportDiagnostic(diagnostic); #else Console.WriteLine("Failed to generate type providers.", new Exception("Failed to generate type providers." + message, e)); #endif } }
public void Execute(GeneratorExecutionContext context) { context.ReportDiagnostic( Diagnostic.Create( DiagnosticDescriptors.Warning, Location.None, $"ISourceGenerator.Execute {Assembly.GetExecutingAssembly().Location}")); // the generator infrastructure will create a receiver and populate it // we can retrieve the populated instance via the context if (context.SyntaxContextReceiver is not MySyntaxReceiver syntaxReceiver) { return; } List <(string GeneratorName, HbsLoadType loadType, AdditionalText file)> templates = GetLoadOptions(context).Where(r => "AutoInterfaceImplement".Equals(r.GeneratorName)).ToList(); var startupTemplateFile = templates.FirstOrDefault(r => r.loadType.Equals(HbsLoadType.Startup)).file; var partialTemplateFiles = templates.Where(r => r.loadType.Equals(HbsLoadType.Partial)).Select(r => r.file); if (startupTemplateFile is null) { return; } foreach (var partialTemplateFile in partialTemplateFiles) { var partialTemplateName = Path.GetFileNameWithoutExtension(partialTemplateFile.Path); var partialTemplateText = partialTemplateFile.GetText()?.ToString() ?? string.Empty; Handlebars.RegisterTemplate(partialTemplateName, partialTemplateText); } Handlebars.RegisterHelper("ifCond", (output, options, context, arguments) => { if (arguments.Length < 3) { return; } var arg0 = arguments[0]; var arg1 = arguments[1]; var arg2 = arguments[2]; switch (arg1) { case "Equals": if (arg0.Equals(arg2)) { options.Template(output, context); } else { options.Inverse(output, context); } break; } }); var startupTemplateText = startupTemplateFile.GetText()?.ToString() ?? string.Empty; if (string.IsNullOrWhiteSpace(startupTemplateText)) { context.ReportDiagnostic( Diagnostic.Create( DiagnosticDescriptors.Warning, Location.None, $"template file '{startupTemplateFile.Path}' is empty")); return; } var startupTemplate = Handlebars.Compile(startupTemplateText); var autoImplementationInterfaces = syntaxReceiver.AutoImplementationInterfaces; var classHbsContexts = new List <ClassHbsContext>(); foreach (var namedTypeSymbol in autoImplementationInterfaces) { var classHbsContext = new ClassHbsContext { NameSpaceQualifiedIdentifier = namedTypeSymbol.ContainingNamespace.ToDisplayString(), Identifier = namedTypeSymbol.Name, Properties = new List <PropertyHbsContext>() }; var propertySymbols = namedTypeSymbol.AllInterfaces .Concat(new INamedTypeSymbol[] { namedTypeSymbol }) .SelectMany(interfaceSymbol => interfaceSymbol.GetMembers() .OfType <IPropertySymbol>()); var propertyInfos = propertySymbols.Select( propertySymbol => { var accessibilities = new Accessibility[] { propertySymbol.DeclaredAccessibility, propertySymbol.GetMethod?.DeclaredAccessibility ?? Accessibility.Public, propertySymbol.SetMethod?.DeclaredAccessibility ?? Accessibility.Public }; var isPublic = accessibilities.All(a => a.Equals(Accessibility.Public)); var accessorList = (propertySymbol.GetMethod, propertySymbol.SetMethod) switch { (IMethodSymbol get, IMethodSymbol set) => new HashSet <string>() { "get", "set" }, (IMethodSymbol get, null) => new HashSet <string>() { "get" }, (null, IMethodSymbol set) => new HashSet <string>() { "set" }, (_, _) => new HashSet <string>() }; return(new PropertyDeclaration { IsPublic = isPublic, AccessorList = accessorList, IsClassMember = false, IsMerged = false, Symbol = propertySymbol }); }).ToList(); var classMembers = propertyInfos .Where(r => r.IsPublic) .GroupBy(r => r.Symbol.Name) .Select(g1 => g1 .GroupBy(r => r.Symbol.Type.ToDisplayString()) .Select(g2 => new { PropertyDeclaration = g2.First(), InterfaceCount = g2.Count() }) .OrderByDescending(r => r.InterfaceCount) .FirstOrDefault().PropertyDeclaration) .ToList(); (from c in classMembers join p in propertyInfos.Where(r => r.IsPublic) on new { c.Symbol.Name, Type = c.Symbol.Type.ToDisplayString() } equals new { p.Symbol.Name, Type = p.Symbol.Type.ToDisplayString() } into g select MergeAccessorList(c, g)) .ToList(); propertyInfos = propertyInfos.Where(p => !p.IsMerged).ToList(); foreach (var propertyInfo in propertyInfos) { var propertyHbsContext = new PropertyHbsContext { Accessors = propertyInfo.AccessorList, TypeIdentifier = propertyInfo.Symbol.Type.ToDisplayString() }; if (propertyInfo.IsClassMember) { propertyHbsContext.AccessModifiers = "public "; propertyHbsContext.Identifier = propertyInfo.Symbol.Name; } else { propertyHbsContext.AccessModifiers = string.Empty; propertyHbsContext.Identifier = propertyInfo.Symbol.ToDisplayString(); } classHbsContext.Properties.Add(propertyHbsContext); } classHbsContexts.Add(classHbsContext); var classSourceCode = startupTemplate(classHbsContext); context.AddSource($"{classHbsContext.NameSpaceQualifiedIdentifier}.AutoImplementation{classHbsContext.Identifier}.cs", SourceText.From(classSourceCode, Encoding.UTF8)); } }
public void Execute(GeneratorExecutionContext context) { if (context.Compilation is not CSharpCompilation compilation) { context.ReportDiagnostic( Diagnostic.Create( DescriptorParameterError, Location.None, "incompatible language: " + context.Compilation.Language)); return; } try { context.AnalyzerConfigOptions.GlobalOptions.TryGetValue(BuildPropertyKeyPrefix + "ServiceUrl", out var serviceUrl); var isServiceUrlMissing = String.IsNullOrWhiteSpace(serviceUrl); var graphQlSchemaFiles = context.AdditionalFiles.Where(f => Path.GetFileName(f.Path).EndsWith(".gql.schema.json", StringComparison.OrdinalIgnoreCase)).ToList(); var indexRegexScalarFieldTypeMappingProviderConfigurationFile = graphQlSchemaFiles.FindIndex(f => String.Equals(Path.GetFileName(f.Path), FileNameRegexScalarFieldTypeMappingProviderConfiguration, StringComparison.OrdinalIgnoreCase)); ICollection <RegexScalarFieldTypeMappingRule> regexScalarFieldTypeMappingProviderRules = null; if (indexRegexScalarFieldTypeMappingProviderConfigurationFile != -1) { regexScalarFieldTypeMappingProviderRules = JsonConvert.DeserializeObject <ICollection <RegexScalarFieldTypeMappingRule> >( graphQlSchemaFiles[indexRegexScalarFieldTypeMappingProviderConfigurationFile].GetText().ToString()); graphQlSchemaFiles.RemoveAt(indexRegexScalarFieldTypeMappingProviderConfigurationFile); } var isSchemaFileSpecified = graphQlSchemaFiles.Any(); if (isServiceUrlMissing && !isSchemaFileSpecified) { context.ReportDiagnostic( Diagnostic.Create( DescriptorInfo, Location.None, "Neither \"GraphQlClientGenerator_ServiceUrl\" parameter nor GraphQL JSON schema additional file specified; terminating. ")); return; } if (!isServiceUrlMissing && isSchemaFileSpecified) { context.ReportDiagnostic( Diagnostic.Create( DescriptorParameterError, Location.None, "\"GraphQlClientGenerator_ServiceUrl\" parameter and GraphQL JSON schema additional file are mutually exclusive. ")); return; } context.AnalyzerConfigOptions.GlobalOptions.TryGetValue(BuildPropertyKeyPrefix + "Namespace", out var @namespace); if (String.IsNullOrWhiteSpace(@namespace)) { var root = (CompilationUnitSyntax)compilation.SyntaxTrees.FirstOrDefault()?.GetRoot(); var namespaceIdentifier = (IdentifierNameSyntax)root?.Members.OfType <NamespaceDeclarationSyntax>().FirstOrDefault()?.Name; if (namespaceIdentifier == null) { context.ReportDiagnostic( Diagnostic.Create( DescriptorParameterError, Location.None, "\"GraphQlClientGenerator_Namespace\" required")); return; } @namespace = namespaceIdentifier.Identifier.ValueText; context.ReportDiagnostic( Diagnostic.Create( DescriptorInfo, Location.None, $"\"GraphQlClientGenerator_Namespace\" not specified; using \"{@namespace}\"")); } var configuration = new GraphQlGeneratorConfiguration { TreatUnknownObjectAsScalar = true }; context.AnalyzerConfigOptions.GlobalOptions.TryGetValue(BuildPropertyKeyPrefix + "ClassPrefix", out var classPrefix); configuration.ClassPrefix = classPrefix; context.AnalyzerConfigOptions.GlobalOptions.TryGetValue(BuildPropertyKeyPrefix + "ClassSuffix", out var classSuffix); configuration.ClassSuffix = classSuffix; if (compilation.LanguageVersion >= LanguageVersion.CSharp6) { configuration.CSharpVersion = compilation.Options.NullableContextOptions == NullableContextOptions.Disable ? CSharpVersion.Newest : CSharpVersion.NewestWithNullableReferences; } var currentParameterName = "IncludeDeprecatedFields"; context.AnalyzerConfigOptions.GlobalOptions.TryGetValue(BuildPropertyKeyPrefix + currentParameterName, out var includeDeprecatedFieldsRaw); configuration.IncludeDeprecatedFields = !String.IsNullOrWhiteSpace(includeDeprecatedFieldsRaw) && Convert.ToBoolean(includeDeprecatedFieldsRaw); currentParameterName = "HttpMethod"; if (!context.AnalyzerConfigOptions.GlobalOptions.TryGetValue(BuildPropertyKeyPrefix + currentParameterName, out var httpMethod)) { httpMethod = "POST"; } currentParameterName = "CommentGeneration"; context.AnalyzerConfigOptions.GlobalOptions.TryGetValue(BuildPropertyKeyPrefix + currentParameterName, out var commentGenerationRaw); configuration.CommentGeneration = String.IsNullOrWhiteSpace(commentGenerationRaw) ? CommentGenerationOption.CodeSummary : (CommentGenerationOption)Enum.Parse(typeof(CommentGenerationOption), commentGenerationRaw, true); currentParameterName = "FloatTypeMapping"; context.AnalyzerConfigOptions.GlobalOptions.TryGetValue(BuildPropertyKeyPrefix + currentParameterName, out var floatTypeMappingRaw); configuration.FloatTypeMapping = String.IsNullOrWhiteSpace(floatTypeMappingRaw) ? FloatTypeMapping.Decimal : (FloatTypeMapping)Enum.Parse(typeof(FloatTypeMapping), floatTypeMappingRaw, true); currentParameterName = "BooleanTypeMapping"; context.AnalyzerConfigOptions.GlobalOptions.TryGetValue(BuildPropertyKeyPrefix + currentParameterName, out var booleanTypeMappingRaw); configuration.BooleanTypeMapping = String.IsNullOrWhiteSpace(booleanTypeMappingRaw) ? BooleanTypeMapping.Boolean : (BooleanTypeMapping)Enum.Parse(typeof(BooleanTypeMapping), booleanTypeMappingRaw, true); currentParameterName = "IdTypeMapping"; context.AnalyzerConfigOptions.GlobalOptions.TryGetValue(BuildPropertyKeyPrefix + currentParameterName, out var idTypeMappingRaw); configuration.IdTypeMapping = String.IsNullOrWhiteSpace(idTypeMappingRaw) ? IdTypeMapping.Guid : (IdTypeMapping)Enum.Parse(typeof(IdTypeMapping), idTypeMappingRaw, true); currentParameterName = "JsonPropertyGeneration"; context.AnalyzerConfigOptions.GlobalOptions.TryGetValue(BuildPropertyKeyPrefix + currentParameterName, out var jsonPropertyGenerationRaw); configuration.JsonPropertyGeneration = String.IsNullOrWhiteSpace(jsonPropertyGenerationRaw) ? JsonPropertyGenerationOption.CaseInsensitive : (JsonPropertyGenerationOption)Enum.Parse(typeof(JsonPropertyGenerationOption), jsonPropertyGenerationRaw, true); currentParameterName = "EnumValueNaming"; context.AnalyzerConfigOptions.GlobalOptions.TryGetValue(BuildPropertyKeyPrefix + currentParameterName, out var enumValueNamingRaw); configuration.EnumValueNaming = String.IsNullOrWhiteSpace(enumValueNamingRaw) ? EnumValueNamingOption.CSharp : (EnumValueNamingOption)Enum.Parse(typeof(EnumValueNamingOption), enumValueNamingRaw, true); currentParameterName = "CustomClassMapping"; context.AnalyzerConfigOptions.GlobalOptions.TryGetValue(BuildPropertyKeyPrefix + currentParameterName, out var customClassMappingRaw); if (!KeyValueParameterParser.TryGetCustomClassMapping( customClassMappingRaw?.Split(new[] { '|', ';', ' ' }, StringSplitOptions.RemoveEmptyEntries), out var customMapping, out var customMappingParsingErrorMessage)) { context.ReportDiagnostic(Diagnostic.Create(DescriptorParameterError, Location.None, customMappingParsingErrorMessage)); return; } foreach (var kvp in customMapping) { configuration.CustomClassNameMapping.Add(kvp); } currentParameterName = "Headers"; context.AnalyzerConfigOptions.GlobalOptions.TryGetValue(BuildPropertyKeyPrefix + currentParameterName, out var headersRaw); if (!KeyValueParameterParser.TryGetCustomHeaders( headersRaw?.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries), out var headers, out var headerParsingErrorMessage)) { context.ReportDiagnostic(Diagnostic.Create(DescriptorParameterError, Location.None, headerParsingErrorMessage)); return; } currentParameterName = "ScalarFieldTypeMappingProvider"; if (context.AnalyzerConfigOptions.GlobalOptions.TryGetValue(BuildPropertyKeyPrefix + currentParameterName, out var scalarFieldTypeMappingProviderName)) { if (regexScalarFieldTypeMappingProviderRules != null) { context.ReportDiagnostic(Diagnostic.Create(DescriptorParameterError, Location.None, "\"GraphQlClientGenerator_ScalarFieldTypeMappingProvider\" and RegexScalarFieldTypeMappingProviderConfiguration are mutually exclusive")); return; } if (String.IsNullOrWhiteSpace(scalarFieldTypeMappingProviderName)) { context.ReportDiagnostic(Diagnostic.Create(DescriptorParameterError, Location.None, "\"GraphQlClientGenerator_ScalarFieldTypeMappingProvider\" value missing")); return; } var scalarFieldTypeMappingProviderType = Type.GetType(scalarFieldTypeMappingProviderName); if (scalarFieldTypeMappingProviderType == null) { context.ReportDiagnostic(Diagnostic.Create(DescriptorParameterError, Location.None, $"ScalarFieldTypeMappingProvider \"{scalarFieldTypeMappingProviderName}\" not found")); return; } var scalarFieldTypeMappingProvider = (IScalarFieldTypeMappingProvider)Activator.CreateInstance(scalarFieldTypeMappingProviderType); configuration.ScalarFieldTypeMappingProvider = scalarFieldTypeMappingProvider; } else if (regexScalarFieldTypeMappingProviderRules?.Count > 0) { configuration.ScalarFieldTypeMappingProvider = new RegexScalarFieldTypeMappingProvider(regexScalarFieldTypeMappingProviderRules); } var graphQlSchemas = new List <(string TargetFileName, GraphQlSchema Schema)>(); if (isSchemaFileSpecified) { foreach (var schemaFile in graphQlSchemaFiles) { var targetFileName = Path.GetFileNameWithoutExtension(schemaFile.Path) + ".cs"; graphQlSchemas.Add((targetFileName, GraphQlGenerator.DeserializeGraphQlSchema(schemaFile.GetText().ToString()))); } } else { graphQlSchemas.Add((FileNameGraphQlClientSource, GraphQlGenerator.RetrieveSchema(new HttpMethod(httpMethod), serviceUrl, headers).GetAwaiter().GetResult())); context.ReportDiagnostic( Diagnostic.Create( DescriptorInfo, Location.None, "GraphQl schema fetched successfully from " + serviceUrl)); } var generator = new GraphQlGenerator(configuration); foreach (var(targetFileName, schema) in graphQlSchemas) { var builder = new StringBuilder(); using (var writer = new StringWriter(builder)) generator.WriteFullClientCSharpFile(schema, @namespace, writer); context.AddSource(targetFileName, SourceText.From(builder.ToString(), Encoding.UTF8)); } context.ReportDiagnostic( Diagnostic.Create( DescriptorInfo, Location.None, "GraphQlClientGenerator task completed successfully. ")); } catch (Exception exception) { context.ReportDiagnostic(Diagnostic.Create(DescriptorGenerationError, Location.None, exception.Message)); } }
protected void AddSource(ClassBuilder builder) { _context.ReportDiagnostic(Diagnostic.Create(Descriptors.CreatedClass, null, builder.FullyQualifiedName)); _context.AddSource(builder.FullyQualifiedName, builder.Build()); }
/// <inheritdoc/> public void Execute(GeneratorExecutionContext context) { // Add the ElementFactory model source to compilation. context.AddSource("Svg_Model", SourceText.From(ModelText, Encoding.UTF8)); // Check is we have our SyntaxReceiver object used to filter compiled code. if (!(context.SyntaxReceiver is SyntaxReceiver receiver)) { return; } var options = (context.Compilation as CSharpCompilation)?.SyntaxTrees[0].Options as CSharpParseOptions; var compilation = context.Compilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(SourceText.From(ModelText, Encoding.UTF8), options)); var elementFactoryAttribute = compilation.GetTypeByMetadataName("Svg.ElementFactoryAttribute"); if (elementFactoryAttribute is null) { context.ReportDiagnostic(Diagnostic.Create(ErrorDescriptor, Location.None, "Could not get Svg.ElementFactoryAttribute metadata.")); return; } var svgElementBaseSymbol = compilation.GetTypeByMetadataName("Svg.SvgElement"); if (svgElementBaseSymbol is null) { context.ReportDiagnostic(Diagnostic.Create(ErrorDescriptor, Location.None, "Could not get Svg.SvgElement metadata.")); return; } List <INamedTypeSymbol> elementFactorySymbols = new(); List <INamedTypeSymbol> svgElementSymbols = new(); foreach (var candidateClass in receiver.CandidateClasses) { var semanticModel = compilation.GetSemanticModel(candidateClass.SyntaxTree); var namedTypeSymbol = semanticModel.GetDeclaredSymbol(candidateClass); if (namedTypeSymbol is null) { continue; } // Find classes with ElementFactory attribute. if (namedTypeSymbol.GetAttributes().Any(ad => ad?.AttributeClass?.Equals(elementFactoryAttribute, SymbolEqualityComparer.Default) ?? false)) { elementFactorySymbols.Add(namedTypeSymbol); continue; } // Find classes derived from SvgElement. if (!namedTypeSymbol.IsGenericType && HasBaseType(namedTypeSymbol, svgElementBaseSymbol)) { #pragma warning disable RS1024 // Compare symbols correctly if (!svgElementSymbols.Contains(namedTypeSymbol, SymbolEqualityComparer.Default)) #pragma warning restore RS1024 // Compare symbols correctly { svgElementSymbols.Add(namedTypeSymbol); } } } // Generate code for each class marked with ElementFactor attribute. foreach (var elementFactorySymbol in elementFactorySymbols) { try { ProcessClass(context, compilation, elementFactorySymbol, svgElementSymbols, svgElementBaseSymbol); } catch (Exception ex) { context.ReportDiagnostic(Diagnostic.Create(ErrorDescriptor, Location.None, ex.Message)); } } }
private Dictionary <string, List <GenerationInfos.PartialClass.Property.Validation> > GetValidValidationCalls(GeneratorExecutionContext context) { var compilation = context.Compilation; var returnList = new Dictionary <string, List <GenerationInfos.PartialClass.Property.Validation> >(); foreach (var invocation in _invocations) { var invocationModel = compilation.GetSemanticModel(invocation.SyntaxTree); var containingMethod = invocationModel.GetEnclosingSymbol(invocation.Parent.GetLocation().SourceSpan.Start); var containingClass = containingMethod.ContainingType.ToString(); var operation = invocationModel.GetOperation(invocation) as IInvocationOperation; var operationName = operation.TargetMethod.Name; var operationClass = operation.TargetMethod.ContainingType.ToString(); if (operationClass != "SaneWpf.Framework.Validations" || operationName != "Add") { continue; } var children = operation.Children.Cast <IArgumentOperation>().ToList(); var viewModelType = children[0].Parameter.ToString(); if (viewModelType != containingClass) { context.ReportDiagnostic(Diagnostic.Create(new DiagnosticDescriptor("SW002", "Instance must be of same type as ViewModel", "Instance must be of same type as ViewModel", "Error", DiagnosticSeverity.Error, true), invocation.GetLocation())); } var propertyExp = (SimpleLambdaExpressionSyntax)((ArgumentSyntax)children[1].Syntax).Expression; var memberAccess = (MemberAccessExpressionSyntax)propertyExp.Body; var fieldName = memberAccess.Name.ToString(); var validationPropertyType = operation.TargetMethod.TypeArguments[1].ToString(); var func = ((ArgumentSyntax)children[2].Syntax).Expression; string parameterName; string methodBody; if (func is IdentifierNameSyntax id) { methodBody = id.ToString() + "(param_0);"; parameterName = "param_0"; } else { var lambdaExpression = (SimpleLambdaExpressionSyntax)func; methodBody = lambdaExpression.Body.ToString(); parameterName = lambdaExpression.Parameter.ToString(); } var validationErrorExpression = (SimpleLambdaExpressionSyntax)((ArgumentSyntax)children[3].Syntax).Expression; var result = validationErrorExpression.Body.ToString(); var resultParameter = validationErrorExpression.Parameter.ToString(); var validation = new GenerationInfos.PartialClass.Property.Validation { MethodBody = methodBody, ParameterName = parameterName, ValidationErrorBody = result, ValidationErrorParameter = resultParameter, ParameterType = validationPropertyType, FieldName = fieldName }; if (returnList.TryGetValue(containingClass, out var list)) { list.Add(validation); } else { returnList.Add(containingClass, new List <GenerationInfos.PartialClass.Property.Validation> { validation }); } } return(returnList); }
public void Execute(GeneratorExecutionContext context) { if (!context.Compilation.ReferencedAssemblyNames.Any (ai => ai.Name.Equals("Silk.NET.Core", StringComparison.OrdinalIgnoreCase))) { context.ReportDiagnostic(Diagnostic.Create(Diagnostics.SilkNetCoreMissing, Location.None)); return; } if (context.SyntaxContextReceiver is not SyntaxReceiver receiver) { return; } var nativeApiAttribute = context.Compilation.GetTypeByMetadataName ("Silk.NET.Core.Native.NativeApiAttribute"); if (nativeApiAttribute is null) { return; } var pInvokeAttribute = context.Compilation.GetTypeByMetadataName("Silk.NET.Core.Native.PInvokeOverride"); if (pInvokeAttribute is null) { return; } var excludeFromOverrideAttribute = context.Compilation.GetTypeByMetadataName ("Silk.NET.Core.Native.ExcludeFromOverrideAttribute"); if (excludeFromOverrideAttribute is null) { return; } _nativeContextAttributes[pInvokeAttribute] = array => ((int)array[0].Value !, (string)array[1].Value !/* first return is just the lib target */, new PInvokeNativeContextOverride()); var marshalBuilder = new MarshalBuilder(); // begin | end marshalBuilder.Use(Middlewares.InjectMiddleware); marshalBuilder.Use(Middlewares.ParameterInitMiddleware); marshalBuilder.Use(Middlewares.StringMarshaller); marshalBuilder.Use(Middlewares.PinMiddleware); // post init | - marshalBuilder.Use(Middlewares.SpanMarshaller); marshalBuilder.Use(Middlewares.BoolMarshaller); marshalBuilder.Use(Middlewares.PinObjectMarshaller); // post pin marshalBuilder.Use(Middlewares.DelegateMarshaller); marshalBuilder.Use(Middlewares.GenericPointerMarshaller); // pre load | post load List <ITypeSymbol> processedSymbols = new List <ITypeSymbol>(); foreach (var group in receiver.ClassDeclarations.Select(x => (x.Item1, x.Item2, x.Item2.GetDeclaredSymbol(x.Item1))) .GroupBy(x => x.Item3, SymbolEqualityComparer.Default)) { try { var s = ProcessClassDeclaration ( group.Select(x => (x.Item1, x.Item2)), context, nativeApiAttribute, marshalBuilder, ref processedSymbols, excludeFromOverrideAttribute, (INamedTypeSymbol)group.Key ); if (s is null) { continue; } var name = $"{group.Key.Name}.{Guid.NewGuid()}.gen"; context.AddSource(name, SourceText.From(s, Encoding.UTF8)); // File.WriteAllText(@"C:\SILK.NET\src\Lab\" + name, s); } catch (Exception ex) { context.ReportDiagnostic ( Diagnostic.Create (Diagnostics.ProcessClassFailure, group.First().Item1.GetLocation(), ex.ToString()) ); } } }
private IEnumerable <TypeToGenerate> FindTypesToGenerate(SyntaxTree tree, SemanticModel model, GeneratorExecutionContext context, INamedTypeSymbol cssServiceType, INamedTypeSymbol cssServiceConfiguratorType) { var methodInvocations = tree.GetRoot().DescendantNodesAndSelf().OfType <InvocationExpressionSyntax>(); foreach (var invocation in methodInvocations) { var symbol = model.GetSymbolInfo(invocation).Symbol as IMethodSymbol; if (symbol is null || !invocation.ArgumentList.Arguments.Any()) { continue; } var isGetClassNames = SymbolEqualityComparer.Default.Equals(symbol.ContainingType, cssServiceType) && string.Equals(symbol.Name, "GetClassNames"); var isRegisterStyles = SymbolEqualityComparer.Default.Equals(symbol.ContainingType, cssServiceConfiguratorType) && string.Equals(symbol.Name, "RegisterStyles"); if (!isGetClassNames && !isRegisterStyles) { continue; } var typeToGenerate = isGetClassNames ? symbol.ReturnType : symbol.TypeArguments.Single(); var firstArgument = invocation.ArgumentList.Arguments.First().Expression; var expKind = firstArgument.Kind(); if (expKind != SyntaxKind.AnonymousObjectCreationExpression && expKind != SyntaxKind.ObjectCreationExpression && expKind != SyntaxKind.IdentifierName) { continue; // TODO: warning if argument type is weird } ITypeSymbol typeToUse; if (expKind == SyntaxKind.IdentifierName) { var idSyntax = firstArgument as IdentifierNameSyntax; typeToUse = model.GetTypeInfo(idSyntax.Identifier.Parent).Type; } else { typeToUse = model.GetSymbolInfo(firstArgument).Symbol.ContainingType; } if (typeToGenerate.TypeKind != TypeKind.Error && typeToGenerate.TypeKind != TypeKind.Unknown) { context.ReportDiagnostic(Diagnostic.Create("SCSS002", SharpCSS, $"Type '{typeToGenerate.Name}' is already defined and will not be generated.", DiagnosticSeverity.Info, DiagnosticSeverity.Info, true, 1, false)); continue; } var props = typeToUse.GetMembers().Where(m => m.Kind == SymbolKind.Property).ToList(); var propertiesToGenerate = new List <string>(props.Count); foreach (IPropertySymbol property in props) { if (!string.Equals($"{property.Type.ContainingNamespace}.{property.Type.Name}", StyleSetType, StringComparison.OrdinalIgnoreCase)) { context.ReportDiagnostic(Diagnostic.Create("SCSS001", SharpCSS, $"Property '{property.Name}' is not of type `{StyleSetType}` and will be ignore.", DiagnosticSeverity.Warning, DiagnosticSeverity.Warning, true, 4, false, location: property.Locations.First())); continue; } propertiesToGenerate.Add(property.Name); } yield return(new TypeToGenerate { Name = typeToGenerate.Name, Properties = propertiesToGenerate }); } }
public static void ReportInvalidClientName( GeneratorExecutionContext context, string clientName, string filePath) => context.ReportDiagnostic(_invalidClientName, clientName, filePath, new Location(1, 1));
public void Execute(GeneratorExecutionContext context) { if (!(context.SyntaxReceiver is DuckSyntaxInvocationReceiver receiver)) { return; } var duckableAttribute = context.Compilation.GetTypeByMetadataName("DuckableAttribute"); if (context.CancellationToken.IsCancellationRequested) { return; } var ducksFromInvocations = GetDucksFromInvocations(); var ducksFromVariableDeclarations = GetDucksFromVariableDeclarations(); var ducks = ducksFromInvocations .Concat(ducksFromVariableDeclarations) .Distinct() .ToArray(); if (context.CancellationToken.IsCancellationRequested) { return; } foreach (var(duckInterface, typeToDuck) in ducks) { var uniqueName = $"{duckInterface.ToGlobalName().Replace("global::", "")}_{typeToDuck.ToGlobalName().Replace("global::", "")}"; var properties = duckInterface .GetMembers() .OfType <IPropertySymbol>() .SelectMany(o => { var getter = o.GetMethod != null ? $" _{o.Name}Getter = () => value.{o.Name};" : string.Empty; var setter = o.SetMethod != null ? $" _{o.Name}Setter = o => value.{o.Name} = o;" : string.Empty; return(new[] { getter, setter }); }) .Where(o => !string.IsNullOrEmpty(o)) .JoinWithNewLine(); var methods = duckInterface .GetAllMembers() .GetPublicMethods() .Select(o => $" _{o.Name} = value.{o.Name};") .JoinWithNewLine(); var source = $@" using System; namespace {(duckInterface.ContainingNamespace.ToDisplayString())} {{ public partial class D{duckInterface.Name} {{ private D{duckInterface.Name}({typeToDuck.ToGlobalName()} value) {{ {properties} {methods} }} public static implicit operator D{duckInterface.Name}({typeToDuck.ToGlobalName()} value) {{ return new D{duckInterface.Name}(value); }} }} }} "; if (context.CancellationToken.IsCancellationRequested) { return; } context.AddSource(uniqueName, source.ToSourceText()); } IEnumerable <(ITypeSymbol DuckInteface, ITypeSymbol TypeToDuck)> GetDucksFromInvocations() { foreach (var invocation in receiver.Invocations) { if (context.CancellationToken.IsCancellationRequested) { yield break; } var semanticModel = context.Compilation.GetSemanticModel(invocation.SyntaxTree); var symbol = semanticModel.GetSpeculativeSymbolInfo(invocation.SpanStart, invocation, SpeculativeBindingOption.BindAsExpression); var call = symbol.CandidateSymbols.FirstOrDefault() as IMethodSymbol; if (call is null) { continue; } for (int i = 0; i < call.Parameters.Length; i++) { var parameter = call.Parameters[i]; if (!parameter.Type.Name.StartsWith("DI")) { continue; } var nameWithoutD = parameter.Type.Name.Substring(1); var duckInterface = context.Compilation .GetSymbolsWithName(o => o.EndsWith(nameWithoutD), SymbolFilter.Type, context.CancellationToken) .OfType <ITypeSymbol>() .FirstOrDefault(s => s .GetAttributes() .Any(attr => attr.AttributeClass.Equals(duckableAttribute))); if (duckInterface is null) { continue; } TypeSyntax argumentSyntax = null; switch (invocation.ArgumentList.Arguments[i].Expression) { case IdentifierNameSyntax name: argumentSyntax = name; break; case ObjectCreationExpressionSyntax ctor: argumentSyntax = ctor.Type; break; } if (argumentSyntax is null) { continue; } var speculativeArgumentSymbol = semanticModel .GetSpeculativeSymbolInfo(argumentSyntax.SpanStart, argumentSyntax, SpeculativeBindingOption.BindAsExpression); var duckableSymbol = speculativeArgumentSymbol.GetTypeSymbol(); var isDuckable = duckInterface.IsTypeDuckableTo(duckableSymbol); if (isDuckable.IsDuckable) { yield return(duckInterface, duckableSymbol); } else { context.ReportDiagnostic(Diagnostic.Create(DuckMappingCantBeDone, argumentSyntax.GetLocation(), duckInterface.Name, duckableSymbol.Name, isDuckable.MissingSymbols.Select(o => o.Name).JoinWithNewLine())); } } } } IEnumerable <(ITypeSymbol DuckInteface, ITypeSymbol TypeToDuck)> GetDucksFromVariableDeclarations() { foreach (var variableDeclaration in receiver.VariableDeclarations) { if (context.CancellationToken.IsCancellationRequested) { yield break; } var semanticModel = context.Compilation.GetSemanticModel(variableDeclaration.SyntaxTree); var nameWithoutD = variableDeclaration.Type.ToString().Substring(1); var duckInterface = context.Compilation .GetSymbolsWithName(o => o.EndsWith(nameWithoutD), SymbolFilter.Type, context.CancellationToken) .OfType <ITypeSymbol>() .FirstOrDefault(s => s .GetAttributes() .Any(attr => attr.AttributeClass.Equals(duckableAttribute))); if (duckInterface is null) { continue; } var value = variableDeclaration.DescendantNodes().OfType <EqualsValueClauseSyntax>().First().Value; var typeToDuckSymbol = semanticModel.GetSpeculativeSymbolInfo(value.SpanStart, value, SpeculativeBindingOption.BindAsExpression); var typeToDuck = typeToDuckSymbol.GetTypeSymbol(); if (typeToDuck is null) { continue; } yield return(duckInterface, typeToDuck); } } }
public void Execute(GeneratorExecutionContext context) { context.ReportDiagnostic(Diagnostic.Create(Descriptor, _produceLocation(context))); }
public void Report(Diagnostic diagnostic) { _context.ReportDiagnostic(diagnostic); }