예제 #1
0
        private static Docs?ParseDocs(GeneratorExecutionContext context)
        {
            Docs?docs = null;

            if (context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWin32InputDocPaths", out string?delimitedApiDocsPaths) &&
                !string.IsNullOrWhiteSpace(delimitedApiDocsPaths))
            {
                string[] apiDocsPaths = delimitedApiDocsPaths !.Split('|');
                if (apiDocsPaths.Length > 0)
                {
                    List <Docs> docsList = new(apiDocsPaths.Length);
                    foreach (string path in apiDocsPaths)
                    {
                        try
                        {
                            docsList.Add(Docs.Get(path));
                        }
                        catch (Exception e)
                        {
                            context.ReportDiagnostic(Diagnostic.Create(DocParsingError, null, path, e.Message));
                        }
                    }

                    docs = Docs.Merge(docsList);
                }
            }

            return(docs);
        }
예제 #2
0
        public InterfaceType
        (
            // Type properties
            string fullyQualifiedName,
            string assembly,
            string name,
            string? @namespace = null,

            // Type properties
            Docs?docs = null,

            // InterfaceType properties
            string[]?interfaces   = null,
            Method[]?methods      = null,
            Property[]?properties = null,
            bool isDataType       = false
        ) : base
            (
                fullyQualifiedName,
                assembly,
                name,
                @namespace,
                TypeKind.Interface,
                docs
            )
        {
            Interfaces = interfaces;
            Methods    = methods;
            Properties = properties;
            IsDataType = isDataType;
        }
예제 #3
0
파일: EnumType.cs 프로젝트: yglcode/jsii
        public EnumType
        (
            // Type properties
            string fullyQualifiedName,
            string assembly,
            string name,

            // EnumType properties
            EnumMember[] members,

            string? @namespace = null,
            // Type properties
            Docs?docs = null
        )
            : base
            (
                fullyQualifiedName,
                assembly,
                name,
                @namespace,
                TypeKind.Enum,
                docs
            )
        {
            Members = members ?? throw new ArgumentNullException(nameof(members));
        }
예제 #4
0
파일: Method.cs 프로젝트: skorfmann/jsii
 public Method
 (
     string name,
     OptionalValue?returns  = null,
     Parameter[]?parameters = null,
     bool isAbstract        = false,
     bool isAsync           = false,
     bool isProtected       = false,
     bool isVariadic        = false,
     bool isStatic          = false,
     string?overrides       = null,
     Docs?docs = null
 ) : base
     (
         parameters: parameters,
         isProtected: isProtected,
         isVariadic: isVariadic,
         overrides: overrides,
         docs: docs
     )
 {
     Name       = name;
     Returns    = returns;
     IsAbstract = isAbstract;
     IsAsync    = isAsync;
     IsStatic   = isStatic;
 }
예제 #5
0
파일: Assembly.cs 프로젝트: yglcode/jsii
 public Assembly
 (
     string name,
     string description,
     string homepage,
     AssemblyRepository repository,
     Person author,
     string fingerprint,
     string version,
     string license,
     AssemblyTargets?targets = null,
     IDictionary <string, PackageVersion>?dependencies = null,
     Person[]?contributors = null,
     IDictionary <string, string>?bundled = null,
     IDictionary <string, Type>?types     = null,
     Docs?docs     = null,
     Readme?readme = null
 ) : base(targets, dependencies)
 {
     Name         = name ?? throw new ArgumentNullException(nameof(name));
     Description  = description ?? throw new ArgumentNullException(nameof(description));
     Homepage     = homepage ?? throw new ArgumentNullException(nameof(homepage));
     Repository   = repository ?? throw new ArgumentNullException(nameof(repository));
     Author       = author ?? throw new ArgumentNullException(nameof(author));
     Fingerprint  = fingerprint ?? throw new ArgumentNullException(nameof(fingerprint));
     Version      = version ?? throw new ArgumentNullException(nameof(version));
     License      = license ?? throw new ArgumentNullException(nameof(license));
     Contributors = contributors;
     Bundled      = bundled;
     Types        = types;
     Docs         = docs;
     Readme       = readme;
 }
