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);
Пример #3
0
        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 }))
Пример #4
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);
                }
Пример #6
0
        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);
        }
Пример #7
0
        /// <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));
                }
            }
        }
Пример #8
0
        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
                        )
                    );
            }
        }
Пример #9
0
        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(@$ "
Пример #10
0
        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)));
 }
Пример #12
0
        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
                        )
                    );
            }
        }
Пример #13
0
 public static void ReportDiagnostic(this GeneratorExecutionContext context, DiagnosticSeverity severity, string text, SyntaxNode target)
 {
     context.ReportDiagnostic(severity, text, target.GetLocation());
 }
Пример #14
0
    public static void ReportDiagnostic(this GeneratorExecutionContext context, DiagnosticDescriptor descriptor, Location?location = null)
    {
        var diagnostic = Diagnostic.Create(descriptor, location ?? Location.None);

        context.ReportDiagnostic(diagnostic);
    }
Пример #15
0
        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));
            }
        }
Пример #19
0
            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));
            }
        }
Пример #21
0
    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));
        }
    }
Пример #22
0
 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));
                }
            }
        }
Пример #24
0
        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);
        }
Пример #25
0
        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));
Пример #28
0
        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);
                }
            }
        }
Пример #29
0
 public void Execute(GeneratorExecutionContext context)
 {
     context.ReportDiagnostic(Diagnostic.Create(Descriptor, _produceLocation(context)));
 }
Пример #30
0
 public void Report(Diagnostic diagnostic)
 {
     _context.ReportDiagnostic(diagnostic);
 }