Merge pull request #2462 from tree-sitter/api-ext-ub
Fix UB for `LookaheadIterator`
This commit is contained in:
commit
144c096a27
3 changed files with 71 additions and 8 deletions
|
|
@ -14,3 +14,7 @@ pub mod wasm;
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
// To run compile fail tests
|
||||
#[cfg(doctest)]
|
||||
mod tests;
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ fn test_lookahead_iterator() {
|
|||
assert_ne!(cursor.node().grammar_id(), cursor.node().kind_id());
|
||||
|
||||
let expected_symbols = ["identifier", "block_comment", "line_comment"];
|
||||
let lookahead = language.lookahead_iterator(next_state).unwrap();
|
||||
let mut lookahead = language.lookahead_iterator(next_state).unwrap();
|
||||
assert_eq!(lookahead.language(), language);
|
||||
assert!(lookahead.iter_names().eq(expected_symbols));
|
||||
|
||||
|
|
@ -39,3 +39,57 @@ fn test_lookahead_iterator() {
|
|||
.map(|s| language.node_kind_for_id(s).unwrap())
|
||||
.eq(expected_symbols));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lookahead_iterator_modifiable_only_by_mut() {
|
||||
let mut parser = Parser::new();
|
||||
let language = get_language("rust");
|
||||
parser.set_language(language).unwrap();
|
||||
|
||||
let tree = parser.parse("struct Stuff {}", None).unwrap();
|
||||
|
||||
let mut cursor = tree.walk();
|
||||
|
||||
assert!(cursor.goto_first_child()); // struct
|
||||
assert!(cursor.goto_first_child()); // struct keyword
|
||||
|
||||
let next_state = cursor.node().next_parse_state();
|
||||
assert_ne!(next_state, 0);
|
||||
|
||||
let mut lookahead = language.lookahead_iterator(next_state).unwrap();
|
||||
let _ = lookahead.next();
|
||||
|
||||
let mut names = lookahead.iter_names();
|
||||
let _ = names.next();
|
||||
}
|
||||
|
||||
/// It doesn't allowed to use lookahead iterator by shared ref:
|
||||
/// error[E0596]: cannot borrow `lookahead` as mutable, as it is not declared as mutable
|
||||
/// ```compile_fail
|
||||
/// use tree_sitter::{Parser, Language};
|
||||
/// let mut parser = Parser::new();
|
||||
/// let language = unsafe { Language::from_raw(std::ptr::null()) };
|
||||
/// let tree = parser.parse("", None).unwrap();
|
||||
/// let mut cursor = tree.walk();
|
||||
/// let next_state = cursor.node().next_parse_state();
|
||||
/// let lookahead = language.lookahead_iterator(next_state).unwrap();
|
||||
/// let _ = lookahead.next();
|
||||
/// ```
|
||||
|
||||
/// It doesn't allowed to use lookahead names iterator by shared ref:
|
||||
/// error[E0596]: cannot borrow `names` as mutable, as it is not declared as mutable
|
||||
/// ```compile_fail
|
||||
/// use tree_sitter::{Parser, Language};
|
||||
/// let mut parser = Parser::new();
|
||||
/// let language = unsafe { Language::from_raw(std::ptr::null()) };
|
||||
/// let tree = parser.parse("", None).unwrap();
|
||||
/// let mut cursor = tree.walk();
|
||||
/// let next_state = cursor.node().next_parse_state();
|
||||
/// if let Some(mut lookahead) = language.lookahead_iterator(next_state) {
|
||||
/// let _ = lookahead.next();
|
||||
/// let names = lookahead.iter_names();
|
||||
/// let _ = names.next();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
fn _dummy() {}
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ pub struct Parser(NonNull<ffi::TSParser>);
|
|||
/// A stateful object that is used to look up symbols valid in a specific parse state
|
||||
#[doc(alias = "TSLookaheadIterator")]
|
||||
pub struct LookaheadIterator(NonNull<ffi::TSLookaheadIterator>);
|
||||
struct LookaheadNamesIterator<'a>(&'a mut LookaheadIterator);
|
||||
|
||||
/// A type of log message.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
|
|
@ -1525,7 +1526,7 @@ impl LookaheadIterator {
|
|||
/// This returns `true` if the language was set successfully and `false`
|
||||
/// otherwise.
|
||||
#[doc(alias = "ts_lookahead_iterator_reset")]
|
||||
pub fn reset(&self, language: Language, state: u16) -> bool {
|
||||
pub fn reset(&mut self, language: Language, state: u16) -> bool {
|
||||
unsafe { ffi::ts_lookahead_iterator_reset(self.0.as_ptr(), language.0, state) }
|
||||
}
|
||||
|
||||
|
|
@ -1534,19 +1535,17 @@ impl LookaheadIterator {
|
|||
/// This returns `true` if the iterator was reset to the given state and `false`
|
||||
/// otherwise.
|
||||
#[doc(alias = "ts_lookahead_iterator_reset_state")]
|
||||
pub fn reset_state(&self, state: u16) -> bool {
|
||||
pub fn reset_state(&mut self, state: u16) -> bool {
|
||||
unsafe { ffi::ts_lookahead_iterator_reset_state(self.0.as_ptr(), state) }
|
||||
}
|
||||
|
||||
/// Iterate symbol names.
|
||||
pub fn iter_names<'a>(&'a self) -> impl Iterator<Item = &'static str> + 'a {
|
||||
NameLookaheadIterator(&self)
|
||||
pub fn iter_names(&mut self) -> impl Iterator<Item = &'static str> + '_ {
|
||||
LookaheadNamesIterator(self)
|
||||
}
|
||||
}
|
||||
|
||||
struct NameLookaheadIterator<'a>(&'a LookaheadIterator);
|
||||
|
||||
impl<'a> Iterator for NameLookaheadIterator<'a> {
|
||||
impl Iterator for LookaheadNamesIterator<'_> {
|
||||
type Item = &'static str;
|
||||
|
||||
#[doc(alias = "ts_lookahead_iterator_advance")]
|
||||
|
|
@ -2647,6 +2646,12 @@ unsafe impl Sync for Language {}
|
|||
unsafe impl Send for Node<'_> {}
|
||||
unsafe impl Sync for Node<'_> {}
|
||||
|
||||
unsafe impl Send for LookaheadIterator {}
|
||||
unsafe impl Sync for LookaheadIterator {}
|
||||
|
||||
unsafe impl Send for LookaheadNamesIterator<'_> {}
|
||||
unsafe impl Sync for LookaheadNamesIterator<'_> {}
|
||||
|
||||
unsafe impl Send for Parser {}
|
||||
unsafe impl Sync for Parser {}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue