]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
xgettext: Vala: Flag strings on which the method 'printf' is used as c-format.
authorBruno Haible <bruno@clisp.org>
Thu, 30 Nov 2023 16:16:36 +0000 (17:16 +0100)
committerBruno Haible <bruno@clisp.org>
Thu, 30 Nov 2023 16:32:48 +0000 (17:32 +0100)
* gettext-tools/src/x-vala.c (token_type_semicolon): New enum item.
(phase3_get): Recognize semicolon tokens.
(phase4_pushback, phase4_pushback_length): New variables.
(phase4_get): Renamed from x_vala_lex. Handle pushback.
(phase4_unget, x_vala_lex, x_vala_unlex): New functions.
(extract_balanced): Handle method invocations .printf and .vprintf. Return when
a semicolon was seen.
(extract_vala): Initialize phase4_pushback_length.
* gettext-tools/tests/xgettext-vala-6: Add tests for printf used as method.
* gettext-tools/tests/xgettext-vala-7: New file.
* gettext-tools/tests/Makefile.am (TESTS): Add it.
* NEWS: Mention the change.

NEWS
gettext-tools/src/x-vala.c
gettext-tools/tests/Makefile.am
gettext-tools/tests/xgettext-vala-6
gettext-tools/tests/xgettext-vala-7 [new file with mode: 0755]

diff --git a/NEWS b/NEWS
index 0af9d04390fe1ebfea80dbdc265df8246962e380..f9e7ae073d70f405f2a30c0c7e0a919e119bdaaf 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,8 @@
 Version 0.23 - December 2023
 
 * Programming languages support:
+  - Vala: Improved recognition of format strings when the string.printf method
+    is used.
   - Glade: xgettext has improved support for GtkBuilder 4.
 
 * Runtime behaviour:
index 0b58d929abafeb11c5e81314c9ed632c0df4c11a..ac41aa2332f7099eb42f6953309cd0344d52a98c 100644 (file)
@@ -403,6 +403,7 @@ enum token_type_ty
   token_type_string_literal,            /* "abc" */
   token_type_string_template,           /* @"abc" */
   token_type_regex_literal,             /* /.../ */
+  token_type_semicolon,                 /* ; */
   token_type_symbol,                    /* if else etc. */
   token_type_other
 };
@@ -1206,6 +1207,10 @@ phase3_get (token_ty *tp)
             return;
           }
 
+        case ';':
+          tp->type = last_token_type = token_type_semicolon;
+          return;
+
         default:
           tp->type = last_token_type = token_type_other;
           return;
@@ -1226,11 +1231,20 @@ phase3_unget (token_ty *tp)
 }
 
 
-/* String concatenation with '+'.  */
+/* 4. String concatenation with '+'.  */
+
+static token_ty phase4_pushback[2];
+static int phase4_pushback_length;
 
 static void
-x_vala_lex (token_ty *tp)
+phase4_get (token_ty *tp)
 {
+  if (phase4_pushback_length)
+    {
+      *tp = phase4_pushback[--phase4_pushback_length];
+      return;
+    }
+
   phase3_get (tp);
   if (tp->type == token_type_string_literal)
     {
@@ -1263,6 +1277,31 @@ x_vala_lex (token_ty *tp)
     }
 }
 
+static void
+phase4_unget (token_ty *tp)
+{
+  if (tp->type != token_type_eof)
+    {
+      if (phase4_pushback_length == SIZEOF (phase4_pushback))
+        abort ();
+      phase4_pushback[phase4_pushback_length++] = *tp;
+    }
+}
+
+
+static void
+x_vala_lex (token_ty *tp)
+{
+  phase4_get (tp);
+}
+
+/* Supports 2 tokens of pushback.  */
+static void
+x_vala_unlex (token_ty *tp)
+{
+  phase4_unget (tp);
+}
+
 
 /* ========================= Extracting strings.  ========================== */
 
@@ -1293,7 +1332,8 @@ static int nesting_depth;
    We use recursion because the arguments before msgid or between msgid
    and msgid_plural can contain subexpressions of the same form.  */
 