예제 #6
0
 public Parameter
 (
     string name,
     TypeReference type,
     bool isOptional = false,
     bool isVariadic = false,
     Docs?docs       = null
 ) : base(type: type, isOptional: isOptional)
 {
     Name       = name ?? throw new ArgumentNullException(nameof(name));
     Docs       = docs;
     IsVariadic = isVariadic;
 }
예제 #7
0
파일: Callable.cs 프로젝트: yglcode/jsii
 protected Callable
 (
     Parameter[]?parameters = null,
     bool isProtected       = false,
     bool isVariadic        = false,
     string?overrides       = null,
     Docs?docs = null
 )
 {
     Parameters  = parameters;
     IsProtected = isProtected;
     IsVariadic  = isVariadic;
     Overrides   = overrides;
     Docs        = docs;
 }
예제 #8
0
 public Initializer
 (
     Parameter[]?parameters = null,
     bool isProtected       = false,
     bool isVariadic        = false,
     string?overrides       = null,
     Docs?docs = null
 ) : base(
         parameters: parameters,
         isProtected: isProtected,
         isVariadic: isVariadic,
         overrides: overrides,
         docs: docs
         )
 {
 }
예제 #9
0
 protected Type
 (
     string fullyQualifiedName,
     string assembly,
     string name,
     string? @namespace,
     TypeKind kind,
     Docs?docs = null
 )
 {
     FullyQualifiedName = fullyQualifiedName ?? throw new ArgumentNullException(nameof(fullyQualifiedName));
     Assembly           = assembly ?? throw new ArgumentNullException(nameof(assembly));
     Name      = name ?? throw new ArgumentNullException(nameof(name));
     Namespace = @namespace;
     Kind      = kind;
     Docs      = docs;
 }
예제 #10
0
파일: ClassType.cs 프로젝트: skorfmann/jsii
        public ClassType
        (
            // Type properties
            string fullyQualifiedName,
            string assembly,
            string name,

            // ClassType properties
            bool isAbstract = false,

            string? @namespace = null,
            // Type properties
            Docs?docs = null,

            // ClassType properties
            string? @base           = null,
            Initializer?initializer = null,
            Property[]?properties   = null,
            Method[]?methods        = null,
            string[]?interfaces     = null
        )
            : base
            (
                fullyQualifiedName,
                assembly,
                name,
                @namespace,
                TypeKind.Class,
                docs
            )
        {
            IsAbstract = isAbstract;

            Base        = @base;
            Initializer = initializer;
            Properties  = properties;
            Methods     = methods;
            Interfaces  = interfaces;
        }
예제 #11
0
 public Property
 (
     string name,
     TypeReference type,
     bool isImmutable = false,
     bool isOptional  = false,
     bool isProtected = false,
     bool isAbstract  = false,
     bool isStatic    = false,
     bool isConstant  = false,
     string?overrides = null,
     Docs?docs        = null
 ) : base(type: type, isOptional: isOptional)
 {
     Name        = name ?? throw new ArgumentNullException(nameof(name));
     IsImmutable = isImmutable;
     IsProtected = isProtected;
     IsAbstract  = isAbstract;
     Docs        = docs;
     IsStatic    = isStatic;
     IsConstant  = isConstant;
     Overrides   = overrides;
 }
예제 #12
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))
                        {
                            var 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)
                {
                    var compilationUnits = generator.GetCompilationUnits(context.CancellationToken)
                                           .OrderBy(pair => pair.Key, StringComparer.OrdinalIgnoreCase)
                                           .ThenBy(pair => pair.Key, StringComparer.Ordinal);
                    foreach (var 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(NoMatchingMethodOrType, location, failedAttempt));
                    }
                }
            }
            finally
            {
                foreach (Generator generator in generators)
                {
                    generator.Dispose();
                }
            }
        }
예제 #13
0
 public EnumMember(string name, Docs?docs = null)
 {
     Name = name ?? throw new ArgumentNullException(nameof(name));
     Docs = docs;
 }