private ICollection <TypeSymbol> ImportAssemblies(string applicationAssemblyName, MetadataSource mdSource, string intermediaryAssembly = null) { importedTypes = new List <TypeSymbol>(); var isApplicationAssembly = Path.GetFullPath(mdSource.CoreAssemblyPath) == intermediaryAssembly; ImportScriptAssembly(applicationAssemblyName, mdSource, mdSource.CoreAssemblyPath, coreAssembly: true, applicationAssembly: isApplicationAssembly); foreach (TypeSymbol typeSymbol in importedTypes) { if (typeSymbol.Type == SymbolType.Class && typeSymbol.Name.Equals(nameof(Array), StringComparison.Ordinal)) { // Array is special - it is used to build other Arrays of more // specific types we load members for in the second pass... ImportMembers(typeSymbol); } } foreach (TypeSymbol typeSymbol in importedTypes) { if (typeSymbol.IsGeneric) { // Generics are also special - they are used to build other generic instances // with specific types for generic arguments as we load members for other // types subsequently... ImportMembers(typeSymbol); } } foreach (TypeSymbol typeSymbol in importedTypes) { if (typeSymbol.IsGeneric == false && (typeSymbol.Type != SymbolType.Class || typeSymbol.Name.Equals(nameof(Array), StringComparison.Ordinal) == false)) { ImportMembers(typeSymbol); } // There is some special-case logic to be performed on some members of the // global namespace. if (typeSymbol.Type == SymbolType.Class) { if (typeSymbol.Name.Equals("Script", StringComparison.Ordinal)) { // The Script class contains additional pseudo global methods that cannot // be referenced at compile-time by the app author, but can be // referenced by generated code during compilation. ImportPseudoMembers(PseudoClassMembers.Script, (ClassSymbol)typeSymbol); } else if (typeSymbol.Name.Equals(nameof(Object), StringComparison.Ordinal)) { // We need to add a static GetType method ImportPseudoMembers(PseudoClassMembers.Object, (ClassSymbol)typeSymbol); } else if (typeSymbol.Name.Equals(typeof(Dictionary <,>).Name, StringComparison.Ordinal)) { // The Dictionary class contains static methods at runtime, rather // than instance methods. ImportPseudoMembers(PseudoClassMembers.Dictionary, (ClassSymbol)typeSymbol); } else if (typeSymbol.Name.Equals("Arguments", StringComparison.Ordinal)) { // We need to add a static indexer, which isn't allowed in C# ImportPseudoMembers(PseudoClassMembers.Arguments, (ClassSymbol)typeSymbol); } } } // Import all the types first. // Types need to be loaded upfront so that they can be used in resolving types associated // with members. foreach (string assemblyPath in mdSource.Assemblies) { isApplicationAssembly = Path.GetFullPath(assemblyPath) == intermediaryAssembly; ImportScriptAssembly(applicationAssemblyName, mdSource, assemblyPath, coreAssembly: false, applicationAssembly: isApplicationAssembly); } // Resolve Base Types foreach (TypeSymbol typeSymbol in importedTypes) { if (typeSymbol is ClassSymbol classSymbol) { ImportBaseType(classSymbol); BuildInterfaceAssociations(classSymbol); } else if (typeSymbol.Type == SymbolType.Interface) { ImportInterfaces((InterfaceSymbol)typeSymbol); } } // Import members foreach (TypeSymbol typeSymbol in importedTypes) { if (typeSymbol.IsCoreType) { // already processed above continue; } ImportMembers(typeSymbol); } foreach (TypeSymbol typeSymbol in importedTypes) { if (typeSymbol is ClassSymbol classSymbol && classSymbol.IsPublic) { foreach (var method in GetExtensionMethods(typeSymbol.Members)) { ParameterDefinition parameter = ((MethodDefinition)method.ParseContext).Parameters.First(); symbols.AddExtensionMethod(method, parameter.ParameterType.FullName, false); } } } return(importedTypes); }
private void ImportType(MetadataSource mdSource, TypeDefinition type, bool inScriptCoreAssembly, bool inApplicationAssembly, ScriptReference dependency, TypeSymbol outerType = null) { if (!type.IsPublic && !type.IsNestedPublic && dependency?.InternalesVisible == false) { return; } if (inScriptCoreAssembly && MetadataHelpers.ShouldImportScriptCoreType(type) == false) { return; } string name = outerType is TypeSymbol ? $"{outerType.Name}${type.Name}" : type.Name; string namespaceName = outerType is TypeSymbol ? outerType.Namespace : type.Namespace; bool dummy; string scriptName = MetadataHelpers.GetScriptName(type, out dummy, out dummy); NamespaceSymbol namespaceSymbol = symbols.GetNamespace(namespaceName); TypeSymbol typeSymbol = null; if (type.IsInterface) { typeSymbol = new InterfaceSymbol(name, namespaceSymbol); } else if (MetadataHelpers.IsEnum(type)) { // NOTE: We don't care about the flags bit on imported enums // because this is only consumed by the generation logic. typeSymbol = new EnumerationSymbol(name, namespaceSymbol, /* flags */ false); if (MetadataHelpers.ShouldUseEnumNames(type)) { ((EnumerationSymbol)typeSymbol).SetNamedValues(); } else if (MetadataHelpers.ShouldUseEnumValues(type)) { ((EnumerationSymbol)typeSymbol).SetNumericValues(); } } else if (MetadataHelpers.IsDelegate(type)) { typeSymbol = new DelegateSymbol(name, namespaceSymbol); typeSymbol.SetTransformedName("Function"); typeSymbol.SetIgnoreGenerics(); typeSymbol.SetIgnoreNamespace(); } else { if (MetadataHelpers.ShouldTreatAsRecordType(type)) { typeSymbol = new RecordSymbol(name, namespaceSymbol); typeSymbol.SetTransformedName(nameof(Object)); } else { typeSymbol = new ClassSymbol(name, namespaceSymbol); } } if (typeSymbol != null) { if (MetadataHelpers.ShouldIgnoreGenerics(type, out var useGenericName)) { typeSymbol.SetIgnoreGenerics(useGenericName); } if (type.HasGenericParameters) { List <GenericParameterSymbol> genericArguments = new List <GenericParameterSymbol>(); foreach (GenericParameter genericParameter in type.GenericParameters) { GenericParameterSymbol arg = new GenericParameterSymbol(genericParameter.Position, genericParameter.Name, true, symbols.GlobalNamespace); genericArguments.Add(arg); } typeSymbol.AddGenericParameters(genericArguments); } string dependencyName = MetadataHelpers.GetScriptDependencyName(type, out string dependencyIdentifier); if (dependencyName != null) { dependency = ScriptReferenceProvider.Instance.GetReference(dependencyName, dependencyIdentifier); } if (!inApplicationAssembly) { typeSymbol.SetImported(dependency); } typeSymbol.SetMetadataToken(type, inScriptCoreAssembly); bool ignoreNamespace = MetadataHelpers.ShouldIgnoreNamespace(type); if (ignoreNamespace || dependency == null || string.IsNullOrEmpty(dependency.Identifier)) { typeSymbol.SetIgnoreNamespace(); } else { typeSymbol.ScriptNamespace = dependency.Identifier; } //todo: improve the logic here to support private/protected access modifiers for nested classes typeSymbol.IsPublic = type.IsPublic; typeSymbol.IsInternal = type.IsNotPublic; if (string.IsNullOrEmpty(scriptName) == false) { typeSymbol.SetTransformedName(scriptName); } SetArrayTypeMetadata(type, typeSymbol, scriptName); typeSymbol.SetSource(dependency); namespaceSymbol.AddType(typeSymbol); importedTypes.Add(typeSymbol); if (outerType is TypeSymbol) { outerType.AddType(typeSymbol); } if (type.HasNestedTypes) { foreach (TypeDefinition nestedType in type.NestedTypes) { ImportType(mdSource, nestedType, inScriptCoreAssembly, inApplicationAssembly, dependency, typeSymbol); } } } }
private void ImportType(MetadataSource mdSource, TypeDefinition type, bool inScriptCoreAssembly, string scriptNamespace) { if (type.IsPublic == false) { return; } if (inScriptCoreAssembly && MetadataHelpers.ShouldImportScriptCoreType(type) == false) { return; } string name = type.Name; string namespaceName = type.Namespace; bool dummy; string scriptName = MetadataHelpers.GetScriptName(type, out dummy, out dummy); NamespaceSymbol namespaceSymbol = symbols.GetNamespace(namespaceName); TypeSymbol typeSymbol = null; if (type.IsInterface) { typeSymbol = new InterfaceSymbol(name, namespaceSymbol); } else if (MetadataHelpers.IsEnum(type)) { // NOTE: We don't care about the flags bit on imported enums // because this is only consumed by the generation logic. typeSymbol = new EnumerationSymbol(name, namespaceSymbol, /* flags */ false); if (MetadataHelpers.ShouldUseEnumNames(type)) { ((EnumerationSymbol)typeSymbol).SetNamedValues(); } else if (MetadataHelpers.ShouldUseEnumValues(type)) { ((EnumerationSymbol)typeSymbol).SetNumericValues(); } } else if (MetadataHelpers.IsDelegate(type)) { typeSymbol = new DelegateSymbol(name, namespaceSymbol); typeSymbol.SetTransformedName("Function"); } else { if (MetadataHelpers.ShouldTreatAsRecordType(type)) { typeSymbol = new RecordSymbol(name, namespaceSymbol); typeSymbol.SetTransformedName(nameof(Object)); } else { typeSymbol = new ClassSymbol(name, namespaceSymbol); if (MetadataHelpers.IsScriptExtension(type, out string extendee)) { ((ClassSymbol)typeSymbol).SetExtenderClass(extendee); } } } if (typeSymbol != null) { if (type.HasGenericParameters) { List <GenericParameterSymbol> genericArguments = new List <GenericParameterSymbol>(); foreach (GenericParameter genericParameter in type.GenericParameters) { GenericParameterSymbol arg = new GenericParameterSymbol(genericParameter.Position, genericParameter.Name, /* typeArgument */ true, symbols.GlobalNamespace); genericArguments.Add(arg); } typeSymbol.AddGenericParameters(genericArguments); } ScriptReference dependency = null; string dependencyName = MetadataHelpers.GetScriptDependencyName(type, out string dependencyIdentifier); if (dependencyName != null) { dependency = new ScriptReference(dependencyName, dependencyIdentifier); scriptNamespace = dependency.Identifier; } typeSymbol.SetImported(dependency); typeSymbol.SetMetadataToken(type, inScriptCoreAssembly); bool ignoreNamespace = MetadataHelpers.ShouldIgnoreNamespace(type); if (ignoreNamespace || string.IsNullOrEmpty(scriptNamespace)) { typeSymbol.SetIgnoreNamespace(); } else { typeSymbol.ScriptNamespace = scriptNamespace; } typeSymbol.IsPublic = true; if (string.IsNullOrEmpty(scriptName) == false) { typeSymbol.SetTransformedName(scriptName); } SetArrayTypeMetadata(type, typeSymbol, scriptName); namespaceSymbol.AddType(typeSymbol); importedTypes.Add(typeSymbol); } }