1 /*
   2  * Copyright (C) 2013 Oracle.
   3  *
   4  * This program is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU General Public License
   6  * as published by the Free Software Foundation; either version 2
   7  * of the License, or (at your option) any later version.
   8  *
   9  * This program is distributed in the hope that it will be useful,
  10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  * GNU General Public License for more details.
  13  *
  14  * You should have received a copy of the GNU General Public License
  15  * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
  16  */
  17 
  18 #include "smatch.h"
  19 
  20 #define RECURSE_LIMIT 10
  21 
  22 static int recurse(struct expression *expr,
  23                    int (func)(struct expression *expr, void *p),
  24                    void *param, int nr)
  25 {
  26         int ret;
  27 
  28         if (!expr)
  29                 return 0;
  30 
  31         ret = func(expr, param);
  32         if (ret)
  33                 return ret;
  34 
  35         if (nr > RECURSE_LIMIT)
  36                 return -1;
  37         nr++;
  38 
  39         switch (expr->type) {
  40         case EXPR_PREOP:
  41                 ret = recurse(expr->unop, func, param, nr);
  42                 break;
  43         case EXPR_POSTOP:
  44                 ret = recurse(expr->unop, func, param, nr);
  45                 break;
  46         case EXPR_STATEMENT:
  47                 return -1;
  48                 break;
  49         case EXPR_LOGICAL:
  50         case EXPR_COMPARE:
  51         case EXPR_BINOP:
  52         case EXPR_COMMA:
  53                 ret = recurse(expr->left, func, param, nr);
  54                 if (ret)
  55                         return ret;
  56                 ret = recurse(expr->right, func, param, nr);
  57                 break;
  58         case EXPR_ASSIGNMENT:
  59                 ret = recurse(expr->right, func, param, nr);
  60                 if (ret)
  61                         return ret;
  62                 ret = recurse(expr->left, func, param, nr);
  63                 break;
  64         case EXPR_DEREF:
  65                 ret = recurse(expr->deref, func, param, nr);
  66                 break;
  67         case EXPR_SLICE:
  68                 ret = recurse(expr->base, func, param, nr);
  69                 break;
  70         case EXPR_CAST:
  71         case EXPR_FORCE_CAST:
  72                 ret = recurse(expr->cast_expression, func, param, nr);
  73                 break;
  74         case EXPR_SIZEOF:
  75         case EXPR_OFFSETOF:
  76         case EXPR_ALIGNOF:
  77                 break;
  78         case EXPR_CONDITIONAL:
  79         case EXPR_SELECT:
  80                 ret = recurse(expr->conditional, func, param, nr);
  81                 if (ret)
  82                         return ret;
  83                 ret = recurse(expr->cond_true, func, param, nr);
  84                 if (ret)
  85                         return ret;
  86                 ret = recurse(expr->cond_false, func, param, nr);
  87                 break;
  88         case EXPR_CALL:
  89                 return -1;
  90                 break;
  91         case EXPR_INITIALIZER:
  92                 return -1;
  93                 break;
  94         case EXPR_IDENTIFIER:
  95                 ret = recurse(expr->ident_expression, func, param, nr);
  96                 break;
  97         case EXPR_INDEX:
  98                 ret = recurse(expr->idx_expression, func, param, nr);
  99                 break;
 100         case EXPR_POS:
 101                 ret = recurse(expr->init_expr, func, param, nr);
 102                 break;
 103         case EXPR_SYMBOL:
 104         case EXPR_STRING:
 105         case EXPR_VALUE:
 106                 break;
 107         default:
 108                 return -1;
 109                 break;
 110         };
 111         return ret;
 112 }
 113 
 114 static int has_symbol_helper(struct expression *expr, void *_sym)
 115 {
 116         struct symbol *sym = _sym;
 117 
 118         if (!expr || expr->type != EXPR_SYMBOL)
 119                 return 0;
 120         if (expr->symbol == sym)
 121                 return 1;
 122         return 0;
 123 }
 124 
 125 int has_symbol(struct expression *expr, struct symbol *sym)
 126 {
 127         return recurse(expr, has_symbol_helper, sym, 0);
 128 }
 129 
 130 struct expr_name_sym {
 131         struct expression *expr;
 132         char *name;
 133         struct symbol *sym;
 134 };
 135 
 136 static int has_var_helper(struct expression *expr, void *_var)
 137 {
 138         struct expr_name_sym *xns = _var;
 139         char *name;
 140         struct symbol *sym;
 141         int matched = 0;
 142 
 143         if (!expr)
 144                 return 0;
 145         if (expr->type != xns->expr->type)
 146                 return 0;
 147         // I hope this is defined for everything?  It should work, right?
 148         if (expr->op != xns->expr->op)
 149                 return 0;
 150 
 151         name = expr_to_var_sym(expr, &sym);
 152         if (!name || !sym)
 153                 goto free;
 154         if (sym == xns->sym && strcmp(name, xns->name) == 0)
 155                 matched = 1;
 156 free:
 157         free_string(name);
 158         return matched;
 159 }
 160 
 161 int has_variable(struct expression *expr, struct expression *var)
 162 {
 163         struct expr_name_sym xns;
 164         int ret = -1;
 165 
 166         xns.expr = var;
 167         xns.name = expr_to_var_sym(var, &xns.sym);
 168         if (!xns.name || !xns.sym)
 169                 goto free;
 170         ret = recurse(expr, has_var_helper, &xns, 0);
 171 free:
 172         free_string(xns.name);
 173         return ret;
 174 }
 175 
 176 static int has_inc_dec_helper(struct expression *expr, void *unused)
 177 {
 178         if (!expr)
 179                 return 0;
 180         if (expr->type != EXPR_PREOP && expr->type != EXPR_POSTOP)
 181                 return 0;
 182         if (expr->op == SPECIAL_INCREMENT || expr->op == SPECIAL_DECREMENT)
 183                 return 1;
 184         return 0;
 185 }
 186 
 187 int has_inc_dec(struct expression *expr)
 188 {
 189         return recurse(expr, has_inc_dec_helper, NULL, 0);
 190 }
 191