Skip to content

Commit

Permalink
Add support for multiple NativeMethods.txt files in a project
Browse files Browse the repository at this point in the history
Any that do not appear in the project directory must be added as an `AdditionalFiles` item by the project itself. Only the one in the project directory itself is automatically added by the CsWin32 nuget package.
  • Loading branch information
AArnott committed May 31, 2022
1 parent 74e738a commit 4326f8c
Showing 1 changed file with 66 additions and 63 deletions.
129 changes: 66 additions & 63 deletions src/Microsoft.Windows.CsWin32/SourceGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,9 @@ public void Execute(GeneratorExecutionContext context)
options = new GeneratorOptions();
}

AdditionalText? nativeMethodsTxtFile = context.AdditionalFiles
.FirstOrDefault(af => string.Equals(Path.GetFileName(af.Path), NativeMethodsTxtAdditionalFileName, StringComparison.OrdinalIgnoreCase));
if (nativeMethodsTxtFile is null)
IEnumerable<AdditionalText> nativeMethodsTxtFiles = context.AdditionalFiles
.Where(af => string.Equals(Path.GetFileName(af.Path), NativeMethodsTxtAdditionalFileName, StringComparison.OrdinalIgnoreCase));
if (!nativeMethodsTxtFiles.Any())
{
return;
}
Expand All @@ -184,95 +184,98 @@ public void Execute(GeneratorExecutionContext context)
try
{
SuperGenerator.Combine(generators);
SourceText? nativeMethodsTxt = nativeMethodsTxtFile.GetText(context.CancellationToken);
if (nativeMethodsTxt is null)
foreach (AdditionalText nativeMethodsTxtFile in nativeMethodsTxtFiles)
{
return;
}

foreach (TextLine line in nativeMethodsTxt.Lines)
{
context.CancellationToken.ThrowIfCancellationRequested();
string name = line.ToString();
if (string.IsNullOrWhiteSpace(name) || name.StartsWith("//", StringComparison.InvariantCulture))
SourceText? nativeMethodsTxt = nativeMethodsTxtFile.GetText(context.CancellationToken);
if (nativeMethodsTxt is null)
{
continue;
return;
}

name = name.Trim();
var location = Location.Create(nativeMethodsTxtFile.Path, line.Span, nativeMethodsTxt.Lines.GetLinePositionSpan(line.Span));
try
foreach (TextLine line in nativeMethodsTxt.Lines)
{
if (Generator.GetBannedAPIs(options).TryGetValue(name, out string? reason))
context.CancellationToken.ThrowIfCancellationRequested();
string name = line.ToString();
if (string.IsNullOrWhiteSpace(name) || name.StartsWith("//", StringComparison.InvariantCulture))
{
context.ReportDiagnostic(Diagnostic.Create(BannedApi, location, reason));
continue;
}

if (name.EndsWith(".*", StringComparison.Ordinal))
name = name.Trim();
var location = Location.Create(nativeMethodsTxtFile.Path, line.Span, nativeMethodsTxt.Lines.GetLinePositionSpan(line.Span));
try
{
string? moduleName = name.Substring(0, name.Length - 2);
int matches = 0;
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.TryGenerateAllExternMethods(moduleName, context.CancellationToken))
if (generator.TryGenerate(name, out IReadOnlyList<string> preciseApi, context.CancellationToken))
{
matches++;
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 (matches)
switch (matchingApis.Count)
{
case 0:
context.ReportDiagnostic(Diagnostic.Create(NoMethodsForModule, location, moduleName));
ReportNoMatch(location, name);
break;
case > 1:
context.ReportDiagnostic(Diagnostic.Create(AmbiguousMatchError, location, moduleName));
context.ReportDiagnostic(Diagnostic.Create(AmbiguousMatchErrorWithSuggestions, location, name, ConcatSuggestions(matchingApis)));
break;
}

continue;
}

List<string> matchingApis = new();
foreach (Generator generator in generators)
catch (GenerationFailedException ex)
{
if (generator.TryGenerate(name, out IReadOnlyList<string> preciseApi, context.CancellationToken))
if (Generator.IsPlatformCompatibleException(ex))
{
matchingApis.AddRange(preciseApi);
continue;
context.ReportDiagnostic(Diagnostic.Create(CpuArchitectureIncompatibility, location));
}

matchingApis.AddRange(preciseApi);
if (generator.TryGetEnumName(name, out string? declaringEnum))
else
{
context.ReportDiagnostic(Diagnostic.Create(UseEnumValueDeclaringType, location, declaringEnum));
generator.TryGenerate(declaringEnum, out preciseApi, context.CancellationToken);
matchingApis.AddRange(preciseApi);
// Build up a complete error message.
context.ReportDiagnostic(Diagnostic.Create(InternalError, location, AssembleFullExceptionMessage(ex)));
}
}

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)));
}
}
}

Expand Down

0 comments on commit 4326f8c

Please sign in to comment.