This patch adds the ability to context-sensitively analyze constructor bodies, by changing pushCall to allow both CallExpr and CXXConstructExpr, and extracting the main context-sensitive logic out of VisitCallExpr into a new transferInlineCall method which is now also called at the end of VisitCXXConstructExpr.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
Looks good overall. I want to think a bit more about potential additional tests...
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp | ||
---|---|---|
230 | i think that llvm_unreachable is preferable for this purpose. | |
256 | same. | |
clang/lib/Analysis/FlowSensitive/Transfer.cpp | ||
678–684 | Why can't this stay in VisitCallExpr? |
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h | ||
---|---|---|
138 | How about we define overloads that take these types instead of taking an Expr here? This should remove the need for type-checking and guarding against bad input in the implementation. transferInlineCall can be a template if necessary. |
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp | ||
---|---|---|
4371 | What about a default constructor, including when there are field initializers like: class MyClass { public: MyClass() = default; bool MyField = true; }; Should we expect to handle that correctly? If so, can you add some tests? |
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h | ||
---|---|---|
138 | Hmm I guess we could; is there much of a benefit to doing this templated? | |
clang/lib/Analysis/FlowSensitive/Transfer.cpp | ||
678–684 | I had it there in an earlier version of this patch; it was causing tests to fail (the SelfReferential* ones, if I remember correctly). | |
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp | ||
4371 | Good idea! I'll add a test for this. |
I feel like this is a repeated pattern. The CSA solved a very similar issue by introducing the CallEvent class hierarchy. I also remember seeing many disparate code snippets littered throughout the clang codebase that tries to deal with the problem of not having facilities to treat call-like nodes uniformly. At some point, I believe there were even some AST changes or supporting structures proposed to ameliorate this problem, but I can't find those at the moment. While I think it might be OK to introduce yet another workaround here, this is a cleanup that is long overdue, and I hope someone will have the time to actually improve the situation. Sorry for the rant, I will actually look at the code but had to vent this.
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp | ||
---|---|---|
247–252 | I think the more idiomatic solution in Clang is to create an ArrayRef for the arguments from the ConstructExpr and the CallExpr. The args should be stored in a continuous memory area in both cases so you should be able to create the ArrayRef in constant time and you would no longer need to have these pesky if statements in your loop. |
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp | ||
---|---|---|
247–252 | Ah OK, thanks! How should I do that? I was previously using iterators but it looked like the types were different between CallExpr and CXXConstructExpr, so I switched away from iterators in this patch; is there an easy way to make the ArrayRef? |
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp | ||
---|---|---|
247–252 | Here is an example: https://github.com/llvm/llvm-project/blob/main/clang/lib/Sema/SemaInit.cpp#L7086 |
No worries at all for the rant, I appreciate the broader context. I was definitely surprised to learn that the two types don't share a common ancestor.
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp | ||
---|---|---|
207–243 | I think you can push all of this logic to the type-specialized pushCalls now and just have pushCallInternal take the FunctionDecl, ArrayRef, etc.. WDYT? |
Thanks!
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp | ||
---|---|---|
207–243 | +1, I like that. |
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp | ||
---|---|---|
207–243 | Great idea, thanks! Doing that now. |
Nice! We went from branches in the loop to branches before the loop first. And now the branches are at compile time during overload resolution. I love it.
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp | ||
---|---|---|
207–208 | I'd go farther: just duplicate this line in both pushCalls and then the two if that follow can be moved out as well. at that point, I think Call is no longer needed. |
Remove Call parameter from pushCallInternal method
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp | ||
---|---|---|
207–208 | Smart! Done. |
Sorry but I had to revert this because of the conflicts with another revert: https://reviews.llvm.org/D131065
How about we define overloads that take these types instead of taking an Expr here? This should remove the need for type-checking and guarding against bad input in the implementation. transferInlineCall can be a template if necessary.