Thanks Artem, Aleksei for those precious information.
Yes, I observed exactly the same thing about MaterializeTemporaryExpr and I actually spent quite sometime trace into the clang’s codebase and reached to the exactly same place in the link: createTemporaryRegionIfNeeded. My workaround was inspired by one of the example checkers, that uses a checkPostStmt on MaterializeTemporaryExpr. Thanks for pointing out this.
Aleksei, thanks for pointing out the getQualifiedNameAsString, I didn’t know I could use that . I personally prefers it because getParent()->getName() doesn’t contain the namespace, but only the class name. So to make it safe, I need to go all the way up to traverse all parent decls, and getQualifiedNameAsString already does the thing for me.
Thanks for taking your time to answer my question. I appreciate it.
Now I observed some other weird thing, and I wonder if anyone has seen this before and knows any solution.
As a reminder, the checker I am writing is for a particular class T in my company’s code base and the checker is to ensure T.ok() == true before calling T.value().
The above is actually a over-simplification to my task. The class T actually has a member, Let’s say s_ (in type S) to keep track of the status, so T.ok() actually returns s_.ok(). And type S is used directly by a few other classes and macros which are used to creates T. So to make the check fully working, I also need to model the behaviors of S and a few other classes.
Fortunately, T are template class and therefore all method implementations are visible to current TU. I was thinking, it is a whole lot easier if I can just model the behavior of S, and rely on inline evaluation in the static analyzer. In most cases, it works, except I found the following corner case (suppose T has a conversion constructor from X: T(X&&) and default move constructor T(T&&)):
X f();
T t = f();
This is essentially constructs a temporary T t2{f()} and then doing a move T t{std::move(t2)}. It looks fine if everything is inlined, however, the inline doesn’t work because t2 is a temporary. I dived into the code base and what happened is
-
At the end of ExprEngine::getRegionForConstructedObject, it is marked as improperly modeled target region:
CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true; -
In ExprEngine::mayInlineCallKind, it returns false if the flag is set:
// If we did not find the correct this-region, it would be pointless
// to inline the constructor. Instead we will simply invalidate
// the fake temporary target.
if ([CallOpts](https://cs.corp.google.com/piper///depot/google3/third_party/llvm/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp?l=618&ct=xref_jump_to_def&gsn=CallOpts&rcl=186553626).[IsCtorOrDtorWithImproperlyModeledTargetRegion](https://cs.corp.google.com/piper///depot/google3/third_party/llvm/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h?l=62&ct=xref_jump_to_def&gsn=IsCtorOrDtorWithImproperlyModeledTargetRegion&rcl=186553626))
return [CIP_DisallowedOnce](https://cs.corp.google.com/piper///depot/google3/third_party/llvm/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h?l=623&ct=xref_jump_to_def&gsn=CIP_DisallowedOnce&rcl=186553626);
I am not an expert in C++ compiler. I just wonder why it can’t allocates a temporary region for temporary variables? Having this special case means I need to model all T’s constructors, which is really annoying. Does anyone knows some workarounds? Thanks.