diff options
author | Christoph Reiter <reiter.christoph@gmail.com> | 2018-12-08 22:01:12 +0000 |
---|---|---|
committer | Christoph Reiter <reiter.christoph@gmail.com> | 2018-12-08 22:01:12 +0000 |
commit | eb9b263589f78e245c8b374467707ce2abe570d2 (patch) | |
tree | 71b78f9ddc8cc45198ce560acded84da90b094cb | |
parent | 0f4dd5e39a86e9ae749b3b4627488e19d18dd8a5 (diff) | |
parent | f9a873a0881e189a2d20e4904d40bb0c5cbf0d94 (diff) | |
download | gobject-introspection-eb9b263589f78e245c8b374467707ce2abe570d2.tar.gz |
Merge branch 'sourcescanner-get-errors' into 'master'
sourcescanner: collect error messages and expose them
See merge request GNOME/gobject-introspection!83
-rw-r--r-- | giscanner/giscannermodule.c | 23 | ||||
-rw-r--r-- | giscanner/scannerlexer.l | 3 | ||||
-rw-r--r-- | giscanner/scannermain.py | 8 | ||||
-rw-r--r-- | giscanner/scannerparser.y | 11 | ||||
-rw-r--r-- | giscanner/sourcescanner.c | 14 | ||||
-rw-r--r-- | giscanner/sourcescanner.h | 2 | ||||
-rw-r--r-- | giscanner/sourcescanner.py | 3 | ||||
-rw-r--r-- | tests/scanner/test_sourcescanner.py | 61 |
8 files changed, 98 insertions, 27 deletions
diff --git a/giscanner/giscannermodule.c b/giscanner/giscannermodule.c index 45701d17..24b84050 100644 --- a/giscanner/giscannermodule.c +++ b/giscanner/giscannermodule.c @@ -81,7 +81,7 @@ typedef struct { NEW_CLASS (PyGISourceSymbol, "SourceSymbol", GISourceSymbol, 10); NEW_CLASS (PyGISourceType, "SourceType", GISourceType, 9); -NEW_CLASS (PyGISourceScanner, "SourceScanner", GISourceScanner, 8); +NEW_CLASS (PyGISourceScanner, "SourceScanner", GISourceScanner, 9); /* Symbol */ @@ -508,6 +508,26 @@ pygi_source_scanner_get_symbols (PyGISourceScanner *self, G_GNUC_UNUSED PyObject } static PyObject * +pygi_source_scanner_get_errors (PyGISourceScanner *self, G_GNUC_UNUSED PyObject *unused) +{ + GSList *l, *errors; + PyObject *list; + int i = 0; + + errors = gi_source_scanner_get_errors (self->scanner); + list = PyList_New (g_slist_length (errors)); + + for (l = errors; l; l = l->next) + { + PyObject *item = PyUnicode_FromString (l->data); + PyList_SetItem (list, i++, item); + } + + g_slist_free (errors); + return list; +} + +static PyObject * pygi_source_scanner_get_comments (PyGISourceScanner *self, G_GNUC_UNUSED PyObject *unused) { GSList *l, *comments; @@ -563,6 +583,7 @@ pygi_source_scanner_get_comments (PyGISourceScanner *self, G_GNUC_UNUSED PyObjec } static const PyMethodDef _PyGISourceScanner_methods[] = { + { "get_errors", (PyCFunction) pygi_source_scanner_get_errors, METH_NOARGS }, { "get_comments", (PyCFunction) pygi_source_scanner_get_comments, METH_NOARGS }, { "get_symbols", (PyCFunction) pygi_source_scanner_get_symbols, METH_NOARGS }, { "append_filename", (PyCFunction) pygi_source_scanner_append_filename, METH_VARARGS }, diff --git a/giscanner/scannerlexer.l b/giscanner/scannerlexer.l index 971b3a73..c2fb7234 100644 --- a/giscanner/scannerlexer.l +++ b/giscanner/scannerlexer.l @@ -513,7 +513,8 @@ print_error (GISourceScanner *scanner) { if (yytext[0]) { char *filename = g_file_get_parse_name (scanner->current_file); - fprintf(stderr, "%s:%d: unexpected character `%c'\n", filename, lineno, yytext[0]); + gchar *error = g_strdup_printf ("%s:%d: unexpected character `%c'", filename, lineno, yytext[0]); + scanner->errors = g_slist_prepend (scanner->errors, error); g_free (filename); } } diff --git a/giscanner/scannermain.py b/giscanner/scannermain.py index ceca66f4..c2c1ac3d 100644 --- a/giscanner/scannermain.py +++ b/giscanner/scannermain.py @@ -444,8 +444,12 @@ def create_source_scanner(options, args): options.cpp_defines, options.cpp_undefines, cflags=options.cflags) - ss.parse_files(filenames) - ss.parse_macros(filenames) + try: + ss.parse_files(filenames) + ss.parse_macros(filenames) + finally: + for error in ss.get_errors(): + print(error, file=sys.stderr) return ss, filenames diff --git a/giscanner/scannerparser.y b/giscanner/scannerparser.y index bf7bb37f..72c17ec3 100644 --- a/giscanner/scannerparser.y +++ b/giscanner/scannerparser.y @@ -165,7 +165,8 @@ pop_conditional (GISourceScanner *scanner) if (type == 0) { gchar *filename = g_file_get_path (scanner->current_file); - fprintf (stderr, "%s:%d: mismatched %s", filename, lineno, yytext); + gchar *error = g_strdup_printf ("%s:%d: mismatched %s", filename, lineno, yytext); + scanner->errors = g_slist_prepend (scanner->errors, error); g_free (filename); } @@ -180,8 +181,9 @@ warn_if_cond_has_gi_scanner (GISourceScanner *scanner, if (strstr (text, "__GI_SCANNER__")) { gchar *filename = g_file_get_path (scanner->current_file); - fprintf (stderr, "%s:%d: the __GI_SCANNER__ constant should only be used with simple #ifdef or #endif: %s", + gchar *error = g_strdup_printf ("%s:%d: the __GI_SCANNER__ constant should only be used with simple #ifdef or #endif: %s", filename, lineno, text); + scanner->errors = g_slist_prepend (scanner->errors, error); g_free (filename); } } @@ -1567,8 +1569,9 @@ yyerror (GISourceScanner *scanner, const char *s) * have valid expressions */ if (!scanner->macro_scan) { - fprintf(stderr, "%s:%d: %s in '%s' at '%s'\n", - g_file_get_parse_name (scanner->current_file), lineno, s, linebuf, yytext); + gchar *error = g_strdup_printf ("%s:%d: %s in '%s' at '%s'", + g_file_get_parse_name (scanner->current_file), lineno, s, linebuf, yytext); + scanner->errors = g_slist_prepend (scanner->errors, error); } } diff --git a/giscanner/sourcescanner.c b/giscanner/sourcescanner.c index 464e4695..4d10c88b 100644 --- a/giscanner/sourcescanner.c +++ b/giscanner/sourcescanner.c @@ -246,6 +246,7 @@ gi_source_scanner_free (GISourceScanner *scanner) g_slist_free (scanner->comments); g_slist_foreach (scanner->symbols, (GFunc)(void *)gi_source_symbol_unref, NULL); g_slist_free (scanner->symbols); + g_slist_free_full (scanner->errors, g_free); g_hash_table_unref (scanner->files); @@ -326,6 +327,19 @@ gi_source_scanner_get_symbols (GISourceScanner *scanner) } /** + * gi_source_scanner_get_errors: + * @scanner: scanner instance + * + * Returns: (transfer container): List of strings. + * Free resulting list with g_slist_free(). + */ +GSList * +gi_source_scanner_get_errors (GISourceScanner *scanner) +{ + return g_slist_reverse (g_slist_copy (scanner->errors)); +} + +/** * gi_source_scanner_get_comments: * @scanner: scanner instance * diff --git a/giscanner/sourcescanner.h b/giscanner/sourcescanner.h index e9fa5421..bcf1afc4 100644 --- a/giscanner/sourcescanner.h +++ b/giscanner/sourcescanner.h @@ -118,6 +118,7 @@ struct _GISourceScanner GHashTable *const_table; gboolean skipping; GQueue conditionals; + GSList *errors; }; struct _GISourceSymbol @@ -162,6 +163,7 @@ void gi_source_scanner_set_macro_scan (GISourceScanner *scanne gboolean macro_scan); GSList * gi_source_scanner_get_symbols (GISourceScanner *scanner); GSList * gi_source_scanner_get_comments (GISourceScanner *scanner); +GSList * gi_source_scanner_get_errors (GISourceScanner *scanner); void gi_source_scanner_free (GISourceScanner *scanner); GISourceSymbol * gi_source_symbol_new (GISourceSymbolType type, GFile *file, int line); diff --git a/giscanner/sourcescanner.py b/giscanner/sourcescanner.py index d867a4e9..6a0bace7 100644 --- a/giscanner/sourcescanner.py +++ b/giscanner/sourcescanner.py @@ -274,6 +274,9 @@ class SourceScanner(object): def get_comments(self): return self._scanner.get_comments() + def get_errors(self): + return self._scanner.get_errors() + def dump(self): print('-' * 30) for symbol in self._scanner.get_symbols(): diff --git a/tests/scanner/test_sourcescanner.py b/tests/scanner/test_sourcescanner.py index 831af486..624d9df9 100644 --- a/tests/scanner/test_sourcescanner.py +++ b/tests/scanner/test_sourcescanner.py @@ -10,7 +10,20 @@ import os from giscanner.sourcescanner import SourceScanner -two_typedefs_source = """ +class Test(unittest.TestCase): + + def _parse_files(self, code, header=True): + scanner = SourceScanner() + tmp_fd, tmp_name = tempfile.mkstemp(suffix=".h" if header else ".c") + fileobj = os.fdopen(tmp_fd, 'wb') + with fileobj: + fileobj.write(code.encode("utf-8")) + scanner.parse_files([tmp_name]) + os.unlink(tmp_name) + return scanner + + def test_length_consistency(self): + scanner = self._parse_files(""" /** * Spam: */ @@ -20,26 +33,36 @@ typedef struct _spam Spam; * Eggs: */ typedef struct _eggs Eggs; -""" +""") + self.assertEqual(len(list(scanner.get_symbols())), 2) + self.assertEqual(len(list(scanner.get_symbols())), 2) + self.assertEqual(len(list(scanner.get_comments())), 2) + self.assertEqual(len(list(scanner.get_comments())), 2) + self.assertFalse(scanner.get_errors()) -class Test(unittest.TestCase): - def setUp(self): - self.ss = SourceScanner() - tmp_fd, tmp_name = tempfile.mkstemp() - file = os.fdopen(tmp_fd, 'wt') - file.write(two_typedefs_source) - file.close() - - self.ss.parse_files([tmp_name]) - - def test_get_symbols_length_consistency(self): - self.assertEqual(len(list(self.ss.get_symbols())), 2) - self.assertEqual(len(list(self.ss.get_symbols())), 2) - - def test_get_comments_length_consistency(self): - self.assertEqual(len(list(self.ss.get_comments())), 2) - self.assertEqual(len(list(self.ss.get_comments())), 2) + def test_parser_error(self): + scanner = self._parse_files(""" +void foo() { + a = +}""") + + errors = scanner.get_errors() + self.assertEqual(len(errors), 1) + self.assertTrue("syntax error" in errors[0]) + + def test_ignore_typeof(self): + # https://gitlab.gnome.org/GNOME/gobject-introspection/merge_requests/71 + scanner = self._parse_files(""" +/** +* foo: +*/ +void foo(int bar) { + bar = ((__typeof__(bar)) (foo) (bar)); +} +""") + self.assertEqual(len(list(scanner.get_comments())), 1) + self.assertFalse(scanner.get_errors()) if __name__ == '__main__': |