public static void Go(ScalaWriter 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("symbolInfo.Symbol null at " + Utility.Descriptor(invocationExpression)); } if (symbolInfo.Symbol.OriginalDefinition == null) { throw new Exception("symbolInfo.Symbol.OriginalDefinition null at " + Utility.Descriptor(invocationExpression)); } var methodSymbol = symbolInfo.Symbol.OriginalDefinition.As <IMethodSymbol>().UnReduce(); var translateOpt = MethodTranslation.Get(symbolInfo.Symbol.As <IMethodSymbol>()); var memberReferenceExpressionOpt = invocationExpression.Expression as MemberAccessExpressionSyntax; var firstParameter = true; var extensionNamespace = methodSymbol.IsExtensionMethod ? methodSymbol.ContainingNamespace.FullNameWithDot() + methodSymbol.ContainingType.Name : null; //null means it's not an extension method, non-null means it is string methodName; string typeParameters = null; ExpressionSyntax subExpressionOpt; if (methodSymbol.ContainingType.Name == "Enum") { if (methodSymbol.Name == "Parse") { WriteEnumParse(writer, invocationExpression); return; } if (methodSymbol.Name == "TryParse") { WriteEnumTryParse(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": if (invocationExpression.ArgumentList.Arguments.Count > 1) { throw new Exception("Multiple arguments to .Parse methods are not supported: " + Utility.Descriptor(invocationExpression)); } Core.Write(writer, invocationExpression.ArgumentList.Arguments.Single().Expression); writer.Write(".trim().to"); //we must trim strings before parsing them. In C#, a string like "4 " parses just fine, but if we don't trim this same string would false to parse in java writer.Write(TypeProcessor.ConvertType(methodSymbol.ReturnType)); return; case "TryParse": methodName = "TryParse" + TypeProcessor.ConvertType(methodSymbol.Parameters[1].Type); extensionNamespace = "CsScala"; break; default: methodName = methodSymbol.Name; extensionNamespace = "CsScala"; 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); 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; } //When the code specifically names generic arguments, include them in the method name var genNameExpression = invocationExpression.Expression as GenericNameSyntax; if (genNameExpression == null && memberReferenceExpressionOpt != null) { genNameExpression = memberReferenceExpressionOpt.Name as GenericNameSyntax; } if (genNameExpression != null && genNameExpression.TypeArgumentList.Arguments.Count > 0) { typeParameters = "[" + string.Join(", ", genNameExpression.TypeArgumentList.Arguments.Select(TypeProcessor.ConvertType)) + "]"; } //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; } var memberType = memberReferenceExpressionOpt == null ? null : model.GetTypeInfo(memberReferenceExpressionOpt.Expression).Type; var isNullableEnum = memberType != null && (memberType.Name == "Nullable" && memberType.ContainingNamespace.FullName() == "System") && memberType.As <INamedTypeSymbol>().TypeArguments.Single().TypeKind == TypeKind.Enum; if (isNullableEnum && methodSymbol.Name == "ToString") { extensionNamespace = null; //override Translations.xml for nullable enums. We want them to convert to the enum's ToString method methodName = "toString"; } if (extensionNamespace != null) { writer.Write(extensionNamespace); if (methodName != null) { writer.Write("."); writer.Write(methodName); } WriteTypeParameters(writer, translateOpt, typeParameters, invocationExpression); writer.Write("("); if (subExpressionOpt != null) { firstParameter = false; Core.Write(writer, subExpressionOpt); } } else { if (memberReferenceExpressionOpt != null) { //Check against lowercase toString since it gets replaced with the lowered version before we get here if (methodName == "toString") { if (memberType.TypeKind == TypeKind.Enum || isNullableEnum) { var enumType = memberType.TypeKind == TypeKind.Enum ? memberType : memberType.As <INamedTypeSymbol>().TypeArguments.Single(); //calling ToString() on an enum forwards to our enum's special ToString method writer.Write(enumType.ContainingNamespace.FullNameWithDot()); writer.Write(WriteType.TypeName((INamedTypeSymbol)enumType)); 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_Byte) { //Calling ToString on a byte needs to take special care since it's signed in the JVM writer.Write("System.CsScala.ByteToString("); Core.Write(writer, memberReferenceExpressionOpt.Expression); writer.Write(")"); if (invocationExpression.ArgumentList.Arguments.Count > 0) { throw new Exception("Byte's ToString detected with parameters. These are not supported " + Utility.Descriptor(invocationExpression)); } return; } } } if (subExpressionOpt != null) { WriteMemberAccessExpression.WriteMember(writer, subExpressionOpt); if (methodName != null) { writer.Write("."); } } else if (methodSymbol.IsStatic && extensionNamespace == null) { writer.Write(methodSymbol.ContainingNamespace.FullNameWithDot()); writer.Write(WriteType.TypeName(methodSymbol.ContainingType)); writer.Write("."); } writer.Write(methodName); WriteTypeParameters(writer, translateOpt, typeParameters, invocationExpression); writer.Write("("); } bool inParams = false; bool foundParamsArray = false; foreach (var arg in TranslateParameters(translateOpt, invocationExpression.ArgumentList.Arguments, invocationExpression)) { if (firstParameter) { firstParameter = false; } else { writer.Write(", "); } if (!inParams && IsParamsArgument(invocationExpression, arg.ArgumentOpt, methodSymbol)) { foundParamsArray = true; if (!TypeProcessor.ConvertType(model.GetTypeInfo(arg.ArgumentOpt.Expression).Type).StartsWith("Array[")) { inParams = true; writer.Write("Array("); } } 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 { arg.Write(writer); } } if (inParams) { writer.Write(")"); } else if (!foundParamsArray && methodSymbol.Parameters.Any() && methodSymbol.Parameters.Last().IsParams) { writer.Write(", Array()"); //params method called without any params argument. Send an empty array. } writer.Write(")"); }
private static void Factory(ScalaWriter writer, SyntaxNode node, bool isConst) { 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) { WriteConstructorBody.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>(), isConst); } 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 AssignmentExpressionSyntax) { WriteBinaryExpression.Go(writer, node.As <AssignmentExpressionSyntax>()); } 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.WriteThrowExpression(writer, node.As <ThrowExpressionSyntax>()); } 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 ContinueStatementSyntax) { WriteContinueStatement.Go(writer, node.As <ContinueStatementSyntax>()); } 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 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 - TypeProcessor converts them to function types directly } 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 PrefixUnaryExpressionSyntax) { WriteUnaryExpression.WritePrefix(writer, node.As <PrefixUnaryExpressionSyntax>()); } else if (node is PostfixUnaryExpressionSyntax) { WriteUnaryExpression.WritePostfix(writer, node.As <PostfixUnaryExpressionSyntax>()); } else if (node is SizeOfExpressionSyntax) { WriteSizeOfExpression.Go(writer, node.As <SizeOfExpressionSyntax>()); } else { throw new NotImplementedException(node.GetType().Name + " is not supported. " + Utility.Descriptor(node)); } }