Position Tracking Guide
March 30, 2026 ยท View on GitHub
Overview
The enhanced position tracking system provides accurate line/column mapping for LSP compliance with comprehensive Unicode support. PR #153 includes critical security enhancements with symmetric UTF-16 position conversion and boundary validation.
Features
- O(log n) Position Mapping: Efficient binary search-based position lookups using LineStartsCache
- LSP-Compliant UTF-16 Support: Accurate character counting for multi-byte Unicode characters and emoji
- Symmetric Position Conversion: Security-enhanced UTF-16 โ UTF-8 conversion with boundary validation (PR #153)
- Multi-line Token Support: Proper position tracking for tokens spanning multiple lines (strings, comments, heredocs)
- Line Ending Agnostic: Handles CRLF, LF, and CR line endings consistently across platforms
- Integration: Seamless integration with parser context and LSP server for real-time editing
- Security: Overflow prevention and fractional position handling (PR #153)
- Comprehensive Testing: Enhanced test suite with UTF-16 security validation and mutation testing coverage
API Reference
Core PositionTracker methods
impl PositionTracker {
/// Create from source text with line start caching
pub fn new(source: String) -> Self;
/// Convert byte offset to Position with UTF-16 support
pub fn byte_to_position(&self, byte_offset: usize) -> Position;
/// SECURE: Convert UTF-8 offset to UTF-16 position (PR #153)
pub fn convert_utf8_to_utf16_position(&self, text: &str, utf8_offset: usize) -> u32;
/// SECURE: Convert UTF-16 position to UTF-8 offset (PR #153)
pub fn convert_utf16_to_utf8_position(&self, text: &str, utf16_pos: u32) -> usize;
}
// LineStartsCache for O(log n) lookups
impl LineStartsCache {
/// Build cache with CRLF/LF/CR line ending support
pub fn new(text: &str) -> Self;
/// Convert byte offset to (line, utf16_column) with boundary validation
pub fn offset_to_position(&self, text: &str, offset: usize) -> (u32, u32);
/// SECURE: Symmetric position conversion with overflow protection (PR #153)
pub fn safe_position_conversion(&self, text: &str, pos: usize, target_encoding: Encoding) -> u32;
}
Usage Guide
Using PositionTracker in Parser Context
use crate::parser_context::ParserContext;
// Create parser with automatic position tracking
let ctx = ParserContext::new(source);
// Access accurate token positions
let token = ctx.current_token().unwrap();
let range = token.range();
println!("Token at line {}, column {}", range.start.line, range.start.column);
Secure UTF-16 Position Conversion (PR #153)
Security-Enhanced Position Handling: Always use the secure conversion methods to prevent boundary violations and overflow issues:
use crate::position_tracker::PositionTracker;
// SECURE: UTF-8 to UTF-16 conversion with boundary validation
fn secure_position_conversion(tracker: &PositionTracker, text: &str, utf8_pos: usize) -> u32 {
// Safe conversion with overflow protection
tracker.convert_utf8_to_utf16_position(text, utf8_pos)
}
// Example with Unicode text containing emoji
let text = "Hello ๐ฆ Rust ๐ World";
let tracker = PositionTracker::new(text.to_string());
// Safe conversions that handle multi-byte characters properly
let utf16_pos = tracker.convert_utf8_to_utf16_position(text, 7); // Within emoji
let utf8_pos = tracker.convert_utf16_to_utf8_position(text, utf16_pos);
// These operations are symmetric and secure:
assert_eq!(utf8_pos, 7); // Round-trip conversion is exact
Security Features
- Boundary Validation: All conversions check input bounds before processing
- Symmetric Operations: UTF-8 โ UTF-16 conversions use identical validation logic
- Overflow Prevention: Arithmetic operations include safe bounds checking
- Fractional Handling: Proper handling of positions within multi-byte sequences
// Examples of secure handling
let text = "Multi-byte: ๐ฆ๐๐";
// Safe: Handles position beyond text length
let safe_pos = tracker.convert_utf8_to_utf16_position(text, text.len() + 100);
// Safe: Handles position within multi-byte sequence
let emoji_pos = tracker.convert_utf8_to_utf16_position(text, 13); // Within emoji
// Safe: All conversions validate boundaries
assert!(safe_pos <= text.chars().count() as u32);
Testing
Test Commands
# Run position tracking tests
cargo test -p perl-parser --test parser_context -- test_multiline_positions
cargo test -p perl-parser --test parser_context -- test_utf16_position_mapping
cargo test -p perl-parser --test parser_context -- test_crlf_line_endings
# Test UTF-16 security enhancements (PR #153)
cargo test -p perl-parser --test mutation_hardening_tests -- utf16_security
cargo test -p perl-lsp-rs lsp_encoding_edge_cases -- --nocapture
cargo test -p perl-parser position_tracker_tests -- test_boundary_validation
# Test with specific edge cases including security scenarios
cargo test -p perl-parser parser_context_tests::test_multiline_string_token_positions
cargo test -p perl-parser parser_context_tests::test_utf16_boundary_security
cargo test -p perl-parser parser_context_tests::test_symmetric_position_conversion
Security Test Examples
#[test]
fn test_utf16_security_validation() {
let text = "Test with ๐ฆ emoji and ๐ symbols";
let tracker = PositionTracker::new(text.to_string());
// Test boundary conditions
assert_eq!(tracker.convert_utf8_to_utf16_position(text, 0), 0);
assert_eq!(tracker.convert_utf8_to_utf16_position(text, text.len()),
text.chars().count() as u32);
// Test overflow protection
let overflow_result = tracker.convert_utf8_to_utf16_position(text, usize::MAX);
assert!(overflow_result <= text.chars().count() as u32);
// Test symmetric conversion
for i in 0..=text.len() {
let utf16_pos = tracker.convert_utf8_to_utf16_position(text, i);
let back_to_utf8 = tracker.convert_utf16_to_utf8_position(text, utf16_pos);
assert!(back_to_utf8 <= text.len());
}
}
Integration with LSP
The position tracking system is fully integrated with:
- Enhanced LSP position conversion (UTF-16 โ UTF-8) with security-validated symmetric conversion (PR #153)
- Secure multi-line token handling with boundary validation
- Real-time editing support with overflow protection
- Cross-platform line ending support with Unicode safety
- Security with comprehensive mutation testing validation
This ensures accurate position reporting for all LSP features including hover, go-to-definition, and diagnostics while maintaining security standards and preventing UTF-16 boundary violations.
Mutation Testing Validation
The UTF-16 position conversion security enhancements have been validated through comprehensive mutation testing that achieved:
- 87% mutation score for position conversion logic
- Real vulnerability discovery: Detected and eliminated asymmetric conversion bugs
- Security boundary testing: Validated overflow prevention and boundary handling
- Comprehensive edge case coverage: Multi-byte characters, emoji, boundary conditions