From 2560bf6cc3196284ced913e4445539b0ec6f3928 Mon Sep 17 00:00:00 2001 From: Merlin <36685500+Merlin-san@users.noreply.github.com> Date: Wed, 1 Apr 2020 02:22:35 -0700 Subject: [PATCH] Fix chained accesses of user defined fields - Fix accessing chained user defined fields to maintain the type of the field correctly - Add slightly better handling than an null reference exception when attempting to reference a property that doesn't exist - Add check for attempting to use something for a condition that didin't return a valid symbol --- .../UdonSharp/Editor/UdonSharpASTVisitor.cs | 3 ++ .../Editor/UdonSharpExpressionCapture.cs | 36 ++++++++++++++----- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/Assets/UdonSharp/Editor/UdonSharpASTVisitor.cs b/Assets/UdonSharp/Editor/UdonSharpASTVisitor.cs index 65ed6aec..9621fbfb 100644 --- a/Assets/UdonSharp/Editor/UdonSharpASTVisitor.cs +++ b/Assets/UdonSharp/Editor/UdonSharpASTVisitor.cs @@ -1802,6 +1802,9 @@ public override void VisitContinueStatement(ContinueStatementSyntax node) private SymbolDefinition HandleImplicitBoolCast(SymbolDefinition symbol) { + if (symbol == null) + throw new System.ArgumentException("Cannot implicitly convert type 'void' to 'bool'"); + if (symbol.symbolCsType != typeof(bool)) { SymbolDefinition conditionBoolCast = visitorContext.topTable.CreateUnnamedSymbol(typeof(bool), SymbolDeclTypeFlags.Internal); diff --git a/Assets/UdonSharp/Editor/UdonSharpExpressionCapture.cs b/Assets/UdonSharp/Editor/UdonSharpExpressionCapture.cs index 86507afc..77d7502c 100644 --- a/Assets/UdonSharp/Editor/UdonSharpExpressionCapture.cs +++ b/Assets/UdonSharp/Editor/UdonSharpExpressionCapture.cs @@ -255,7 +255,13 @@ private MethodInfo GetUdonGetMethodInfo() throw new System.Exception("Cannot get property get method on non-properties"); if (captureProperty.ReflectedType == typeof(VRC.Udon.UdonBehaviour)) - return typeof(Component).GetProperty(captureProperty.Name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static).GetGetMethod(); + { + PropertyInfo property = typeof(Component).GetProperty(captureProperty.Name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); + if (property == null) + return null; + + return property.GetGetMethod(); + } return captureProperty.GetGetMethod(); } @@ -266,7 +272,13 @@ private MethodInfo GetUdonSetMethodInfo() throw new System.Exception("Cannot get property get method on non-properties"); if (captureProperty.ReflectedType == typeof(VRC.Udon.UdonBehaviour)) - return typeof(Component).GetProperty(captureProperty.Name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static).GetGetMethod(); + { + PropertyInfo property = typeof(Component).GetProperty(captureProperty.Name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); + if (property == null) + return null; + + return property.GetGetMethod(); + } return captureProperty.GetSetMethod(); } @@ -285,6 +297,9 @@ public SymbolDefinition ExecuteGet() { MethodInfo getMethod = GetUdonGetMethodInfo(); + if (getMethod == null) + throw new System.MemberAccessException($"Property or indexer '{captureProperty.DeclaringType.Name}.{captureProperty.Name}' doesn't exist"); + if (getMethod.ReturnType == typeof(void)) throw new System.TypeLoadException("Cannot return type of void from a get statement"); @@ -386,7 +401,7 @@ public void ExecuteSet(SymbolDefinition value, bool explicitCast = false) MethodInfo setMethod = GetUdonSetMethodInfo(); if (setMethod == null) - throw new System.MemberAccessException($"Property or indexer '{captureProperty.DeclaringType.Name}.{captureProperty.Name}' cannot be assigned to -- it is read only"); + throw new System.MemberAccessException($"Property or indexer '{captureProperty.DeclaringType.Name}.{captureProperty.Name}' cannot be assigned to -- it is read only or doesn't exist"); string udonMethodString = visitorContext.resolverContext.GetUdonMethodName(setMethod); @@ -479,7 +494,7 @@ public SymbolDefinition CastSymbolToType(SymbolDefinition sourceSymbol, System.T throw new System.ArgumentException($"Cannot implicitly convert type '{UdonSharpUtils.PrettifyTypeName(sourceSymbol.userCsType)}' to '{UdonSharpUtils.PrettifyTypeName(targetType)}'"); // Exact type match, just return the symbol, this is what will happen a majority of the time. - if (targetType == sourceSymbol.symbolCsType || isObjectAssignable) + if (targetType == sourceSymbol.symbolCsType || (isObjectAssignable && !needsNewSymbol)) return sourceSymbol; // We can just return the symbol as-is @@ -1734,7 +1749,8 @@ private bool HandleMemberPropertyAccess(string propertyToken) if (captureArchetype != ExpressionCaptureArchetype.LocalSymbol && captureArchetype != ExpressionCaptureArchetype.Property && captureArchetype != ExpressionCaptureArchetype.Field && - captureArchetype != ExpressionCaptureArchetype.ArrayIndexer) + captureArchetype != ExpressionCaptureArchetype.ArrayIndexer && + captureArchetype != ExpressionCaptureArchetype.ExternUserField) { throw new System.Exception("Can only access properties on Local Symbols, Properties, and Fields"); } @@ -1768,7 +1784,8 @@ private bool HandleMemberFieldAccess(string fieldToken) if (captureArchetype != ExpressionCaptureArchetype.LocalSymbol && captureArchetype != ExpressionCaptureArchetype.Property && captureArchetype != ExpressionCaptureArchetype.Field && - captureArchetype != ExpressionCaptureArchetype.ArrayIndexer) + captureArchetype != ExpressionCaptureArchetype.ArrayIndexer && + captureArchetype != ExpressionCaptureArchetype.ExternUserField) { throw new System.Exception("Can only access fields on Local Symbols, Properties, and Fields"); } @@ -1800,7 +1817,8 @@ private bool HandleMemberMethodLookup(string methodToken) captureArchetype != ExpressionCaptureArchetype.Property && captureArchetype != ExpressionCaptureArchetype.Field && captureArchetype != ExpressionCaptureArchetype.ArrayIndexer && - captureArchetype != ExpressionCaptureArchetype.Enum) + captureArchetype != ExpressionCaptureArchetype.Enum && + captureArchetype != ExpressionCaptureArchetype.ExternUserField) { throw new System.Exception("Can only access member methods on Local Symbols, Properties, and Fields"); } @@ -1829,7 +1847,9 @@ private bool HandleExternUserFieldLookup(string fieldToken) if (accessSymbol == null || !accessSymbol.IsUserDefinedBehaviour()) return false; - ClassDefinition externClass = visitorContext.externClassDefinitions.Where(e => e.userClassType == accessSymbol.userCsType).FirstOrDefault(); + System.Type returnType = GetReturnType(true); + + ClassDefinition externClass = visitorContext.externClassDefinitions.Where(e => e.userClassType == returnType).FirstOrDefault(); if (externClass == null) return false;