From 10e86929ab5064af928421f9d7ffec8660df2310 Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Tue, 19 Dec 2023 21:18:12 -0800 Subject: [PATCH] Classify generic constraints Fixes #301 --- grammars/csharp.tmLanguage | 18 ++++++++++ grammars/csharp.tmLanguage.cson | 12 +++++++ src/csharp.tmLanguage.yml | 6 ++++ test/class.tests.ts | 59 +++++++++++++++++++++++++++++++++ test/utils/tokenize.ts | 6 ++++ 5 files changed, 101 insertions(+) diff --git a/grammars/csharp.tmLanguage b/grammars/csharp.tmLanguage index 2195f9f..90bc891 100644 --- a/grammars/csharp.tmLanguage +++ b/grammars/csharp.tmLanguage @@ -1566,6 +1566,24 @@ match \bstruct\b + + name + keyword.other.constraint.default.cs + match + \bdefault\b + + + name + keyword.other.constraint.notnull.cs + match + \bnotnull\b + + + name + keyword.other.constraint.unmanaged.cs + match + \bunmanaged\b + match (new)\s*(\()\s*(\)) diff --git a/grammars/csharp.tmLanguage.cson b/grammars/csharp.tmLanguage.cson index d8534ce..aa8cfdc 100644 --- a/grammars/csharp.tmLanguage.cson +++ b/grammars/csharp.tmLanguage.cson @@ -979,6 +979,18 @@ repository: name: "storage.type.struct.cs" match: "\\bstruct\\b" } + { + name: "keyword.other.constraint.default.cs" + match: "\\bdefault\\b" + } + { + name: "keyword.other.constraint.notnull.cs" + match: "\\bnotnull\\b" + } + { + name: "keyword.other.constraint.unmanaged.cs" + match: "\\bunmanaged\\b" + } { match: "(new)\\s*(\\()\\s*(\\))" captures: diff --git a/src/csharp.tmLanguage.yml b/src/csharp.tmLanguage.yml index d331b57..eb3ff8b 100644 --- a/src/csharp.tmLanguage.yml +++ b/src/csharp.tmLanguage.yml @@ -496,6 +496,12 @@ repository: match: \bclass\b - name: storage.type.struct.cs match: \bstruct\b + - name: keyword.other.constraint.default.cs + match: \bdefault\b + - name: keyword.other.constraint.notnull.cs + match: \bnotnull\b + - name: keyword.other.constraint.unmanaged.cs + match: \bunmanaged\b - match: (new)\s*(\()\s*(\)) captures: '1': { name: keyword.operator.expression.new.cs } diff --git a/test/class.tests.ts b/test/class.tests.ts index a575cda..4849620 100644 --- a/test/class.tests.ts +++ b/test/class.tests.ts @@ -330,6 +330,65 @@ unsafe class C Token.Punctuation.CloseBrace]); }); + it(`class with various generic type constraints (#301)`, async () => { + const input = Input.InNamespace(` +class NotNullContainer where T : notnull +{ + private unsafe static void DisplaySize() + where T : unmanaged { } + public override void M(T? item) + where T : default { } +}`, namespaceStyle); + const tokens = await tokenize(input); + + tokens.should.deep.equal([ + Token.Keyword.Definition.Class, + Token.Identifier.ClassName("NotNullContainer"), + Token.Punctuation.TypeParameter.Begin, + Token.Identifier.TypeParameterName("T"), + Token.Punctuation.TypeParameter.End, + Token.Keyword.Modifier.Where, + Token.Identifier.TypeParameterName("T"), + Token.Punctuation.Colon, + Token.Keyword.Constraint.NotNull, + Token.Punctuation.OpenBrace, + Token.Keyword.Modifier.Private, + Token.Keyword.Modifier.Unsafe, + Token.Keyword.Modifier.Static, + Token.PrimitiveType.Void, + Token.Identifier.MethodName("DisplaySize"), + Token.Punctuation.TypeParameter.Begin, + Token.Identifier.TypeParameterName("T"), + Token.Punctuation.TypeParameter.End, + Token.Punctuation.OpenParen, + Token.Punctuation.CloseParen, + Token.Keyword.Modifier.Where, + Token.Identifier.TypeParameterName("T"), + Token.Punctuation.Colon, + Token.Keyword.Constraint.Unmanaged, + Token.Punctuation.OpenBrace, + Token.Punctuation.CloseBrace, + Token.Keyword.Modifier.Public, + Token.Keyword.Modifier.Override, + Token.PrimitiveType.Void, + Token.Identifier.MethodName("M"), + Token.Punctuation.TypeParameter.Begin, + Token.Identifier.TypeParameterName("T"), + Token.Punctuation.TypeParameter.End, + Token.Punctuation.OpenParen, + Token.Type("T"), + Token.Punctuation.QuestionMark, + Token.Identifier.ParameterName("item"), + Token.Punctuation.CloseParen, + Token.Keyword.Modifier.Where, + Token.Identifier.TypeParameterName("T"), + Token.Punctuation.Colon, + Token.Keyword.Constraint.Default, + Token.Punctuation.OpenBrace, + Token.Punctuation.CloseBrace, + Token.Punctuation.CloseBrace]); + }); + it(`primary constructor (${styleName} Namespace)`, async () => { const input = Input.InNamespace(` diff --git a/test/utils/tokenize.ts b/test/utils/tokenize.ts index de33a85..71f950d 100644 --- a/test/utils/tokenize.ts +++ b/test/utils/tokenize.ts @@ -269,6 +269,12 @@ export namespace Token { export const When = createToken('when', 'keyword.control.conditional.when.cs'); } + export namespace Constraint { + export const Default = createToken('default', 'keyword.other.constraint.default.cs'); + export const NotNull = createToken('notnull', 'keyword.other.constraint.notnull.cs'); + export const Unmanaged = createToken('unmanaged', 'keyword.other.constraint.unmanaged.cs'); + } + export namespace Context { export const Checked = createToken('checked', 'keyword.control.context.checked.cs'); export const Fixed = createToken('fixed', 'keyword.control.context.fixed.cs');