LegalizeAdulthood added inline comments.

================
Comment at: unittests/ASTMatchers/ASTMatchersTest.cpp:4992
@@ +4991,3 @@
+  EXPECT_TRUE(matches("typedef int hasUnderlyingTypeTest;",
+                      typedefDecl(hasUnderlyingType(asString("int")))));
+  EXPECT_TRUE(matches("typedef const int T;",
----------------
LegalizeAdulthood wrote:
> aaron.ballman wrote:
> > LegalizeAdulthood wrote:
> > > aaron.ballman wrote:
> > > > > I'm happy to make the improvement, but I don't know how. I simply 
> > > > > call the Node.underlyingType(), just like hasType calls 
> > > > > Node.getType(). I don't know why they are different.
> > > > 
> > > > hasType() and hasUnderlyingType() have different operational semantic 
> > > > implications, at least to me. hasType() asks, "ultimately, what is the 
> > > > type of this thing?", and Node.underlyingType() answers that. To me, 
> > > > hasUnderlyingType() asks, "in the chain of types that this typedef 
> > > > refers to, does this thing match any of them?", and 
> > > > Node.underlyingType() does not answer that -- it only looks at the 
> > > > final desugared type. The difference we want is that hasType() 
> > > > continues to look at the final type, but hasUnderlyingType() needs to 
> > > > do more work to look at intermediary types and terminate that loop when 
> > > > the answer is "yes, it has this type" or "no, we can't desugar any 
> > > > further."
> > > > 
> > > > If we don't care about the intermediate types for your needs, then I 
> > > > don't see the point to hasUnderlyingType() being an AST matcher at all. 
> > > > hasType() does exactly what is needed, and you can instead modify that 
> > > > to accept a TypedefDecl in addition to Expr and ValueDecl. However, I 
> > > > still see value in hasUnderlyingType() because typedef chains can be 
> > > > long and complex (like in the Win32 APIs), and being able to query for 
> > > > intermediary types would be useful. e.g., I want to know about all 
> > > > types that have an intermediary type of DWORD (which itself is a 
> > > > typedef for an unsigned integer type). hasType() will always go to the 
> > > > final type, making such a matcher impossible without something like 
> > > > hasUnderlyingType().
> > > I just named the matcher after the 
> > > [accessor](http://clang.llvm.org/doxygen/classclang_1_1TypedefNameDecl.html#a5fccedff6d3854db365a540145029158)
> > >  on a typedefDecl node.  To me it's just a narrowing matcher on that node 
> > > that gives you access to whatever the accessor returns.
> > > 
> > > Things may have changed in the meantime, but when I originally created 
> > > this patch you couldn't do `typedefDecl(hasType(asString("int")))`.  It 
> > > doesn't compile.  Since `hasType` just matched against the value of 
> > > whatever `Node.getType()` returned it seemed natural to add a matcher 
> > > called `hasUnderlyingType` that just matched against the value of 
> > > whatever `Node.getUnderlyingType()` returned.
> > > 
> > > As I said, I'm happy to make the suggested improvement, but beyond simple 
> > > immitation of existing matchers, I have no idea how to traverse the 
> > > encodings of types within the guts of clang.  This is what I mean when I 
> > > say "I don't know how".  I understand conceptually what you are saying 
> > > but I have no idea how to express that in clang's code base.
> > That's why I am trying to understand what your goal is. As best I can tell, 
> > there are two distinct things someone may want to do with a typedef's type: 
> > figure out what it ultimately boils down to, or traverse the typedef chain. 
> > I was uncertain which one fit your needs better, but it sounds like "get 
> > the ultimate type" is what you want. From there we can discuss what the 
> > proper design of the matcher is. I think I was thrown off by you naming it 
> > *has*UnderlyingType instead of *get*UnderlyingType because *has* implies a 
> > different relationship than *get* and I couldn't see why you wouldn't just 
> > update hasType() instead.
> > 
> > Another thing to think about: the typedef matcher is a bit controversial in 
> > terms of the semantics, but the other matchers are not. Perhaps it makes 
> > sense to split the patch into two parts?
> > 
> > As for how to actually implement the traversal, I think it looks something 
> > like (totally untested):
> > ```
> > QualType QT = Context.getTypedefType(&Node);
> > for (QualType NextQT; QT != NextQT; NextQT = 
> > QT.getSingleStepDesugaredType(Context)) {
> >   // If matches, return Type
> > }
> > return QT;
> > ```
> This all came up because of the work I was doing on clang-tidy to implement 
> the modernize-redundant-void-arg check.  There wasn't a way to narrow 
> typedefDecl nodes based on the actual type for which a synonym was being 
> introduced.  In that situation, suppose we have something like this:
> 
> ```
> typedef void (fnReturningVoid)(void);
> typedef foo fnReturningVoid;
> ```
> 
> I would want to match the first typedef because that is the one my check 
> needs to modify.  I don't want to match the second typedef because even 
> though it has the same ultimate type as the first, it doesn't contain the 
> redundant void argument tokens that need to be fixed up.
> 
> So for my needs in this scenario, the existing matcher does **exactly** what 
> I need, namely match the first typedef, but not the second.  It turns out 
> that on a typedefDecl node you call the member function `getUnderlyingType()` 
> in order to match the first typedef, so that is what I have called the 
> matcher.
> 
> If the phrase "underlying type" in common clang parlance means the ultimate 
> desugaring of a type down to it's most basic form with all intervening 
> typedefs removed, then it seems that not only is my matcher misnamed, but 
> also this member function is misnamed.  Because that's not what this member 
> function is returning for the typedef-of-a-typedef situation (as the earlier 
> failed test fragment discussed).
> 
> Am I making sense?
Oops, that code snippet should have been:

```
typedef void (fnReturningVoid)(void);
typedef fnReturningVoid foo;
```

In other words, `foo` was just anohter synonym for `fnReturningVoid`.


http://reviews.llvm.org/D8149



_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to