Skip to content

Commit

Permalink
Classify generic constraints
Browse files Browse the repository at this point in the history
Fixes #301
  • Loading branch information
JoeRobich committed Dec 20, 2023
1 parent 0febdc7 commit 10e8692
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 0 deletions.
18 changes: 18 additions & 0 deletions grammars/csharp.tmLanguage
Original file line number Diff line number Diff line change
Expand Up @@ -1566,6 +1566,24 @@
<key>match</key>
<string>\bstruct\b</string>
</dict>
<dict>
<key>name</key>
<string>keyword.other.constraint.default.cs</string>
<key>match</key>
<string>\bdefault\b</string>
</dict>
<dict>
<key>name</key>
<string>keyword.other.constraint.notnull.cs</string>
<key>match</key>
<string>\bnotnull\b</string>
</dict>
<dict>
<key>name</key>
<string>keyword.other.constraint.unmanaged.cs</string>
<key>match</key>
<string>\bunmanaged\b</string>
</dict>
<dict>
<key>match</key>
<string>(new)\s*(\()\s*(\))</string>
Expand Down
12 changes: 12 additions & 0 deletions grammars/csharp.tmLanguage.cson
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
6 changes: 6 additions & 0 deletions src/csharp.tmLanguage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
59 changes: 59 additions & 0 deletions test/class.tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<T> where T : notnull
{
private unsafe static void DisplaySize<T>()
where T : unmanaged { }
public override void M<T>(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(`
Expand Down
6 changes: 6 additions & 0 deletions test/utils/tokenize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down

0 comments on commit 10e8692

Please sign in to comment.