Ok, so I implemented what I think is all the suggestions...<div><br></div><div>The patch is around 100 lines shorter, so that's a definite improvement.</div><div><br></div><div>I'm not sure this is as minimal as it could be.</div>
<div><br></div><div>While I was there, I also changed the use of std::sort in the nonnull parsing, since that's where I picked it up from in the first place.</div><div><br></div><div>Andrew<br><br><div class="gmail_quote">
On Tue, Jun 29, 2010 at 2:43 PM, Ted Kremenek <span dir="ltr"><<a href="mailto:kremenek@apple.com">kremenek@apple.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div class="im">On Jun 28, 2010, at 7:00 PM, Andrew McGregor wrote:<br>
<br>
> So, thinking about this led me to this idea:<br>
><br>
> These attributes actually have minimal differences so far as the checker is concerned.  So how about there being only one attribute object  type, probably an OwnershipAttr, with an enum kind embedded in it, that can be applied to an argument.  Each one would apply to just one argument or the return value, but may have several arguments (the so far unimplemented calloc case will need this, as will pointer-to-pointer malloc).  The parser would have to construct two attribute objects for __attribute((ownership_holds, 1, 2)).  That way the dispatch can be a case statement on the enum rather than the current mess of casts and tests.  This would also save some of the methods from being templates, which I think would be unnecessary complexity.<br>

><br>
> Or, again in order to reduce the duplication, I could make templates of some of the methods and use the type to represent the attribute kind the same way as I have so far.  Disadvantage: this is probably going to bloat.<br>

<br>
</div>I'm fine with having one attribute with an enum, but I don't think it is mutually exclusive from having subclasses.  You can keep all the key logic in one class, and for clients that want to do queries that are specific to a particular attribute they can do downcast.  For example:<br>

<br>
class OwnershipAttr {<br>
  enum OwnershipKind { Holds, Takes, ... };<br>
  OwnershipKind OKind;<br>
...<br>
};<br>
<br>
class OwnershipReturnsAttr : public OwnershipAttr {<br>
public:<br>
  OwnershipReturnsAttr() : OwnershipAttr(Returns) {}<br>
<br>
  static bool classof(OwnershipAttr *A) { return A->OKind == Returns; }<br>
};<br>
<br>
This is basically the same idiom we use with Stmts and Exprs in Clang's ASTS.  This gives you the best of both worlds.  You can use the 'enum' when you want switch on the ownership kind, but still can use the classes to encapsulate the relevant logic and add APIs that are only meaningful for a particular attribute.  For example, consider the main analysis function in the static analyzer.  It is littered with case statements like:<br>

<br>
   case Stmt::BlockExprClass:<br>
      VisitBlockExpr(cast<BlockExpr>(S), Pred, Dst);<br>
      break;<br>
<br>
The strength of this approach is you get strong-typing when you want it, but it doesn't add a burden if you don't need it (e.g., if you only care that something is a OwnershipAttr* instead of a OwnershipReturnsAttr*).</blockquote>
</div><br></div>