From d31a25398347f1646b0c37a27f82ac3771a7cc15 Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Tue, 6 Dec 2022 19:56:25 -0800 Subject: [PATCH] Improve parameter checking in tree-sitter functions * src/treesit.c (treesit_check_position): Extract out new function. (Ftreesit_node_first_child_for_pos) (Ftreesit_node_descendant_for_range): Replace code with the new function. (Ftreesit_query_capture): Add missing check for node and parser. Add check for range for BEG and END. Move treesit_initialize to the beginning of the function. * test/src/treesit-tests.el (treesit-node-api) (treesit-query-api): Add tests for out-of-range error. --- src/treesit.c | 50 ++++++++++++++++++++++++--------------- test/src/treesit-tests.el | 8 +++++++ 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/src/treesit.c b/src/treesit.c index 9926806612a..8b485ca4ece 100644 --- a/src/treesit.c +++ b/src/treesit.c @@ -1642,6 +1642,17 @@ treesit_check_node (Lisp_Object obj) xsignal1 (Qtreesit_node_outdated, obj); } +/* Checks that OBJ is a positive integer and it is within the visible + portion of BUF. */ +static void +treesit_check_position (Lisp_Object obj, struct buffer *buf) +{ + treesit_check_positive_integer (obj); + ptrdiff_t pos = XFIXNUM (obj); + if (pos < BUF_BEGV (buf) || pos > BUF_ZV (buf)) + xsignal1 (Qargs_out_of_range, obj); +} + bool treesit_node_uptodate_p (Lisp_Object obj) { @@ -1990,14 +2001,12 @@ Note that this function returns an immediate child, not the smallest if (NILP (node)) return Qnil; treesit_check_node (node); - treesit_check_positive_integer (pos); struct buffer *buf = XBUFFER (XTS_PARSER (XTS_NODE (node)->parser)->buffer); ptrdiff_t visible_beg = XTS_PARSER (XTS_NODE (node)->parser)->visible_beg; ptrdiff_t byte_pos = buf_charpos_to_bytepos (buf, XFIXNUM (pos)); - if (byte_pos < BUF_BEGV_BYTE (buf) || byte_pos > BUF_ZV_BYTE (buf)) - xsignal1 (Qargs_out_of_range, pos); + treesit_check_position (pos, buf); treesit_initialize (); @@ -2028,19 +2037,14 @@ If NODE is nil, return nil. */) { if (NILP (node)) return Qnil; treesit_check_node (node); - CHECK_INTEGER (beg); - CHECK_INTEGER (end); struct buffer *buf = XBUFFER (XTS_PARSER (XTS_NODE (node)->parser)->buffer); ptrdiff_t visible_beg = XTS_PARSER (XTS_NODE (node)->parser)->visible_beg; ptrdiff_t byte_beg = buf_charpos_to_bytepos (buf, XFIXNUM (beg)); ptrdiff_t byte_end = buf_charpos_to_bytepos (buf, XFIXNUM (end)); - /* Checks for BUFFER_BEG <= BEG <= END <= BUFFER_END. */ - if (!(BUF_BEGV_BYTE (buf) <= byte_beg - && byte_beg <= byte_end - && byte_end <= BUF_ZV_BYTE (buf))) - xsignal2 (Qargs_out_of_range, beg, end); + treesit_check_position (beg, buf); + treesit_check_position (end, buf); treesit_initialize (); @@ -2426,21 +2430,24 @@ the query. */) (Lisp_Object node, Lisp_Object query, Lisp_Object beg, Lisp_Object end, Lisp_Object node_only) { - if (!NILP (beg)) - CHECK_INTEGER (beg); - if (!NILP (end)) - CHECK_INTEGER (end); - if (!(TS_COMPILED_QUERY_P (query) || CONSP (query) || STRINGP (query))) wrong_type_argument (Qtreesit_query_p, query); + treesit_initialize (); + /* Resolve NODE into an actual node. */ Lisp_Object lisp_node; if (TS_NODEP (node)) - lisp_node = node; + { + treesit_check_node (node); /* Check if up-to-date. */ + lisp_node = node; + } else if (TS_PARSERP (node)) - lisp_node = Ftreesit_parser_root_node (node); + { + treesit_check_parser (node); /* Check if deleted. */ + lisp_node = Ftreesit_parser_root_node (node); + } else if (SYMBOLP (node)) { Lisp_Object parser @@ -2452,8 +2459,6 @@ the query. */) list4 (Qor, Qtreesit_node_p, Qtreesit_parser_p, Qsymbolp), node); - treesit_initialize (); - /* Extract C values from Lisp objects. */ TSNode treesit_node = XTS_NODE (lisp_node)->node; @@ -2464,6 +2469,13 @@ the query. */) const TSLanguage *lang = ts_parser_language (XTS_PARSER (lisp_parser)->parser); + /* Check BEG and END. */ + struct buffer *buf = XBUFFER (XTS_PARSER (lisp_parser)->buffer); + if (!NILP (beg)) + treesit_check_position (beg, buf); + if (!NILP (end)) + treesit_check_position (end, buf); + /* Initialize query objects. At the end of this block, we should have a working TSQuery and a TSQueryCursor. */ TSQuery *treesit_query; diff --git a/test/src/treesit-tests.el b/test/src/treesit-tests.el index 80fde408cd3..aba12759c34 100644 --- a/test/src/treesit-tests.el +++ b/test/src/treesit-tests.el @@ -143,6 +143,8 @@ (treesit-node-string (treesit-node-first-child-for-pos doc-node 3)))) + (should-error (treesit-node-first-child-for-pos doc-node 100) + :type 'args-out-of-range) ;; `treesit-node-descendant-for-range'. (should (equal "(\"{\")" (treesit-node-string @@ -152,6 +154,9 @@ (treesit-node-string (treesit-node-descendant-for-range root-node 6 7 t)))) + (should-error (treesit-node-descendant-for-range + root-node 100 101) + :type 'args-out-of-range) ;; `treesit-node-eq'. (should (treesit-node-eq root-node root-node)) (should (not (treesit-node-eq root-node doc-node)))))) @@ -167,6 +172,9 @@ (setq root-node (treesit-parser-root-node parser))) + (should-error (treesit-query-capture root-node "" 100 101) + :type 'args-out-of-range) + ;; Test `treesit-query-capture' on string, sexp and compiled ;; queries. (dolist (query1 -- 2.39.2