summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStef Walter <stefw@gnome.org>2013-04-19 16:18:40 +0200
committerStef Walter <stefw@gnome.org>2013-10-21 20:42:10 +0200
commit917da2d1aeffdc884a5fd5cf5b38a60ef088d0fb (patch)
tree115a99b4da986468aca556aec5af292626807948
parentebb80508d6959a0c94351e841c2cab6220602e62 (diff)
downloadgobject-introspection-917da2d1aeffdc884a5fd5cf5b38a60ef088d0fb.tar.gz
giscanner: Respect __GI_SCANNER__ when scanning for macros
When scanning for macros respect ifdefs of __GI_SCANNER__ in the various header files. Only #ifdef and #ifndef are supported. If __GI_SCANNER__ appears in plain #if statements, a warning is printed. https://bugzilla.gnome.org/show_bug.cgi?id=698367
-rw-r--r--giscanner/scannerlexer.l10
-rw-r--r--giscanner/scannerparser.y157
-rw-r--r--giscanner/sourcescanner.c23
-rw-r--r--giscanner/sourcescanner.h4
-rw-r--r--tests/scanner/Regress-1.0-expected.gir10
-rw-r--r--tests/scanner/regress.h12
6 files changed, 213 insertions, 3 deletions
diff --git a/giscanner/scannerlexer.l b/giscanner/scannerlexer.l
index f30191db..7734938a 100644
--- a/giscanner/scannerlexer.l
+++ b/giscanner/scannerlexer.l
@@ -80,6 +80,14 @@ stringtext ([^\\\"])|(\\.)
"#define "[a-zA-Z_][a-zA-Z_0-9]*"(" { yyless (yyleng - 1); return FUNCTION_MACRO; }
"#define "[a-zA-Z_][a-zA-Z_0-9]* { return OBJECT_MACRO; }
+"#ifdef"[\t ]+"__GI_SCANNER__"[\t ]?.*"\n" { return IFDEF_GI_SCANNER; }
+"#ifndef"[\t ]+"__GI_SCANNER__"[\t ]?.*"\n" { return IFNDEF_GI_SCANNER; }
+"#ifndef ".*"\n" { return IFNDEF_COND; }
+"#ifdef ".*"\n" { return IFDEF_COND; }
+"#if ".*"\n" { return IF_COND; }
+"#elif ".*"\n" { return ELIF_COND; }
+"#else".*"\n" { return ELSE_COND; }
+"#endif".*"\n" { return ENDIF_COND; }
"#pragma ".*"\n" { /* Ignore pragma. */ }
"# "[0-9]+" ".*"\n" { process_linemarks(scanner); }
@@ -269,7 +277,7 @@ parse_comment (GISourceScanner *scanner)
comment->line = comment_lineno;
comment->filename = g_file_get_parse_name (scanner->current_file);
- scanner->comments = g_slist_prepend (scanner->comments, comment);
+ gi_source_scanner_take_comment (scanner, comment);
} else {
/*
* Ignore all other comment blocks
diff --git a/giscanner/scannerparser.y b/giscanner/scannerparser.y
index d440fd38..faf73410 100644
--- a/giscanner/scannerparser.y
+++ b/giscanner/scannerparser.y
@@ -128,6 +128,84 @@ out:
return dest;
}
+enum {
+ IRRELEVANT = 1,
+ NOT_GI_SCANNER = 2,
+ FOR_GI_SCANNER = 3,
+};
+
+static void
+update_skipping (GISourceScanner *scanner)
+{
+ GList *l;
+ for (l = scanner->conditionals.head; l != NULL; l = g_list_next (l))
+ {
+ if (GPOINTER_TO_INT (l->data) == NOT_GI_SCANNER)
+ {
+ scanner->skipping = TRUE;
+ return;
+ }
+ }
+
+ scanner->skipping = FALSE;
+}
+
+static void
+push_conditional (GISourceScanner *scanner,
+ gint type)
+{
+ g_assert (type != 0);
+ g_queue_push_head (&scanner->conditionals, GINT_TO_POINTER (type));
+}
+
+static gint
+pop_conditional (GISourceScanner *scanner)
+{
+ gint type = GPOINTER_TO_INT (g_queue_pop_head (&scanner->conditionals));
+
+ if (type == 0)
+ {
+ gchar *filename = g_file_get_path (scanner->current_file);
+ fprintf (stderr, "%s:%d: mismatched %s", filename, lineno, yytext);
+ g_free (filename);
+ }
+
+ return type;
+}
+
+static void
+warn_if_cond_has_gi_scanner (GISourceScanner *scanner,
+ const gchar *text)
+{
+ /* Some other conditional that is not __GI_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",
+ filename, lineno, text);
+ g_free (filename);
+ }
+}
+
+static void
+toggle_conditional (GISourceScanner *scanner)
+{
+ switch (pop_conditional (scanner))
+ {
+ case FOR_GI_SCANNER:
+ push_conditional (scanner, NOT_GI_SCANNER);
+ break;
+ case NOT_GI_SCANNER:
+ push_conditional (scanner, FOR_GI_SCANNER);
+ break;
+ case 0:
+ break;
+ default:
+ push_conditional (scanner, IRRELEVANT);
+ break;
+ }
+}
+
%}
%error-verbose
@@ -160,6 +238,8 @@ out:
%token VOID VOLATILE WHILE
%token FUNCTION_MACRO OBJECT_MACRO
+%token IFDEF_GI_SCANNER IFNDEF_GI_SCANNER
+%token IFDEF_COND IFNDEF_COND IF_COND ELIF_COND ELSE_COND ENDIF_COND
%start translation_unit
@@ -1403,9 +1483,55 @@ object_macro_define
}
;
+preproc_conditional
+ : IFDEF_GI_SCANNER
+ {
+ push_conditional (scanner, FOR_GI_SCANNER);
+ update_skipping (scanner);
+ }
+ | IFNDEF_GI_SCANNER
+ {
+ push_conditional (scanner, NOT_GI_SCANNER);
+ update_skipping (scanner);
+ }
+ | IFDEF_COND
+ {
+ warn_if_cond_has_gi_scanner (scanner, yytext);
+ push_conditional (scanner, IRRELEVANT);
+ }
+ | IFNDEF_COND
+ {
+ warn_if_cond_has_gi_scanner (scanner, yytext);
+ push_conditional (scanner, IRRELEVANT);
+ }
+ | IF_COND
+ {
+ warn_if_cond_has_gi_scanner (scanner, yytext);
+ push_conditional (scanner, IRRELEVANT);
+ }
+ | ELIF_COND
+ {
+ warn_if_cond_has_gi_scanner (scanner, yytext);
+ pop_conditional (scanner);
+ push_conditional (scanner, IRRELEVANT);
+ update_skipping (scanner);
+ }
+ | ELSE_COND
+ {
+ toggle_conditional (scanner);
+ update_skipping (scanner);
+ }
+ | ENDIF_COND
+ {
+ pop_conditional (scanner);
+ update_skipping (scanner);
+ }
+ ;
+
macro
: function_macro_define
| object_macro_define
+ | preproc_conditional
| error
;
@@ -1435,14 +1561,19 @@ eat_hspace (FILE * f)
}
static int
-eat_line (FILE * f, int c)
+pass_line (FILE * f, int c,
+ FILE *out)
{
while (c != EOF && c != '\n')
{
+ if (out)
+ fputc (c, out);
c = fgetc (f);
}
if (c == '\n')
{
+ if (out)
+ fputc (c, out);
c = fgetc (f);
if (c == ' ' || c == '\t')
{
@@ -1453,6 +1584,12 @@ eat_line (FILE * f, int c)
}
static int
+eat_line (FILE * f, int c)
+{
+ return pass_line (f, c, NULL);
+}
+
+static int
read_identifier (FILE * f, int c, char **identifier)
{
GString *id = g_string_new ("");
@@ -1484,6 +1621,7 @@ gi_source_scanner_parse_macros (GISourceScanner *scanner, GList *filenames)
GString *define_line;
char *str;
gboolean error_line = FALSE;
+ gboolean end_of_word;
int c = eat_hspace (f);
while (c != EOF)
{
@@ -1502,7 +1640,22 @@ gi_source_scanner_parse_macros (GISourceScanner *scanner, GList *filenames)
c = eat_hspace (f);
c = read_identifier (f, c, &str);
- if (strcmp (str, "define") != 0 || (c != ' ' && c != '\t'))
+ end_of_word = (c == ' ' || c == '\t' || c == '\n' || c == EOF);
+ if (end_of_word &&
+ (g_str_equal (str, "if") ||
+ g_str_equal (str, "endif") ||
+ g_str_equal (str, "ifndef") ||
+ g_str_equal (str, "ifdef") ||
+ g_str_equal (str, "else") ||
+ g_str_equal (str, "elif")))
+ {
+ fprintf (fmacros, "#%s ", str);
+ g_free (str);
+ c = pass_line (f, c, fmacros);
+ line++;
+ continue;
+ }
+ else if (strcmp (str, "define") != 0 || !end_of_word)
{
g_free (str);
/* ignore line */
diff --git a/giscanner/sourcescanner.c b/giscanner/sourcescanner.c
index 70eca8d0..30c2b036 100644
--- a/giscanner/sourcescanner.c
+++ b/giscanner/sourcescanner.c
@@ -221,6 +221,7 @@ gi_source_scanner_new (void)
scanner->files = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal,
g_object_unref, NULL);
+ g_queue_init (&scanner->conditionals);
return scanner;
}
@@ -247,6 +248,7 @@ gi_source_scanner_free (GISourceScanner *scanner)
g_hash_table_unref (scanner->files);
+ g_queue_clear (&scanner->conditionals);
}
gboolean
@@ -268,6 +270,12 @@ void
gi_source_scanner_add_symbol (GISourceScanner *scanner,
GISourceSymbol *symbol)
{
+ if (scanner->skipping)
+ {
+ g_debug ("skipping symbol due to __GI_SCANNER__ cond: %s", symbol->ident);
+ return;
+ }
+
g_assert (scanner->current_file);
if (scanner->macro_scan || g_hash_table_contains (scanner->files, scanner->current_file))
@@ -295,6 +303,21 @@ gi_source_scanner_add_symbol (GISourceScanner *scanner,
}
}
+void
+gi_source_scanner_take_comment (GISourceScanner *scanner,
+ GISourceComment *comment)
+{
+ if (scanner->skipping)
+ {
+ g_debug ("skipping comment due to __GI_SCANNER__ cond");
+ gi_source_comment_free (comment);
+ return;
+ }
+
+ scanner->comments = g_slist_prepend (scanner->comments,
+ comment);
+}
+
GSList *
gi_source_scanner_get_symbols (GISourceScanner *scanner)
{
diff --git a/giscanner/sourcescanner.h b/giscanner/sourcescanner.h
index 2db9bdf6..254e43bf 100644
--- a/giscanner/sourcescanner.h
+++ b/giscanner/sourcescanner.h
@@ -115,6 +115,8 @@ struct _GISourceScanner
GSList *comments; /* _GIComment */
GHashTable *typedef_table;
GHashTable *struct_or_union_or_enum_table;
+ gboolean skipping;
+ GQueue conditionals;
};
struct _GISourceSymbol
@@ -168,6 +170,8 @@ GISourceSymbol * gi_source_symbol_copy (GISourceSymbol *symb
/* Private */
void gi_source_scanner_add_symbol (GISourceScanner *scanner,
GISourceSymbol *symbol);
+void gi_source_scanner_take_comment (GISourceScanner *scanner,
+ GISourceComment *comment);
gboolean gi_source_scanner_is_typedef (GISourceScanner *scanner,
const char *name);
void gi_source_symbol_merge_type (GISourceSymbol *symbol,
diff --git a/tests/scanner/Regress-1.0-expected.gir b/tests/scanner/Regress-1.0-expected.gir
index 637a2735..bb83e225 100644
--- a/tests/scanner/Regress-1.0-expected.gir
+++ b/tests/scanner/Regress-1.0-expected.gir
@@ -1911,6 +1911,16 @@ exposed to language bindings.</doc>
</parameter>
</parameters>
</callback>
+ <constant name="GI_SCANNER_ELSE"
+ value="3"
+ c:type="REGRESS_GI_SCANNER_ELSE">
+ <type name="gint" c:type="gint"/>
+ </constant>
+ <constant name="GI_SCANNER_IFDEF"
+ value="3"
+ c:type="REGRESS_GI_SCANNER_IFDEF">
+ <type name="gint" c:type="gint"/>
+ </constant>
<constant name="GUINT64_CONSTANT"
value="18446744073709551615"
c:type="REGRESS_GUINT64_CONSTANT">
diff --git a/tests/scanner/regress.h b/tests/scanner/regress.h
index 274d0e4b..9c858840 100644
--- a/tests/scanner/regress.h
+++ b/tests/scanner/regress.h
@@ -950,4 +950,16 @@ typedef struct {
#define REGRESS_MININT64 ((gint64) G_GINT64_CONSTANT(0x8000000000000000))
#define REGRESS_MAXUINT64 (G_GINT64_CONSTANT(0xffffffffffffffffU))
+/* https://bugzilla.gnome.org/show_bug.cgi?id=698367 */
+#ifndef __GI_SCANNER__
+#define REGRESS_DONTSCANTHIS 1
+#else
+#define REGRESS_GI_SCANNER_ELSE 3
+#endif
+#ifndef BLAH
+#ifdef __GI_SCANNER__
+#define REGRESS_GI_SCANNER_IFDEF 3
+#endif
+#endif
+
#endif /* __GITESTTYPES_H__ */