private void BuildExposedTypeList() { if (_exposedTypes != null) { return; } // Stopwatch timer = Stopwatch.StartNew(); try { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); object typeSetLock = new object(); HashSet <Type> exposedTypeSet = new HashSet <Type>(); int mainThreadID = Thread.CurrentThread.ManagedThreadId; _assemblyCounter = 0; int totalAssemblies = assemblies.Length; Parallel.ForEach(assemblies, new ParallelOptions { MaxDegreeOfParallelism = 3 }, assembly => { if (assembly.FullName.Contains("UdonSharp") || assembly.FullName.Contains("CodeAnalysis")) { return; } Interlocked.Increment(ref _assemblyCounter); if (Thread.CurrentThread.ManagedThreadId == mainThreadID) // Can only be called from the main thread, since Parallel.ForEach uses the calling thread for some loops we just only run this in that thread. { EditorUtility.DisplayProgressBar("Processing methods and types...", $"{_assemblyCounter}/{totalAssemblies}", _assemblyCounter / (float)totalAssemblies); } Type[] assemblyTypes = assembly.GetTypes(); List <Type> types = new List <Type>(); foreach (Type assemblyType in assemblyTypes) { types.Add(assemblyType); types.AddRange(GetNestedTypes(assemblyType)); } types = types.Distinct().ToList(); HashSet <Type> localExposedTypeSet = new HashSet <Type>(); foreach (Type type in types) { if (type.IsByRef) { continue; } string typeName = CompilerUdonInterface.GetUdonTypeName(type); if (UdonEditorManager.Instance.GetTypeFromTypeString(typeName) != null) { localExposedTypeSet.Add(type); if (!type.IsGenericType && !type.IsGenericTypeDefinition) { localExposedTypeSet.Add(type.MakeArrayType()); } } MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); foreach (MethodInfo method in methods) { if (CompilerUdonInterface.IsExposedToUdon(CompilerUdonInterface.GetUdonMethodName(method))) { localExposedTypeSet.Add(method.DeclaringType); // We also want to highlight types that can be returned or taken as parameters if (method.ReturnType != typeof(void) && method.ReturnType.Name != "T" && method.ReturnType.Name != "T[]") { localExposedTypeSet.Add(method.ReturnType); if (!method.ReturnType.IsArray && !method.ReturnType.IsGenericType && !method.ReturnType.IsGenericTypeDefinition) { localExposedTypeSet.Add(method.ReturnType.MakeArrayType()); } } foreach (ParameterInfo parameterInfo in method.GetParameters()) { if (!parameterInfo.ParameterType.IsByRef) { localExposedTypeSet.Add(parameterInfo.ParameterType); if (!parameterInfo.ParameterType.IsArray) { localExposedTypeSet.Add(parameterInfo.ParameterType.MakeArrayType()); } } } } } foreach (PropertyInfo property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)) { MethodInfo propertyGetter = property.GetGetMethod(); if (propertyGetter == null) { continue; } if (CompilerUdonInterface.IsExposedToUdon(CompilerUdonInterface.GetUdonMethodName(propertyGetter))) { Type returnType = propertyGetter.ReturnType; localExposedTypeSet.Add(property.DeclaringType); if (returnType != typeof(void) && returnType.Name != "T" && returnType.Name != "T[]") { localExposedTypeSet.Add(returnType); if (!returnType.IsArray && !returnType.IsGenericType && !returnType.IsGenericTypeDefinition) { localExposedTypeSet.Add(returnType.MakeArrayType()); } } } } foreach (FieldInfo field in type.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)) { if (field.DeclaringType?.FullName == null) // Fix some weird types in Odin that don't have a name for their declaring type { continue; } if (CompilerUdonInterface.IsExposedToUdon(CompilerUdonInterface.GetUdonAccessorName(field, CompilerUdonInterface.FieldAccessorType.Get))) { Type returnType = field.FieldType; localExposedTypeSet.Add(field.DeclaringType); if (returnType != typeof(void) && returnType.Name != "T" && returnType.Name != "T[]") { localExposedTypeSet.Add(returnType); if (!returnType.IsArray && !returnType.IsGenericType && !returnType.IsGenericTypeDefinition) { localExposedTypeSet.Add(returnType.MakeArrayType()); } } } } } if (localExposedTypeSet.Count == 0) { return; } lock (typeSetLock) { exposedTypeSet.UnionWith(localExposedTypeSet); } }); _exposedTypes = exposedTypeSet.ToList(); } finally { EditorUtility.ClearProgressBar(); } _exposedTypes.RemoveAll(e => e.Name == "T" || e.Name == "T[]"); // Debug.Log($"Elapsed time {timer.Elapsed.TotalSeconds * 1000.0}ms"); }
private void AddChildNode(TreeViewItem parentItem, MemberInfo memberInfo, ref int currentID) { var obsoleteAttribute = memberInfo.GetCustomAttribute <System.ObsoleteAttribute>(); if (obsoleteAttribute != null) { return; } if (memberInfo.MemberType == MemberTypes.Property && (!((PropertyInfo)memberInfo).GetGetMethod()?.IsPublic ?? false)) { return; } if (memberInfo.DeclaringType.IsEnum) { return; } string staticStr = ""; { if ((memberInfo is FieldInfo fieldInfo && fieldInfo.IsStatic) || (memberInfo is PropertyInfo propertyInfo && (propertyInfo.GetGetMethod()?.IsStatic ?? false)) || (memberInfo is MethodInfo methodInfo && methodInfo.IsStatic)) { staticStr = "<Static>"; } } TreeViewItem memberItem = new TreeViewItem(currentID++, parentItem.depth + 1, $"<{memberInfo.MemberType}>{staticStr} {memberInfo}"); TypeItemMetadata itemMetadata = new TypeItemMetadata(); itemMetadata.member = memberInfo; switch (memberInfo.MemberType) { case MemberTypes.Constructor: case MemberTypes.Method: itemMetadata.exposed = CompilerUdonInterface.IsExposedToUdon(CompilerUdonInterface.GetUdonMethodName((MethodBase)memberInfo)); break; case MemberTypes.Field: string getAccessor = CompilerUdonInterface.GetUdonAccessorName((FieldInfo)memberInfo, CompilerUdonInterface.FieldAccessorType.Get); // string setAccessor = resolver.GetUdonFieldAccessorName((FieldInfo)memberInfo, CompilerUdonInterface.FieldAccessorType.Set, false); itemMetadata.exposed = CompilerUdonInterface.IsExposedToUdon(getAccessor); break; case MemberTypes.Property: MethodInfo getMethod = ((PropertyInfo)memberInfo).GetGetMethod(); if (getMethod == null) { return; } string getProperty = CompilerUdonInterface.GetUdonMethodName(getMethod); // if (((PropertyInfo)memberInfo).GetSetMethod() != null) // { // string setProperty = resolver.GetUdonMethodName(((PropertyInfo)memberInfo).GetSetMethod(), false); // } itemMetadata.exposed = CompilerUdonInterface.IsExposedToUdon(getProperty); break; } parentItem.AddChild(memberItem); itemMetadatas.Add(memberItem, itemMetadata); }