linux-sparse.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 2/3] evaluate: warn on identical exprs around '||'
  2011-08-27 22:26 Chris Forbes
@ 2011-08-27 22:26 ` Chris Forbes
  0 siblings, 0 replies; 6+ messages in thread
From: Chris Forbes @ 2011-08-27 22:26 UTC (permalink / raw)
  To: linux-sparse; +Cc: Chris Forbes

Same as prev, but for || operator.

Signed-off-by: Chris Forbes <chrisf@ijw.co.nz>
---
 evaluate.c                               |    4 ++++
 validation/check_identical_exprs_on_or.c |   24 ++++++++++++++++++++++++
 2 files changed, 28 insertions(+), 0 deletions(-)
 create mode 100644 validation/check_identical_exprs_on_or.c

diff --git a/evaluate.c b/evaluate.c
index 08f6ae6..11de7aa 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -985,6 +985,10 @@ static struct symbol *evaluate_logical(struct expression *expr)
 			expr_equiv(expr->left, expr->right)) {
 			warning(expr->pos, "identical expressions on both "
 				"sides of '&&'");
+		} else if (expr->op == SPECIAL_LOGICAL_OR &&
+			expr_equiv(expr->left, expr->right)) {
+			warning(expr->pos, "identical expressions on both "
+				"sides of '||'");
 		}
 	}
 
diff --git a/validation/check_identical_exprs_on_or.c b/validation/check_identical_exprs_on_or.c
new file mode 100644
index 0000000..74fe226
--- /dev/null
+++ b/validation/check_identical_exprs_on_or.c
@@ -0,0 +1,24 @@
+extern void bar(void);
+
+static void foo(void *a, void *b, void *c)
+{
+	if (a || a)	/* should warn */
+		bar();
+
+	if (a || b)	/* should not warn */
+		bar();
+
+	if ((a == b) || (a == b))	/* should warn */
+		bar();
+
+	if ((a == b) || (b == c))	/* should not warn */
+		bar();
+}
+/*
+ * check-name: A warning should be issued for identical expressions on both sides of the '||' operator.
+ *
+ * check-error-start
+check_identical_exprs_on_or.c:5:15: warning: identical expressions on both sides of '||'
+check_identical_exprs_on_or.c:11:22: warning: identical expressions on both sides of '||'
+ * check-error-end
+ */
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 1/3] evaluate: warn on identical exprs around '&&'
@ 2011-08-28  3:14 Chris Forbes
  2011-08-28  3:14 ` [PATCH 2/3] evaluate: warn on identical exprs around '||' Chris Forbes
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Chris Forbes @ 2011-08-28  3:14 UTC (permalink / raw)
  To: linux-sparse; +Cc: Chris Forbes

Adds a warning when identical expressions are found on both sides of the '&&' operator. This is a common error resulting from copy & paste.

Excludes identical expressions found while preprocessing, so we don't get upset about #if defined(FOO) && defined(BAR), which happens all the time, and is perfectly valid.

Signed-off-by: Chris Forbes <chrisf@ijw.co.nz>
---
 evaluate.c                                |  133 +++++++++++++++++++++++++++++
 validation/check_identical_exprs_on_and.c |   30 +++++++
 2 files changed, 163 insertions(+), 0 deletions(-)
 create mode 100644 validation/check_identical_exprs_on_and.c

diff --git a/evaluate.c b/evaluate.c
index f7a5678..4914442 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -853,8 +853,141 @@ static struct symbol *evaluate_conditional(struct expression *expr, int iterator
 	return ctype;
 }
 