-/* Extract messages until the next balanced closing parenthesis or bracket.
+/* Extract messages until the next balanced closing parenthesis or bracket
+   or the next semicolon.
    Extracted messages are added to MLP.
    DELIM can be either token_type_rparen or token_type_rbracket, or
    token_type_eof to accept both.
@@ -1366,6 +1406,36 @@ extract_balanced (message_list_ty *mlp, token_type_ty delim,
               return true;
             }
           nesting_depth--;
+          /* Test whether the next tokens are '.' and 'printf' or 'vprintf'.  */
+          {
+            token_ty token2;
+            x_vala_lex (&token2);
+            if (token2.type == token_type_symbol
+                && strcmp (token2.string, ".") == 0)
+              {
+                token_ty token3;
+                x_vala_lex (&token3);
+                if (token3.type == token_type_symbol
+                    && (strcmp (token3.string, "printf") == 0
+                        || strcmp (token3.string, "vprintf") == 0))
+                  {
+                    /* Mark the messages found in the region as c-format
+                       a posteriori.  */
+                    inner_region->for_formatstring[XFORMAT_PRIMARY].is_format = yes_according_to_context;
+                    struct remembered_message_list_ty *rmlp =
+                      inner_region->for_formatstring[XFORMAT_PRIMARY].remembered;
+                    size_t i;
+                    for (i = 0; i < rmlp->nitems; i++)
+                      {
+                        struct remembered_message_ty *rmp = &rmlp->item[i];
+                        set_format_flag_from_context (rmp->mp, rmp->plural, &rmp->pos,
+                                                      XFORMAT_PRIMARY, inner_region);
+                      }
+                  }
+                x_vala_unlex (&token3);
+              }
+            x_vala_unlex (&token2);
+          }
           next_context_iter = null_context_list_iterator;
           state = 0;
           break;
@@ -1393,6 +1463,11 @@ extract_balanced (message_list_ty *mlp, token_type_ty delim,
           state = 0;
           continue;
 
+        case token_type_semicolon:
+          arglist_parser_done (argparser, arg);
+          unref_region (inner_region);
+          return false;
+
         case token_type_eof:
           arglist_parser_done (argparser, arg);
           unref_region (inner_region);
@@ -1485,6 +1560,8 @@ extract_vala (FILE *f,
   phase3_pushback_length = 0;
   last_token_type = token_type_other;
 
+  phase4_pushback_length = 0;
+
   flag_context_list_table = flag_table;
   nesting_depth = 0;
 
index e6e6b040d3168c2e0a94ffc544262bd9bf2bb12d..4e432e63a1e5052d5fa4aeea9e37561d827f6c74 100644 (file)
@@ -165,7 +165,7 @@ TESTS = gettext-1 gettext-2 \
        xgettext-tcl-stackovfl-1 xgettext-tcl-stackovfl-2 \
        xgettext-tcl-stackovfl-3 xgettext-tcl-stackovfl-4 \
        xgettext-vala-1 xgettext-vala-2 xgettext-vala-3 xgettext-vala-4 \
-       xgettext-vala-5 xgettext-vala-6 \
+       xgettext-vala-5 xgettext-vala-6 xgettext-vala-7 \
        xgettext-vala-stackovfl-1 xgettext-vala-stackovfl-2 \
        xgettext-ycp-1 xgettext-ycp-2 xgettext-ycp-3 xgettext-ycp-4 \
        xgettext-ycp-stackovfl-1 xgettext-ycp-stackovfl-2 \
index afd78e9e4d65be9839630caa43a4dafd8f75ed5f..f215f8218ec885472110e3967dcef7a287605bef 100755 (executable)
@@ -8,6 +8,10 @@
 cat <<\EOF > xg-vala-6.vala
 "<b>%s</b>".printf(_("Hello 1"));
 _("Explanation: %s").printf(_("Hello 2"));
+_("No error 1");
+_("No error 2").printf();
+(_("No error 3")).printf();
+foo(_("No error 4")).printf();
 Posix.printf(_("Hello 3"));
 Posix.printf(_("Hello 4 %s!"), _("Sir"));
 EOF
@@ -26,6 +30,20 @@ msgstr ""
 msgid "Hello 2"
 msgstr ""
 
+msgid "No error 1"
+msgstr ""
+
+#, c-format
+msgid "No error 2"
+msgstr ""
+
+#, c-format
+msgid "No error 3"
+msgstr ""
+
+msgid "No error 4"
+msgstr ""
+
 msgid "Hello 3"
 msgstr ""
 
diff --git a/gettext-tools/tests/xgettext-vala-7 b/gettext-tools/tests/xgettext-vala-7
new file mode 100755 (executable)
index 0000000..b680747
--- /dev/null
@@ -0,0 +1,26 @@
+#! /bin/sh
+. "${srcdir=.}/init.sh"; path_prepend_ . ../src
+
+# Test Vala support: diagnostics for invalid format strings.
+
+: ${XGETTEXT=xgettext}
+
+cat <<\EOF > xg-vala-7.vala
+_("Invalid C format %z").printf();
+EOF
+
+LANGUAGE= LC_ALL=C ${XGETTEXT} --omit-header --no-location -o xg-vala-7.tmp xg-vala-7.vala 2>xg-vala-7.err || Exit 1
+cat xg-vala-7.err
+grep 'warning: Although being used in a format string position, the msgid is not a valid C format string.' xg-vala-7.err >/dev/null || Exit 1
+func_filter_POT_Creation_Date xg-vala-7.tmp xg-vala-7.po
+
+cat <<\EOF > xg-vala-7.ok
+msgid "Invalid C format %z"
+msgstr ""
+EOF
+
+: ${DIFF=diff}
+${DIFF} xg-vala-7.ok xg-vala-7.po
+result=$?
+
+exit $result