Semantic Roles and Syntax Kinds
Relevant source files
The following files were used as context for generating this wiki page:
Semantic Roles and Syntax Kinds are fundamental components of the SCIP Code Intelligence Protocol that categorize and describe occurrences of symbols within source code. While Semantic Roles (SymbolRole) define the relationship between a range and a symbol (such as whether the symbol is being defined, referenced, or imported), Syntax Kinds (SyntaxKind) provide information for syntax highlighting and classification of code elements like keywords, comments, and delimiters.
These classifications are stored within the Occurrence message, which associates a specific source range with a symbol and its metadata. This granular data allows consumers to power features like "Go to definition," "Find references," and high-fidelity syntax highlighting.
Sources: scip.proto:496-512, scip.proto:591-620
Semantic Roles (SymbolRole)
The SymbolRole field is a bitset where each bit represents a different semantic role. This allows a single symbol occurrence to have multiple roles simultaneously, such as being both a definition and a test symbol.
Role Definitions and Bit Flags
| Role | Hex Value | Description |
|---|---|---|
UnspecifiedSymbolRole | 0x0 | Default value; not intended for active use. |
Definition | 0x1 | The symbol is defined at this location. |
Import | 0x2 | The symbol is imported at this location. |
WriteAccess | 0x4 | The occurrence involves a write operation to the symbol. |
ReadAccess | 0x8 | The occurrence involves a read operation from the symbol. |
Generated | 0x10 | The occurrence appears in generated code. |
Test | 0x20 | The occurrence appears in test code. |
ForwardDefinition | 0x40 | A signature/forward declaration for a symbol defined elsewhere (e.g., C++ headers). |
Sources: scip.proto:564-589, bindings/typescript/scip.ts:25-34
Implementation Logic
To check if a specific role is set within an Occurrence.symbol_roles field, bitwise AND logic is used. For example, to verify the Import role:
const isImportRole = (role.value & SymbolRole.Import.value) > 0
Sources: scip.proto:562-563, bindings/go/scip/scip.pb.go:207-209
Validation and Conflicts
The SCIP linting tools enforce logical consistency between roles. For instance, an occurrence cannot be marked as both a standard Definition and a ForwardDefinition simultaneously.
The diagram shows the logic used by indexers to prevent mutually exclusive semantic roles.
Sources: cmd/scip/lint.go:193-195
Syntax Kinds (SyntaxKind)
Syntax Kinds classify the syntactic nature of a source code range. This classification is primarily used for syntax highlighting and identifying the structural category of code elements independent of their semantic symbol.
Categories of Syntax Kinds
- Structural Elements:
Comment: Includes comment markers and text content.PunctuationDelimiter: Standard delimiters like;,., and,.PunctuationBracket: Syntactic brackets like(),{}, and[].
- Identifiers:
Keyword: Reserved words likeif,else,class.IdentifierBuiltin: Language-level built-ins (e.g.,printin Python).IdentifierLocal: Variables within a local scope.IdentifierNamespace: Names representing modules or packages.
- Literals:
StringLiteral,NumericLiteral,BooleanLiteral,CharacterLiteral.
- Specialized Syntax:
- Regex:
RegexEscape,RegexWildcard,RegexDelimiter. - Markup:
Tag,TagAttribute,TagDelimiterfor XML-like languages.
- Regex:
Sources: scip.proto:591-683, bindings/typescript/scip.ts:35-77
Symbol Kinds (SymbolInformation.Kind)
While SyntaxKind describes the range's appearance, SymbolInformation.Kind represents the fine-grained semantic category of the symbol itself. This is used in the SymbolInformation metadata to provide more detail than the symbol's structural descriptor suffix.
Key Symbol Kinds
The protocol supports over 80 distinct kinds, including:
- OOP Entities:
Class,Interface,Method,Property. - Functional Entities:
Function,TypeClass,Trait,Lemma. - Language Specific:
Concept(C++),Extension(Dart),Mixin(Dart),Contract(Solidity).
Relationship with Descriptors
If two symbols share the same Kind, they should ideally share the same Suffix in their symbol descriptor string. However, Kind is intended to be more fine-grained. For example, a Java method and a Go function might both use the Method suffix in their symbol IDs, but they would be classified as Kind.Method and Kind.Function respectively.
Sources: scip.proto:264-443, CHANGELOG.md:27-28, 48-49
Interaction in Occurrences
The Occurrence message acts as the junction point for these classifications. It maps a source range to a symbol, applies bitmask roles, and assigns a syntax kind for UI rendering.
The ER diagram illustrates how semantic roles and syntax kinds are integrated into the core SCIP data model through the Occurrence message.
Sources: scip.proto:697-789, bindings/go/scip/scip.pb.go:1385-1447
Snapshot Formatting
During testing, roles and kinds are formatted into human-readable strings. Definitions are explicitly labeled as definition, while others default to reference. Specific information like kind is appended to definition lines in snapshot files.
Sources: bindings/go/scip/testutil/format.go:107-133
Summary
Semantic Roles and Syntax Kinds provide a dual-layer classification system for code intelligence. Semantic Roles manage the logical interaction with symbols via bitsets, enabling complex cross-referencing and access tracking. Syntax Kinds provide the necessary metadata for visual classification and structural analysis. Together with fine-grained Symbol Kinds, these systems ensure that SCIP can represent both the structural appearance and the deep semantic meaning of source code across a vast array of programming languages.