Skip to content

Commit

Permalink
Fix source generator issues (#1732)
Browse files Browse the repository at this point in the history
* Fix instantiations of generic classes not being put of lookup table

* Fix check for WinRT classes

* Add more scenarios for unsafe diagnostics

* Fix sln

* Fix build

* Fix issue in WPF scenarios where our source generator was getting included twice.

* Revert "Fix issue in WPF scenarios where our source generator was getting included twice."

This reverts commit 7d3ee33.

* Move to debug as intended
  • Loading branch information
manodasanW committed Sep 5, 2024
1 parent 5ad543d commit c109e10
Show file tree
Hide file tree
Showing 11 changed files with 629 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,11 @@ CsWinRT1027 | Usage | Error | Class incorrectly implements an interface
Rule ID | Category | Severity | Notes
--------|----------|----------|-------
CsWinRT1028 | Usage | Warning | Class should be marked partial
CsWinRT1029 | Usage | Warning | Class implements WinRT interfaces generated using an older version of CsWinRT.
CsWinRT1029 | Usage | Warning | Class implements WinRT interfaces generated using an older version of CsWinRT.

## Release 2.1.2

### New Rules
Rule ID | Category | Severity | Notes
--------|----------|----------|-------
CsWinRT1030 | Usage | Warning | Project needs to be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>' to allow generic interface code generation.
124 changes: 76 additions & 48 deletions src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@
<value>All types within a Windows Metadata file must exist in a sub namespace of the namespace that is implied by the file name.</value>
<comment>"sub namespace" means a namespace defined within another namespace</comment>
</data>
<data name="EnableUnsafe_Brief" xml:space="preserve">
<value>Project does not enable unsafe blocks</value>
</data>
<data name="EnableUnsafe_Text" xml:space="preserve">
<value>Type '{0}' implements generic WinRT interfaces which requires generated code using unsafe for trimming and AOT compatibility if passed across the ABI. Project needs to be updated with '&lt;AllowUnsafeBlocks&gt;true&lt;/AllowUnsafeBlocks&gt;'.</value>
</data>
<data name="GenericTypeRule_Brief" xml:space="preserve">
<value>Class (or interface) is generic</value>
</data>
Expand Down
67 changes: 67 additions & 0 deletions src/Authoring/WinRT.SourceGenerator/Helper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,25 @@ public static bool IsOldProjectionAssembly(IAssemblySymbol assemblySymbol)
return false;
}

public static bool AllowUnsafe(Compilation compilation)
{
return compilation is CSharpCompilation csharpCompilation && csharpCompilation.Options.AllowUnsafe;
}

// Whether the class itself is a WinRT projected class.
// This is similar to whether it is a WinRT type, but custom type mappings
// are excluded given those are C# implemented classes.
public static Func<ISymbol, bool> IsWinRTClass(Compilation compilation)
{
var winrtRuntimeTypeAttribute = compilation.GetTypeByMetadataName("WinRT.WindowsRuntimeTypeAttribute");
return IsWinRTClassHelper;

bool IsWinRTClassHelper(ISymbol type)
{
return HasAttributeWithType(type, winrtRuntimeTypeAttribute);
}
}

public static bool IsWinRTType(ISymbol type, TypeMapper mapper)
{
return IsWinRTType(type, null, mapper);
Expand Down Expand Up @@ -360,6 +379,22 @@ type is INamedTypeSymbol namedType &&
return isProjectedType;
}

public static bool IsWinRTTypeOrImplementsWinRTType(ISymbol type, ITypeSymbol winrtRuntimeTypeAttribute, TypeMapper mapper, bool isComponentProject, IAssemblySymbol currentAssembly)
{
if (IsWinRTType(type, winrtRuntimeTypeAttribute, mapper, isComponentProject, currentAssembly))
{
return true;
}

if (type is INamedTypeSymbol namedType &&
namedType.AllInterfaces.Any(iface => IsWinRTType(iface, winrtRuntimeTypeAttribute, mapper, isComponentProject, currentAssembly)))
{
return true;
}

return false;
}

// Assuming a type is a WinRT type, this determines whether it is a WinRT type from custom type mappings.
// i.e Whether it is a built-in type that is also a WinRT type.
public static bool IsCustomMappedType(ISymbol type, TypeMapper mapper)
Expand Down Expand Up @@ -1038,5 +1073,37 @@ public bool IsBlittable()
return isValueType && isBlittable;
}
}

private static readonly Dictionary<string, string> AsyncMethodToTaskAdapter = new()
{
// AsAsyncOperation is an extension method, due to that using the format of ReducedFrom.
{ "System.WindowsRuntimeSystemExtensions.AsAsyncOperation<TResult>(System.Threading.Tasks.Task<TResult>)", "System.Threading.Tasks.TaskToAsyncOperationAdapter`1" },
{ "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.Run<TResult>(System.Func<System.Threading.CancellationToken, System.Threading.Tasks.Task<TResult>>)", "System.Threading.Tasks.TaskToAsyncOperationAdapter`1"},
{ "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.FromResult<TResult>(TResult)", "System.Threading.Tasks.TaskToAsyncOperationAdapter`1" },
{ "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.FromException<TResult>(System.Exception)", "System.Threading.Tasks.TaskToAsyncOperationAdapter`1" },
{ "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.CanceledOperation<TResult>()", "System.Threading.Tasks.TaskToAsyncOperationAdapter`1" },
{ "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.Run<TResult, TProgress>(System.Func<System.Threading.CancellationToken, System.IProgress<TProgress>, System.Threading.Tasks.Task<TResult>>)", "System.Threading.Tasks.TaskToAsyncOperationWithProgressAdapter`2" },
{ "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.FromResultWithProgress<TResult, TProgress>(TResult)", "System.Threading.Tasks.TaskToAsyncOperationWithProgressAdapter`2" },
{ "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.FromExceptionWithProgress<TResult, TProgress>(System.Exception)", "System.Threading.Tasks.TaskToAsyncOperationWithProgressAdapter`2" },
{ "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.CanceledOperationWithProgress<TResult, TProgress>()", "System.Threading.Tasks.TaskToAsyncOperationWithProgressAdapter`2" },
{ "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.Run<TProgress>(System.Func<System.Threading.CancellationToken, System.IProgress<TProgress>, System.Threading.Tasks.Task>)", "System.Threading.Tasks.TaskToAsyncActionWithProgressAdapter`1" },
{ "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.CompletedActionWithProgress<TProgress>()", "System.Threading.Tasks.TaskToAsyncActionWithProgressAdapter`1" },
{ "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.FromExceptionWithProgress<TProgress>(System.Exception)", "System.Threading.Tasks.TaskToAsyncActionWithProgressAdapter`1" },
{ "System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.CanceledActionWithProgress<TProgress>()", "System.Threading.Tasks.TaskToAsyncActionWithProgressAdapter`1" }
};

public static string GetTaskAdapterIfAsyncMethod(IMethodSymbol symbol)
{
var symbolStr = symbol.IsExtensionMethod ? symbol.ReducedFrom?.ToDisplayString() : symbol.OriginalDefinition?.ToDisplayString();
if (!string.IsNullOrEmpty(symbolStr))
{
if (AsyncMethodToTaskAdapter.TryGetValue(symbolStr, out var adapterTypeStr))
{
return adapterTypeStr;
}
}

return null;
}
}
}
Loading

0 comments on commit c109e10

Please sign in to comment.