+static int str_equal(struct string *a, struct string *b)
+{
+	return a->length == b->length &&
+		!memcmp(a->data, b->data, a->length);
+}
+
+static int ident_equal(struct ident *a, struct ident *b)
+{
+	/* only correct when used in the context of expr_equiv.
+		should compare symbols? for general case? */
+	return a->len == b->len &&
+		!memcmp(a->name, b->name, a->len);
+}
+
+/* expr_equiv and expr_list_equiv are mutually recursive */
+static int expr_equiv(struct expression *lhs, struct expression *rhs);
+
+static int expr_list_equiv(struct expression_list *lhs,
+			   struct expression_list *rhs)
+{
+	int l_length = expression_list_size(lhs);
+	int r_length = expression_list_size(rhs);
+	struct expression **l_items, **r_items;
+	int i;
+
+	if (l_length != r_length)
+		return 0;
+
+	l_items = alloca(sizeof( *l_items ) * l_length);
+	r_items = alloca(sizeof( *r_items ) * r_length);
+
+	linearize_ptr_list((struct ptr_list *)lhs, (void **)l_items, l_length);
+	linearize_ptr_list((struct ptr_list *)rhs, (void **)r_items, r_length);
+
+	for (i = 0; i < l_length; i++) {
+		if (!expr_equiv(l_items[i], r_items[i]))
+			return 0;
+	}
+
+	return 1;
+}
+
+int expr_equiv(struct expression *lhs, struct expression *rhs)
+{
+	/* recursively determine if lhs ~ rhs. */
+	if (!lhs || !rhs) return 0;
+
+	if (lhs->type != rhs->type) return 0;
+	if (lhs->flags != rhs->flags) return 0;
+	if (lhs->op != rhs->op) return 0;
+	if (lhs->ctype != rhs->ctype) return 0;
+
+	switch (lhs->type) {
+	case EXPR_VALUE:
+		return lhs->value == rhs->value &&
+			lhs->taint == rhs->taint;
+	case EXPR_FVALUE:
+		return lhs->fvalue == rhs->fvalue;
+	case EXPR_STRING:
+		return lhs->wide == rhs->wide &&
+			str_equal(lhs->string, rhs->string);
+/*	case EXPR_UNOP:	*/	/* this is mentioned in the union, but doesn't
+				actually exist */
+	case EXPR_PREOP:
+	case EXPR_POSTOP:
+		return lhs->op_value == rhs->op_value &&
+			expr_equiv(lhs->unop, rhs->unop);
+	case EXPR_SYMBOL:
+	case EXPR_TYPE:
+		return lhs->symbol == rhs->symbol;
+	case EXPR_BINOP:
+	case EXPR_COMMA:
+	case EXPR_COMPARE:
+	case EXPR_LOGICAL:
+	case EXPR_ASSIGNMENT:
+		return expr_equiv(lhs->left, rhs->left) &&
+			expr_equiv(lhs->right, rhs->right);
+	case EXPR_DEREF:
+		return expr_equiv(lhs->deref, rhs->deref) &&
+			ident_equal(lhs->member, rhs->member);
+	case EXPR_SLICE:
+		return expr_equiv(lhs->base, rhs->base) &&
+			lhs->r_bitpos == rhs->r_bitpos &&
+			lhs->r_nrbits == rhs->r_nrbits;
+	case EXPR_CAST:
+	case EXPR_SIZEOF:
+		return lhs->cast_type == rhs->cast_type &&
+			expr_equiv(lhs->cast_expression,
+				rhs->cast_expression);
+	case EXPR_CONDITIONAL:
+	case EXPR_SELECT:
+		return expr_equiv(lhs->conditional, rhs->conditional) &&
+			expr_equiv(lhs->cond_true, rhs->cond_true) &&
+			expr_equiv(lhs->cond_false, rhs->cond_false);
+	case EXPR_CALL:
+		return expr_equiv(lhs->fn, rhs->fn) &&
+			expr_list_equiv(lhs->args, rhs->args);
+	case EXPR_LABEL:
+		return lhs->label_symbol == rhs->label_symbol;
+	case EXPR_INITIALIZER:
+		return expr_list_equiv(lhs->expr_list, rhs->expr_list);
+	case EXPR_IDENTIFIER:
+		return ident_equal(lhs->expr_ident, rhs->expr_ident) &&
+			lhs->field == rhs->field &&
+			expr_equiv(lhs->ident_expression,
+				rhs->ident_expression);
+	case EXPR_INDEX:
+		return lhs->idx_from == rhs->idx_from &&
+			lhs->idx_to == rhs->idx_to &&
+			expr_equiv(lhs->idx_expression, rhs->idx_expression);
+	case EXPR_POS:
+		return lhs->init_offset == rhs->init_offset &&
+			lhs->init_nr == rhs->init_nr &&
+			expr_equiv(lhs->init_expr, rhs->init_expr);
+	case EXPR_OFFSETOF:
+		return lhs->in == rhs->in &&
+			expr_equiv(lhs->down, rhs->down);
+
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
 static struct symbol *evaluate_logical(struct expression *expr)
 {
+	if (!preprocessing) {
+		if (expr->op == SPECIAL_LOGICAL_AND &&
+			expr_equiv(expr->left, expr->right)) {
+			warning(expr->pos, "identical expressions on both "
+				"sides of '&&'");
+		}
+	}
+
 	if (!evaluate_conditional(expr->left, 0))
 		return NULL;
 	if (!evaluate_conditional(expr->right, 0))
diff --git a/validation/check_identical_exprs_on_and.c b/validation/check_identical_exprs_on_and.c
new file mode 100644
index 0000000..6560429
--- /dev/null
+++ b/validation/check_identical_exprs_on_and.c
@@ -0,0 +1,30 @@
+extern void bar(void);
+
+static void foo(void *a, void *b, void *c)
+{
+	if (a && a)	/* should warn */
+		bar();
+
+	if (a && b)	/* should not warn */
+		bar();
+
+	if ((a == b) && (a == b))	/* should warn */
+		bar();
+
+	if ((a == b) && (b == c))	/* should not warn */
+		bar();
+}
+
+/* should not warn */
+#if defined(BLETCHEROUS_PLATFORM) && defined(BROKEN_VERSION_OF_SAME)
+	/* do something suitably bizarre */
+#endif
+
+/*
+ * check-name: A warning should be issued for identical expressions on both sides of the '&&' operator.
+ *
+ * check-error-start
+check_identical_exprs_on_and.c:5:15: warning: identical expressions on both sides of '&&'
+check_identical_exprs_on_and.c:11:22: warning: identical expressions on both sides of '&&'
+ * check-error-end
+ */
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/3] evaluate: warn on identical exprs around '||'
  2011-08-28  3:14 [PATCH 1/3] evaluate: warn on identical exprs around '&&' Chris Forbes
@ 2011-08-28  3:14 ` Chris Forbes
  2011-08-28  3:14 ` [PATCH 3/3] evaluate: warn on identical exprs on ?: Chris Forbes
  2011-08-29 10:01 ` [PATCH 1/3] evaluate: warn on identical exprs around '&&' Jonathan Neuschäfer
  2 siblings, 0 replies; 6+ messages in thread
From: Chris Forbes @ 2011-08-28  3:14 UTC (permalink / raw)
  To: linux-sparse; +Cc: Chris Forbes

Same as prev, but for || operator.

Signed-off-by: Chris Forbes <chrisf@ijw.co.nz>
---
 evaluate.c                               |    4 ++++
 validation/check_identical_exprs_on_or.c |   24 ++++++++++++++++++++++++
 2 files changed, 28 insertions(+), 0 deletions(-)
 create mode 100644 validation/check_identical_exprs_on_or.c

diff --git a/evaluate.c b/evaluate.c
index 4914442..0e5d691 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -985,6 +985,10 @@ static struct symbol *evaluate_logical(struct expression *expr)
 			expr_equiv(expr->left, expr->right)) {
 			warning(expr->pos, "identical expressions on both "
 				"sides of '&&'");
+		} else if (expr->op == SPECIAL_LOGICAL_OR &&
+			expr_equiv(expr->left, expr->right)) {
+			warning(expr->pos, "identical expressions on both "
+				"sides of '||'");
 		}
 	}
 
diff --git a/validation/check_identical_exprs_on_or.c b/validation/check_identical_exprs_on_or.c
new file mode 100644
index 0000000..74fe226
--- /dev/null
+++ b/validation/check_identical_exprs_on_or.c
@@ -0,0 +1,24 @@
+extern void bar(void);
+
+static void foo(void *a, void *b, void *c)
+{
+	if (a || a)	/* should warn */
+		bar();
+
+	if (a || b)	/* should not warn */
+		bar();
+
+	if ((a == b) || (a == b))	/* should warn */
+		bar();
+
+	if ((a == b) || (b == c))	/* should not warn */
+		bar();
+}
+/*
+ * check-name: A warning should be issued for identical expressions on both sides of the '||' operator.
+ *
+ * check-error-start
+check_identical_exprs_on_or.c:5:15: warning: identical expressions on both sides of '||'
+check_identical_exprs_on_or.c:11:22: warning: identical expressions on both sides of '||'
+ * check-error-end
+ */
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/3] evaluate: warn on identical exprs on ?:
  2011-08-28  3:14 [PATCH 1/3] evaluate: warn on identical exprs around '&&' Chris Forbes
  2011-08-28  3:14 ` [PATCH 2/3] evaluate: warn on identical exprs around '||' Chris Forbes
@ 2011-08-28  3:14 ` Chris Forbes
  2011-08-29 10:01 ` [PATCH 1/3] evaluate: warn on identical exprs around '&&' Jonathan Neuschäfer
  2 siblings, 0 replies; 6+ messages in thread
From: Chris Forbes @ 2011-08-28  3:14 UTC (permalink / raw)
  To: linux-sparse; +Cc: Chris Forbes

Adds a warning when identical expressions are found on both the true and false branches of ?:. This is another common copy-paste error.

Signed-off-by: Chris Forbes <chrisf@ijw.co.nz>
---
 evaluate.c                                 |    6 ++++++
 validation/check_identical_exprs_on_cond.c |   13 +++++++++++++
 2 files changed, 19 insertions(+), 0 deletions(-)
 create mode 100644 validation/check_identical_exprs_on_cond.c

diff --git a/evaluate.c b/evaluate.c
index 0e5d691..c339e63 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -1220,6 +1220,12 @@ static struct symbol *evaluate_conditional_expression(struct expression *expr)
 	const char * typediff;
 	int qual;
 
+	if (!preprocessing) {
+		if (expr_equiv(expr->cond_true, expr->cond_false))
+			warning(expr->pos, "identical expressions on both "
+				"branches of '?:'");
+	}
+
 	if (!evaluate_conditional(expr->conditional, 0))
 		return NULL;
 	if (!evaluate_expression(expr->cond_false))
diff --git a/validation/check_identical_exprs_on_cond.c b/validation/check_identical_exprs_on_cond.c
new file mode 100644
index 0000000..85a9938
--- /dev/null
+++ b/validation/check_identical_exprs_on_cond.c
@@ -0,0 +1,13 @@
+extern void bar(void);
+
+static void foo(void *a, void *b, void *c)
+{
+	void * d = a ? b : b; /* should warn */
+}
+/*
+ * check-name: A warning should be issued for identical expressions on both the true and false branches of the '?:' operator.
+ *
+ * check-error-start
+check_identical_exprs_on_cond.c:5:22: warning: identical expressions on both branches of '?:'
+ * check-error-end
+ */
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/3] evaluate: warn on identical exprs around '&&'
  2011-08-28  3:14 [PATCH 1/3] evaluate: warn on identical exprs around '&&' Chris Forbes
  2011-08-28  3:14 ` [PATCH 2/3] evaluate: warn on identical exprs around '||' Chris Forbes
  2011-08-28  3:14 ` [PATCH 3/3] evaluate: warn on identical exprs on ?: Chris Forbes
@ 2011-08-29 10:01 ` Jonathan Neuschäfer
  2011-08-29 10:25   ` Josh Triplett
  2 siblings, 1 reply; 6+ messages in thread
From: Jonathan Neuschäfer @ 2011-08-29 10:01 UTC (permalink / raw)
  To: Chris Forbes; +Cc: linux-sparse

On Sun, Aug 28, 2011 at 03:14:18PM +1200, Chris Forbes wrote:
> +	case EXPR_BINOP:
> +	case EXPR_COMMA:
> +	case EXPR_COMPARE:
> +	case EXPR_LOGICAL:
> +	case EXPR_ASSIGNMENT:
> +		return expr_equiv(lhs->left, rhs->left) &&
> +			expr_equiv(lhs->right, rhs->right);
[...]
> +	if ((a == b) && (a == b))	/* should warn */
> +		bar();
> +
> +	if ((a == b) && (b == c))	/* should not warn */
> +		bar();

Should it maybe also handle cases like this?

if ((a == b) && (b == a))
	bar();

Thanks,
	Jonathan Neuschäfer
--
To unsubscribe from this list: send the line "unsubscribe linux-sparse" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/3] evaluate: warn on identical exprs around '&&'
  2011-08-29 10:01 ` [PATCH 1/3] evaluate: warn on identical exprs around '&&' Jonathan Neuschäfer
@ 2011-08-29 10:25   ` Josh Triplett
  0 siblings, 0 replies; 6+ messages in thread
