diff --git a/docs/en/features/semantic-tokens.md b/docs/en/features/semantic-tokens.md
index e6c01e4ac..5494b5ae5 100644
--- a/docs/en/features/semantic-tokens.md
+++ b/docs/en/features/semantic-tokens.md
@@ -104,6 +104,10 @@ Kinds derived from the token stream itself, independent of the AST.
#endif
#pragma pack(1)
+
+ #
+ #define STRINGIZE(x) #x
+ const char* stringized = STRINGIZE(abc);
```
@@ -173,7 +177,7 @@ Kinds derived from the token stream itself, independent of the AST.
-- [ ] Primitive token type — a distinct kind for built-in types instead of plain `keyword`
+- [x] Primitive token type — a distinct kind for built-in types instead of plain `keyword`
Example
@@ -182,6 +186,9 @@ Kinds derived from the token stream itself, independent of the AST.
int number = 0;
float ratio = 0.5f;
void act();
+ unsigned long long wide_number = 0;
+ __int128 extended_int = 0;
+ _Float16 extended_float = 0;
```
diff --git a/docs/zh/features/semantic-tokens.md b/docs/zh/features/semantic-tokens.md
index 61ea412a4..626784846 100644
--- a/docs/zh/features/semantic-tokens.md
+++ b/docs/zh/features/semantic-tokens.md
@@ -146,7 +146,7 @@
### 额外 Token 类型
-- [ ] Primitive token 类型用于内置类型(`int`、`float`、`void` 等)
+- [x] Primitive token 类型用于内置类型(`int`、`float`、`void` 等)
- [ ] Bracket token 类型用于匹配的括号对(`[]`、`()`、`{}`、`<>`)
## Token 修饰符
diff --git a/editors/vscode/package.json b/editors/vscode/package.json
index dc751a3a3..09711cc08 100644
--- a/editors/vscode/package.json
+++ b/editors/vscode/package.json
@@ -164,6 +164,11 @@
"id": "angle",
"description": "Angle brackets `<>`",
"superType": "operator"
+ },
+ {
+ "id": "primitive",
+ "description": "C/C++ primitive type (e.g., int, float)",
+ "superType": "keyword"
}
],
"views": {
diff --git a/src/feature/document_symbols.cpp b/src/feature/document_symbols.cpp
index 6c81e6ba7..ba24832bf 100644
--- a/src/feature/document_symbols.cpp
+++ b/src/feature/document_symbols.cpp
@@ -42,6 +42,7 @@ auto to_protocol_symbol_kind(SymbolKind kind) -> protocol::SymbolKind {
case SymbolKind::Parameter:
case SymbolKind::Label:
case SymbolKind::Keyword:
+ case SymbolKind::Primitive:
case SymbolKind::Directive:
case SymbolKind::MacroParameter:
case SymbolKind::Attribute: return Variable;
diff --git a/src/feature/semantic_tokens.cpp b/src/feature/semantic_tokens.cpp
index 76a83aa36..3d9a68fa6 100644
--- a/src/feature/semantic_tokens.cpp
+++ b/src/feature/semantic_tokens.cpp
@@ -14,6 +14,7 @@
#include "llvm/ADT/DenseMap.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/TokenKinds.h"
namespace clice::feature {
@@ -322,47 +323,69 @@ class SemanticTokensCollector {
/// small state machine for preprocessor directive context.
Classified classify_lexical(const clang::syntax::Token& token, std::uint32_t offset) {
Classified lexical;
+ bool is_identifier_like = clang::tok::isAnyIdentifier(token.kind());
switch(token.kind()) {
case clang::tok::numeric_constant: lexical.kind = SymbolKind::Number; break;
+
+ /// Character literals
case clang::tok::char_constant:
case clang::tok::wide_char_constant:
case clang::tok::utf8_char_constant:
case clang::tok::utf16_char_constant:
case clang::tok::utf32_char_constant: lexical.kind = SymbolKind::Character; break;
+
+ /// String literals
case clang::tok::string_literal:
case clang::tok::wide_string_literal:
case clang::tok::utf8_string_literal:
case clang::tok::utf16_string_literal:
case clang::tok::utf32_string_literal: lexical.kind = SymbolKind::String; break;
- case clang::tok::hash: {
- if(directive_context == DirectiveContext::None) {
- lexical.kind = SymbolKind::Directive;
- directive_context = DirectiveContext::AfterHash;
- }
+
+ /// Fundamental and Clang/GNU builtin types; `__fp16` lexes as
+ /// `kw_half`.
+ case clang::tok::kw_bool:
+ case clang::tok::kw_char:
+ case clang::tok::kw_wchar_t:
+ case clang::tok::kw_char8_t:
+ case clang::tok::kw_char16_t:
+ case clang::tok::kw_char32_t:
+ case clang::tok::kw_double:
+ case clang::tok::kw_float:
+ case clang::tok::kw_int:
+ case clang::tok::kw_long:
+ case clang::tok::kw_short:
+ case clang::tok::kw_signed:
+ case clang::tok::kw_unsigned:
+ case clang::tok::kw_void:
+ case clang::tok::kw_half:
+ case clang::tok::kw__BitInt:
+ case clang::tok::kw__Bool:
+ case clang::tok::kw__Complex:
+ case clang::tok::kw__Decimal128:
+ case clang::tok::kw__Decimal32:
+ case clang::tok::kw__Decimal64:
+ case clang::tok::kw__ExtInt:
+ case clang::tok::kw__Float16:
+ case clang::tok::kw__Imaginary:
+ case clang::tok::kw___bf16:
+ case clang::tok::kw___float128:
+ case clang::tok::kw___ibm128:
+ case clang::tok::kw___int64:
+ case clang::tok::kw___int128: {
+ lexical.kind = SymbolKind::Primitive;
+ is_identifier_like = true;
break;
}
+
+ /// PP directive hash
+ case clang::tok::hash: break;
+
default: {
- if(directive_context == DirectiveContext::AfterHash) {
- /// The directive name right after `#`, e.g. `include`, `if`.
- lexical.kind = SymbolKind::Directive;
- auto spelling = content.substr(offset, token.length());
- if(spelling == "include" || spelling == "include_next" ||
- spelling == "import" || spelling == "embed") {
- directive_context = DirectiveContext::InIncludeName;
- } else if(spelling == "define") {
- directive_context = DirectiveContext::AfterDefine;
- } else {
- directive_context = DirectiveContext::InDirective;
- }
- } else if(directive_context == DirectiveContext::AfterDefine) {
- /// The macro name of a #define. Also covers preamble
- /// defines under a PCH, where no MacroDefine node exists
- /// (the preamble's directives live in the PCH compile).
- lexical.kind = SymbolKind::Macro;
- directive_context = DirectiveContext::InDirective;
- } else if(clang::tok::getKeywordSpelling(token.kind())) {
+ if(clang::tok::getKeywordSpelling(token.kind())) {
lexical.kind = SymbolKind::Keyword;
+ is_identifier_like = true;
+ break;
} else if(auto* punctuator = clang::tok::getPunctuatorSpelling(token.kind())) {
/// Alternative operator spellings (and, or, not, ...) lex
/// as their punctuator kinds but are written as words.
@@ -376,26 +399,66 @@ class SemanticTokensCollector {
}
}
- /// The filename of an #include: either a string literal or the
- /// `` token sequence; adjacent merging joins the pieces.
- /// The header context ends with the filename, so directive operands
- /// after it (e.g. #embed parameters) keep their own classification.
- if(directive_context == DirectiveContext::InIncludeName &&
- lexical.kind != SymbolKind::Directive) {
- if(token.kind() == clang::tok::less) {
- directive_context = DirectiveContext::InAngledName;
- lexical = {SymbolKind::Header, 0};
- } else if(lexical.kind == SymbolKind::String) {
- directive_context = DirectiveContext::InDirective;
+ /// Move the directive state machine to classify tokens in a PP directive.
+ switch(directive_context) {
+ case DirectiveContext::None: {
+ if(token.kind() == clang::tok::hash) {
+ directive_context = DirectiveContext::AfterHash;
+ lexical.kind = SymbolKind::Directive;
+ }
+ break;
+ }
+ case DirectiveContext::AfterHash: {
+ /// The directive name right after `#`, e.g. `include`, `if`.
+ if(is_identifier_like) {
+ lexical.kind = SymbolKind::Directive;
+ }
+
+ auto spelling = content.substr(offset, token.length());
+ if(spelling == "include" || spelling == "include_next" || spelling == "import" ||
+ spelling == "embed") {
+ directive_context = DirectiveContext::InIncludeName;
+ } else if(spelling == "define") {
+ directive_context = DirectiveContext::AfterDefine;
+ } else {
+ directive_context = DirectiveContext::InDirective;
+ }
+ break;
+ }
+ case DirectiveContext::InIncludeName: {
+ /// The filename of an #include: either a string literal or the
+ /// `` token sequence; adjacent merging joins the pieces.
+ /// The header context ends with the filename, so directive operands
+ /// after it (e.g. #embed parameters) keep their own classification.
+ if(token.kind() == clang::tok::less) {
+ directive_context = DirectiveContext::InAngledName;
+ lexical = {SymbolKind::Header, 0};
+ } else if(lexical.kind == SymbolKind::String) {
+ directive_context = DirectiveContext::InDirective;
+ lexical = {SymbolKind::Header, 0};
+ } else {
+ directive_context = DirectiveContext::InDirective;
+ }
+ break;
+ }
+ case DirectiveContext::InAngledName: {
+ if(token.kind() == clang::tok::greater) {
+ directive_context = DirectiveContext::InDirective;
+ }
lexical = {SymbolKind::Header, 0};
- } else {
- directive_context = DirectiveContext::InDirective;
+ break;
}
- } else if(directive_context == DirectiveContext::InAngledName) {
- if(token.kind() == clang::tok::greater) {
+ case DirectiveContext::AfterDefine: {
+ /// The macro name of a #define. Also covers preamble
+ /// defines under a PCH, where no MacroDefine node exists
+ /// (the preamble's directives live in the PCH compile).
+ if(is_identifier_like) {
+ lexical.kind = SymbolKind::Macro;
+ }
directive_context = DirectiveContext::InDirective;
+ break;
}
- lexical = {SymbolKind::Header, 0};
+ case DirectiveContext::InDirective: break;
}
return lexical;
@@ -647,10 +710,10 @@ class SemanticTokensCollector {
enum class DirectiveContext : std::uint8_t {
None,
AfterHash,
- InDirective,
InIncludeName,
InAngledName,
AfterDefine,
+ InDirective,
};
CompilationUnitRef unit;
diff --git a/src/index/serialization.h b/src/index/serialization.h
index f8781f6d7..33df4fe50 100644
--- a/src/index/serialization.h
+++ b/src/index/serialization.h
@@ -103,7 +103,7 @@ namespace clice::index {
/// Bump it whenever a persisted type's reflected layout changes, or when
/// symbol-hash semantics change (stored rows keyed by old hashes would
/// silently stop matching newly computed ones).
-constexpr inline std::uint32_t index_format_version = 7;
+constexpr inline std::uint32_t index_format_version = 8;
/// Serialize a reflected index blob to `os` as a verified-readable
/// flatbuffer. Encoding only fails on structural impossibilities (e.g. more
diff --git a/src/semantic/symbol.cpp b/src/semantic/symbol.cpp
index 898c6095e..19ab84020 100644
--- a/src/semantic/symbol.cpp
+++ b/src/semantic/symbol.cpp
@@ -38,8 +38,4 @@ SymbolKind SymbolKind::from(const clang::Decl* decl) {
}
}
-SymbolKind SymbolKind::from(const clang::tok::TokenKind kind) {
- return {};
-}
-
} // namespace clice
diff --git a/src/semantic/symbol.h b/src/semantic/symbol.h
index e8574ad6a..2ea3d4cb5 100644
--- a/src/semantic/symbol.h
+++ b/src/semantic/symbol.h
@@ -4,7 +4,6 @@
#include
#include "clang/AST/Decl.h"
-#include "clang/Basic/TokenKinds.h"
namespace clice {
@@ -49,6 +48,7 @@ struct SymbolKind {
Brace, ///> `{` and `}`.
Angle, ///> `<` and `>`.
Conflict, ///> This token have multiple kinds.
+ Primitive, ///< C/C++ built-in primitive type keyword.
Invalid,
};
@@ -72,8 +72,6 @@ struct SymbolKind {
static SymbolKind from(const clang::Decl* decl);
- static SymbolKind from(const clang::tok::TokenKind kind);
-
private:
Kind kind_value = Invalid;
};
diff --git a/tests/snap/semantic_tokens/comments.snap.yml b/tests/snap/semantic_tokens/comments.snap.yml
index 6566b2f47..c07051e87 100644
--- a/tests/snap/semantic_tokens/comments.snap.yml
+++ b/tests/snap/semantic_tokens/comments.snap.yml
@@ -15,11 +15,11 @@ input_file: comments.cpp
- { loc: "11:0", text: " * spanning several lines", kind: comment }
- { loc: "12:0", text: " */", kind: comment }
- { loc: "13:0", text: "/// a doc comment", kind: comment }
-- { loc: "14:0", text: "int", kind: keyword }
+- { loc: "14:0", text: "int", kind: primitive }
- { loc: "14:4", text: "after_comments", kind: variable, modifiers: [definition] }
- { loc: "14:21", text: "0", kind: number }
- { loc: "16:0", text: "/* first", kind: comment }
- { loc: "17:0", text: "second */", kind: comment }
-- { loc: "17:10", text: "int", kind: keyword }
+- { loc: "17:10", text: "int", kind: primitive }
- { loc: "17:14", text: "after_block", kind: variable, modifiers: [definition] }
- { loc: "17:28", text: "1", kind: number }
diff --git a/tests/snap/semantic_tokens/declaration_tokens.snap.yml b/tests/snap/semantic_tokens/declaration_tokens.snap.yml
index 4d0c32415..3048361ae 100644
--- a/tests/snap/semantic_tokens/declaration_tokens.snap.yml
+++ b/tests/snap/semantic_tokens/declaration_tokens.snap.yml
@@ -14,12 +14,12 @@ input_file: declaration_tokens.cpp
- { loc: "6:24", text: "Green", kind: enumMember, modifiers: [definition, readonly] }
- { loc: "8:0", text: "struct", kind: keyword }
- { loc: "8:7", text: "Shape", kind: struct, modifiers: [definition] }
-- { loc: "9:4", text: "int", kind: keyword }
+- { loc: "9:4", text: "int", kind: primitive }
- { loc: "9:8", text: "sides", kind: field, modifiers: [definition] }
-- { loc: "12:0", text: "int", kind: keyword }
+- { loc: "12:0", text: "int", kind: primitive }
- { loc: "12:4", text: "area", kind: function, modifiers: [declaration] }
-- { loc: "12:9", text: "int", kind: keyword }
+- { loc: "12:9", text: "int", kind: primitive }
- { loc: "12:13", text: "width", kind: parameter, modifiers: [definition] }
-- { loc: "12:20", text: "int", kind: keyword }
+- { loc: "12:20", text: "int", kind: primitive }
- { loc: "12:24", text: "height", kind: parameter, modifiers: [definition] }
- { loc: "14:3", text: "// namespace demo", kind: comment }
diff --git a/tests/snap/semantic_tokens/directives.cpp b/tests/snap/semantic_tokens/directives.cpp
index 86f12e81f..de64adbcc 100644
--- a/tests/snap/semantic_tokens/directives.cpp
+++ b/tests/snap/semantic_tokens/directives.cpp
@@ -19,3 +19,7 @@ int flagged = 2;
#endif
#pragma pack(1)
+
+#
+#define STRINGIZE(x) #x
+const char* stringized = STRINGIZE(abc);
diff --git a/tests/snap/semantic_tokens/directives.snap.yml b/tests/snap/semantic_tokens/directives.snap.yml
index 121f24562..9b6f09e0c 100644
--- a/tests/snap/semantic_tokens/directives.snap.yml
+++ b/tests/snap/semantic_tokens/directives.snap.yml
@@ -8,14 +8,14 @@ input_file: directives.cpp
- { loc: "3:0", text: "///", kind: comment }
- { loc: "4:0", text: "/// - status: supported", kind: comment }
- { loc: "5:0", text: "/// - order: 4", kind: comment }
-- { loc: "7:0", text: "int", kind: keyword }
+- { loc: "7:0", text: "int", kind: primitive }
- { loc: "7:4", text: "before_conditional", kind: variable, modifiers: [definition] }
- { loc: "7:25", text: "0", kind: number }
- { loc: "9:0", text: "#if", kind: directive }
- { loc: "9:4", text: "0", kind: number }
-- { loc: "10:0", text: "int", kind: keyword }
+- { loc: "10:0", text: "int", kind: primitive }
- { loc: "11:0", text: "#else", kind: directive }
-- { loc: "12:0", text: "int", kind: keyword }
+- { loc: "12:0", text: "int", kind: primitive }
- { loc: "12:4", text: "enabled_branch", kind: variable, modifiers: [definition] }
- { loc: "12:21", text: "1", kind: number }
- { loc: "13:0", text: "#endif", kind: directive }
@@ -23,9 +23,16 @@ input_file: directives.cpp
- { loc: "15:8", text: "FLAG", kind: macro, modifiers: [definition] }
- { loc: "16:0", text: "#ifdef", kind: directive }
- { loc: "16:7", text: "FLAG", kind: macro }
-- { loc: "17:0", text: "int", kind: keyword }
+- { loc: "17:0", text: "int", kind: primitive }
- { loc: "17:4", text: "flagged", kind: variable, modifiers: [definition] }
- { loc: "17:14", text: "2", kind: number }
- { loc: "18:0", text: "#endif", kind: directive }
- { loc: "20:0", text: "#pragma", kind: directive }
- { loc: "20:13", text: "1", kind: number }
+- { loc: "22:0", text: "#", kind: directive }
+- { loc: "23:0", text: "#define", kind: directive }
+- { loc: "23:8", text: "STRINGIZE", kind: macro, modifiers: [definition] }
+- { loc: "24:0", text: "const", kind: keyword }
+- { loc: "24:6", text: "char", kind: primitive }
+- { loc: "24:12", text: "stringized", kind: variable, modifiers: [definition, readonly] }
+- { loc: "24:25", text: "STRINGIZE", kind: macro }
diff --git a/tests/snap/semantic_tokens/expression_tokens.snap.yml b/tests/snap/semantic_tokens/expression_tokens.snap.yml
index ea67e254d..f2a6370eb 100644
--- a/tests/snap/semantic_tokens/expression_tokens.snap.yml
+++ b/tests/snap/semantic_tokens/expression_tokens.snap.yml
@@ -12,18 +12,18 @@ input_file: expression_tokens.cpp
- { loc: "5:19", text: "Red", kind: enumMember, modifiers: [definition, readonly] }
- { loc: "7:0", text: "struct", kind: keyword }
- { loc: "7:7", text: "Shape", kind: struct, modifiers: [definition] }
-- { loc: "8:4", text: "int", kind: keyword }
+- { loc: "8:4", text: "int", kind: primitive }
- { loc: "8:8", text: "sides", kind: field, modifiers: [definition] }
-- { loc: "11:0", text: "int", kind: keyword }
+- { loc: "11:0", text: "int", kind: primitive }
- { loc: "11:4", text: "area", kind: function, modifiers: [definition] }
-- { loc: "11:9", text: "int", kind: keyword }
+- { loc: "11:9", text: "int", kind: primitive }
- { loc: "11:13", text: "width", kind: parameter, modifiers: [definition] }
-- { loc: "11:20", text: "int", kind: keyword }
+- { loc: "11:20", text: "int", kind: primitive }
- { loc: "11:24", text: "height", kind: parameter, modifiers: [definition] }
- { loc: "12:4", text: "return", kind: keyword }
- { loc: "12:11", text: "width", kind: parameter }
- { loc: "12:19", text: "height", kind: parameter }
-- { loc: "15:0", text: "void", kind: keyword }
+- { loc: "15:0", text: "void", kind: primitive }
- { loc: "15:5", text: "test", kind: function, modifiers: [definition] }
- { loc: "16:4", text: "Shape", kind: struct }
- { loc: "16:10", text: "square", kind: variable, modifiers: [definition] }
@@ -32,14 +32,14 @@ input_file: expression_tokens.cpp
- { loc: "17:10", text: "c", kind: variable, modifiers: [definition] }
- { loc: "17:14", text: "Color", kind: enum }
- { loc: "17:21", text: "Red", kind: enumMember, modifiers: [readonly] }
-- { loc: "18:21", text: "int", kind: keyword }
+- { loc: "18:21", text: "int", kind: primitive }
- { loc: "18:25", text: "a", kind: variable, modifiers: [definition] }
- { loc: "18:29", text: "area", kind: function }
- { loc: "18:34", text: "2", kind: number }
- { loc: "18:38", text: "2", kind: number }
- { loc: "18:41", text: "square", kind: variable }
- { loc: "18:48", text: "sides", kind: field }
-- { loc: "19:21", text: "bool", kind: keyword }
+- { loc: "19:21", text: "bool", kind: primitive }
- { loc: "19:26", text: "red", kind: variable, modifiers: [definition] }
- { loc: "19:32", text: "c", kind: variable }
- { loc: "19:37", text: "Color", kind: enum }
diff --git a/tests/snap/semantic_tokens/include_names.snap.yml b/tests/snap/semantic_tokens/include_names.snap.yml
index 6da0ffcef..90d9238a7 100644
--- a/tests/snap/semantic_tokens/include_names.snap.yml
+++ b/tests/snap/semantic_tokens/include_names.snap.yml
@@ -15,6 +15,6 @@ input_file: include_names.cpp
- { loc: "9:0", text: "#", kind: directive }
- { loc: "9:2", text: "include", kind: directive }
- { loc: "9:10", text: "\"inc/angled.h\"", kind: header }
-- { loc: "11:0", text: "int", kind: keyword }
+- { loc: "11:0", text: "int", kind: primitive }
- { loc: "11:4", text: "after_includes", kind: variable, modifiers: [definition] }
- { loc: "11:21", text: "0", kind: number }
diff --git a/tests/snap/semantic_tokens/literals.snap.yml b/tests/snap/semantic_tokens/literals.snap.yml
index cd844d1bf..555398fae 100644
--- a/tests/snap/semantic_tokens/literals.snap.yml
+++ b/tests/snap/semantic_tokens/literals.snap.yml
@@ -8,35 +8,35 @@ input_file: literals.cpp
- { loc: "3:0", text: "///", kind: comment }
- { loc: "4:0", text: "/// - status: supported", kind: comment }
- { loc: "5:0", text: "/// - order: 2", kind: comment }
-- { loc: "7:0", text: "int", kind: keyword }
+- { loc: "7:0", text: "int", kind: primitive }
- { loc: "7:4", text: "decimal", kind: variable, modifiers: [definition] }
- { loc: "7:14", text: "42", kind: number }
-- { loc: "8:0", text: "int", kind: keyword }
+- { loc: "8:0", text: "int", kind: primitive }
- { loc: "8:4", text: "hexadecimal", kind: variable, modifiers: [definition] }
- { loc: "8:18", text: "0xFF", kind: number }
-- { loc: "9:0", text: "double", kind: keyword }
+- { loc: "9:0", text: "double", kind: primitive }
- { loc: "9:7", text: "floating", kind: variable, modifiers: [definition] }
- { loc: "9:18", text: "3.14", kind: number }
-- { loc: "10:0", text: "char", kind: keyword }
+- { loc: "10:0", text: "char", kind: primitive }
- { loc: "10:5", text: "letter", kind: variable, modifiers: [definition] }
- { loc: "10:14", text: "'x'", kind: character }
- { loc: "11:0", text: "const", kind: keyword }
-- { loc: "11:6", text: "char", kind: keyword }
+- { loc: "11:6", text: "char", kind: primitive }
- { loc: "11:12", text: "text", kind: variable, modifiers: [definition, readonly] }
- { loc: "11:19", text: "\"hello\"", kind: string }
- { loc: "12:0", text: "const", kind: keyword }
-- { loc: "12:6", text: "char", kind: keyword }
+- { loc: "12:6", text: "char", kind: primitive }
- { loc: "12:12", text: "raw", kind: variable, modifiers: [definition, readonly] }
- { loc: "12:18", text: "R\"(no \"escapes\" in here)\"", kind: string }
-- { loc: "13:0", text: "int", kind: keyword }
+- { loc: "13:0", text: "int", kind: primitive }
- { loc: "13:4", text: "after_raw", kind: variable, modifiers: [definition] }
- { loc: "13:16", text: "1", kind: number }
- { loc: "15:0", text: "const", kind: keyword }
-- { loc: "15:6", text: "char", kind: keyword }
+- { loc: "15:6", text: "char", kind: primitive }
- { loc: "15:12", text: "multiline", kind: variable, modifiers: [definition, readonly] }
- { loc: "15:24", text: "R\"(line1", kind: string }
- { loc: "16:0", text: "line2", kind: string }
- { loc: "17:0", text: ")\"", kind: string }
-- { loc: "17:4", text: "int", kind: keyword }
+- { loc: "17:4", text: "int", kind: primitive }
- { loc: "17:8", text: "after_closing", kind: variable, modifiers: [definition] }
- { loc: "17:24", text: "2", kind: number }
diff --git a/tests/snap/semantic_tokens/module_partition.snap.yml b/tests/snap/semantic_tokens/module_partition.snap.yml
index a6e0e27dc..18cda49b6 100644
--- a/tests/snap/semantic_tokens/module_partition.snap.yml
+++ b/tests/snap/semantic_tokens/module_partition.snap.yml
@@ -14,6 +14,6 @@ input_file: module_partition.cpp
- { loc: "7:19", text: "core", kind: module }
- { loc: "7:24", text: "part", kind: module }
- { loc: "9:0", text: "export", kind: keyword }
-- { loc: "9:7", text: "int", kind: keyword }
+- { loc: "9:7", text: "int", kind: primitive }
- { loc: "9:11", text: "partition_value", kind: variable, modifiers: [definition] }
- { loc: "9:29", text: "1", kind: number }
diff --git a/tests/snap/semantic_tokens/modules.snap.yml b/tests/snap/semantic_tokens/modules.snap.yml
index ccb5c1905..cf3423a16 100644
--- a/tests/snap/semantic_tokens/modules.snap.yml
+++ b/tests/snap/semantic_tokens/modules.snap.yml
@@ -14,12 +14,12 @@ input_file: modules.cpp
- { loc: "9:14", text: "demo", kind: module }
- { loc: "9:19", text: "core", kind: module }
- { loc: "11:0", text: "export", kind: keyword }
-- { loc: "11:7", text: "int", kind: keyword }
+- { loc: "11:7", text: "int", kind: primitive }
- { loc: "11:11", text: "exported_value", kind: variable, modifiers: [definition] }
- { loc: "11:28", text: "1", kind: number }
- { loc: "13:0", text: "module", kind: keyword }
- { loc: "13:8", text: "private", kind: keyword }
-- { loc: "15:0", text: "int", kind: keyword }
+- { loc: "15:0", text: "int", kind: primitive }
- { loc: "15:4", text: "private_value", kind: variable, modifiers: [definition] }
- { loc: "15:20", text: "2", kind: number }
- { loc: "17:0", text: "#if", kind: directive }
diff --git a/tests/snap/semantic_tokens/primitive_types.cpp b/tests/snap/semantic_tokens/primitive_types.cpp
index e6ae57db4..cfab76306 100644
--- a/tests/snap/semantic_tokens/primitive_types.cpp
+++ b/tests/snap/semantic_tokens/primitive_types.cpp
@@ -2,9 +2,12 @@
///
/// ## Primitive token type — a distinct kind for built-in types instead of plain `keyword`
///
-/// - status: unsupported
+/// - status: supported
/// - order: 9
-int number = 0;
-float ratio = 0.5f;
-void act();
+§int number = 0;
+§float ratio = 0.5f;
+§void act();
+§unsigned §long §long wide_number = 0;
+§__int128 extended_int = 0;
+§_Float16 extended_float = 0;
diff --git a/tests/snap/semantic_tokens/primitive_types.snap.yml b/tests/snap/semantic_tokens/primitive_types.snap.yml
new file mode 100644
index 000000000..cf4192a45
--- /dev/null
+++ b/tests/snap/semantic_tokens/primitive_types.snap.yml
@@ -0,0 +1,12 @@
+---
+created_at: 2026-08-15
+input_file: primitive_types.cpp
+---
+- { loc: "7:0", text: "int", kind: primitive }
+- { loc: "8:0", text: "float", kind: primitive }
+- { loc: "9:0", text: "void", kind: primitive }
+- { loc: "10:0", text: "unsigned", kind: primitive }
+- { loc: "10:9", text: "long", kind: primitive }
+- { loc: "10:14", text: "long", kind: primitive }
+- { loc: "11:0", text: "__int128", kind: primitive }
+- { loc: "12:0", text: "_Float16", kind: primitive }
diff --git a/tests/unit/feature/semantic_tokens_tests.cpp b/tests/unit/feature/semantic_tokens_tests.cpp
index 26d1e5f59..376067897 100644
--- a/tests/unit/feature/semantic_tokens_tests.cpp
+++ b/tests/unit/feature/semantic_tokens_tests.cpp
@@ -162,7 +162,7 @@ TEST_CASE(PreambleDefineUnderPch) {
EXPECT_TOKEN("d1", SymbolKind::Directive);
EXPECT_TOKEN("m0", SymbolKind::Macro);
- EXPECT_TOKEN("k0", SymbolKind::Keyword);
+ EXPECT_TOKEN("k0", SymbolKind::Primitive);
EXPECT_TOKEN("k1", SymbolKind::Keyword);
EXPECT_TOKEN("c0", SymbolKind::Comment);
}