X-Git-Url: http://git.ozlabs.org/?a=blobdiff_plain;f=tools%2Fccanlint%2Fidempotent.c;h=fa65b05faa8559e4158335c7c57ae9665c45b54a;hb=6b73d11998591ec50e726cc2d4105ca85f38d87d;hp=81984ec713198abed4f94baa88a421d7f9efa042;hpb=7beaa3448fa8e6015798c1609f33d96e8986063d;p=ccan diff --git a/tools/ccanlint/idempotent.c b/tools/ccanlint/idempotent.c index 81984ec7..fa65b05f 100644 --- a/tools/ccanlint/idempotent.c +++ b/tools/ccanlint/idempotent.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include "../tools.h" static const char explain[] = "Headers usually start with the C preprocessor lines to prevent multiple\n" @@ -22,24 +24,90 @@ static const char explain[] static char *report_idem(struct ccan_file *f, char *sofar) { - char **lines; - char *secondline; + struct line_info *line_info; + unsigned int i, first_preproc_line; + const char *line, *sym; - lines = get_ccan_file_lines(f); + line_info = get_ccan_line_info(f); if (f->num_lines < 3) /* FIXME: We assume small headers probably uninteresting. */ - return NULL; + return sofar; - if (!strstarts(lines[0], "#ifndef ")) + for (i = 0; i < f->num_lines; i++) { + if (line_info[i].type == DOC_LINE + || line_info[i].type == COMMENT_LINE) + continue; + if (line_info[i].type == CODE_LINE) + return talloc_asprintf_append(sofar, + "%s:%u:expect first non-comment line to be #ifndef.\n", f->name, i+1); + else if (line_info[i].type == PREPROC_LINE) + break; + } + + /* No code at all? Don't complain. */ + if (i == f->num_lines) + return sofar; + + first_preproc_line = i; + for (i = first_preproc_line+1; i < f->num_lines; i++) { + if (line_info[i].type == DOC_LINE + || line_info[i].type == COMMENT_LINE) + continue; + if (line_info[i].type == CODE_LINE) + return talloc_asprintf_append(sofar, + "%s:%u:expect second line to be #define.\n", f->name, i+1); + else if (line_info[i].type == PREPROC_LINE) + break; + } + + /* No code at all? Weird. */ + if (i == f->num_lines) + return sofar; + + /* We expect a condition on this line. */ + if (!line_info[i].cond) { return talloc_asprintf_append(sofar, - "%s:1:expect first line to be #ifndef.\n", f->name); + "%s:%u:expected #ifndef.\n", + f->name, first_preproc_line+1); + } + + line = f->lines[i]; - secondline = talloc_asprintf(f, "#define %s", - lines[0] + strlen("#ifndef ")); - if (!streq(lines[1], secondline)) + /* We expect the condition to be ! IFDEF . */ + if (line_info[i].cond->type != PP_COND_IFDEF + || !line_info[i].cond->inverse) { return talloc_asprintf_append(sofar, - "%s:2:expect second line to be '%s'.\n", - f->name, secondline); + "%s:%u:expected #ifndef.\n", + f->name, first_preproc_line+1); + } + + /* And this to be #define */ + if (!get_token(&line, "#")) + abort(); + if (!get_token(&line, "define")) { + return talloc_asprintf_append(sofar, + "%s:%u:expected '#define %s'.\n", + f->name, i+1, line_info[i].cond->symbol); + } + sym = get_symbol_token(f, &line); + if (!sym || !streq(sym, line_info[i].cond->symbol)) { + return talloc_asprintf_append(sofar, + "%s:%u:expected '#define %s'.\n", + f->name, i+1, line_info[i].cond->symbol); + } + + /* Rest of code should all be covered by that conditional. */ + for (i++; i < f->num_lines; i++) { + unsigned int val = 0; + if (line_info[i].type == DOC_LINE + || line_info[i].type == COMMENT_LINE) + continue; + if (get_ccan_line_pp(line_info[i].cond, sym, &val, NULL) + != NOT_COMPILED) + return talloc_asprintf_append(sofar, + "%s:%u:code outside idempotent region.\n", + f->name, i+1); + } return sofar; }