Example #1
0
 private static void Factory(HaxeWriter writer, SyntaxNode node)
 {
     if (node is MethodDeclarationSyntax)
     {
         WriteMethod.Go(writer, node.As <MethodDeclarationSyntax>());
     }
     else if (node is PropertyDeclarationSyntax)
     {
         WriteProperty.Go(writer, node.As <PropertyDeclarationSyntax>());
     }
     else if (node is FieldDeclarationSyntax)
     {
         WriteField.Go(writer, node.As <FieldDeclarationSyntax>());
     }
     else if (node is ConstructorDeclarationSyntax)
     {
         WriteConstructor.Go(writer, node.As <ConstructorDeclarationSyntax>());
     }
     else if (node is ExpressionStatementSyntax)
     {
         WriteStatement(writer, node.As <ExpressionStatementSyntax>());
     }
     else if (node is LocalDeclarationStatementSyntax)
     {
         WriteLocalDeclaration.Go(writer, node.As <LocalDeclarationStatementSyntax>());
     }
     else if (node is BlockSyntax)
     {
         WriteBlock(writer, node.As <BlockSyntax>());
     }
     else if (node is InvocationExpressionSyntax)
     {
         WriteInvocationExpression.Go(writer, node.As <InvocationExpressionSyntax>());
     }
     else if (node is LiteralExpressionSyntax)
     {
         WriteLiteralExpression.Go(writer, node.As <LiteralExpressionSyntax>());
     }
     else if (node is IdentifierNameSyntax)
     {
         WriteIdentifierName.Go(writer, node.As <IdentifierNameSyntax>());
     }
     else if (node is ImplicitArrayCreationExpressionSyntax)
     {
         WriteArrayCreationExpression.Go(writer, node.As <ImplicitArrayCreationExpressionSyntax>());
     }
     else if (node is ArrayCreationExpressionSyntax)
     {
         WriteArrayCreationExpression.Go(writer, node.As <ArrayCreationExpressionSyntax>());
     }
     else if (node is MemberAccessExpressionSyntax)
     {
         WriteMemberAccessExpression.Go(writer, node.As <MemberAccessExpressionSyntax>());
     }
     else if (node is ParenthesizedLambdaExpressionSyntax)
     {
         WriteLambdaExpression.Go(writer, node.As <ParenthesizedLambdaExpressionSyntax>());
     }
     else if (node is SimpleLambdaExpressionSyntax)
     {
         WriteLambdaExpression.Go(writer, node.As <SimpleLambdaExpressionSyntax>());
     }
     else if (node is ReturnStatementSyntax)
     {
         WriteReturnStatement.Go(writer, node.As <ReturnStatementSyntax>());
     }
     else if (node is ObjectCreationExpressionSyntax)
     {
         WriteObjectCreationExpression.Go(writer, node.As <ObjectCreationExpressionSyntax>());
     }
     else if (node is ElementAccessExpressionSyntax)
     {
         WriteElementAccessExpression.Go(writer, node.As <ElementAccessExpressionSyntax>());
     }
     else if (node is ForEachStatementSyntax)
     {
         WriteForEachStatement.Go(writer, node.As <ForEachStatementSyntax>());
     }
     else if (node is IfStatementSyntax)
     {
         WriteIfStatement.Go(writer, node.As <IfStatementSyntax>());
     }
     else if (node is BinaryExpressionSyntax)
     {
         WriteBinaryExpression.Go(writer, node.As <BinaryExpressionSyntax>());
     }
     else if (node is ConditionalExpressionSyntax)
     {
         WriteConditionalExpression.Go(writer, node.As <ConditionalExpressionSyntax>());
     }
     else if (node is BaseExpressionSyntax)
     {
         WriteBaseExpression.Go(writer, node.As <BaseExpressionSyntax>());
     }
     else if (node is ThisExpressionSyntax)
     {
         WriteThisExpression.Go(writer, node.As <ThisExpressionSyntax>());
     }
     else if (node is CastExpressionSyntax)
     {
         WriteCastExpression.Go(writer, node.As <CastExpressionSyntax>());
     }
     else if (node is ThrowStatementSyntax)
     {
         WriteThrowStatement.Go(writer, node.As <ThrowStatementSyntax>());
     }
     else if (node is ThrowExpressionSyntax)
     {
         WriteThrowStatement.GoExpression(writer, node.As <ThrowExpressionSyntax>());
     }
     else if (node is PrefixUnaryExpressionSyntax)
     {
         WriteUnaryExpression.Go(writer, node.As <PrefixUnaryExpressionSyntax>());
     }
     else if (node is PostfixUnaryExpressionSyntax)
     {
         WriteUnaryExpression.Go(writer, node.As <PostfixUnaryExpressionSyntax>());
     }
     else if (node is EqualsValueClauseSyntax)
     {
         WriteEqualsValueClause.Go(writer, node.As <EqualsValueClauseSyntax>());
     }
     else if (node is ForStatementSyntax)
     {
         WriteForStatement.Go(writer, node.As <ForStatementSyntax>());
     }
     else if (node is WhileStatementSyntax)
     {
         WriteWhileStatement.Go(writer, node.As <WhileStatementSyntax>());
     }
     else if (node is BreakStatementSyntax)
     {
         WriteBreakStatement.Go(writer, node.As <BreakStatementSyntax>());
     }
     else if (node is DoStatementSyntax)
     {
         WriteDoStatement.Go(writer, node.As <DoStatementSyntax>());
     }
     else if (node is SwitchStatementSyntax)
     {
         WriteSwitchStatement.Go(writer, node.As <SwitchStatementSyntax>());
     }
     else if (node is TryStatementSyntax)
     {
         WriteTryStatement.Go(writer, node.As <TryStatementSyntax>());
     }
     else if (node is UsingStatementSyntax)
     {
         WriteUsingStatement.Go(writer, node.As <UsingStatementSyntax>());
     }
     else if (node is ParenthesizedExpressionSyntax)
     {
         WriteParenthesizedExpression.Go(writer, node.As <ParenthesizedExpressionSyntax>());
     }
     else if (node is LockStatementSyntax)
     {
         WriteLockStatement.Go(writer, node.As <LockStatementSyntax>());
     }
     else if (node is ContinueStatementSyntax)
     {
         WriteContinueStatement.Go(writer, node.As <ContinueStatementSyntax>());
     }
     else if (node is TypeOfExpressionSyntax)
     {
         WriteTypeOfExpression.Go(writer, node.As <TypeOfExpressionSyntax>());
     }
     else if (node is AnonymousObjectCreationExpressionSyntax)
     {
         WriteAnonymousObjectCreationExpression.Go(writer, node.As <AnonymousObjectCreationExpressionSyntax>());
     }
     else if (node is EmptyStatementSyntax)
     {
         return; //ignore empty statements
     }
     else if (node is DelegateDeclarationSyntax)
     {
         return; //don't write delegates - we convert them to types directly
     }
     else if (node is EventFieldDeclarationSyntax)
     {
         WriteEventFieldDeclaration.Go(writer, node.As <EventFieldDeclarationSyntax>());
     }
     else if (node is DefaultExpressionSyntax)
     {
         WriteDefaultExpression.Go(writer, node.As <DefaultExpressionSyntax>());
     }
     else if (node is GenericNameSyntax)
     {
         WriteGenericName.Go(writer, node.As <GenericNameSyntax>());
     }
     else if (node is ConversionOperatorDeclarationSyntax)
     {
         WriteConversionOperatorDeclaration.Go(writer, node.As <ConversionOperatorDeclarationSyntax>());
     }
     else if (node is AssignmentExpressionSyntax)
     {
         WriteAssignmentExpressionSyntax.Go(writer, node.As <AssignmentExpressionSyntax>());
     }
     else if (node is OperatorDeclarationSyntax)
     {
         WriteMethod.WriteOperatorDeclaration(writer, node.As <OperatorDeclarationSyntax>());
     }
     else if (node is IndexerDeclarationSyntax)
     {
         WriteMethod.WriteIndexerDeclaration(writer, node.As <IndexerDeclarationSyntax>());
     }
     else
     {
         throw new NotImplementedException(node.GetType().Name + " is not supported. " + Utility.Descriptor(node));
     }
 }
        public static void Go(HaxeWriter writer, InvocationExpressionSyntax invocationExpression)
        {
            var model = Program.GetModel(invocationExpression);

            var symbolInfo       = model.GetSymbolInfo(invocationExpression);
            var expressionSymbol = model.GetSymbolInfo(invocationExpression.Expression);

            if (symbolInfo.Symbol == null)
            {
                throw new Exception("InvocationExpression could not be identified.  Are you sure the C# is valid? " + Utility.Descriptor(invocationExpression));
            }
            var methodSymbol     = (IMethodSymbol)symbolInfo.Symbol;
            var origMethodSymbol = methodSymbol.OriginalDefinition.As <IMethodSymbol>().UnReduce();

            var translateOpt = MethodTranslation.Get(symbolInfo.Symbol.As <IMethodSymbol>());
            var memberReferenceExpressionOpt = invocationExpression.Expression as MemberAccessExpressionSyntax;
            //var returnTypeHaxe = TypeProcessor.ConvertType(methodSymbol.ReturnType);
            var firstParameter = true;

            if (methodSymbol.TypeArguments.Any(o => o.SpecialType == SpecialType.System_Char) && origMethodSymbol.ContainingType.Name != "Enumerable")
            {
                throw new Exception("Char cannot be passed as a type argument. methodName=" + origMethodSymbol.Name + " " + Utility.Descriptor(invocationExpression));                                 //the called function could call .ToString on it, which would give the int representation instead of the char.  We could fix this by wrapping chars in a class but that would hit performance, so instead just re-write the offending C#.  Skip this requirement for System.Linq.Enumerable because it is typically just mapping to a lambda, such as Select or TakeWhile, and our lambda can handle it correctly.  Ideally we'd detect if the type parameter is only used in a lambda
            }
            var              extensionNamespace = origMethodSymbol.IsExtensionMethod ? origMethodSymbol.ContainingNamespace.FullNameWithDot().ToLower() + origMethodSymbol.ContainingType.Name : null; //null means it's not an extension method, non-null means it is
            string           methodName;
            ExpressionSyntax subExpressionOpt;

            if (origMethodSymbol.ContainingType.Name == "Enum")
            {
                if (origMethodSymbol.Name == "Parse")
                {
                    WriteEnumParse(writer, invocationExpression);
                    return;
                }

                if (origMethodSymbol.Name == "GetValues")
                {
                    WriteEnumGetValues(writer, invocationExpression);
                    return;
                }
            }

            if (expressionSymbol.Symbol is IEventSymbol)
            {
                methodName = "Invoke";                 //Would need to append the number of arguments to this to support events.  However, events are not currently supported
            }
            else if (memberReferenceExpressionOpt != null && memberReferenceExpressionOpt.Expression is PredefinedTypeSyntax)
            {
                switch (origMethodSymbol.Name)
                {
                case "Parse":
                    var t = TypeProcessor.ConvertType(origMethodSymbol.ReturnType);

                    if (t == "Bool")
                    {
                        methodName         = "ParseBool";
                        extensionNamespace = "Cs2Hx";
                    }
                    else if (t == "Int" || t == "Float")
                    {
                        methodName         = "parse" + t;
                        extensionNamespace = "Std";
                    }
                    else
                    {
                        throw new Exception("Parse method on " + t + " is not supported.  " + Utility.Descriptor(memberReferenceExpressionOpt));
                    }

                    break;

                case "TryParse":
                    methodName         = "TryParse" + TypeProcessor.ConvertType(origMethodSymbol.Parameters[1].Type);
                    extensionNamespace = "Cs2Hx";
                    break;

                default:
                    methodName         = origMethodSymbol.Name;
                    extensionNamespace = "Cs2Hx";
                    break;
                }
            }
            else if (translateOpt != null && translateOpt.ReplaceWith != null)
            {
                methodName = translateOpt.ReplaceWith;
            }
            else if (origMethodSymbol.MethodKind == MethodKind.DelegateInvoke)
            {
                methodName = null;
            }
            else
            {
                methodName = OverloadResolver.MethodName(origMethodSymbol);
            }

            if (translateOpt != null && translateOpt.HasComplexReplaceWith)
            {
                translateOpt.DoComplexReplaceWith(writer, memberReferenceExpressionOpt);                 //TODO: What if this is null?
                return;
            }

            if (translateOpt != null && translateOpt.SkipExtensionParameter)
            {
                subExpressionOpt = null;
            }
            else if (origMethodSymbol.MethodKind == MethodKind.DelegateInvoke)
            {
                subExpressionOpt = invocationExpression.Expression;
            }
            else if (memberReferenceExpressionOpt != null)
            {
                if (memberReferenceExpressionOpt.Expression is PredefinedTypeSyntax)
                {
                    subExpressionOpt = null;
                }
                else
                {
                    subExpressionOpt = memberReferenceExpressionOpt.Expression;
                }
            }
            else
            {
                subExpressionOpt = null;                 //TODO
            }
            //Determine if it's an extension method called in a non-extension way.  In this case, just pretend it's not an extension method
            if (extensionNamespace != null && subExpressionOpt != null && model.GetTypeInfo(subExpressionOpt).ConvertedType.ToString() == origMethodSymbol.ContainingNamespace + "." + origMethodSymbol.ContainingType.Name)
            {
                extensionNamespace = null;
            }

            if (translateOpt != null && !string.IsNullOrEmpty(translateOpt.ExtensionNamespace))
            {
                extensionNamespace = translateOpt.ExtensionNamespace;
            }
            else if (translateOpt != null && translateOpt.ExtensionNamespace == "")
            {
                extensionNamespace = null;
            }

            if (extensionNamespace != null)
            {
                writer.Write(extensionNamespace);

                if (methodName != null)
                {
                    writer.Write(".");
                    writer.Write(methodName);
                }

                writer.Write("(");

                if (subExpressionOpt != null)
                {
                    firstParameter = false;

                    if (origMethodSymbol.IsExtensionMethod)
                    {
                        WriteForEachStatement.CheckWriteEnumerator(writer, subExpressionOpt, true);
                    }
                    else
                    {
                        Core.Write(writer, subExpressionOpt);
                    }
                }
            }
            else
            {
                if (memberReferenceExpressionOpt != null)
                {
                    var memberType     = model.GetTypeInfo(memberReferenceExpressionOpt.Expression).Type;
                    var memberTypeHaxe = TypeProcessor.ConvertType(memberType);

                    //sort calls without any parameters need to get the default sort parameter
                    if (methodName == "sort" && invocationExpression.ArgumentList.Arguments.Count == 0)
                    {
                        Core.Write(writer, memberReferenceExpressionOpt.Expression);
                        writer.Write(".sort(");

                        switch (memberTypeHaxe)
                        {
                        case "Array<Int>":
                            writer.Write("Cs2Hx.SortInts");
                            break;

                        case "Array<Float>":
                            writer.Write("Cs2Hx.SortFloats");
                            break;

                        case "Array<String>":
                            writer.Write("Cs2Hx.SortStrings");
                            break;

                        default:
                            throw new Exception("Unknown default sort type: " + memberTypeHaxe + ".  " + Utility.Descriptor(invocationExpression));
                        }

                        writer.Write(")");
                        return;
                    }

                    //Check against lowercase toString since it gets replaced with the haxe name before we get here
                    if (methodName == "toString")
                    {
                        if (memberType.TypeKind == TypeKind.Enum)
                        {
                            //calling ToString() on an enum forwards to our enum's special ToString method
                            writer.Write(memberType.ContainingNamespace.FullNameWithDot().ToLower());
                            writer.Write(WriteType.TypeName((INamedTypeSymbol)memberType));
                            writer.Write(".ToString(");
                            Core.Write(writer, memberReferenceExpressionOpt.Expression);
                            writer.Write(")");

                            if (invocationExpression.ArgumentList.Arguments.Count > 0)
                            {
                                throw new Exception("Enum's ToString detected with parameters.  These are not supported " + Utility.Descriptor(invocationExpression));
                            }

                            return;
                        }

                        if (memberType.SpecialType == SpecialType.System_Char)
                        {
                            writer.Write("Cs2Hx.CharToString(");
                            Core.Write(writer, memberReferenceExpressionOpt.Expression);
                            writer.Write(")");

                            if (invocationExpression.ArgumentList.Arguments.Count > 0)
                            {
                                throw new Exception("Char's ToString detected with parameters.  These are not supported " + Utility.Descriptor(invocationExpression));
                            }

                            return;
                        }

                        if (memberTypeHaxe == "Int" || memberTypeHaxe == "Float" || memberTypeHaxe == "Bool" || memberType.TypeKind == TypeKind.TypeParameter)
                        {
                            //ToString()'s on primitive types get replaced with Std.string
                            writer.Write("Std.string(");

                            if (memberReferenceExpressionOpt.Expression is ParenthesizedExpressionSyntax)
                            {
                                Core.Write(writer, memberReferenceExpressionOpt.Expression.As <ParenthesizedExpressionSyntax>().Expression);                                //eat a set of parenthesis, just to make the output code a bit nicer.
                            }
                            else
                            {
                                Core.Write(writer, memberReferenceExpressionOpt.Expression);
                            }

                            writer.Write(")");

                            if (invocationExpression.ArgumentList.Arguments.Count > 0)
                            {
                                throw new Exception("Primitive type's ToString detected with parameters.  These are not supported " + Utility.Descriptor(invocationExpression));
                            }

                            return;                             //Skip parameters
                        }
                    }
                }

                if (subExpressionOpt != null)
                {
                    WriteMemberAccessExpression.WriteMember(writer, subExpressionOpt);
                }

                if (subExpressionOpt != null && methodName != null)
                {
                    writer.Write(".");
                }

                writer.Write(methodName);
                writer.Write("(");
            }

            var prms = TranslateParameters(translateOpt, SortArguments(origMethodSymbol, invocationExpression.ArgumentList.Arguments, invocationExpression, extensionNamespace != null), invocationExpression).ToList();

            //If we invoke a method with type parameters that aren't used in the argument list, the haxe function won't have a way to see what args were used. To give it a way, add those as parameters at the end
            foreach (var typePrm in Utility.PassTypeArgsToMethod(origMethodSymbol))
            {
                var name = invocationExpression.Expression.ChildNodes().OfType <GenericNameSyntax>().ToList();
                if (name.Count == 0)
                {
                    name = invocationExpression.Expression.DescendantNodesAndSelf().OfType <GenericNameSyntax>().ToList(); //TODO: This will pick up false positives, we need a proper recursion function here
                }
                if (name.Count != 1)
                {
                    throw new Exception("Expected a single generic name, got " + string.Join(", ", name) + "  " + Utility.Descriptor(invocationExpression));
                }
                if (name.Count > 0 && name.Single().TypeArgumentList.Arguments.Count > 0)
                {
                    var typePrmIndex = origMethodSymbol.TypeParameters.IndexOf(origMethodSymbol.TypeParameters.Single(o => SymbolEqualityComparer.Default.Equals(o, typePrm)));
                    var genericVar   = name.Single().TypeArgumentList.Arguments.ElementAt(typePrmIndex);
                    if (genericVar.ToString() == typePrm.ToString())
                    {
                        writer.Write("t" + (typePrmIndex + 1));
                    }
                    else
                    {
                        prms.Add(new TransformedArgument(TypeProcessor.ConvertType(genericVar)));
                    }
                }
            }


            bool inParams = false;

            foreach (var arg in prms)
            {
                if (firstParameter)
                {
                    firstParameter = false;
                }
                else
                {
                    writer.Write(", ");
                }

                if (!inParams && IsParamsArgument(invocationExpression, arg.ArgumentOpt, origMethodSymbol) && TypeProcessor.ConvertType(model.GetTypeInfo(arg.ArgumentOpt.Expression).Type).StartsWith("Array<") == false)
                {
                    inParams = true;
                    writer.Write("[ ");
                }


                if (arg.ArgumentOpt != null &&
                    arg.ArgumentOpt.RefOrOutKeyword.Kind() != SyntaxKind.None &&
                    model.GetSymbolInfo(arg.ArgumentOpt.Expression).Symbol is IFieldSymbol)
                {
                    throw new Exception("ref/out cannot reference fields, only local variables.  Consider using ref/out on a local variable and then assigning it into the field. " + Utility.Descriptor(invocationExpression));
                }


                //When passing an argument by ref or out, leave off the .Value suffix
                if (arg.ArgumentOpt != null && arg.ArgumentOpt.RefOrOutKeyword.Kind() != SyntaxKind.None)
                {
                    WriteIdentifierName.Go(writer, arg.ArgumentOpt.Expression.As <IdentifierNameSyntax>(), true);
                }
                else if (arg.ArgumentOpt != null)
                {
                    WriteForEachStatement.CheckWriteEnumerator(writer, arg.ArgumentOpt.Expression, false);
                }
                else
                {
                    arg.Write(writer);
                }
            }

            if (inParams)
            {
                writer.Write(" ]");
            }


            writer.Write(")");
        }
        public static void Go(HaxeWriter writer, InvocationExpressionSyntax invocationExpression)
        {
            var model = Program.GetModel(invocationExpression);

            var symbolInfo       = model.GetSymbolInfo(invocationExpression);
            var expressionSymbol = model.GetSymbolInfo(invocationExpression.Expression);
            var methodSymbol     = symbolInfo.Symbol.OriginalDefinition.As <IMethodSymbol>().UnReduce();

            var translateOpt = MethodTranslation.Get(symbolInfo.Symbol.As <IMethodSymbol>());
            var memberReferenceExpressionOpt = invocationExpression.Expression as MemberAccessExpressionSyntax;
            var returnTypeHaxe = TypeProcessor.ConvertType(methodSymbol.ReturnType);
            var firstParameter = true;

            var              extensionNamespace = methodSymbol.IsExtensionMethod ? methodSymbol.ContainingNamespace.FullNameWithDot().ToLower() + methodSymbol.ContainingType.Name : null; //null means it's not an extension method, non-null means it is
            string           methodName;
            ExpressionSyntax subExpressionOpt;

            if (methodSymbol.ContainingType.Name == "Enum")
            {
                if (methodSymbol.Name == "Parse")
                {
                    WriteEnumParse(writer, invocationExpression);
                    return;
                }

                if (methodSymbol.Name == "GetValues")
                {
                    WriteEnumGetValues(writer, invocationExpression);
                    return;
                }
            }

            if (expressionSymbol.Symbol is IEventSymbol)
            {
                methodName = "Invoke";                 //Would need to append the number of arguments to this to support events.  However, events are not currently supported
            }
            else if (memberReferenceExpressionOpt != null && memberReferenceExpressionOpt.Expression is PredefinedTypeSyntax)
            {
                switch (methodSymbol.Name)
                {
                case "Parse":
                    var t = TypeProcessor.ConvertType(methodSymbol.ReturnType);

                    if (t == "Bool")
                    {
                        methodName         = "ParseBool";
                        extensionNamespace = "Cs2Hx";
                    }
                    else if (t == "Int" || t == "Float")
                    {
                        methodName         = "parse" + t;
                        extensionNamespace = "Std";
                    }
                    else
                    {
                        throw new Exception("Parse method on " + t + " is not supported.  " + Utility.Descriptor(memberReferenceExpressionOpt));
                    }

                    break;

                case "TryParse":
                    methodName         = "TryParse" + TypeProcessor.ConvertType(methodSymbol.Parameters[1].Type);
                    extensionNamespace = "Cs2Hx";
                    break;

                default:
                    methodName         = methodSymbol.Name;
                    extensionNamespace = "Cs2Hx";
                    break;
                }
            }
            else if (translateOpt != null && translateOpt.ReplaceWith != null)
            {
                methodName = translateOpt.ReplaceWith;
            }
            else if (methodSymbol.MethodKind == MethodKind.DelegateInvoke)
            {
                methodName = null;
            }
            else
            {
                methodName = OverloadResolver.MethodName(methodSymbol);
            }

            if (translateOpt != null && translateOpt.HasComplexReplaceWith)
            {
                translateOpt.DoComplexReplaceWith(writer, memberReferenceExpressionOpt);                 //TODO: What if this is null?
                return;
            }

            if (translateOpt != null && translateOpt.SkipExtensionParameter)
            {
                subExpressionOpt = null;
            }
            else if (methodSymbol.MethodKind == MethodKind.DelegateInvoke)
            {
                subExpressionOpt = invocationExpression.Expression;
            }
            else if (memberReferenceExpressionOpt != null)
            {
                if (memberReferenceExpressionOpt.Expression is PredefinedTypeSyntax)
                {
                    subExpressionOpt = null;
                }
                else
                {
                    subExpressionOpt = memberReferenceExpressionOpt.Expression;
                }
            }
            else
            {
                subExpressionOpt = null;                 //TODO
            }
            //Determine if it's an extension method called in a non-extension way.  In this case, just pretend it's not an extension method
            if (extensionNamespace != null && subExpressionOpt != null && model.GetTypeInfo(subExpressionOpt).ConvertedType.ToString() == methodSymbol.ContainingNamespace + "." + methodSymbol.ContainingType.Name)
            {
                extensionNamespace = null;
            }

            if (translateOpt != null && !string.IsNullOrEmpty(translateOpt.ExtensionNamespace))
            {
                extensionNamespace = translateOpt.ExtensionNamespace;
            }
            else if (translateOpt != null && translateOpt.ExtensionNamespace == "")
            {
                extensionNamespace = null;
            }

            if (extensionNamespace != null)
            {
                writer.Write(extensionNamespace);

                if (methodName != null)
                {
                    writer.Write(".");
                    writer.Write(methodName);
                }

                writer.Write("(");

                if (subExpressionOpt != null)
                {
                    firstParameter = false;

                    if (methodSymbol.IsExtensionMethod)
                    {
                        WriteForEachStatement.CheckWriteEnumerator(writer, subExpressionOpt, true);
                    }
                    else
                    {
                        Core.Write(writer, subExpressionOpt);
                    }
                }
            }
            else
            {
                if (memberReferenceExpressionOpt != null)
                {
                    var memberType     = model.GetTypeInfo(memberReferenceExpressionOpt.Expression).Type;
                    var memberTypeHaxe = TypeProcessor.ConvertType(memberType);

                    //sort calls without any parameters need to get the default sort parameter
                    if (methodName == "sort" && invocationExpression.ArgumentList.Arguments.Count == 0)
                    {
                        Core.Write(writer, memberReferenceExpressionOpt.Expression);
                        writer.Write(".sort(");

                        switch (memberTypeHaxe)
                        {
                        case "Array<Int>":
                            writer.Write("Cs2Hx.SortInts");
                            break;

                        case "Array<Float>":
                            writer.Write("Cs2Hx.SortFloats");
                            break;

                        case "Array<String>":
                            writer.Write("Cs2Hx.SortStrings");
                            break;

                        default:
                            throw new Exception("Unknown default sort type: " + memberTypeHaxe + ".  " + Utility.Descriptor(invocationExpression));
                        }

                        writer.Write(")");
                        return;
                    }

                    //Check against lowercase toString since it gets replaced with the haxe name before we get here
                    if (methodName == "toString")
                    {
                        if (memberType.TypeKind == TypeKind.Enum)
                        {
                            //calling ToString() on an enum forwards to our enum's special ToString method
                            writer.Write(memberType.ContainingNamespace.FullNameWithDot().ToLower());
                            writer.Write(WriteType.TypeName((INamedTypeSymbol)memberType));
                            writer.Write(".ToString(");
                            Core.Write(writer, memberReferenceExpressionOpt.Expression);
                            writer.Write(")");

                            if (invocationExpression.ArgumentList.Arguments.Count > 0)
                            {
                                throw new Exception("Enum's ToString detected with parameters.  These are not supported " + Utility.Descriptor(invocationExpression));
                            }

                            return;
                        }

                        if (memberType.SpecialType == SpecialType.System_Char)
                        {
                            writer.Write("Cs2Hx.CharToString(");
                            Core.Write(writer, memberReferenceExpressionOpt.Expression);
                            writer.Write(")");

                            if (invocationExpression.ArgumentList.Arguments.Count > 0)
                            {
                                throw new Exception("Char's ToString detected with parameters.  These are not supported " + Utility.Descriptor(invocationExpression));
                            }

                            return;
                        }

                        if (memberTypeHaxe == "Int" || memberTypeHaxe == "Float" || memberTypeHaxe == "Bool" || memberType.TypeKind == TypeKind.TypeParameter)
                        {
                            //ToString()'s on primitive types get replaced with Std.string
                            writer.Write("Std.string(");

                            if (memberReferenceExpressionOpt.Expression is ParenthesizedExpressionSyntax)
                            {
                                Core.Write(writer, memberReferenceExpressionOpt.Expression.As <ParenthesizedExpressionSyntax>().Expression);                                //eat a set of parenthesis, just to make the output code a bit nicer.
                            }
                            else
                            {
                                Core.Write(writer, memberReferenceExpressionOpt.Expression);
                            }

                            writer.Write(")");

                            if (invocationExpression.ArgumentList.Arguments.Count > 0)
                            {
                                throw new Exception("Primitive type's ToString detected with parameters.  These are not supported " + Utility.Descriptor(invocationExpression));
                            }

                            return;                             //Skip parameters
                        }
                    }
                }

                if (subExpressionOpt != null)
                {
                    WriteMemberAccessExpression.WriteMember(writer, subExpressionOpt);
                }

                if (subExpressionOpt != null && methodName != null)
                {
                    writer.Write(".");
                }

                writer.Write(methodName);
                writer.Write("(");
            }

            bool inParams = false;

            foreach (var arg in TranslateParameters(translateOpt, SortArguments(methodSymbol, invocationExpression.ArgumentList.Arguments, invocationExpression), invocationExpression))
            {
                if (firstParameter)
                {
                    firstParameter = false;
                }
                else
                {
                    writer.Write(", ");
                }

                if (!inParams && IsParamsArgument(invocationExpression, arg.ArgumentOpt, methodSymbol) && TypeProcessor.ConvertType(model.GetTypeInfo(arg.ArgumentOpt.Expression).Type).StartsWith("Array<") == false)
                {
                    inParams = true;
                    writer.Write("[ ");
                }


                if (arg.ArgumentOpt != null &&
                    arg.ArgumentOpt.RefOrOutKeyword.Kind() != SyntaxKind.None &&
                    model.GetSymbolInfo(arg.ArgumentOpt.Expression).Symbol is IFieldSymbol)
                {
                    throw new Exception("ref/out cannot reference fields, only local variables.  Consider using ref/out on a local variable and then assigning it into the field. " + Utility.Descriptor(invocationExpression));
                }


                //When passing an argument by ref or out, leave off the .Value suffix
                if (arg.ArgumentOpt != null && arg.ArgumentOpt.RefOrOutKeyword.Kind() != SyntaxKind.None)
                {
                    WriteIdentifierName.Go(writer, arg.ArgumentOpt.Expression.As <IdentifierNameSyntax>(), true);
                }
                else if (arg.ArgumentOpt != null)
                {
                    WriteForEachStatement.CheckWriteEnumerator(writer, arg.ArgumentOpt.Expression, false);
                }
                else
                {
                    arg.Write(writer);
                }
            }

            if (inParams)
            {
                writer.Write(" ]");
            }


            writer.Write(")");
        }