From: Josh Triplett @ 2011-08-29 10:25 UTC (permalink / raw)
  To: Jonathan Neuschäfer; +Cc: Chris Forbes, linux-sparse

On Mon, Aug 29, 2011 at 12:01:06PM +0200, Jonathan Neuschäfer wrote:
> On Sun, Aug 28, 2011 at 03:14:18PM +1200, Chris Forbes wrote:
> > +	case EXPR_BINOP:
> > +	case EXPR_COMMA:
> > +	case EXPR_COMPARE:
> > +	case EXPR_LOGICAL:
> > +	case EXPR_ASSIGNMENT:
> > +		return expr_equiv(lhs->left, rhs->left) &&
> > +			expr_equiv(lhs->right, rhs->right);
> [...]
> > +	if ((a == b) && (a == b))	/* should warn */
> > +		bar();
> > +
> > +	if ((a == b) && (b == c))	/* should not warn */
> > +		bar();
> 
> Should it maybe also handle cases like this?
> 
> if ((a == b) && (b == a))
> 	bar();

That seems both significantly harder to handle and significantly less
likely (since it won't occur due to simple copy/paste).  Probably worth
doing at some point, but I don't think a first pass needs to consider
it.

- Josh Triplett
--
To unsubscribe from this list: send the line "unsubscribe linux-sparse" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2011-08-29 10:25 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-08-28  3:14 [PATCH 1/3] evaluate: warn on identical exprs around '&&' Chris Forbes
2011-08-28  3:14 ` [PATCH 2/3] evaluate: warn on identical exprs around '||' Chris Forbes
2011-08-28  3:14 ` [PATCH 3/3] evaluate: warn on identical exprs on ?: Chris Forbes
2011-08-29 10:01 ` [PATCH 1/3] evaluate: warn on identical exprs around '&&' Jonathan Neuschäfer
2011-08-29 10:25   ` Josh Triplett
  -- strict thread matches above, loose matches on Subject: below --
2011-08-27 22:26 Chris Forbes
2011-08-27 22:26 ` [PATCH 2/3] evaluate: warn on identical exprs around '||' Chris Forbes

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).