// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using Microsoft.CodeAnalysis; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; namespace Microsoft.ReactNative.Managed.CodeGen.Model { /// /// Helper class that stores all types needed for analysis and code generation /// from Microsoft.ReactNative and Microsoft.ReactNative.Managed /// public class ReactTypes { private const string m_ReactNativeAssemblyName = "Microsoft.ReactNative"; private const string m_ReactNativeNamespace = "Microsoft.ReactNative"; private const string m_ReactNativeManagedAssemblyName = "Microsoft.ReactNative.Managed"; private const string m_ReactNativeManagedNamespace = "Microsoft.ReactNative.Managed"; public INamedTypeSymbol SystemVoid { get; } public INamedTypeSymbol Task { get; } public INamedTypeSymbol TaskOfT { get; } public INamedTypeSymbol IReactPackageProvider { get; } public INamedTypeSymbol IReactPackageBuilder { get; } public INamedTypeSymbol IReactModuleBuilder { get; } public INamedTypeSymbol IReactContext { get; } public INamedTypeSymbol ReactContext { get; } public INamedTypeSymbol IJSValueWriter { get; } public INamedTypeSymbol IJSValueReader { get; } public INamedTypeSymbol JSValueType { get; } public INamedTypeSymbol JSValue { get; } public INamedTypeSymbol JSValueWriter { get; } public INamedTypeSymbol JSValueReader { get; } public INamedTypeSymbol JSValueWriterGenerator { get; } public INamedTypeSymbol JSValueReaderGenerator { get; } public INamedTypeSymbol JSValueWriterOf { get; } public INamedTypeSymbol JSValueReaderOf { get; } public INamedTypeSymbol IReactPromise { get; } public INamedTypeSymbol ReactPromise { get; } public INamedTypeSymbol ReactPromiseOfVoid { get; } public INamedTypeSymbol MethodReturnType { get; } public INamedTypeSymbol MethodResultCallback { get; } public INamedTypeSymbol ReactConstantProvider { get; } public INamedTypeSymbol ReactModuleAttribute { get; } public INamedTypeSymbol ReactInitializerAttribute { get; } public INamedTypeSymbol ReactConstantAttribute { get; } public INamedTypeSymbol ReactConstantProviderAttribute { get; } public INamedTypeSymbol ReactGetConstantsAttribute { get; } public INamedTypeSymbol ReactMethodAttribute { get; } public INamedTypeSymbol ReactSyncMethodAttribute { get; } public INamedTypeSymbol ReactEventAttribute { get; } public INamedTypeSymbol ReactFunctionAttribute { get; } public INamedTypeSymbol ReactPropertyAttribute { get; } public INamedTypeSymbol ReactTaskExtensions { get; } private readonly ICollection m_diagnostics = new List(); private ReactTypes(Compilation compilation) { SystemVoid = compilation.GetSpecialType(SpecialType.System_Void); Task = FindBclType(compilation, "System.Threading.Tasks.Task"); TaskOfT = FindBclType(compilation, "System.Threading.Tasks.Task`1")!.ConstructUnboundGenericType(); IReactPackageProvider = FindReactNativeType(compilation, "IReactPackageProvider"); IReactPackageBuilder = FindReactNativeType(compilation, "IReactPackageBuilder"); IReactModuleBuilder = FindReactNativeType(compilation, "IReactModuleBuilder"); IReactContext = FindReactNativeType(compilation, "IReactContext"); IJSValueWriter = FindReactNativeType(compilation, "IJSValueWriter"); IJSValueReader = FindReactNativeType(compilation, "IJSValueReader"); JSValueType = FindReactNativeType(compilation, "JSValueType"); MethodReturnType = FindReactNativeType(compilation, "MethodReturnType"); MethodResultCallback = FindReactNativeType(compilation, "MethodResultCallback"); ReactContext = FindReactNativeManagedType(compilation, "ReactContext"); ReactConstantProvider = FindReactNativeManagedType(compilation, "ReactConstantProvider"); IReactPromise = FindReactNativeManagedType(compilation, "IReactPromise`1"); ReactPromise = FindReactNativeManagedType(compilation, "ReactPromise`1"); ReactPromiseOfVoid = FindReactNativeManagedType(compilation, "ReactPromise"); JSValue = FindReactNativeManagedType(compilation, "JSValue"); JSValueWriter = FindReactNativeManagedType(compilation, "JSValueWriter"); JSValueReader = FindReactNativeManagedType(compilation, "JSValueReader"); JSValueWriterGenerator = FindReactNativeManagedType(compilation, "JSValueWriterGenerator"); JSValueReaderGenerator = FindReactNativeManagedType(compilation, "JSValueReaderGenerator"); JSValueWriterOf = FindReactNativeManagedType(compilation, "JSValueWriterOf`1"); JSValueReaderOf = FindReactNativeManagedType(compilation, "JSValueReaderOf`1"); ReactModuleAttribute = FindReactNativeManagedType(compilation, "ReactModuleAttribute"); ReactInitializerAttribute = FindReactNativeManagedType(compilation, "ReactInitializerAttribute"); ReactConstantAttribute = FindReactNativeManagedType(compilation, "ReactConstantAttribute"); ReactConstantProviderAttribute = FindReactNativeManagedType(compilation, "ReactConstantProviderAttribute"); ReactGetConstantsAttribute = FindReactNativeManagedType(compilation, "ReactGetConstantsAttribute"); ReactMethodAttribute = FindReactNativeManagedType(compilation, "ReactMethodAttribute"); ReactSyncMethodAttribute = FindReactNativeManagedType(compilation, "ReactSyncMethodAttribute"); ReactEventAttribute = FindReactNativeManagedType(compilation, "ReactEventAttribute"); ReactFunctionAttribute = FindReactNativeManagedType(compilation, "ReactFunctionAttribute"); ReactPropertyAttribute = FindReactNativeManagedType(compilation, "ReactPropertyAttribute"); ReactTaskExtensions = FindReactNativeManagedType(compilation, "ReactTaskExtensions"); } public static bool TryLoad(Compilation compilation, ICollection diagnostics, [NotNullWhen(returnValue: true)] out ReactTypes types) { types = new ReactTypes(compilation); if (types.m_diagnostics.Count > 0) { foreach (var diagnostic in types.m_diagnostics) { diagnostics.Add(diagnostic); } return false; } return true; } private INamedTypeSymbol FindReactNativeType(Compilation compilation, string typeName) { return FindType(compilation, m_ReactNativeAssemblyName, m_ReactNativeNamespace + "." + typeName); } private INamedTypeSymbol FindReactNativeManagedType(Compilation compilation, string typeName) { return FindType(compilation, m_ReactNativeManagedAssemblyName, m_ReactNativeManagedNamespace + "." + typeName); } private INamedTypeSymbol FindBclType(Compilation compilation, string typeName) { var type = compilation.GetTypeByMetadataName(typeName); if (type == null) { m_diagnostics.Add(Diagnostic.Create(DiagnosticDescriptors.CantFindReferenceAssembly, Location.None, typeName, "BCL")); // Return object to avoid null, the reported error tracks failure. return compilation.ObjectType; } return type; } private INamedTypeSymbol FindType(Compilation compilation, string assemblyName, string typeName) { var assemblySymbol = compilation .References .Select(compilation.GetAssemblyOrModuleSymbol) .OfType() .FirstOrDefault(asm => string.Equals(asm.Name, assemblyName, StringComparison.Ordinal)); if (assemblySymbol == null) { m_diagnostics.Add(Diagnostic.Create(DiagnosticDescriptors.CantFindReferenceAssembly, Location.None, assemblyName)); // Return object to avoid null, the reported error tracks failure. return compilation.ObjectType; } var type = assemblySymbol.GetTypeByMetadataName(typeName); if (type == null) { m_diagnostics.Add(Diagnostic.Create(DiagnosticDescriptors.CantFindReferenceAssembly, Location.None, typeName, assemblySymbol.Identity.GetDisplayName(true))); // Return object to avoid null, the reported error tracks failure. return compilation.ObjectType; } return type; } } }