roslyn: Code generation involving some literals does not work correctly

For instance, I want to generate something like:

class A
{
    public A() : this(2.0d)
    {
    }

    public A(double value)
    {
    }
}

What we do with value is really beside the point. The point is the double literal d is dropped from the Literal specification. As is the f if I wanted to specify a float literal.

There are double and float versions of Microsoft.CodeAnalysis.CSharp.SyntaxFactory.Literal, right? i.e.

public static SyntaxToken Literal(float value);
public static SyntaxToken Literal(double value);

By contrast, the long version of the same does respect the literal specification, i.e. 2L,

public static SyntaxToken Literal(long value);

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 58 (34 by maintainers)

Most upvoted comments

Note: i don’t know what the antlr bit was about. It seems like a non-sequitor here. As do the comments about nodes/tokens/etc. As this is a code generation problem, and the code generation is working as expected, with appropriate mechanisms for all code-gen authors to get the behavior they want, it seems like this was not an API problem but stemmed from a misunderstanding from the user on how these APIs worked.

It might be worthwhile to improve the docs here in the future if there is more confusion.

@mwpowellhtx It sounds like the D suffix is omitted for doubles. This suffix is optional whenever there is a decimal point in the literal text. Can you confirm that the text you get for Literal(0.0d) is 0.0, which is one of several allowed forms for this token?

Note: i wrote this up in about 20 seconds 😃

        var workspace = new AdhocWorkspace();
        var proj = workspace.AddProject("temp", LanguageNames.CSharp);
        var doc = workspace.AddDocument(proj.Id, "temp.cs", SourceText.From(""));

        var generator = SyntaxGenerator.GetGenerator(doc);
        double d = 0;
        var literal = generator.LiteralExpression(d);
        Console.WriteLine(literal.ToFullString());

As you want, it produces the value with the D:

image

The only thing with SyntaxGenerator is that it requires, Microsoft.CodeAnalysis.CSharp.Workspace, which is a bit heavier of a lift than we are aiming for for code generation purposes.

Why? It’s just an added dll…

Probably a non-starter to go that route.

In that case, you will have to use the appropriate overloads where you specify the text you want.

The right answer is to fix the Literal(double), or Literal(float) to do the right thing.

They are doing the right thing. Literal(float) should already be adding F (like Literal(long) adds L), and Literal(double) should not be adding anything (just like Literal(int)).

@CyrusNajmabadi I disagree, it is useful. It shows you that the result is not generating given the expected double literal outcome.

It looks like it generated exactly the right thing. 0 is the representation for the double-value 0 to .net.

As i mentioned above, the two expected ways to handle this are to either explicitly provide the string in the format you want (since there are tons of ways it could be formatted). Or to use SyntaxGenerator, which attempts to be less strict and makes these sorts of decisions on your behalf.

You’re using the raw API which doesn’t interpret (which i mentioned yesterday). When you use the raw API, you get almost no special handling on your behalf. It gives you a huge amount of control, but you’re taking a lot of the effort into your own hands. If you want that effort reduced, you can use the existing APIs that attempt to do that (however, you may lose some control you want at some points).

However, SyntaxFactory is not going to become SyntaxGenerator. Its purpose is to be the low-level raw api that everyone else can build on top of.

The behavior looks correct to me. There are two things you can do here. The first, as mentioned above, is to call the appropriate overload of Literal that allows you to specify exactly what you want for the text.

The second is to use SyntaxGenerator which is the nicer user-facing (i.e. “less-raw”) approach to syntax generation. It will always place a ‘D’ after a double for example.

The generated code isn’t useful to me here 😃 I need to see waht you’re actually doing to generate it 😄 We can take this to gitter if you want.

However, based on what you’ve said, you can address this the appropriate way by calling Literal(value.ToString("R", CultureInfo.InvariantCulture) + "D", value)