Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(C#) Keyword before tuple return type is highlighted as a method name #2681

Closed
Youssef1313 opened this issue Sep 10, 2020 · 15 comments · Fixed by #2683
Closed

(C#) Keyword before tuple return type is highlighted as a method name #2681

Youssef1313 opened this issue Sep 10, 2020 · 15 comments · Fixed by #2683
Labels
bug help welcome Could use help from community language

Comments

@Youssef1313
Copy link
Contributor

Describe the issue

image

See https://docs.microsoft.com/en-us/dotnet/csharp/discards#tuple-and-object-deconstruction for example.

Which language seems to have the issue?

C#

Sample Code to Reproduce

private static (int, int) GetOriginCoordinates()
{
    return (0, 0);
}

Expected behavior

static should be highlighted as a keyword (i.e. hljs-keyword), not as a function name (i.e. hljs-title)

To avoid merge conflicts, this should wait until #2679 is merged.

@Youssef1313 Youssef1313 added bug help welcome Could use help from community language labels Sep 10, 2020
@IEvangelist
Copy link
Contributor

I'm assuming that the title mechanism is based on a RegExp that scan for the first occurrence on a line with the opening parenthesis (. This would cause the return tuple types to cause any keyword before to be treated as a hljs-title, not just static.

@joshgoebel
Copy link
Member

I'd guess TYPE_IDENT_RE isn't wide enough to know what a tuple type is. PR would be welcome. :)

@joshgoebel
Copy link
Member

Can tuples include other advanced types also such as Vector<string>[] or whatever? (I don't know c# types)

@Youssef1313
Copy link
Contributor Author

Youssef1313 commented Sep 11, 2020

@joshgoebel Here are some different variations (some may be rarely used, but still valid):

using System.Collections.Generic;

public class C
{
    private static (int, int) GetOriginCoordinates()
    {
        return (0, 0);
    }

    private static (int X, int Y) GetOriginCoordinates2()
    {
        return (0, 0);
    }
    
    private static Dictionary<string, (int, int)> GetCoordinates()
    {
        return new Dictionary<string, (int, int)>
        {
            { "Origin", (0, 0) },
            { "One_One", (1, 1) }
        };
    }
    
    private static Dictionary<string, (int X, int Y)> GetCoordinates2()
    {
        return new Dictionary<string, (int X, int Y)>
        {
            { "Origin", (0, 0) },
            { "One_One", (1, 1) }
        };
    }
    
    private static (int DivisibleBy, List<int> Numbers) DivisiblesByTwo()
    {
        return (2, new List<int> { 2, 4, 6, 8, 10 });
    }
}

@joshgoebel
Copy link
Member

@joshgoebel Can a tuple include a tuple?

@Youssef1313
Copy link
Contributor Author

@joshgoebel Yes they can be nested to multiple levels.

@joshgoebel
Copy link
Member

e8eef17#diff-8b07d3d641e06fd8cbdabdf8115c0ddeR121

Any other leading keywords I'm not thinking of we should add?

@Youssef1313
Copy link
Contributor Author

internal and protected.

Pinging @IEvangelist to confirm if I'm not missing any others.

Also this change is for C# not Java

@IEvangelist
Copy link
Contributor

IEvangelist commented Sep 11, 2020

Hi @Youssef1313 and @joshgoebel

How would async be treated? Is that something that is separate? It too would be a keyword that is valid before the return type is defined in a method signature in C#. In fact there are lots of modifiers that could appear before the return type:

  • abstract
  • async
  • extern
  • override
  • unsafe
  • virtual

Are these what you're after? See C# keywords, and look at the Modifiers section. Not all of these are available prior to a return type, but a lot are. This is making me think that we should add more C# tests, with more variations of the syntax. We should also expand the C# example in the demo to include more code.

@joshgoebel
Copy link
Member

joshgoebel commented Sep 11, 2020

In fact there are lots of modifiers that could appear before the return type:

Why wouldn't we want to add the full list (of the ones available) - so they would be detected as keywords and never as the accidental name of a function?

@joshgoebel
Copy link
Member

@IEvangelist Why would "async" be special?

Again, the context here is "preventing keywords from being falsley detected as name of function"... one easy way to do that (given a finite set) is to just exclude them all and tell it they are modifiers...

@IEvangelist
Copy link
Contributor

I guess I was confused by how this all comes together, I'm not really sure how it works internally - I was more or less stating that there are additional keywords that come before return types in C#. All of these keywords are already captured in my previously merged PR, so why is this change necessary?

@joshgoebel
Copy link
Member

joshgoebel commented Sep 11, 2020

Because #context.

        v ----- this looks TOO much like a function named `unsafe`
private unsafe (int, int) GetOriginCoordinates()

So we need a safe list of modifier words to prevent them from being wrongly detected as function names. Then the tuple is wrongly/conveniently detected as "params" and just works. The alternative is someone writing an amazingly complicated "type regex" to detect all possible type declarations, and I'm not even sure that's possible.

So just have a safe list of modifiers seems to be a simple solution.

@IEvangelist
Copy link
Contributor

Ah, ok. Thank you for the added context, that is really helpful. I agree. Then the safe list of modifiers would be something like:

  • abstract
  • async
  • extern
  • override
  • unsafe
  • virtual
  • private
  • protected
  • internal
  • public
  • static

What do you think @Youssef1313?

@Youssef1313
Copy link
Contributor Author

Youssef1313 commented Sep 11, 2020

Ah, ok. Thank you for the added context, that is really helpful. I agree. Then the safe list of modifiers would be something like:

* `abstract`

* `async`

* `extern`

* `override`

* `unsafe`

* `virtual`

* `private`

* `protected`

* `internal`

* `public`

* `static`

What do you think @Youssef1313?

That list looks great and adds many many that dropped of my mind. Probably add new (when used for shadowing base class method), sealed, and partial to this list too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug help welcome Could use help from community language
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants