I came up with the following: @@ type t; const t *x; identifier y,z; expression a; assignment operator aop; @@ ( (<+...(<+...x->y...+>)[...]...+>) aop a | (<+...(<+...x->y...+>)->z...+>) aop a | * (<+...x->y...+>) aop a ) @fn disable optional_qualifier@ identifier f,x; type t; parameter list[n] ps; @@ f(ps,t *x,...) { ... } @@ identifier fn.f; expression list[fn.n] es; type t; const t *e; @@ *f(es,e,...) --------------- The first rule takes care of assignments, while the remaining rules check function calls. This is not extensively tested and has false positives. One case is when you have a->b[x->y] = 12; and it is x not a that is const. Maybe I can improve it to avoid this problem. I would suggest to replace the occurrences of t by your specific type of interest (and then drop the occurrences type t;), to reduce the amount of work to be done and the chance of false positives. This is also limited in that it only works on a single file. Thus in particular the last rule on function calls will only be triggered when the called function is defined in the same file. Despite the current limitations, maybe it will find something useful. julia