[PATCH] D27918: [analyzer] OStreamChecker
Endre Fülöp via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Mon Jul 24 09:55:55 PDT 2017
gamesh411 added a comment.
Hello,
After experimentation the following AST difference between the mock and the standard library implementation still stands (which necessitates the special handling of the complex manipulators). Example:
// The different behaviour of the AST is illustrated on the test4 function of the test suite:
//
// void test4(float f) {
// std::cout << std::setprecision(2)
// << f; // The stream state is chaged, but not restored.
// } // expected-warning{{Possibly forgotten ostream format modification in scope}}
//
// The AST of the function with the standard library include
// (note the wrapping CXXConstructorExpr):
// |-FunctionDecl 0x5642e3f80b70 <line:33:1, line:36:1> line:33:6 test4 'void (float)'
// | |-ParmVarDecl 0x5642e3f80ab0 <col:12, col:18> col:18 used f 'float'
// | `-CompoundStmt 0x5642e3f818b0 <col:21, line:36:1>
// | `-ExprWithCleanups 0x5642e3f81898 <line:34:3, line:35:16> 'std::basic_ostream<char, struct std::char_traits<char> >::__ostream_type':'class std::basic_ostream<char>' lvalue
// | `-CXXOperatorCallExpr 0x5642e3f81850 <line:34:3, line:35:16> 'std::basic_ostream<char, struct std::char_traits<char> >::__ostream_type':'class std::basic_ostream<char>' lvalue
// | |-ImplicitCastExpr 0x5642e3f81838 <col:13> 'std::basic_ostream<char, struct std::char_traits<char> >::__ostream_type &(*)(float)' <FunctionToPointerDecay>
// | | `-DeclRefExpr 0x5642e3f817b8 <col:13> 'std::basic_ostream<char, struct std::char_traits<char> >::__ostream_type &(float)' lvalue CXXMethod 0x5642e3edf120 'operator<<' 'std::basic_ostream<char, struct std::char_traits<char> >::__ostream_type &(float)'
// | |-CXXOperatorCallExpr 0x5642e3f81270 <line:34:3, col:35> 'basic_ostream<char, struct std::char_traits<char> >':'class std::basic_ostream<char>' lvalue
// | | |-ImplicitCastExpr 0x5642e3f81258 <col:13> 'basic_ostream<char, struct std::char_traits<char> > &(*)(basic_ostream<char, struct std::char_traits<char> > &, struct std::_Setprecision)' <FunctionToPointerDecay>
// | | | `-DeclRefExpr 0x5642e3f811d0 <col:13> 'basic_ostream<char, struct std::char_traits<char> > &(basic_ostream<char, struct std::char_traits<char> > &, struct std::_Setprecision)' lvalue Function 0x5642e3f6a6e0 'operator<<' 'basic_ostream<char, struct std::char_traits<char> > &(basic_ostream<char, struct std::char_traits<char> > &, struct std::_Setprecision)'
// | | |-DeclRefExpr 0x5642e3f80c30 <col:3, col:8> 'std::ostream':'class std::basic_ostream<char>' lvalue Var 0x5642e3f56578 'cout' 'std::ostream':'class std::basic_ostream<char>'
// | | `-CXXConstructExpr 0x5642e3f81198 <col:16, col:35> 'struct std::_Setprecision' 'void (const struct std::_Setprecision &) throw()' elidable
// | | `-MaterializeTemporaryExpr 0x5642e3f81088 <col:16, col:35> 'const struct std::_Setprecision' lvalue
// | | `-ImplicitCastExpr 0x5642e3f81070 <col:16, col:35> 'const struct std::_Setprecision' <NoOp>
// | | `-CallExpr 0x5642e3f80d20 <col:16, col:35> 'struct std::_Setprecision'
// | | |-ImplicitCastExpr 0x5642e3f80d08 <col:16, col:21> 'struct std::_Setprecision (*)(int)' <FunctionToPointerDecay>
// | | | `-DeclRefExpr 0x5642e3f80c88 <col:16, col:21> 'struct std::_Setprecision (int)' lvalue Function 0x5642e3f63f70 'setprecision' 'struct std::_Setprecision (int)'
// | | `-IntegerLiteral 0x5642e3f80cc0 <col:34> 'int' 2
// | `-ImplicitCastExpr 0x5642e3f817a0 <line:35:16> 'float' <LValueToRValue>
// | `-DeclRefExpr 0x5642e3f812b8 <col:16> 'float' lvalue ParmVar 0x5642e3f80ab0 'f' 'float'
// | | `-IntegerLiteral 0x5642e3f80cc0 <col:34> 'int' 2
// The AST of the function with the mock library include
// |-FunctionDecl 0x55c053dfaa70 <line:32:1, line:35:1> line:32:6 test4 'void (float)'
// | |-ParmVarDecl 0x55c053dfa9b0 <col:12, col:18> col:18 used f 'float'
// | `-CompoundStmt 0x55c053dfb7c0 <col:21, line:35:1>
// | `-ExprWithCleanups 0x55c053dfb7a8 <line:33:3, line:34:16> 'class std::basic_ostream<char>' lvalue
// | `-CXXOperatorCallExpr 0x55c053dfb760 <line:33:3, line:34:16> 'class std::basic_ostream<char>' lvalue
// | |-ImplicitCastExpr 0x55c053dfb748 <col:13> 'class std::basic_ostream<char> &(*)(float)' <FunctionToPointerDecay>
// | | `-DeclRefExpr 0x55c053dfb6f8 <col:13> 'class std::basic_ostream<char> &(float)' lvalue CXXMethod 0x55c053df8120 'operator<<' 'class std::basic_ostream<char> &(float)'
// | |-CXXOperatorCallExpr 0x55c053dfb670 <line:33:3, col:35> 'basic_ostream<char>':'class std::basic_ostream<char>' lvalue
// | | |-ImplicitCastExpr 0x55c053dfb658 <col:13> 'basic_ostream<char> &(*)(basic_ostream<char> &, const class std::setprecision_manip &)' <FunctionToPointerDecay>
// | | | `-DeclRefExpr 0x55c053dfb5d0 <col:13> 'basic_ostream<char> &(basic_ostream<char> &, const class std::setprecision_manip &)' lvalue Function 0x55c053dfb490 'operator<<' 'basic_ostream<char> &(basic_ostream<char> &, const class std::setprecision_manip &)'
// | | |-DeclRefExpr 0x55c053dfab30 <col:3, col:8> 'std::ostream':'class std::basic_ostream<char>' lvalue Var 0x55c053df6210 'cout' 'std::ostream':'class std::basic_ostream<char>'
// | | `-MaterializeTemporaryExpr 0x55c053dfb5b8 <col:16, col:35> 'const class std::setprecision_manip' lvalue
// | | `-ImplicitCastExpr 0x55c053dfb5a0 <col:16, col:35> 'const class std::setprecision_manip' <NoOp>
// | | `-CallExpr 0x55c053dfac20 <col:16, col:35> 'class std::setprecision_manip'
// | | |-ImplicitCastExpr 0x55c053dfac08 <col:16, col:21> 'class std::setprecision_manip (*)(int)' <FunctionToPointerDecay>
// | | | `-DeclRefExpr 0x55c053dfab88 <col:16, col:21> 'class std::setprecision_manip (int)' lvalue Function 0x55c053df2f20 'setprecision' 'class std::setprecision_manip (int)'
// | | `-IntegerLiteral 0x55c053dfabc0 <col:34> 'int' 2
// | `-ImplicitCastExpr 0x55c053dfb6e0 <line:34:16> 'float' <LValueToRValue>
// | `-DeclRefExpr 0x55c053dfb6b8 <col:16> 'float' lvalue ParmVar 0x55c053dfa9b0 'f' 'float'
//
// I haven't been able to modify the mock to exhibit the same behaviour.
I think its fine to leave it like this, because if this behaviour changes in case of the real life implementation of the standard library, the fallback branch still catches the case.
As for the evalCall concerns, I have implemented the invalidation of the global stream object. With API of the ProgramState::invalidateRegions I could solve the invalidation of the stream object (which in turn takes care of the corresponding global memory region as well if it is indeed globally stored, like std::cout).
I would like proceed with adding this checker to codebase if no further concerns arise.
https://reviews.llvm.org/D27918
More information about the cfe-commits
mailing list