Skip to content
This repository has been archived by the owner on Jan 22, 2022. It is now read-only.

Commit

Permalink
Fix chained accesses of user defined fields
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
MerlinVR committed Apr 1, 2020
1 parent aaf9474 commit 2560bf6
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 8 deletions.
3 changes: 3 additions & 0 deletions Assets/UdonSharp/Editor/UdonSharpASTVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
36 changes: 28 additions & 8 deletions Assets/UdonSharp/Editor/UdonSharpExpressionCapture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand All @@ -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();
}
Expand All @@ -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");

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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");
}
Expand Down Expand Up @@ -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");
}
Expand Down Expand Up @@ -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");
}
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 2560bf6

Please sign in to comment.