2014-01-04 20:57:02 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2018-01-14 15:37:52 +01:00
* Copyright ( C ) 2007 - 2018 Cppcheck team .
2014-01-04 20:57:02 +01:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2017-05-27 04:33:47 +02:00
# include "library.h"
# include "platform.h"
# include "settings.h"
2014-01-04 20:57:02 +01:00
# include "testsuite.h"
# include "token.h"
2017-05-27 04:33:47 +02:00
# include "tokenize.h"
# include "valueflow.h"
2014-01-04 20:57:02 +01:00
2017-05-18 21:52:31 +02:00
# include <simplecpp.h>
2016-11-13 22:59:56 +01:00
# include <cmath>
2017-05-27 04:33:47 +02:00
# include <list>
# include <map>
# include <ostream>
# include <string>
# include <utility>
# include <vector>
2015-03-11 22:26:33 +01:00
2014-01-04 20:57:02 +01:00
class TestValueFlow : public TestFixture {
public :
2014-11-20 14:20:09 +01:00
TestValueFlow ( ) : TestFixture ( " TestValueFlow " ) {
2014-01-04 20:57:02 +01:00
}
private :
2015-10-07 18:33:57 +02:00
Settings settings ;
2014-01-04 20:57:02 +01:00
2014-11-20 14:20:09 +01:00
void run ( ) {
2018-02-11 22:14:44 +01:00
// strcpy, abort cfg
2015-10-07 18:33:57 +02:00
const char cfg [ ] = " <?xml version= \" 1.0 \" ?> \n "
" <def> \n "
" <function name= \" strcpy \" > <arg nr= \" 1 \" ><not-null/></arg> </function> \n "
2018-02-11 22:14:44 +01:00
" <function name= \" abort \" > <noreturn>true</noreturn> </function> \n " // abort is a noreturn function
2015-10-07 18:33:57 +02:00
" </def> " ;
settings . library . loadxmldata ( cfg , sizeof ( cfg ) ) ;
2014-01-18 19:30:44 +01:00
TEST_CASE ( valueFlowNumber ) ;
2014-08-03 20:11:22 +02:00
TEST_CASE ( valueFlowString ) ;
TEST_CASE ( valueFlowPointerAlias ) ;
2015-02-24 15:57:39 +01:00
TEST_CASE ( valueFlowArrayElement ) ;
2016-11-20 15:14:49 +01:00
TEST_CASE ( valueFlowMove ) ;
2014-01-18 19:30:44 +01:00
2014-04-14 06:45:39 +02:00
TEST_CASE ( valueFlowBitAnd ) ;
2014-01-18 19:30:44 +01:00
TEST_CASE ( valueFlowCalculations ) ;
2018-03-23 08:28:12 +01:00
TEST_CASE ( valueFlowSizeof ) ;
2014-01-18 19:30:44 +01:00
2017-05-19 14:34:59 +02:00
TEST_CASE ( valueFlowErrorPath ) ;
2014-01-06 10:09:49 +01:00
TEST_CASE ( valueFlowBeforeCondition ) ;
2014-01-18 08:45:24 +01:00
TEST_CASE ( valueFlowBeforeConditionAndAndOrOrGuard ) ;
TEST_CASE ( valueFlowBeforeConditionAssignIncDec ) ;
TEST_CASE ( valueFlowBeforeConditionFunctionCall ) ;
TEST_CASE ( valueFlowBeforeConditionGlobalVariables ) ;
TEST_CASE ( valueFlowBeforeConditionGoto ) ;
TEST_CASE ( valueFlowBeforeConditionIfElse ) ;
TEST_CASE ( valueFlowBeforeConditionLoop ) ;
TEST_CASE ( valueFlowBeforeConditionMacro ) ;
TEST_CASE ( valueFlowBeforeConditionSizeof ) ;
TEST_CASE ( valueFlowBeforeConditionSwitch ) ;
TEST_CASE ( valueFlowBeforeConditionTernaryOp ) ;
2014-01-21 21:13:49 +01:00
TEST_CASE ( valueFlowAfterAssign ) ;
2014-06-15 16:47:01 +02:00
TEST_CASE ( valueFlowAfterCondition ) ;
2017-08-23 11:13:47 +02:00
TEST_CASE ( valueFlowForwardCompoundAssign ) ;
2017-08-27 19:50:44 +02:00
TEST_CASE ( valueFlowForwardCorrelatedVariables ) ;
2017-09-20 12:53:25 +02:00
TEST_CASE ( valueFlowForwardFunction ) ;
2018-03-16 19:13:48 +01:00
TEST_CASE ( valueFlowForwardTernary ) ;
2017-08-28 22:39:12 +02:00
TEST_CASE ( valueFlowForwardLambda ) ;
2014-06-15 16:47:01 +02:00
2015-07-20 19:45:38 +02:00
TEST_CASE ( valueFlowSwitchVariable ) ;
2014-01-07 19:20:56 +01:00
TEST_CASE ( valueFlowForLoop ) ;
2014-01-06 16:37:52 +01:00
TEST_CASE ( valueFlowSubFunction ) ;
2014-06-29 18:04:38 +02:00
TEST_CASE ( valueFlowFunctionReturn ) ;
2015-02-03 22:12:05 +01:00
TEST_CASE ( valueFlowFunctionDefaultParameter ) ;
2015-07-16 17:33:16 +02:00
TEST_CASE ( knownValue ) ;
2016-10-26 10:36:02 +02:00
TEST_CASE ( valueFlowSizeofForwardDeclaredEnum ) ;
2017-01-09 15:53:08 +01:00
TEST_CASE ( valueFlowGlobalVar ) ;
2017-03-23 20:01:16 +01:00
2017-09-15 15:58:19 +02:00
TEST_CASE ( valueFlowGlobalStaticVar ) ;
2017-03-23 20:01:16 +01:00
TEST_CASE ( valueFlowInlineAssembly ) ;
2017-04-23 18:05:14 +02:00
TEST_CASE ( valueFlowUninit ) ;
2014-01-04 20:57:02 +01:00
}
2014-11-20 14:20:09 +01:00
bool testValueOfX ( const char code [ ] , unsigned int linenr , int value ) {
2014-01-04 20:57:02 +01:00
// Tokenize..
Tokenizer tokenizer ( & settings , this ) ;
std : : istringstream istr ( code ) ;
tokenizer . tokenize ( istr , " test.cpp " ) ;
for ( const Token * tok = tokenizer . tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( tok - > str ( ) = = " x " & & tok - > linenr ( ) = = linenr ) {
std : : list < ValueFlow : : Value > : : const_iterator it ;
2017-03-27 18:48:34 +02:00
for ( it = tok - > values ( ) . begin ( ) ; it ! = tok - > values ( ) . end ( ) ; + + it ) {
2016-11-13 22:59:56 +01:00
if ( it - > isIntValue ( ) & & it - > intvalue = = value )
2014-01-04 20:57:02 +01:00
return true ;
}
}
}
return false ;
}
2017-08-23 11:13:47 +02:00
bool testValueOfX ( const char code [ ] , unsigned int linenr , float value , float diff ) {
// Tokenize..
Tokenizer tokenizer ( & settings , this ) ;
std : : istringstream istr ( code ) ;
tokenizer . tokenize ( istr , " test.cpp " ) ;
for ( const Token * tok = tokenizer . tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( tok - > str ( ) = = " x " & & tok - > linenr ( ) = = linenr ) {
std : : list < ValueFlow : : Value > : : const_iterator it ;
for ( it = tok - > values ( ) . begin ( ) ; it ! = tok - > values ( ) . end ( ) ; + + it ) {
if ( it - > isFloatValue ( ) & & it - > floatValue > = value - diff & & it - > floatValue < = value + diff )
return true ;
}
}
}
return false ;
}
2017-05-19 14:34:59 +02:00
std : : string getErrorPathForX ( const char code [ ] , unsigned int linenr ) {
// Tokenize..
Tokenizer tokenizer ( & settings , this ) ;
std : : istringstream istr ( code ) ;
tokenizer . tokenize ( istr , " test.cpp " ) ;
for ( const Token * tok = tokenizer . tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( tok - > str ( ) ! = " x " | | tok - > linenr ( ) ! = linenr )
continue ;
std : : ostringstream ostr ;
std : : list < ValueFlow : : Value > : : const_iterator it ;
for ( it = tok - > values ( ) . begin ( ) ; it ! = tok - > values ( ) . end ( ) ; + + it ) {
for ( ValueFlow : : Value : : ErrorPath : : const_iterator ep = it - > errorPath . begin ( ) ; ep ! = it - > errorPath . end ( ) ; + + ep ) {
const Token * eptok = ep - > first ;
const std : : string & msg = ep - > second ;
ostr < < eptok - > linenr ( ) < < ' , ' < < msg < < ' \n ' ;
}
}
return ostr . str ( ) ;
}
return " " ;
}
2014-01-06 07:44:58 +01:00
2014-11-20 14:20:09 +01:00
bool testValueOfX ( const char code [ ] , unsigned int linenr , const char value [ ] ) {
2014-08-03 20:11:22 +02:00
// Tokenize..
Tokenizer tokenizer ( & settings , this ) ;
std : : istringstream istr ( code ) ;
tokenizer . tokenize ( istr , " test.cpp " ) ;
for ( const Token * tok = tokenizer . tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( tok - > str ( ) = = " x " & & tok - > linenr ( ) = = linenr ) {
std : : list < ValueFlow : : Value > : : const_iterator it ;
2017-03-27 18:48:34 +02:00
for ( it = tok - > values ( ) . begin ( ) ; it ! = tok - > values ( ) . end ( ) ; + + it ) {
2016-11-13 22:59:56 +01:00
if ( it - > isTokValue ( ) & & Token : : simpleMatch ( it - > tokvalue , value ) )
2014-08-03 20:11:22 +02:00
return true ;
}
}
}
return false ;
}
2016-11-20 15:14:49 +01:00
bool testValueOfX ( const char code [ ] , unsigned int linenr , ValueFlow : : Value : : MoveKind moveKind ) {
// Tokenize..
Tokenizer tokenizer ( & settings , this ) ;
std : : istringstream istr ( code ) ;
tokenizer . tokenize ( istr , " test.cpp " ) ;
for ( const Token * tok = tokenizer . tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( tok - > str ( ) = = " x " & & tok - > linenr ( ) = = linenr ) {
std : : list < ValueFlow : : Value > : : const_iterator it ;
2017-03-27 18:48:34 +02:00
for ( it = tok - > values ( ) . begin ( ) ; it ! = tok - > values ( ) . end ( ) ; + + it ) {
2016-11-20 15:14:49 +01:00
if ( it - > isMovedValue ( ) & & it - > moveKind = = moveKind )
return true ;
}
}
}
return false ;
}
2015-07-29 19:54:57 +02:00
bool testConditionalValueOfX ( const char code [ ] , unsigned int linenr , int value ) {
// Tokenize..
Tokenizer tokenizer ( & settings , this ) ;
std : : istringstream istr ( code ) ;
tokenizer . tokenize ( istr , " test.cpp " ) ;
for ( const Token * tok = tokenizer . tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( tok - > str ( ) = = " x " & & tok - > linenr ( ) = = linenr ) {
std : : list < ValueFlow : : Value > : : const_iterator it ;
2017-03-27 18:48:34 +02:00
for ( it = tok - > values ( ) . begin ( ) ; it ! = tok - > values ( ) . end ( ) ; + + it ) {
2016-11-13 22:59:56 +01:00
if ( it - > isIntValue ( ) & & it - > intvalue = = value & & it - > condition )
2015-07-29 19:54:57 +02:00
return true ;
}
}
}
return false ;
}
2014-11-20 14:20:09 +01:00
void bailout ( const char code [ ] ) {
2014-01-06 07:44:58 +01:00
settings . debugwarnings = true ;
2017-05-18 21:52:31 +02:00
errout . str ( " " ) ;
std : : vector < std : : string > files ;
files . push_back ( " test.cpp " ) ;
std : : istringstream istr ( code ) ;
const simplecpp : : TokenList tokens1 ( istr , files , files [ 0 ] ) ;
simplecpp : : TokenList tokens2 ( files ) ;
std : : map < std : : string , simplecpp : : TokenList * > filedata ;
simplecpp : : preprocess ( tokens2 , tokens1 , files , filedata , simplecpp : : DUI ( ) ) ;
2014-01-06 07:44:58 +01:00
// Tokenize..
Tokenizer tokenizer ( & settings , this ) ;
2017-05-18 21:52:31 +02:00
tokenizer . createTokens ( & tokens2 ) ;
tokenizer . simplifyTokens1 ( " " ) ;
2015-10-07 18:33:57 +02:00
settings . debugwarnings = false ;
2014-01-06 07:44:58 +01:00
}
2014-11-20 14:20:09 +01:00
std : : list < ValueFlow : : Value > tokenValues ( const char code [ ] , const char tokstr [ ] ) {
2014-01-18 19:30:44 +01:00
Tokenizer tokenizer ( & settings , this ) ;
std : : istringstream istr ( code ) ;
errout . str ( " " ) ;
tokenizer . tokenize ( istr , " test.cpp " ) ;
const Token * tok = Token : : findmatch ( tokenizer . tokens ( ) , tokstr ) ;
2017-03-27 18:48:34 +02:00
return tok ? tok - > values ( ) : std : : list < ValueFlow : : Value > ( ) ;
2014-01-20 21:45:30 +01:00
}
2014-11-20 14:20:09 +01:00
ValueFlow : : Value valueOfTok ( const char code [ ] , const char tokstr [ ] ) {
2014-01-20 21:45:30 +01:00
std : : list < ValueFlow : : Value > values = tokenValues ( code , tokstr ) ;
2016-11-13 22:59:56 +01:00
return values . size ( ) = = 1U & & ! values . front ( ) . isTokValue ( ) ? values . front ( ) : ValueFlow : : Value ( ) ;
2014-01-18 19:30:44 +01:00
}
2014-11-20 14:20:09 +01:00
void valueFlowNumber ( ) {
2016-05-07 20:18:07 +02:00
ASSERT_EQUALS ( 123 , valueOfTok ( " x=123; " , " 123 " ) . intvalue ) ;
2016-11-13 22:59:56 +01:00
ASSERT ( std : : fabs ( valueOfTok ( " x=0.5; " , " 0.5 " ) . floatValue - 0.5f ) < 0.1f ) ;
2016-05-07 20:18:07 +02:00
ASSERT_EQUALS ( 10 , valueOfTok ( " enum {A=10,B=15}; x=A+0; " , " + " ) . intvalue ) ;
2015-11-12 16:38:58 +01:00
ASSERT_EQUALS ( 0 , valueOfTok ( " x=false; " , " false " ) . intvalue ) ;
2016-05-07 20:18:07 +02:00
ASSERT_EQUALS ( 1 , valueOfTok ( " x=true; " , " true " ) . intvalue ) ;
ASSERT_EQUALS ( 0 , valueOfTok ( " x(NULL); " , " NULL " ) . intvalue ) ;
ASSERT_EQUALS ( ( int ) ( ' a ' ) , valueOfTok ( " x='a'; " , " 'a' " ) . intvalue ) ;
2015-11-12 16:38:58 +01:00
ASSERT_EQUALS ( ( int ) ( ' \n ' ) , valueOfTok ( " x=' \\ n'; " , " ' \\ n' " ) . intvalue ) ;
2017-07-22 16:23:33 +02:00
ASSERT_EQUALS ( 0xFFFFFFFF00000000 , valueOfTok ( " x=0xFFFFFFFF00000000; " , " 18446744069414584320U " ) . intvalue ) ; // #7701
2014-01-18 19:30:44 +01:00
}
2014-11-20 14:20:09 +01:00
void valueFlowString ( ) {
2014-08-03 20:11:22 +02:00
const char * code ;
2014-08-04 12:13:15 +02:00
// valueFlowAfterAssign
2014-08-03 20:11:22 +02:00
code = " const char * f() { \n "
" static const char *x; \n "
" if (a) x = \" 123 \" ; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4 , " \" 123 \" " ) ) ;
2014-08-04 12:13:15 +02:00
// valueFlowSubFunction
code = " void dostuff(const char *x) { \n "
" f(x); \n "
" } \n "
" \n "
" void test() { dostuff( \" abc \" ); } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2 , " \" abc \" " ) ) ;
2014-08-03 20:11:22 +02:00
}
2014-11-20 14:20:09 +01:00
void valueFlowPointerAlias ( ) {
2014-08-03 20:11:22 +02:00
const char * code ;
code = " const char * f() { \n "
" static const char *x; \n "
" static char ret[10]; \n "
" if (a) x = &ret[0]; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 5 , " & ret [ 0 ] " ) ) ;
2014-08-05 06:24:23 +02:00
// dead pointer
code = " void f() { \n "
" int *x; \n "
" if (cond) { int i; x = &i; } \n "
" *x = 0; \n " // <- x can point at i
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4 , " & i " ) ) ;
2015-11-15 23:38:23 +01:00
code = " void f() { \n "
" struct X *x; \n "
" x = &x[1]; \n "
" } " ;
ASSERT_EQUALS ( true , tokenValues ( code , " & " ) . empty ( ) ) ;
ASSERT_EQUALS ( true , tokenValues ( code , " x [ " ) . empty ( ) ) ;
2014-08-03 20:11:22 +02:00
}
2015-02-24 15:57:39 +01:00
void valueFlowArrayElement ( ) {
const char * code ;
code = " void f() { \n "
2015-07-27 16:25:14 +02:00
" const int x[] = {43,23,12}; \n "
2015-02-24 15:57:39 +01:00
" return x; \n "
" } " ;
2015-07-27 16:25:14 +02:00
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , " { 43 , 23 , 12 } " ) ) ;
2015-02-24 15:57:39 +01:00
code = " void f() { \n "
2015-07-27 16:25:14 +02:00
" const char x[] = \" abcd \" ; \n "
2015-02-24 15:57:39 +01:00
" return x; \n "
" } " ;
2015-07-27 16:25:14 +02:00
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , " \" abcd \" " ) ) ;
code = " void f() { \n "
" char x[32] = \" abcd \" ; \n "
" return x; \n "
" } " ;
TODO_ASSERT_EQUALS ( true , false , testValueOfX ( code , 3U , " \" abcd \" " ) ) ;
2015-11-07 15:07:26 +01:00
code = " void f() { \n "
" int a[10]; \n "
" int *x = a; \n " // <- a value is a
" *x = 0; \n " // .. => x value is a
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4 , " a " ) ) ;
2015-11-12 16:14:27 +01:00
code = " char f() { \n "
" const char *x = \" abcd \" ; \n "
" return x[0]; \n "
" } " ;
ASSERT_EQUALS ( ( int ) ( ' a ' ) , valueOfTok ( code , " [ " ) . intvalue ) ;
code = " char f() { \n "
" const char *x = \" \" ; \n "
" return x[0]; \n "
" } " ;
ASSERT_EQUALS ( 0 , valueOfTok ( code , " [ " ) . intvalue ) ;
2015-02-24 15:57:39 +01:00
}
2016-11-20 15:14:49 +01:00
void valueFlowMove ( ) {
const char * code ;
code = " void f() { \n "
" X x; \n "
" g(std::move(x)); \n "
" y=x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , ValueFlow : : Value : : MovedVariable ) ) ;
code = " void f() { \n "
" X x; \n "
" g(std::forward<X>(x)); \n "
" y=x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , ValueFlow : : Value : : ForwardedVariable ) ) ;
code = " void f() { \n "
" X x; \n "
" g(std::move(x).getA()); \n " // Only parts of x might be moved out
" y=x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , ValueFlow : : Value : : MovedVariable ) ) ;
code = " void f() { \n "
" X x; \n "
" g(std::forward<X>(x).getA()); \n " // Only parts of x might be moved out
" y=x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , ValueFlow : : Value : : ForwardedVariable ) ) ;
code = " void f() { \n "
" X x; \n "
" g(std::move(x)); \n "
" x.clear(); \n "
" y=x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , ValueFlow : : Value : : MovedVariable ) ) ;
code = " void f() { \n "
" X x; \n "
" g(std::move(x)); \n "
" y=x->y; \n "
" z=x->z; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 5U , ValueFlow : : Value : : MovedVariable ) ) ;
code = " void f(int i) { \n "
" X x; \n "
" z = g(std::move(x)); \n "
" y = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , ValueFlow : : Value : : MovedVariable ) ) ;
2016-12-12 21:46:05 +01:00
code = " void f(int i) { \n "
" X x; \n "
" y = g(std::move(x), \n "
" x.size()); \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , ValueFlow : : Value : : MovedVariable ) ) ;
2016-11-20 15:14:49 +01:00
code = " void f(int i) { \n "
" X x; \n "
" x = g(std::move(x)); \n "
" y = x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , ValueFlow : : Value : : MovedVariable ) ) ;
code = " A f(int i) { \n "
" X x; \n "
" if (i) "
" return g(std::move(x)); \n "
" return h(std::move(x)); \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , ValueFlow : : Value : : MovedVariable ) ) ;
}
2014-11-20 14:20:09 +01:00
void valueFlowCalculations ( ) {
2014-01-18 19:30:44 +01:00
const char * code ;
2015-07-18 15:03:57 +02:00
2015-07-26 12:00:42 +02:00
// Different operators
ASSERT_EQUALS ( 5 , valueOfTok ( " 3 + (a ? b : 2); " , " + " ) . intvalue ) ;
ASSERT_EQUALS ( 1 , valueOfTok ( " 3 - (a ? b : 2); " , " - " ) . intvalue ) ;
ASSERT_EQUALS ( 6 , valueOfTok ( " 3 * (a ? b : 2); " , " * " ) . intvalue ) ;
ASSERT_EQUALS ( 6 , valueOfTok ( " 13 / (a ? b : 2); " , " / " ) . intvalue ) ;
ASSERT_EQUALS ( 1 , valueOfTok ( " 13 % (a ? b : 2); " , " % " ) . intvalue ) ;
ASSERT_EQUALS ( 0 , valueOfTok ( " 3 == (a ? b : 2); " , " == " ) . intvalue ) ;
ASSERT_EQUALS ( 1 , valueOfTok ( " 3 != (a ? b : 2); " , " != " ) . intvalue ) ;
ASSERT_EQUALS ( 1 , valueOfTok ( " 3 > (a ? b : 2); " , " > " ) . intvalue ) ;
ASSERT_EQUALS ( 1 , valueOfTok ( " 3 >= (a ? b : 2); " , " >= " ) . intvalue ) ;
ASSERT_EQUALS ( 0 , valueOfTok ( " 3 < (a ? b : 2); " , " < " ) . intvalue ) ;
ASSERT_EQUALS ( 0 , valueOfTok ( " 3 <= (a ? b : 2); " , " <= " ) . intvalue ) ;
2016-12-20 21:37:25 +01:00
ASSERT_EQUALS ( 1 , valueOfTok ( " (UNKNOWN_TYPE)1; " , " ( " ) . intvalue ) ;
ASSERT ( tokenValues ( " (UNKNOWN_TYPE)1000; " , " ( " ) . empty ( ) ) ; // don't know if there is truncation, sign extension
2016-12-20 19:32:21 +01:00
ASSERT_EQUALS ( 255 , valueOfTok ( " (unsigned char)~0; " , " ( " ) . intvalue ) ;
ASSERT_EQUALS ( 0 , valueOfTok ( " (int)0; " , " ( " ) . intvalue ) ;
2016-12-20 23:09:50 +01:00
ASSERT_EQUALS ( 3 , valueOfTok ( " (int)(1+2); " , " ( " ) . intvalue ) ;
2016-12-20 19:32:21 +01:00
ASSERT_EQUALS ( 0 , valueOfTok ( " (UNKNOWN_TYPE*)0; " , " ( " ) . intvalue ) ;
ASSERT_EQUALS ( 100 , valueOfTok ( " (int)100.0; " , " ( " ) . intvalue ) ;
2016-12-10 22:09:01 +01:00
2016-11-06 17:42:01 +01:00
// Don't calculate if there is UB
2016-11-20 17:59:50 +01:00
ASSERT ( tokenValues ( " ;-1<<10; " , " << " ) . empty ( ) ) ;
ASSERT ( tokenValues ( " ;10<<-1; " , " << " ) . empty ( ) ) ;
ASSERT ( tokenValues ( " ;10<<64; " , " << " ) . empty ( ) ) ;
ASSERT ( tokenValues ( " ;-1>>10; " , " >> " ) . empty ( ) ) ;
ASSERT ( tokenValues ( " ;10>>-1; " , " >> " ) . empty ( ) ) ;
ASSERT ( tokenValues ( " ;10>>64; " , " >> " ) . empty ( ) ) ;
2016-11-06 17:42:01 +01:00
2015-07-26 12:00:42 +02:00
// calculation using 1,2 variables/values
2014-01-18 19:30:44 +01:00
code = " void f(int x) { \n "
" a = x+456; \n "
" if (x==123) {} "
" } " ;
ASSERT_EQUALS ( 579 , valueOfTok ( code , " + " ) . intvalue ) ;
2014-01-20 21:45:30 +01:00
code = " void f(int x, int y) { \n "
" a = x+y; \n "
" if (x==123 || y==456) {} "
" } " ;
ASSERT_EQUALS ( 0 , valueOfTok ( code , " + " ) . intvalue ) ;
2014-01-18 19:30:44 +01:00
code = " void f(int x) { \n "
" a = x+x; \n "
" if (x==123) {} "
" } " ;
ASSERT_EQUALS ( 246 , valueOfTok ( code , " + " ) . intvalue ) ;
code = " void f(int x, int y) { \n "
2014-01-20 21:45:30 +01:00
" a = x*x; \n "
" if (x==2) {} \n "
" if (x==4) {} \n "
2014-01-18 19:30:44 +01:00
" } " ;
2014-01-20 21:45:30 +01:00
std : : list < ValueFlow : : Value > values = tokenValues ( code , " * " ) ;
ASSERT_EQUALS ( 2U , values . size ( ) ) ;
ASSERT_EQUALS ( 4 , values . front ( ) . intvalue ) ;
ASSERT_EQUALS ( 16 , values . back ( ) . intvalue ) ;
2014-06-13 16:34:57 +02:00
2016-12-04 22:39:59 +01:00
code = " void f(int x) { \n "
" if (x == 3) {} \n "
" a = x * (1 - x - 1); \n "
" } " ;
ASSERT_EQUALS ( - 9 , valueOfTok ( code , " * " ) . intvalue ) ;
2015-07-18 15:03:57 +02:00
// addition of different variables with known values
code = " int f(int x) { \n "
" int a = 1; \n "
" while (x!=3) { x+=a; } \n "
" return x/a; \n "
" } \n " ;
ASSERT_EQUALS ( 3 , valueOfTok ( code , " / " ) . intvalue ) ;
2015-07-02 20:11:27 +02:00
// ? :
code = " x = y ? 2 : 3; \n " ;
values = tokenValues ( code , " ? " ) ;
ASSERT_EQUALS ( 2U , values . size ( ) ) ;
ASSERT_EQUALS ( 2 , values . front ( ) . intvalue ) ;
ASSERT_EQUALS ( 3 , values . back ( ) . intvalue ) ;
2015-07-02 20:52:04 +02:00
code = " void f(int a) { x = a ? 2 : 3; } \n " ;
values = tokenValues ( code , " ? " ) ;
ASSERT_EQUALS ( 2U , values . size ( ) ) ;
ASSERT_EQUALS ( 2 , values . front ( ) . intvalue ) ;
ASSERT_EQUALS ( 3 , values . back ( ) . intvalue ) ;
2016-08-15 14:19:35 +02:00
code = " x = (2<5) ? 2 : 3; \n " ;
values = tokenValues ( code , " ? " ) ;
ASSERT_EQUALS ( 1U , values . size ( ) ) ;
ASSERT_EQUALS ( 2 , values . front ( ) . intvalue ) ;
2016-08-17 18:44:41 +02:00
code = " x = 123 ? : 456; \n " ;
values = tokenValues ( code , " ? " ) ;
ASSERT_EQUALS ( 1U , values . size ( ) ) ;
ASSERT_EQUALS ( 123 , values . empty ( ) ? 0 : values . front ( ) . intvalue ) ;
2016-11-05 09:29:22 +01:00
// ~
code = " x = ~0U; " ;
settings . platform ( cppcheck : : Platform : : Native ) ; // ensure platform is native
values = tokenValues ( code , " ~ " ) ;
ASSERT_EQUALS ( 1U , values . size ( ) ) ;
ASSERT_EQUALS ( ~ 0U , values . back ( ) . intvalue ) ;
2015-07-16 21:17:44 +02:00
// !
code = " void f(int x) { \n "
" a = !x; \n "
" if (x==0) {} \n "
" } " ;
values = tokenValues ( code , " ! " ) ;
ASSERT_EQUALS ( 1U , values . size ( ) ) ;
ASSERT_EQUALS ( 1 , values . back ( ) . intvalue ) ;
2016-08-14 22:19:06 +02:00
// unary minus
code = " void f(int x) { \n "
" a = -x; \n "
" if (x==10) {} \n "
" } " ;
values = tokenValues ( code , " - " ) ;
ASSERT_EQUALS ( 1U , values . size ( ) ) ;
ASSERT_EQUALS ( - 10 , values . back ( ) . intvalue ) ;
2014-06-13 16:34:57 +02:00
// function call => calculation
code = " void f(int x) { \n "
" a = x + 8; \n "
" } \n "
" void callf() { \n "
" f(7); \n "
" } " ;
ASSERT_EQUALS ( 15 , valueOfTok ( code , " + " ) . intvalue ) ;
2014-06-29 10:57:39 +02:00
code = " void f(int x, int y) { \n "
" a = x + y; \n "
" } \n "
" void callf() { \n "
" f(1,1); \n "
" f(10,10); \n "
" } " ;
values = tokenValues ( code , " + " ) ;
ASSERT_EQUALS ( true , values . empty ( ) ) ;
if ( ! values . empty ( ) ) {
/* todo.. */
ASSERT_EQUALS ( 2U , values . size ( ) ) ;
ASSERT_EQUALS ( 2 , values . front ( ) . intvalue ) ;
ASSERT_EQUALS ( 22 , values . back ( ) . intvalue ) ;
}
2015-08-02 18:12:03 +02:00
// Comparison of string
values = tokenValues ( " f( \" xyz \" == \" xyz \" ); " , " == " ) ; // implementation defined
ASSERT_EQUALS ( 0U , values . size ( ) ) ; // <- no value
values = tokenValues ( " f( \" xyz \" == 0); " , " == " ) ;
ASSERT_EQUALS ( 1U , values . size ( ) ) ;
ASSERT_EQUALS ( 0 , values . front ( ) . intvalue ) ;
values = tokenValues ( " f(0 == \" xyz \" ); " , " == " ) ;
ASSERT_EQUALS ( 1U , values . size ( ) ) ;
ASSERT_EQUALS ( 0 , values . front ( ) . intvalue ) ;
values = tokenValues ( " f( \" xyz \" != 0); " , " != " ) ;
ASSERT_EQUALS ( 1U , values . size ( ) ) ;
ASSERT_EQUALS ( 1 , values . front ( ) . intvalue ) ;
values = tokenValues ( " f(0 != \" xyz \" ); " , " != " ) ;
ASSERT_EQUALS ( 1U , values . size ( ) ) ;
ASSERT_EQUALS ( 1 , values . front ( ) . intvalue ) ;
2014-01-18 19:30:44 +01:00
}
2014-01-06 07:44:58 +01:00
2018-03-23 08:28:12 +01:00
void valueFlowSizeof ( ) {
const char * code ;
std : : list < ValueFlow : : Value > values ;
# define CHECK(A, B) \
code = " void f() { \n " \
" x = sizeof( " A " ); \n " \
" } " ; \
values = tokenValues ( code , " ( " A " ) " ) ; \
ASSERT_EQUALS ( 1U , values . size ( ) ) ; \
ASSERT_EQUALS ( B , values . back ( ) . intvalue ) ;
// standard types
CHECK ( " void * " , settings . sizeof_pointer ) ;
CHECK ( " char " , 1U ) ;
CHECK ( " short " , settings . sizeof_short ) ;
CHECK ( " int " , settings . sizeof_int ) ;
CHECK ( " long " , settings . sizeof_long ) ;
# undef CHECK
// array size
code = " void f() { \n "
" struct S *a[10]; "
" x = sizeof(a) / sizeof(a[0]); \n "
" } " ;
values = tokenValues ( code , " / " ) ;
ASSERT_EQUALS ( 1U , values . size ( ) ) ;
ASSERT_EQUALS ( 10 , values . back ( ) . intvalue ) ;
# define CHECK(A, B, C, D) \
code = " enum " A " E " B " { E0, E1 }; \n " \
" void f() { \n " \
" x = sizeof( " C " ); \n " \
" } " ; \
values = tokenValues ( code , " ( " C " ) " ) ; \
ASSERT_EQUALS ( 1U , values . size ( ) ) ; \
ASSERT_EQUALS ( D , values . back ( ) . intvalue ) ;
// enums
CHECK ( " " , " " , " E " , settings . sizeof_int ) ;
// typed enums
CHECK ( " " , " : char " , " E " , 1U ) ;
CHECK ( " " , " : signed char " , " E " , 1U ) ;
CHECK ( " " , " : unsigned char " , " E " , 1U ) ;
CHECK ( " " , " : short " , " E " , settings . sizeof_short ) ;
CHECK ( " " , " : signed short " , " E " , settings . sizeof_short ) ;
CHECK ( " " , " : unsigned short " , " E " , settings . sizeof_short ) ;
CHECK ( " " , " : int " , " E " , settings . sizeof_int ) ;
CHECK ( " " , " : signed int " , " E " , settings . sizeof_int ) ;
CHECK ( " " , " : unsigned int " , " E " , settings . sizeof_int ) ;
CHECK ( " " , " : long " , " E " , settings . sizeof_long ) ;
CHECK ( " " , " : signed long " , " E " , settings . sizeof_long ) ;
CHECK ( " " , " : unsigned long " , " E " , settings . sizeof_long ) ;
CHECK ( " " , " : long long " , " E " , settings . sizeof_long_long ) ;
CHECK ( " " , " : signed long long " , " E " , settings . sizeof_long_long ) ;
CHECK ( " " , " : unsigned long long " , " E " , settings . sizeof_long_long ) ;
CHECK ( " " , " : wchar_t " , " E " , settings . sizeof_wchar_t ) ;
CHECK ( " " , " : size_t " , " E " , settings . sizeof_size_t ) ;
// enumerators
CHECK ( " " , " " , " E0 " , settings . sizeof_int ) ;
// typed enumerators
CHECK ( " " , " : char " , " E0 " , 1U ) ;
CHECK ( " " , " : signed char " , " E0 " , 1U ) ;
CHECK ( " " , " : unsigned char " , " E0 " , 1U ) ;
CHECK ( " " , " : short " , " E0 " , settings . sizeof_short ) ;
CHECK ( " " , " : signed short " , " E0 " , settings . sizeof_short ) ;
CHECK ( " " , " : unsigned short " , " E0 " , settings . sizeof_short ) ;
CHECK ( " " , " : int " , " E0 " , settings . sizeof_int ) ;
CHECK ( " " , " : signed int " , " E0 " , settings . sizeof_int ) ;
CHECK ( " " , " : unsigned int " , " E0 " , settings . sizeof_int ) ;
CHECK ( " " , " : long " , " E0 " , settings . sizeof_long ) ;
CHECK ( " " , " : signed long " , " E0 " , settings . sizeof_long ) ;
CHECK ( " " , " : unsigned long " , " E0 " , settings . sizeof_long ) ;
CHECK ( " " , " : long long " , " E0 " , settings . sizeof_long_long ) ;
CHECK ( " " , " : signed long long " , " E0 " , settings . sizeof_long_long ) ;
CHECK ( " " , " : unsigned long long " , " E0 " , settings . sizeof_long_long ) ;
CHECK ( " " , " : wchar_t " , " E0 " , settings . sizeof_wchar_t ) ;
CHECK ( " " , " : size_t " , " E0 " , settings . sizeof_size_t ) ;
// class typed enumerators
CHECK ( " class " , " : char " , " E :: E0 " , 1U ) ;
CHECK ( " class " , " : signed char " , " E :: E0 " , 1U ) ;
CHECK ( " class " , " : unsigned char " , " E :: E0 " , 1U ) ;
CHECK ( " class " , " : short " , " E :: E0 " , settings . sizeof_short ) ;
CHECK ( " class " , " : signed short " , " E :: E0 " , settings . sizeof_short ) ;
CHECK ( " class " , " : unsigned short " , " E :: E0 " , settings . sizeof_short ) ;
CHECK ( " class " , " : int " , " E :: E0 " , settings . sizeof_int ) ;
CHECK ( " class " , " : signed int " , " E :: E0 " , settings . sizeof_int ) ;
CHECK ( " class " , " : unsigned int " , " E :: E0 " , settings . sizeof_int ) ;
CHECK ( " class " , " : long " , " E :: E0 " , settings . sizeof_long ) ;
CHECK ( " class " , " : signed long " , " E :: E0 " , settings . sizeof_long ) ;
CHECK ( " class " , " : unsigned long " , " E :: E0 " , settings . sizeof_long ) ;
CHECK ( " class " , " : long long " , " E :: E0 " , settings . sizeof_long_long ) ;
CHECK ( " class " , " : signed long long " , " E :: E0 " , settings . sizeof_long_long ) ;
CHECK ( " class " , " : unsigned long long " , " E :: E0 " , settings . sizeof_long_long ) ;
CHECK ( " class " , " : wchar_t " , " E :: E0 " , settings . sizeof_wchar_t ) ;
CHECK ( " class " , " : size_t " , " E :: E0 " , settings . sizeof_size_t ) ;
# undef CHECK
# define CHECK(A, B) \
code = " enum E " A " { E0, E1 }; \n " \
" void f() { \n " \
" E arrE[] = { E0, E1 }; \n " \
" x = sizeof(arrE); \n " \
" } " ; \
values = tokenValues ( code , " ( arrE ) " ) ; \
ASSERT_EQUALS ( 1U , values . size ( ) ) ; \
ASSERT_EQUALS ( B * 2U , values . back ( ) . intvalue ) ;
// enum array
CHECK ( " " , settings . sizeof_int ) ;
// typed enum array
CHECK ( " : char " , 1U ) ;
CHECK ( " : signed char " , 1U ) ;
CHECK ( " : unsigned char " , 1U ) ;
CHECK ( " : short " , settings . sizeof_short ) ;
CHECK ( " : signed short " , settings . sizeof_short ) ;
CHECK ( " : unsigned short " , settings . sizeof_short ) ;
CHECK ( " : int " , settings . sizeof_int ) ;
CHECK ( " : signed int " , settings . sizeof_int ) ;
CHECK ( " : unsigned int " , settings . sizeof_int ) ;
CHECK ( " : long " , settings . sizeof_long ) ;
CHECK ( " : signed long " , settings . sizeof_long ) ;
CHECK ( " : unsigned long " , settings . sizeof_long ) ;
CHECK ( " : long long " , settings . sizeof_long_long ) ;
CHECK ( " : signed long long " , settings . sizeof_long_long ) ;
CHECK ( " : unsigned long long " , settings . sizeof_long_long ) ;
CHECK ( " : wchar_t " , settings . sizeof_wchar_t ) ;
CHECK ( " : size_t " , settings . sizeof_size_t ) ;
# undef CHECK
# define CHECK(A, B) \
code = " enum class E " A " { E0, E1 }; \n " \
" void f() { \n " \
" E arrE[] = { E::E0, E::E1 }; \n " \
" x = sizeof(arrE); \n " \
" } " ; \
values = tokenValues ( code , " ( arrE ) " ) ; \
ASSERT_EQUALS ( 1U , values . size ( ) ) ; \
ASSERT_EQUALS ( B * 2U , values . back ( ) . intvalue ) ;
// enum array
CHECK ( " " , settings . sizeof_int ) ;
// typed enum array
CHECK ( " : char " , 1U ) ;
CHECK ( " : signed char " , 1U ) ;
CHECK ( " : unsigned char " , 1U ) ;
CHECK ( " : short " , settings . sizeof_short ) ;
CHECK ( " : signed short " , settings . sizeof_short ) ;
CHECK ( " : unsigned short " , settings . sizeof_short ) ;
CHECK ( " : int " , settings . sizeof_int ) ;
CHECK ( " : signed int " , settings . sizeof_int ) ;
CHECK ( " : unsigned int " , settings . sizeof_int ) ;
CHECK ( " : long " , settings . sizeof_long ) ;
CHECK ( " : signed long " , settings . sizeof_long ) ;
CHECK ( " : unsigned long " , settings . sizeof_long ) ;
CHECK ( " : long long " , settings . sizeof_long_long ) ;
CHECK ( " : signed long long " , settings . sizeof_long_long ) ;
CHECK ( " : unsigned long long " , settings . sizeof_long_long ) ;
CHECK ( " : wchar_t " , settings . sizeof_wchar_t ) ;
CHECK ( " : size_t " , settings . sizeof_size_t ) ;
# undef CHECK
}
2017-05-19 14:34:59 +02:00
void valueFlowErrorPath ( ) {
const char * code ;
code = " void f() { \n "
" int x = 53; \n "
" a = x; \n "
" } \n " ;
2017-05-20 08:47:35 +02:00
ASSERT_EQUALS ( " 2,Assignment 'x=53', assigned value is 53 \n " ,
2017-05-19 14:34:59 +02:00
getErrorPathForX ( code , 3U ) ) ;
code = " void f(int y) { \n "
" int x = y; \n "
" a = x; \n "
" y += 12; \n "
" if (y == 32) {} "
" } \n " ;
2017-05-20 08:47:35 +02:00
ASSERT_EQUALS ( " 5,Assuming that condition 'y==32' is not redundant \n "
2017-08-24 22:02:49 +02:00
" 4,Compound assignment '+=', before assignment value is 20 \n "
2017-05-20 08:47:35 +02:00
" 2,Assignment 'x=y', assigned value is 20 \n " ,
2017-05-19 14:34:59 +02:00
getErrorPathForX ( code , 3U ) ) ;
code = " void f1(int x) { \n "
" a = x; \n "
" } \n "
" void f2() { \n "
" int x = 3; \n "
" f1(x+1); \n "
" } \n " ;
2017-05-20 08:47:35 +02:00
ASSERT_EQUALS ( " 5,Assignment 'x=3', assigned value is 3 \n "
" 6,Calling function 'f1', 1st argument 'x' value is 4 \n " ,
2017-05-19 14:34:59 +02:00
getErrorPathForX ( code , 2U ) ) ;
2017-05-19 16:32:58 +02:00
code = " void f(int a) { \n "
" int x; \n "
" for (x = a; x < 50; x++) {} \n "
" b = x; \n "
" } \n " ;
2017-05-20 08:47:35 +02:00
ASSERT_EQUALS ( " 3,After for loop, x has value 50 \n " ,
2017-05-19 16:32:58 +02:00
getErrorPathForX ( code , 4U ) ) ;
2017-05-19 14:34:59 +02:00
}
2014-11-20 14:20:09 +01:00
void valueFlowBeforeCondition ( ) {
2014-01-08 06:39:15 +01:00
const char * code ;
code = " void f(int x) { \n "
" int a = x; \n "
" if (x == 123) {} \n "
" } " ;
2014-01-04 20:57:02 +01:00
A SSERT_EQUALS ( true , testValueOfX ( code , 2U , 123 ) ) ;
2014-01-06 07:44:58 +01:00
2014-01-08 06:53:17 +01:00
code = " void f(unsigned int x) { \n "
" int a = x; \n "
" if (x >= 1) {} \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 1 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 0 ) ) ;
2014-01-08 17:37:39 +01:00
2014-01-19 20:16:55 +01:00
code = " void f(unsigned int x) { \n "
" int a = x; \n "
" if (x > 0) {} \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 0 ) ) ;
code = " void f(unsigned int x) { \n "
" int a = x; \n "
" if (x > 1) {} \n " // not zero => don't consider > condition
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 2U , 1 ) ) ;
code = " void f(int x) { \n " // not unsigned => don't consider > condition
" int a = x; \n "
2014-01-20 06:31:28 +01:00
" if (x > 0) {} \n "
2014-01-19 20:16:55 +01:00
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 2U , 0 ) ) ;
2014-01-08 17:37:39 +01:00
code = " void f(int *x) { \n "
" *x = 100; \n "
" if (x) {} \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 0 ) ) ;
2014-01-08 06:53:17 +01:00
2014-01-10 05:47:56 +01:00
code = " extern const int x; \n "
" void f() { \n "
" int a = x; \n "
" if (x == 123) {} \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 123 ) ) ;
2018-02-24 22:07:34 +01:00
// after loop
code = " void f(struct X *x) { \n "
" do { \n "
" if (!x) \n "
" break; \n "
" } while (x->a); \n "
" if (x) {} \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , 0 ) ) ;
2014-01-18 08:45:24 +01:00
}
2014-11-20 14:20:09 +01:00
void valueFlowBeforeConditionAssignIncDec ( ) { // assignment / increment
2014-01-18 08:45:24 +01:00
const char * code ;
2014-01-10 05:47:56 +01:00
2014-01-11 15:36:09 +01:00
code = " void f(int x) { \n "
" x = 2 + x; \n "
" if (x == 65); \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 2U , 65 ) ) ;
2014-01-11 20:53:23 +01:00
code = " void f(int x) { \n "
" x = y = 2 + x; \n "
" if (x == 65); \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 2U , 65 ) ) ;
2014-01-11 15:36:09 +01:00
2014-01-17 19:28:28 +01:00
code = " void f(int x) { \n "
" a[x++] = 0; \n "
" if (x == 5); \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 2U , 5 ) ) ;
code = " void f(int x) { \n "
" a = x; \n "
" x++; \n "
" if (x == 4); \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 3 ) ) ;
2017-08-25 23:07:26 +02:00
ASSERT_EQUALS ( " 4,Assuming that condition 'x==4' is not redundant \n "
" 3,x is incremented, before this increment the value is 3 \n " ,
getErrorPathForX ( code , 2U ) ) ;
2014-01-17 19:28:28 +01:00
2017-04-25 20:45:02 +02:00
// compound assignment += , -= , ...
code = " void f(int x) { \n "
" a = x; \n "
" x += 2; \n "
" if (x == 4); \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 2 ) ) ;
code = " void f(int x) { \n "
" a = x; \n "
" x -= 2; \n "
" if (x == 4); \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 6 ) ) ;
code = " void f(int x) { \n "
" a = x; \n "
" x *= 2; \n "
" if (x == 42); \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 21 ) ) ;
code = " void f(int x) { \n "
" a = x; \n "
" x /= 5; \n "
" if (x == 42); \n "
" } " ;
ASSERT ( tokenValues ( code , " x ; " ) . empty ( ) ) ;
2014-01-18 08:45:24 +01:00
// bailout: assignment
bailout ( " void f(int x) { \n "
" x = y; \n "
" if (x == 123) {} \n "
" } " ) ;
2017-10-05 23:03:13 +02:00
ASSERT_EQUALS_WITHOUT_LINENUMBERS ( " [test.cpp:2]: (debug) valueflow.cpp:1035:valueFlowReverse bailout: assignment of x \n " , errout . str ( ) ) ;
2014-01-18 08:45:24 +01:00
}
2014-11-20 14:20:09 +01:00
void valueFlowBeforeConditionAndAndOrOrGuard ( ) { // guarding by &&
2014-01-18 08:45:24 +01:00
const char * code ;
2014-01-11 12:44:55 +01:00
code = " void f(int x) { \n "
" if (!x || \n " // <- x can be 0
" a/x) {} \n " // <- x can't be 0
" if (x==0) {} \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 0 ) ) ;
2014-01-11 11:30:34 +01:00
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0 ) ) ;
2014-01-11 14:54:10 +01:00
code = " void f(int *x) { \n "
2014-01-11 15:18:39 +01:00
" ((x=ret())&& \n "
" (*x==0)); \n " // <- x is not 0
2014-01-11 14:54:10 +01:00
" if (x==0) {} \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0 ) ) ;
2015-09-27 13:29:28 +02:00
code = " void f(int *x) { \n "
" int a = (x && *x == '1'); \n "
" int b = a ? atoi(x) : 0; \n " // <- x is not 0
" if (x==0) {} \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0 ) ) ;
2014-01-18 08:45:24 +01:00
}
2014-11-20 14:20:09 +01:00
void valueFlowBeforeConditionFunctionCall ( ) { // function calls
2014-01-18 08:45:24 +01:00
const char * code ;
2014-01-11 14:54:10 +01:00
2014-01-11 14:31:51 +01:00
code = " void f(int x) { \n "
" a = x; \n "
" setx(x); \n "
" if (x == 1) {} \n "
" } " ;
2014-04-02 17:33:04 +02:00
ASSERT_EQUALS ( true , testValueOfX ( ( std : : string ( " void setx(int x); " ) + code ) . c_str ( ) , 2U , 1 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( ( std : : string ( " void setx(int &x); " ) + code ) . c_str ( ) , 2U , 1 ) ) ;
2014-03-18 17:04:33 +01:00
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 1 ) ) ;
2014-01-11 14:31:51 +01:00
2014-01-12 18:19:00 +01:00
code = " void f(char* x) { \n "
" strcpy(x, \" abc \" ); \n "
" if (x) {} \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 0 ) ) ;
2014-01-13 05:52:28 +01:00
code = " void addNewFunction(Scope**scope, const Token**tok); \n "
" void f(Scope *x) { \n "
" x->functionList.back(); \n "
" addNewFunction(&x,&tok); \n " // address-of, x can be changed by subfunction
" if (x) {} \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0 ) ) ;
2014-01-18 08:45:24 +01:00
}
2014-11-20 14:20:09 +01:00
void valueFlowBeforeConditionLoop ( ) { // while, for, do-while
2014-01-18 08:45:24 +01:00
const char * code ;
2014-01-13 05:52:28 +01:00
2014-01-12 11:58:10 +01:00
code = " void f(int x) { \n " // loop condition, x is not assigned inside loop => use condition
2014-01-11 20:25:49 +01:00
" a = x; \n " // x can be 37
" while (x == 37) {} \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 37 ) ) ;
2016-11-27 11:40:42 +01:00
code = " void f(int x) { \n " // loop condition, x is assigned inside loop => don't use condition
2014-01-11 20:25:49 +01:00
" a = x; \n " // don't assume that x can be 37
" while (x != 37) { x++; } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 2U , 37 ) ) ;
2014-12-14 14:10:42 +01:00
code = " void f(int x) { \n "
" a = x; \n "
" for (; x!=1; x++) { } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 2U , 1 ) ) ;
2014-01-14 17:57:50 +01:00
code = " void f(menu *x) { \n "
" a = x->parent; \n "
" for (i=0;(i<10) && (x!=0); i++) { x = x->next; } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 2U , 0 ) ) ;
2014-01-12 11:58:10 +01:00
code = " void f(int x) { \n " // condition inside loop, x is NOT assigned inside loop => use condition
" a = x; \n "
" do { \n "
" if (x==76) {} \n "
" } while (1); \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 76 ) ) ;
2016-11-27 11:40:42 +01:00
code = " void f(int x) { \n " // conditions inside loop, x is assigned inside do-while => don't use condition
2014-01-12 11:58:10 +01:00
" a = x; \n "
" do { \n "
" if (x!=76) { x=do_something(); } \n "
" } while (1); \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 2U , 76 ) ) ;
2014-01-18 11:54:00 +01:00
2016-11-27 11:40:42 +01:00
code = " void f(X x) { \n " // conditions inside loop, x is assigned inside do-while => don't use condition
2014-01-18 11:54:00 +01:00
" a = x; \n "
" for (i=1;i<=count;i++) { \n "
" BUGON(x==0) \n "
" x = x.next; \n "
" } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 2U , 0 ) ) ;
2014-01-18 08:45:24 +01:00
}
2014-11-20 14:20:09 +01:00
void valueFlowBeforeConditionTernaryOp ( ) { // bailout: ?:
2014-01-18 08:45:24 +01:00
const char * code ;
2014-01-12 11:58:10 +01:00
2014-01-07 19:46:13 +01:00
bailout ( " void f(int x) { \n "
" y = ((x<0) ? x : ((x==2)?3:4)); \n "
" } " ) ;
2017-10-05 23:03:13 +02:00
ASSERT_EQUALS_WITHOUT_LINENUMBERS ( " [test.cpp:2]: (debug) valueflow.cpp:1113:valueFlowReverse bailout: no simplification of x within ?: expression \n " , errout . str ( ) ) ;
2014-01-08 06:39:15 +01:00
bailout ( " int f(int x) { \n "
" int r = x ? 1 / x : 0; \n "
" if (x == 0) {} \n "
" } " ) ;
2017-10-05 23:03:13 +02:00
ASSERT_EQUALS_WITHOUT_LINENUMBERS ( " [test.cpp:2]: (debug) valueflow.cpp:1113:valueFlowReverse bailout: no simplification of x within ?: expression \n " , errout . str ( ) ) ;
2014-01-08 06:39:15 +01:00
code = " void f(int x) { \n "
2014-01-10 16:13:39 +01:00
" int a =v x; \n "
2014-01-08 06:39:15 +01:00
" a = b ? x/2 : 20/x; \n "
" if (x == 123) {} \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 123 ) ) ;
2014-01-07 19:46:13 +01:00
2016-10-16 07:15:28 +02:00
code = " void f(const s *x) { \n "
" x->a = 0; \n "
" if (x ? x->a : 0) {} \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 0 ) ) ;
2014-01-10 16:13:39 +01:00
code = " void f(int x, int y) { \n "
" a = x; \n "
" if (y){} \n "
" if (x==123){} \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 123 ) ) ;
2014-01-18 08:45:24 +01:00
}
2014-11-20 14:20:09 +01:00
void valueFlowBeforeConditionSizeof ( ) { // skip sizeof
2014-01-18 08:45:24 +01:00
const char * code ;
2014-01-10 16:13:39 +01:00
2014-01-11 21:10:01 +01:00
code = " void f(int *x) { \n "
" sizeof(x[0]); \n "
" if (x==63){} \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 2U , 63 ) ) ;
2014-04-29 20:09:11 +02:00
code = " void f(int *x) { \n "
" char a[sizeof x.y]; \n "
" if (x==0){} \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 2U , 0 ) ) ;
2014-01-18 08:45:24 +01:00
}
2014-01-11 21:10:01 +01:00
2014-11-20 14:20:09 +01:00
void valueFlowBeforeConditionIfElse ( ) { // bailout: if/else/etc
2014-01-19 09:05:48 +01:00
const char * code ;
code = " void f(X * x) { \n "
" a = x; \n "
" if ((x != NULL) && \n "
" (a(x->name, html)) && \n "
" (a(x->name, body))) {} \n "
" if (x != NULL) { } \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 0 ) ) ;
2014-01-19 09:31:40 +01:00
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , 0 ) ) ;
2014-01-19 09:05:48 +01:00
2014-01-06 11:27:56 +01:00
bailout ( " void f(int x) { \n "
" if (x != 123) { b = x; } \n "
" if (x == 123) {} \n "
" } " ) ;
2017-10-05 23:03:13 +02:00
ASSERT_EQUALS_WITHOUT_LINENUMBERS ( " [test.cpp:2]: (debug) valueflow.cpp:1144:valueFlowReverse bailout: variable x stopping on } \n " , errout . str ( ) ) ;
2014-06-30 00:02:49 +02:00
code = " void f(int x) { \n "
" a = x; \n "
" if (abc) { x = 1; } \n " // <- condition must be false if x is 7 in next line
" if (x == 7) { } \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 7 ) ) ;
2014-01-18 08:45:24 +01:00
}
2014-01-06 11:27:56 +01:00
2014-11-20 14:20:09 +01:00
void valueFlowBeforeConditionGlobalVariables ( ) {
2014-01-19 11:55:02 +01:00
const char * code ;
2017-10-17 16:55:37 +02:00
// handle global variables
code = " int x; \n "
" void f() { \n "
" int a = x; \n "
" if (x == 123) {} \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3 , 123 ) ) ;
// bailout when there is function call
2014-01-19 11:55:02 +01:00
code = " class Fred { int x; void clear(); void f(); }; \n "
" void Fred::f() { \n "
" int a = x; \n "
" clear(); \n " // <- x might be assigned
" if (x == 234) {} \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3 , 234 ) ) ;
2014-01-18 08:45:24 +01:00
}
2014-01-11 21:21:00 +01:00
2014-11-20 14:20:09 +01:00
void valueFlowBeforeConditionSwitch ( ) {
2014-01-11 21:21:00 +01:00
// bailout: switch
2014-01-12 15:07:58 +01:00
// TODO : handle switch/goto more intelligently
2014-01-11 21:21:00 +01:00
bailout ( " void f(int x, int y) { \n "
" switch (y) { \n "
" case 1: a=x; break; \n "
" case 2: if (x==5) {} break; \n "
" }; \n "
" } " ) ;
2017-10-05 23:03:13 +02:00
ASSERT_EQUALS_WITHOUT_LINENUMBERS ( " [test.cpp:3]: (debug) valueflow.cpp:1180:valueFlowReverse bailout: variable x stopping on break \n " , errout . str ( ) ) ;
2014-01-12 15:07:58 +01:00
bailout ( " void f(int x, int y) { \n "
" switch (y) { \n "
" case 1: a=x; return 1; \n "
" case 2: if (x==5) {} break; \n "
" }; \n "
" } " ) ;
2017-10-05 23:03:13 +02:00
ASSERT_EQUALS_WITHOUT_LINENUMBERS ( " [test.cpp:3]: (debug) valueflow.cpp:1180:valueFlowReverse bailout: variable x stopping on return \n " , errout . str ( ) ) ;
2014-01-18 08:45:24 +01:00
}
2014-01-12 17:16:51 +01:00
2014-11-20 14:20:09 +01:00
void valueFlowBeforeConditionMacro ( ) {
2014-01-12 17:16:51 +01:00
// bailout: condition is a expanded macro
2017-05-18 21:52:31 +02:00
bailout ( " #define M if (x==123) {} \n "
" void f(int x) { \n "
2014-01-12 17:16:51 +01:00
" a = x; \n "
2017-05-18 21:52:31 +02:00
" M; \n "
2014-01-12 17:16:51 +01:00
" } " ) ;
2017-10-05 23:03:13 +02:00
ASSERT_EQUALS_WITHOUT_LINENUMBERS ( " [test.cpp:4]: (debug) valueflow.cpp:1260:valueFlowBeforeCondition bailout: variable x, condition is defined in macro \n " , errout . str ( ) ) ;
2014-01-18 08:45:24 +01:00
}
2014-01-13 16:07:25 +01:00
2014-11-20 14:20:09 +01:00
void valueFlowBeforeConditionGoto ( ) {
2014-01-13 16:07:25 +01:00
// bailout: goto label (TODO: handle gotos more intelligently)
bailout ( " void f(int x) { \n "
" if (x == 123) { goto out; } \n "
" a=x; \n " // <- x is not 123
" out: "
" if (x==123){} \n "
" } " ) ;
2017-10-05 23:03:13 +02:00
ASSERT_EQUALS_WITHOUT_LINENUMBERS ( " [test.cpp:4]: (debug) valueflow.cpp:1131:valueFlowReverse bailout: variable x stopping on goto label \n "
2017-10-05 23:01:42 +02:00
" [test.cpp:2]: (debug) valueflow.cpp:1813:valueFlowForward bailout: variable x. noreturn conditional scope. \n "
, errout . str ( ) ) ;
2014-04-28 06:21:48 +02:00
// #5721 - FP
bailout ( " static void f(int rc) { \n "
" ABC* abc = getabc(); \n "
" if (!abc) { goto out }; \n "
" \n "
" abc->majortype = 0; \n "
" if (FAILED(rc)) {} \n "
" \n "
" out: \n "
" if (abc) {} \n "
" } \n " ) ;
2017-10-05 23:03:13 +02:00
ASSERT_EQUALS_WITHOUT_LINENUMBERS ( " [test.cpp:2]: (debug) valueflow.cpp:1035:valueFlowReverse bailout: assignment of abc \n "
2017-10-05 23:01:42 +02:00
" [test.cpp:8]: (debug) valueflow.cpp:1131:valueFlowReverse bailout: variable abc stopping on goto label \n "
" [test.cpp:3]: (debug) valueflow.cpp:1813:valueFlowForward bailout: variable abc. noreturn conditional scope. \n " ,
errout . str ( ) ) ;
2014-01-04 20:57:02 +01:00
}
2014-01-06 16:37:52 +01:00
2014-11-20 14:20:09 +01:00
void valueFlowAfterAssign ( ) {
2014-01-21 21:13:49 +01:00
const char * code ;
code = " void f() { \n "
" int x = 123; \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 123 ) ) ;
2016-12-19 21:21:18 +01:00
code = " void f() { \n "
" bool x = 32; \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 1 ) ) ;
2014-01-21 21:13:49 +01:00
code = " void f() { \n "
" int x = 123; \n "
" a = sizeof(x); \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 123 ) ) ;
2014-01-22 06:10:17 +01:00
code = " void f() { \n "
" int x = 123; \n "
" a = 2 + x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 123 ) ) ;
2014-01-22 20:16:31 +01:00
2014-01-24 18:22:38 +01:00
code = " void f() { \n "
" int x = 9; \n "
" --x; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 9 ) ) ;
2015-05-02 17:30:09 +02:00
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 8 ) ) ;
2017-08-25 22:15:52 +02:00
ASSERT_EQUALS ( " 2,Assignment 'x=9', assigned value is 9 \n "
" 3,x is decremented', new value is 8 \n " ,
getErrorPathForX ( code , 4U ) ) ;
2014-01-24 18:22:38 +01:00
2016-10-15 19:09:50 +02:00
code = " void x() { \n "
" int x = value ? 6 : 0; \n "
" x = \n "
" 1 + x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 7 ) ) ;
2014-05-03 12:49:07 +02:00
code = " void f() { \n "
" int x = 0; \n "
" y = x += z; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
2014-01-25 18:31:02 +01:00
code = " void f() { \n "
" static int x = 2; \n "
" x++; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 2 ) ) ;
2014-02-22 12:09:54 +01:00
code = " void f() { \n "
" static int x = 2; \n "
" a >> x; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 2 ) ) ;
2014-03-23 17:57:27 +01:00
code = " void f() { \n "
" static int x = 0; \n "
" if (x==0) x = getX(); \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
2014-01-24 17:47:49 +01:00
// function
code = " void f() { \n "
" char *x = 0; \n "
" int success = getx((char**)&x); \n "
" if (success) x[0] = 0; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
2014-04-01 07:06:20 +02:00
code = " void f() { \n "
" char *x = 0; \n "
" getx(reinterpret_cast<void **>(&x)); \n "
" *x = 0; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
2015-07-26 19:28:42 +02:00
// lambda
code = " void f() { \n "
" int x = 0; \n "
" Q q = [&]() { \n "
" if (x > 0) {} \n "
" x++; \n "
" }; \n "
" dosomething(q); \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
2015-11-30 16:15:58 +01:00
// ?:
code = " void f() { \n "
" int x = 8; \n "
" a = ((x > 10) ? \n "
" x : 0); \n " // <- x is not 8
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 8 ) ) ;
code = " void f() { \n " // #6973
" char *x = \" \" ; \n "
" a = ((x[0] == 'U') ? \n "
" x[1] : 0); \n " // <- x is not ""
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , " \" \" " ) ) ;
2015-12-01 07:49:19 +01:00
code = " void f() { \n " // #6973
" char *x = getenv ( \" LC_ALL \" ); \n "
" if (x == NULL) \n "
" x = \" \" ; \n "
" \n "
" if ( (x[0] == 'U') && \n " // x can be ""
" (x[1] ? \n " // x can't be ""
" x[3] : \n " // x can't be ""
" x[2] )) \n " // x can't be ""
" {} \n "
" } \n " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 6U , " \" \" " ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 7U , " \" \" " ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 8U , " \" \" " ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 9U , " \" \" " ) ) ;
2016-07-17 21:51:20 +02:00
code = " void f() { \n " // #7599
" t *x = 0; \n "
" y = (a ? 1 : x \n " // <- x is 0
" && x->y ? 1 : 2); " // <- x is not 0
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
code = " void f() { \n " // #7599
" t *x = 0; \n "
" y = (a ? 1 : !x \n " // <- x is 0
" || x->y ? 1 : 2); " // <- x is not 0
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
2014-01-22 20:16:31 +01:00
// if/else
code = " void f() { \n "
" int x = 123; \n "
" if (condition) return; \n "
" a = 2 + x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 123 ) ) ;
code = " void f() { \n "
" int x = 1; \n "
" if (condition) x = 2; \n "
" a = 2 + x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 1 ) ) ;
2014-08-03 20:11:22 +02:00
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 2 ) ) ;
2014-01-22 20:16:31 +01:00
code = " void f() { \n "
" int x = 123; \n "
" if (condition1) x = 456; \n "
" if (condition2) x = 789; \n "
2014-08-05 08:28:46 +02:00
" a = 2 + x; \n " // <- either assignment "x=123" is redundant or x can be 123 here.
2014-01-22 20:16:31 +01:00
" } " ;
2014-08-05 08:28:46 +02:00
ASSERT_EQUALS ( true , testValueOfX ( code , 5U , 123 ) ) ;
2014-01-22 20:16:31 +01:00
2014-01-24 18:22:38 +01:00
code = " void f(int a) { \n "
" int x = 123; \n "
" if (a > 1) \n "
" ++x; \n "
" else \n "
" ++x; \n "
" return 2 + x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 123 ) ) ;
2014-01-22 20:16:31 +01:00
code = " void f() { \n "
" int x = 1; \n "
" if (condition1) x = 2; \n "
" else return; \n "
" a = 2 + x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , 1 ) ) ;
2014-01-25 19:13:33 +01:00
2014-01-26 15:50:25 +01:00
code = " void f(){ \n "
" int x = 0; \n "
" if (a>=0) { x = getx(); } \n "
" if (x==0) { return; } \n "
" return 123 / x; \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , 0 ) ) ;
2014-01-31 15:43:34 +01:00
code = " void f() { \n "
" X *x = getx(); \n "
2015-10-27 12:33:46 +01:00
" if(0) { x = 0; } \n "
2014-01-31 15:43:34 +01:00
" else { x->y = 1; } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
2015-10-27 12:33:46 +01:00
code = " void f() { \n " // #6239
" int x = 4; \n "
" if(1) { x = 0; } \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 4 ) ) ;
2014-03-18 17:04:33 +01:00
code = " void f() { \n "
" int x = 32; \n "
" if (x>=32) return; \n "
" a[x]=0; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 32 ) ) ;
code = " void f() { \n "
" int x = 32; \n "
" if (x>=32) { \n "
" a[x] = 0; \n " // <- should have possible value 32
" return; \n "
" } \n "
" } " ;
2014-06-15 17:15:09 +02:00
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 32 ) ) ;
2014-03-18 17:04:33 +01:00
2015-01-01 14:29:49 +01:00
code = " void f() { \n "
" int x = 33; \n "
" if (x==33) goto fail; \n "
" a[x]=0; \n "
" fail: \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 33 ) ) ;
2014-04-22 16:10:20 +02:00
code = " void f() { \n "
" int x = 32; \n "
" if (a==1) { z=x+12; } \n "
" if (a==2) { z=x+32; } \n "
" z = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 32 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 32 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 5U , 32 ) ) ;
2014-04-18 16:10:18 +02:00
code = " void f() { \n " // #5656 - FP
" int x = 0; \n "
" if (!x) { \n "
" x = getx(); \n "
" } \n "
" y = x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 6U , 0 ) ) ;
2015-02-08 19:20:05 +01:00
code = " void f(int y) { \n " // alias
" int x = y; \n "
" if (y == 54) {} \n "
" else { a = x; } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 54 ) ) ;
2014-04-26 11:27:58 +02:00
code = " void f () { \n "
" ST * x = g_pST; \n "
" if (x->y == 0) { \n "
" x = NULL; \n "
" return 1; \n "
" } \n "
" a = x->y; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 7U , 0 ) ) ;
2014-04-26 14:41:28 +02:00
code = " void f () { \n "
" ST * x = g_pST; \n "
" if (x->y == 0) { \n "
" x = NULL; \n "
" goto label; \n "
" } \n "
" a = x->y; \n "
" label: \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 7U , 0 ) ) ;
2014-05-01 15:15:26 +02:00
code = " void f() { \n " // #5752 - FP
" int *x = 0; \n "
" if (x && *x == 123) { \n "
" getx(*x); \n "
" } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
2014-07-30 18:12:33 +02:00
code = " void f() { \n "
" int x = 0; \n "
" if (!x) {} \n "
" else { y = x; } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
2014-09-04 17:52:14 +02:00
code = " void f() { \n " // #6118 - FP
" int x = 0; \n "
" x = x & 0x1; \n "
" if (x == 0) { x = 2; } \n "
2015-10-14 10:44:04 +02:00
" y = 42 / x; \n " // <- x is 2
2014-09-04 17:52:14 +02:00
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , 0 ) ) ;
2015-10-14 10:44:04 +02:00
ASSERT_EQUALS ( true , testValueOfX ( code , 5U , 2 ) ) ;
2014-09-04 17:52:14 +02:00
code = " void f() { \n " // #6118 - FN
" int x = 0; \n "
" x = x & 0x1; \n "
" if (x == 0) { x += 2; } \n "
2015-10-14 10:44:04 +02:00
" y = 42 / x; \n " // <- x is 2
2014-09-04 17:52:14 +02:00
" } " ;
2015-10-14 10:44:04 +02:00
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , 0 ) ) ;
TODO_ASSERT_EQUALS ( true , false , testValueOfX ( code , 5U , 2 ) ) ;
2014-09-04 17:52:14 +02:00
2015-01-06 14:12:35 +01:00
code = " void f(int mode) { \n "
" struct ABC *x; \n "
" \n "
" if (mode) { x = &y; } \n "
" else { x = NULL; } \n "
" \n "
" if (!x) exit(1); \n "
" \n "
" a = x->a; \n " // <- x can't be 0
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 9U , 0 ) ) ;
2014-01-25 19:13:33 +01:00
// multivariables
code = " void f(int a) { \n "
" int x = a; \n "
" if (a!=132) { b = x; } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 132 ) ) ;
code = " void f(int a) { \n "
" int x = a; \n "
2014-02-17 20:07:38 +01:00
" b = x; \n " // <- line 3
2014-01-25 19:13:33 +01:00
" if (a!=132) {} \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 132 ) ) ;
2014-01-25 20:14:49 +01:00
code = " void f() { \n "
" int a; \n "
" if (n) { a = n; } \n "
" else { a = 0; } \n "
" int x = a; \n "
2014-02-17 20:07:38 +01:00
" if (a > 0) { a = b / x; } \n " // <- line 6
2014-01-25 20:14:49 +01:00
" } " ;
2014-02-17 20:07:38 +01:00
ASSERT_EQUALS ( false , testValueOfX ( code , 6U , 0 ) ) ; // x is not 0 at line 6
2014-08-27 17:11:38 +02:00
code = " void f(int x1) { \n " // #6086
" int x = x1; \n "
" if (x1 >= 3) { \n "
" return; \n "
" } \n "
" a = x; \n " // <- x is not 3
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 6U , 3 ) ) ;
2015-02-07 10:45:30 +01:00
code = " int f(int *x) { \n " // #5980
" if (!x) { \n "
" switch (i) { \n "
" default: \n "
" throw std::runtime_error(msg); \n "
" }; \n "
" } \n "
" return *x; \n " // <- x is not 0
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 8U , 0 ) ) ;
2015-07-12 19:35:47 +02:00
code = " void f(int a) { \n " // #6826
" int x = a ? a : 87; \n "
" if (a && x) {} \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 87 ) ) ;
2016-01-24 08:57:57 +01:00
code = " void f() { \n "
" int first=-1, x=0; \n "
" do { \n "
" if (first >= 0) { a = x; } \n " // <- x is not 0
" first++; x=3; \n "
" } while (1); \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
2014-10-20 15:54:02 +02:00
// pointer/reference to x
code = " int f(void) { \n "
" int x = 2; \n "
" int *px = &x; \n "
" for (int i = 0; i < 1; i++) { \n "
" *px = 1; \n "
" } \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 7U , 2 ) ) ;
code = " int f(void) { \n "
" int x = 5; \n "
" int &rx = x; \n "
" for (int i = 0; i < 1; i++) { \n "
" rx = 1; \n "
" } \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 7U , 5 ) ) ;
2014-02-17 20:07:38 +01:00
// break
code = " void f() { \n "
" for (;;) { \n "
" int x = 1; \n "
" if (!abc()) { \n "
" x = 2; \n "
" break; \n "
" } \n "
" a = x; \n " // <- line 8
" } \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 8U , 2 ) ) ; // x is not 2 at line 8
2014-06-30 17:56:42 +02:00
code = " void f() { \n "
" int x; \n "
" switch (ab) { \n "
" case A: x = 12; break; \n "
" case B: x = 34; break; \n "
" } \n "
" v = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 7U , 12 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 7U , 34 ) ) ;
2014-07-16 09:12:56 +02:00
code = " void f() { \n " // #5981
" int x; \n "
" switch (ab) { \n "
" case A: x = 12; break; \n "
" case B: x = 34; break; \n "
" } \n "
" switch (ab) { \n "
" case A: v = x; break; \n " // <- x is not 34
" } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 8U , 34 ) ) ;
2014-09-23 16:06:02 +02:00
// while/for
2014-10-11 17:48:51 +02:00
code = " void f() { \n " // #6138
" ENTRY *x = 0; \n "
" while (x = get()) { \n "
" set(x->value); \n " // <- x is not 0
" } \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
2014-09-23 16:06:02 +02:00
code = " void f(const int *buf) { \n "
" int x = 0; \n "
" for (int i = 0; i < 10; i++) { \n "
" if (buf[i] == 123) { \n "
" x = i; \n "
" break; \n "
" } \n "
" } \n "
" a = x; \n " // <- x can be 0
" } \n " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 9U , 0 ) ) ; // x can be 0 at line 9
code = " void f(const int *buf) { \n "
" int x = 0; \n "
" for (int i = 0; i < 10; i++) { \n "
" if (buf[i] == 123) { \n "
" x = i; \n "
" ; \n " // <- no break
" } \n "
" } \n "
2016-11-27 11:40:42 +01:00
" a = x; \n " // <- x can't be 0
2014-09-23 16:06:02 +02:00
" } \n " ;
2016-11-27 11:40:42 +01:00
ASSERT_EQUALS ( false , testValueOfX ( code , 9U , 0 ) ) ; // x can't be 0 at line 9
2014-09-23 16:06:02 +02:00
code = " void f(const int *buf) { \n "
" int x = 0; \n "
" while (++i < 10) { \n "
" if (buf[i] == 123) { \n "
" x = i; \n "
" break; \n "
" } \n "
" } \n "
" a = x; \n " // <- x can be 0
" } \n " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 9U , 0 ) ) ; // x can be 0 at line 9
2016-02-08 10:43:41 +01:00
code = " void f(const int a[]) { \n " // #6616
" const int *x = 0; \n "
" for (int i = 0; i < 10; i = *x) { \n " // <- x is not 0
" x = a[i]; \n "
" } \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0 ) ) ;
2016-11-21 17:26:36 +01:00
// alias
code = " void f() { \n " // #7778
" int x = 0; \n "
" int *p = &x; \n "
" x = 3; \n "
" *p = 2; \n "
" a = x; \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 6U , 3 ) ) ;
TODO_ASSERT_EQUALS ( true , false , testValueOfX ( code , 6U , 2 ) ) ;
2014-01-21 21:13:49 +01:00
}
2014-11-20 14:20:09 +01:00
void valueFlowAfterCondition ( ) {
2014-06-15 16:47:01 +02:00
const char * code ;
2015-07-28 08:58:05 +02:00
// in if
2014-06-15 16:47:01 +02:00
code = " void f(int x) { \n "
" if (x == 123) { \n "
" a = x; \n "
" } \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 123 ) ) ;
code = " void f(int x) { \n "
" if (x != 123) { \n "
" a = x; \n "
" } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 123 ) ) ;
2015-07-28 08:58:05 +02:00
// in else
2014-06-15 16:47:01 +02:00
code = " void f(int x) { \n "
" if (x == 123) {} \n "
" else a = x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 123 ) ) ;
code = " void f(int x) { \n "
" if (x != 123) {} \n "
" else a = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 123 ) ) ;
2014-06-16 16:39:41 +02:00
2015-07-28 08:58:05 +02:00
// after if
code = " void f(int x) { \n "
" if (x == 10) { \n "
" x++; \n "
" } \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , 10 ) ) ;
TODO_ASSERT_EQUALS ( true , false , testValueOfX ( code , 5U , 11 ) ) ;
2014-06-16 16:39:41 +02:00
// !
code = " void f(int x) { \n "
" if (!x) { a = x; } \n "
" else a = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 0 ) ) ;
2014-07-07 17:48:58 +02:00
code = " void f(int x, int y) { \n "
" if (!(x&&y)) { return; } \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0 ) ) ;
2016-01-18 15:39:20 +01:00
code = " void f(int x) { \n "
" if (!x) { { throw new string(); }; } \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0 ) ) ;
2014-06-18 06:57:48 +02:00
// if (var)
code = " void f(int x) { \n "
" if (x) { a = x; } \n " // <- x is not 0
" else { b = x; } \n " // <- x is 0
" c = x; \n " // <- x might be 0
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 2U , 0 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 0 ) ) ;
2014-06-18 05:51:23 +02:00
// After while
code = " void f(int x) { \n "
" while (x != 3) {} \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 3 ) ) ;
2014-06-19 17:29:41 +02:00
2014-08-16 18:32:25 +02:00
code = " void f(int x) { \n "
" while (11 != (x = dostuff())) {} \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 11 ) ) ;
code = " void f(int x) { \n "
" while (11 != (x = dostuff()) && y) {} \n "
" a = x; \n "
" } " ;
TODO_ASSERT_EQUALS ( true , false , testValueOfX ( code , 3U , 11 ) ) ;
code = " void f(int x) { \n "
" while (x = dostuff()) {} \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
code = " void f(const Token *x) { \n " // #5866
" x = x->next(); \n "
" while (x) { x = x->next(); } \n "
" if (x->str()) {} \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 0 ) ) ;
code = " void f(const Token *x) { \n "
" while (0 != (x = x->next)) {} \n "
" x->ab = 0; \n "
" } \n " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
code = " void f(const Token* x) { \n "
" while (0 != (x = x->next)) {} \n "
" if (x->str) { \n " // <- possible value 0
" x = y; \n " // <- this caused some problem
" } \n "
" } \n " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
2014-06-25 16:00:56 +02:00
// conditional code after if/else/while
code = " void f(int x) { \n "
" if (x == 2) {} \n "
" if (x > 0) \n "
2014-10-17 06:50:33 +02:00
" a = x; \n " // <- TODO, x can be 2
2014-06-25 16:00:56 +02:00
" else \n "
" b = x; \n "
" } " ;
2014-10-17 06:50:33 +02:00
TODO_ASSERT_EQUALS ( true , false , testValueOfX ( code , 4U , 2 ) ) ;
2014-06-25 16:00:56 +02:00
ASSERT_EQUALS ( false , testValueOfX ( code , 6U , 2 ) ) ;
2014-08-01 07:35:15 +02:00
// condition with 2nd variable
code = " void f(int x) { \n "
" int y = 0; \n "
" if (x == 7) { y = 1; } \n "
" if (!y) \n "
" a = x; \n " // <- x can not be 7 here
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , 7 ) ) ;
2014-10-17 06:50:33 +02:00
code = " void f(struct X *x) { \n "
" bool b = TRUE; \n "
" if(x) { } \n "
" else \n "
" b = FALSE; \n "
" if (b) \n "
" abc(x->value); \n " // <- x is not 0
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 7U , 0 ) ) ;
2014-06-19 17:29:41 +02:00
// In condition, after && and ||
code = " void f(int x) { \n "
" a = (x != 3 || \n "
" x); \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 3 ) ) ;
code = " void f(int x) { \n "
" a = (x == 4 && \n "
" x); \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 4 ) ) ;
2014-06-25 06:17:44 +02:00
2014-08-11 16:21:20 +02:00
// protected usage with &&
code = " void f(const Token* x) { \n "
" if (x) {} \n "
" for (; x && \n "
" x->str() != y; x = x->next()) {} \n "
" } " ;
2014-10-11 17:48:51 +02:00
TODO_ASSERT_EQUALS ( true , false , testValueOfX ( code , 3U , 0 ) ) ;
2014-08-11 16:21:20 +02:00
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
code = " void f(const Token* x) { \n "
" if (x) {} \n "
" if (x && \n "
" x->str() != y) {} \n "
" } " ;
2015-02-01 15:05:00 +01:00
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
2014-08-11 16:21:20 +02:00
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
2014-08-27 16:59:18 +02:00
// return
code = " void f(int x) { \n " // #6024
2014-08-26 18:48:11 +02:00
" if (x == 5) { \n "
" if (z) return; else return; \n "
" } \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , 5 ) ) ;
2015-08-11 11:21:03 +02:00
code = " void f(int x) { \n " // #6730
" if (x == 5) { \n "
" if (z) continue; else throw e; \n "
" } \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , 5 ) ) ;
2014-06-25 06:17:44 +02:00
// TODO: float
code = " void f(float x) { \n "
" if (x == 0.5) {} \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0 ) ) ;
2017-09-03 23:24:55 +02:00
// aliased variable
code = " void f() { \n "
" int x = 1; \n "
" int *data = &x; \n "
" if (!x) { \n "
" calc(data); \n "
" a = x; \n " // <- x might be changed by calc
" } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 6U , 0 ) ) ;
2014-06-15 16:47:01 +02:00
}
2017-08-23 11:13:47 +02:00
void valueFlowForwardCompoundAssign ( ) {
const char * code ;
code = " void f() { \n "
" int x = 123; \n "
" x += 43; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 166 ) ) ;
2017-08-24 22:02:49 +02:00
ASSERT_EQUALS ( " 2,Assignment 'x=123', assigned value is 123 \n "
" 3,Compound assignment '+=', assigned value is 166 \n " ,
getErrorPathForX ( code , 4U ) ) ;
2017-08-23 11:13:47 +02:00
2017-08-23 17:52:28 +02:00
code = " void f() { \n "
" int x = 123; \n "
" x /= 0; \n " // don't crash when evaluating x/=0
" return x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 123 ) ) ;
2017-08-23 11:13:47 +02:00
code = " void f() { \n "
" float x = 123.45; \n "
" x += 67; \n "
" return x; \n "
" } " ;
2017-10-11 22:36:51 +02:00
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 123.45F + 67 , 0.01F ) ) ;
2017-08-23 11:13:47 +02:00
}
2017-08-27 19:50:44 +02:00
void valueFlowForwardCorrelatedVariables ( ) {
const char * code ;
code = " void f(int x = 0) { \n "
" bool zero(x==0); \n "
" if (zero) a = x; \n " // <- x is 0
" else b = x; \n " // <- x is not 0
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
}
2017-09-20 12:53:25 +02:00
void valueFlowForwardFunction ( ) {
const char * code ;
code = " class C { \n "
" public: \n "
2017-09-20 14:03:56 +02:00
" C(int &i); \n " // non-const argument => might be changed
2017-09-20 12:53:25 +02:00
" }; \n "
" int f() { \n "
" int x=1; \n "
" C c(x); \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 8U , 1 ) ) ;
2017-09-20 14:03:56 +02:00
code = " class C { \n "
" public: \n "
" C(const int &i); \n " // const argument => is not changed
" }; \n "
" int f() { \n "
" int x=1; \n "
" C c(x); \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 8U , 1 ) ) ;
2017-09-20 12:53:25 +02:00
}
2018-03-16 19:13:48 +01:00
void valueFlowForwardTernary ( ) {
const char * code ;
code = " int f() { \n "
" int x=5; \n "
" a = b ? init1(&x) : init2(&x); \n "
" return 1 + x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 5 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 5 ) ) ;
}
2017-08-28 22:39:12 +02:00
void valueFlowForwardLambda ( ) {
const char * code ;
code = " void f() { \n "
" int x=1; \n "
" auto f = [&](){ a=x; } \n " // x is not 1
" x = 2; \n "
" f(); \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 1 ) ) ;
TODO_ASSERT_EQUALS ( true , false , testValueOfX ( code , 3U , 2 ) ) ;
code = " void f() { \n "
" int x=3; \n "
" auto f = [&](){ a=x; } \n " // todo: x is 3
" f(); \n "
" } " ;
TODO_ASSERT_EQUALS ( true , false , testValueOfX ( code , 3U , 3 ) ) ;
}
2014-11-20 14:20:09 +01:00
void valueFlowBitAnd ( ) {
2014-04-14 06:45:39 +02:00
const char * code ;
code = " int f(int a) { \n "
" int x = a & 0x80; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0x80 ) ) ;
2015-07-04 11:17:38 +02:00
code = " int f(int a) { \n "
" int x = a & 0x80 ? 1 : 2; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0x80 ) ) ;
2015-10-14 10:44:04 +02:00
code = " int f() { \n "
" int x = (19 - 3) & 15; \n "
" return x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 16 ) ) ;
2014-04-14 06:45:39 +02:00
}
2015-07-20 19:45:38 +02:00
void valueFlowSwitchVariable ( ) {
const char * code ;
code = " void f(int x) { \n "
2017-10-20 17:31:58 +02:00
" a = x - 1; \n " // <- x can be 14
2015-07-20 19:45:38 +02:00
" switch (x) { \n "
2017-10-16 21:51:30 +02:00
" case 14: a=x+2; break; \n " // <- x is 14
2015-07-20 19:45:38 +02:00
" }; \n "
" a = x; \n " // <- x can be 14
" } " ;
2015-07-29 19:54:57 +02:00
ASSERT_EQUALS ( true , testConditionalValueOfX ( code , 2U , 14 ) ) ;
ASSERT_EQUALS ( true , testConditionalValueOfX ( code , 4U , 14 ) ) ;
ASSERT_EQUALS ( true , testConditionalValueOfX ( code , 6U , 14 ) ) ;
2017-10-16 21:51:30 +02:00
2017-10-20 17:31:58 +02:00
ValueFlow : : Value value1 = valueOfTok ( code , " - " ) ;
ASSERT_EQUALS ( 13 , value1 . intvalue ) ;
ASSERT ( ! value1 . isKnown ( ) ) ;
2017-10-16 21:51:30 +02:00
2017-10-20 17:31:58 +02:00
ValueFlow : : Value value2 = valueOfTok ( code , " + " ) ;
ASSERT_EQUALS ( 16 , value2 . intvalue ) ;
ASSERT ( value2 . isKnown ( ) ) ;
2015-07-20 19:45:38 +02:00
}
2014-11-20 14:20:09 +01:00
void valueFlowForLoop ( ) {
2014-01-10 16:51:58 +01:00
const char * code ;
code = " void f() { \n "
" for (int x = 0; x < 10; x++) \n "
" a[x] = 0; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 9 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 10 ) ) ;
2014-08-18 16:45:22 +02:00
code = " void f() { \n "
2014-12-30 18:50:22 +01:00
" int x; \n "
" for (x = 2; x < 1; x++) \n "
2014-08-18 16:45:22 +02:00
" a[x] = 0; \n " // <- not 2
2014-12-30 18:50:22 +01:00
" b = x; \n " // 2
2014-08-18 16:45:22 +02:00
" } " ;
2014-12-30 18:50:22 +01:00
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 2 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 5U , 2 ) ) ;
code = " void f() { \n "
" int x; \n "
" for (x = 2; x < 1; ++x) \n "
" a[x] = 0; \n " // <- not 2
" b = x; \n " // 2
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 2 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 5U , 2 ) ) ;
2014-08-18 16:45:22 +02:00
2016-12-20 07:54:38 +01:00
code = " enum AB {A,B}; \n " // enum => handled by valueForLoop2
" void f() { \n "
" int x; \n "
" for (x = 1; x < B; ++x) \n "
" a[x] = 0; \n " // <- not 1
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , 1 ) ) ;
2014-03-29 20:20:22 +01:00
code = " void f(int a) { \n "
" for (int x = a; x < 10; x++) \n "
" a[x] = 0; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 9 ) ) ;
2014-03-22 19:02:33 +01:00
code = " void f() { \n "
" for (int x = 0; x < 10; x = x + 2) \n "
" a[x] = 0; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 8 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 10 ) ) ;
2014-03-23 20:37:56 +01:00
code = " void f() { \n "
" for (int x = 0; x < 10; x = x / 0) \n "
" a[x] = 0; \n "
" } " ;
2014-03-24 00:16:02 +01:00
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ; // don't crash
2014-03-23 20:37:56 +01:00
2014-02-22 17:58:48 +01:00
code = " void f() { \n "
" for (int x = 0; x < 10; x++) \n "
" x<4 ? \n "
" a[x] : 0; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 9 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 9 ) ) ;
2014-03-25 18:22:22 +01:00
code = " void f() { \n "
" for (int x = 0; x < 10; x++) \n "
" x==0 ? \n "
" 0 : a[x]; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
2014-04-28 15:54:54 +02:00
2014-12-30 19:56:47 +01:00
code = " void f() { \n " // #5223
" for (int x = 0; x < 300 && x < 18; x++) \n "
" x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 0 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 17 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 299 ) ) ;
2014-04-28 15:54:54 +02:00
code = " void f() { \n "
" int x; \n "
" for (int i = 0; x = bar[i]; i++) \n "
" x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
2014-06-30 07:26:48 +02:00
2015-02-07 18:14:22 +01:00
code = " void f() { \n "
" const char abc[] = \" abc \" ; \n "
" int x; \n "
" for (x = 0; abc[x] != ' \\ 0'; x++) {} \n "
" a[x] = 0; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 5U , 3 ) ) ;
2014-06-30 07:26:48 +02:00
code = " void f() { \n " // #5939
" int x; \n "
" for (int x = 0; (x = do_something()) != 0;) \n "
" x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
code = " void f() { \n "
" int x; \n "
" for (int x = 0; x < 10 && y = do_something();) \n "
" x; \n "
" } " ;
2016-12-20 07:54:38 +01:00
TODO_ASSERT_EQUALS ( true , false , testValueOfX ( code , 4U , 0 ) ) ;
2014-07-17 08:44:55 +02:00
2014-08-17 06:42:16 +02:00
code = " void f() { \n "
" int x,y; \n "
" for (x = 0, y = 0; x < 10, y < 10; x++, y++) \n " // usage of ,
" x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 0 ) ) ;
2014-07-17 08:44:55 +02:00
code = " void foo(double recoveredX) { \n "
" for (double x = 1e-18; x < 1e40; x *= 1.9) { \n "
" double relativeError = (x - recoveredX) / x; \n "
" } \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0 ) ) ;
2014-08-01 16:12:57 +02:00
2018-01-11 14:27:41 +01:00
// Ticket #7139
// "<<" in third expression of for
code = " void f(void) { \n "
" int bit, x; \n "
" for (bit = 1, x = 0; bit < 128; bit = bit << 1, x++) { \n "
" z = x; \n " // <- known value [0..6]
" } \n "
" } \n " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 0 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 6 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 7 ) ) ;
2014-08-01 16:12:57 +02:00
// &&
code = " void foo() { \n "
" for (int x = 0; x < 10; x++) { \n "
" if (x > 1 \n "
" && x) {} " // <- x is not 0
" } \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 9 ) ) ;
2016-12-11 21:19:24 +01:00
code = " void foo() { \n "
" for (int x = 0; x < 10; x++) { \n "
" if (x < value \n "
" && x) {} " // <- maybe x is not 9
" } \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 9 ) ) ;
2014-08-01 16:12:57 +02:00
// ||
code = " void foo() { \n "
" for (int x = 0; x < 10; x++) { \n "
" if (x == 0 \n "
" || x) {} " // <- x is not 0
" } \n "
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , 0 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 9 ) ) ;
2014-08-13 04:03:17 +02:00
2014-08-17 10:40:22 +02:00
// After loop
code = " void foo() { \n "
" int x; \n "
" for (x = 0; x < 10; x++) {} \n "
" a = x; \n "
" } \n " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 10 ) ) ;
code = " void foo() { \n "
" int x; \n "
" for (x = 0; 2 * x < 20; x++) {} \n "
" a = x; \n "
" } \n " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 10 ) ) ;
code = " void foo() { \n " // related with #887
" int x; \n "
" for (x = 0; x < 20; x++) {} \n "
" a = x++; \n "
" } \n " ;
2015-05-02 17:30:09 +02:00
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 20 ) ) ;
2014-08-17 10:40:22 +02:00
2015-01-05 14:00:12 +01:00
code = " void f() { \n "
" int x; \n "
" for (x = 0; x < 5; x++) {} \n "
" if (x == 5) { \n "
" panic(); \n "
" } \n "
2015-01-05 16:39:47 +01:00
" a = x; \n " // <- x can't be 5
2015-01-05 14:00:12 +01:00
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 7U , 5 ) ) ;
2015-01-05 16:39:47 +01:00
code = " void f() { \n "
" int x; \n "
" for (x = 0; x < 5; x++) {} \n "
" if (x < 5) {} \n "
" else return; \n "
" a = x; \n " // <- x can't be 5
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 6U , 5 ) ) ;
2015-01-05 14:00:12 +01:00
2016-12-17 21:23:14 +01:00
// assert after for loop..
code = " static void f() { \n "
" int x; \n "
" int ctls[10]; \n "
" for (x = 0; x <= 10; x++) { \n "
" if (cond) \n "
" break; \n "
" } \n "
" assert(x <= 10); \n "
" ctls[x] = 123; \n " // <- x can't be 11
" } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 9U , 11 ) ) ;
2014-08-13 04:03:17 +02:00
// hang
code = " void f() { \n "
" for(int i = 0; i < 20; i++) \n "
" n = (int)(i < 10 || abs(negWander) < abs(negTravel)); \n "
" } " ;
2016-11-27 11:40:42 +01:00
testValueOfX ( code , 0 , 0 ) ; // <- don't hang
2016-01-24 13:11:51 +01:00
// conditional code in loop
code = " void f(int mask) { \n " // #6000
" for (int x = 10; x < 14; x++) { \n "
" int bit = mask & (1 << i); \n "
" if (bit) { \n "
" if (bit == (1 << 10)) {} \n "
" else { a = x; } \n " // <- x is not 10
" } \n "
" } \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 6U , 10 ) ) ;
2017-03-30 22:02:36 +02:00
// #7886 - valueFlowForLoop must be called after valueFlowAfterAssign
code = " void f() { \n "
" int sz = 4; \n "
" int x,y; \n "
" for(x=0,y=0; x < sz && y < 10; x++) \n "
" a = x; \n " // <- max value is 3
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 5U , 3 ) ) ;
2014-01-07 19:20:56 +01:00
}
2014-11-20 14:20:09 +01:00
void valueFlowSubFunction ( ) {
2014-01-06 16:37:52 +01:00
const char * code ;
code = " void f1(int x) { return x; } \n "
" void f2(int x) { \n "
" f1(123); \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 1U , 123 ) ) ;
code = " void f1(int x) { return x; } \n "
" void f2(int x) { \n "
" f1(x); \n "
" if (x==0){} \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 1U , 0 ) ) ;
2014-01-08 06:04:51 +01:00
code = " void f1(int x) { \n "
" if (x == 0) return; \n "
" int y = 1234 / x; \n "
" } \n "
" \n "
" void f2() { \n "
" f1(0); \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0 ) ) ;
2014-01-08 16:17:47 +01:00
2016-11-13 18:19:51 +01:00
code = " void f1(int x) { \n "
" if (x == 0) return; \n "
" int y = x; \n "
" } \n "
" \n "
" void f2() { \n "
" f1(x&4); \n " // possible {0,4}
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 4 ) ) ;
2014-01-08 16:17:47 +01:00
code = " void f1(int x) { a=x; } \n "
" void f2(int y) { f1(y<123); } \n " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 1U , 0 ) ) ;
ASSERT_EQUALS ( true , testValueOfX ( code , 1U , 1 ) ) ;
2014-01-11 07:52:25 +01:00
code = " void f1(int x) { a=(abc)x; } \n "
" void f2(int y) { f1(123); } \n " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 1U , 123 ) ) ;
2014-06-24 19:30:46 +02:00
code = " void f1(int x) { \n "
" x ? \n "
" 1024 / x : \n "
" 0; } \n "
" void f2() { f1(0); } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 0 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0 ) ) ;
2014-06-28 12:04:20 +02:00
2014-10-15 16:34:03 +02:00
code = " void f1(int *x) { \n "
" if (x && \n "
" *x) {} \n "
" } \n "
" void f2() { f1(0); } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 0 ) ) ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0 ) ) ;
2014-06-28 12:04:20 +02:00
// #5861 - fp with float
code = " void f1(float x) { \n "
" return 1.0 / x; \n "
" } \n "
" void f2() { f1(0.5); } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 2U , 0 ) ) ;
2014-08-04 12:31:04 +02:00
code = " void dostuff(int x) { \n "
" return x/x; \n "
" } \n "
" \n "
" void test(int x) { \n "
" if(x==1) {} \n "
" dostuff(x+1); \n "
" } \n " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 2U , 2 ) ) ;
2015-01-31 10:33:15 +01:00
code = " void leaveNotifyEvent(const XCrossingEvent * const) { } \n "
" void motionNotifyEvent() { \n "
" leaveNotifyEvent(0); \n "
" } " ;
testValueOfX ( code , 2U , 2 ) ; // No complaint about Token::Match called with varid 0. (#6443)
2015-05-24 17:02:00 +02:00
// #6560 - multivariables
code = " void f1(int x) { \n "
" int a = x && y; \n "
" int b = a ? x : 0; \n "
" } \n "
" void f2() { \n "
" f1(0); \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 0 ) ) ;
2016-12-11 10:42:39 +01:00
code = " class A \n "
" { \n "
" void f1(int x) { return x; } \n "
" void f2(int x) { \n "
" f1(123); \n "
" } \n "
" }; " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 123 ) ) ;
code = " class A \n "
" { \n "
" virtual void f1(int x) { return x; } \n "
" void f2(int x) { \n "
" f1(123); \n "
" } \n "
" }; " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 123 ) ) ;
2016-12-20 11:06:20 +01:00
code = " void foo(int x, int y) { \n "
" if (y == 1) { \n "
" a = x; \n " // <- x is not 1
" } \n "
" } \n "
" \n "
" void bar() { \n "
" foo(1, 10); \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 1 ) ) ;
2014-01-06 16:37:52 +01:00
}
2014-06-29 18:04:38 +02:00
2014-11-20 14:20:09 +01:00
void valueFlowFunctionReturn ( ) {
2014-06-29 18:04:38 +02:00
const char * code ;
2016-10-20 16:10:55 +02:00
code = " int f1(int x) { \n "
2014-06-29 18:04:38 +02:00
" return x+1; \n "
" } \n "
" void f2() { \n "
" x = 10 - f1(2); \n "
" } " ;
ASSERT_EQUALS ( 7 , valueOfTok ( code , " - " ) . intvalue ) ;
2016-10-22 12:24:15 +02:00
ASSERT_EQUALS ( true , valueOfTok ( code , " - " ) . isKnown ( ) ) ;
2014-06-29 18:04:38 +02:00
2016-10-20 16:10:55 +02:00
code = " int add(int x, int y) { \n "
2014-06-29 18:04:38 +02:00
" return x+y; \n "
" } \n "
" void f2() { \n "
" x = 1 * add(10+1,4); \n "
" } " ;
ASSERT_EQUALS ( 15 , valueOfTok ( code , " * " ) . intvalue ) ;
2016-10-22 12:24:15 +02:00
ASSERT_EQUALS ( true , valueOfTok ( code , " * " ) . isKnown ( ) ) ;
2016-10-20 16:10:55 +02:00
code = " int one() { return 1; } \n "
" void f() { x = 1 * one(); } " ;
ASSERT_EQUALS ( 1 , valueOfTok ( code , " * " ) . intvalue ) ;
2016-10-22 12:24:15 +02:00
ASSERT_EQUALS ( true , valueOfTok ( code , " * " ) . isKnown ( ) ) ;
2016-10-22 17:22:57 +02:00
code = " int add(int x, int y) { \n "
" return x+y; \n "
" } \n "
" void f2() { \n "
" x = 1 * add(1,add(2,3)); \n "
" } " ;
ASSERT_EQUALS ( 6 , valueOfTok ( code , " * " ) . intvalue ) ;
ASSERT_EQUALS ( true , valueOfTok ( code , " * " ) . isKnown ( ) ) ;
2016-11-20 15:14:49 +01:00
code = " int f(int i, X x) { \n "
" if (i) \n "
" return g(std::move(x)); \n "
" g(x); \n "
" return 0; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 4U , ValueFlow : : Value : : MovedVariable ) ) ;
2016-12-11 10:42:39 +01:00
code = " class A \n "
" { \n "
" int f1(int x) { \n "
" return x+1; \n "
" } \n "
" void f2() { \n "
" x = 10 - f1(2); \n "
" } \n "
" }; " ;
ASSERT_EQUALS ( 7 , valueOfTok ( code , " - " ) . intvalue ) ;
ASSERT_EQUALS ( true , valueOfTok ( code , " - " ) . isKnown ( ) ) ;
code = " class A \n "
" { \n "
" virtual int f1(int x) { \n "
" return x+1; \n "
" } \n "
" void f2() { \n "
" x = 10 - f1(2); \n "
" } \n "
" }; " ;
ASSERT_EQUALS ( 7 , valueOfTok ( code , " - " ) . intvalue ) ;
ASSERT_EQUALS ( false , valueOfTok ( code , " - " ) . isKnown ( ) ) ;
2014-06-29 18:04:38 +02:00
}
2015-02-03 22:12:05 +01:00
void valueFlowFunctionDefaultParameter ( ) {
const char * code ;
code = " class continuous_src_time { \n "
" continuous_src_time(std::complex<double> f, double st = 0.0, double et = infinity) {} \n "
" }; " ;
testValueOfX ( code , 2U , 2 ) ; // Don't crash (#6494)
}
2015-07-16 17:33:16 +02:00
2015-07-20 09:36:56 +02:00
bool isNotKnownValues ( const char code [ ] , const char str [ ] ) {
const std : : list < ValueFlow : : Value > values = tokenValues ( code , str ) ;
for ( std : : list < ValueFlow : : Value > : : const_iterator it = values . begin ( ) ; it ! = values . end ( ) ; + + it ) {
2015-07-25 19:36:29 +02:00
if ( it - > isKnown ( ) )
2015-07-20 09:36:56 +02:00
return false ;
}
2016-01-24 08:57:57 +01:00
return true ;
2015-07-20 09:36:56 +02:00
}
2015-07-16 17:33:16 +02:00
void knownValue ( ) {
const char * code ;
ValueFlow : : Value value ;
2015-07-25 19:36:29 +02:00
ASSERT ( valueOfTok ( " x = 1; " , " 1 " ) . isKnown ( ) ) ;
2015-07-16 17:33:16 +02:00
// after assignment
code = " void f() { \n "
" int x = 1; \n "
" return x + 2; \n " // <- known value
" } " ;
value = valueOfTok ( code , " + " ) ;
ASSERT_EQUALS ( 3 , value . intvalue ) ;
2015-07-25 19:36:29 +02:00
ASSERT ( value . isKnown ( ) ) ;
2015-07-16 17:33:16 +02:00
2016-01-27 19:20:00 +01:00
{
code = " void f() { \n "
" int x = 15; \n "
" if (x == 15) { x += 7; } \n " // <- condition is true
" } " ;
value = valueOfTok ( code , " == " ) ;
ASSERT_EQUALS ( 1 , value . intvalue ) ;
ASSERT ( value . isKnown ( ) ) ;
code = " int f() { \n "
" int a = 0, x = 0; \n "
" a = index(); \n "
" if (a != 0) \n "
" x = next(); \n "
" return x + 1; \n "
" } \n " ;
value = valueOfTok ( code , " + " ) ;
ASSERT ( value . isPossible ( ) ) ;
}
2016-01-26 16:10:15 +01:00
2015-07-16 17:33:16 +02:00
code = " void f() { \n "
" int x; \n "
" if (ab) { x = 7; } \n "
" return x + 2; \n " // <- possible value
" } " ;
value = valueOfTok ( code , " + " ) ;
ASSERT_EQUALS ( 9 , value . intvalue ) ;
2015-07-25 19:36:29 +02:00
ASSERT ( value . isPossible ( ) ) ;
2015-07-16 17:33:16 +02:00
2017-06-01 15:16:07 +02:00
code = " void f(int c) { \n "
" int x = 0; \n "
" if (c) {} else { x++; } \n "
" return x + 2; \n " // <- possible value
" } " ;
ASSERT ( isNotKnownValues ( code , " + " ) ) ;
2017-11-17 23:04:54 +01:00
code = " void f() { \n "
" int x = 0; \n "
" dostuff(&x); \n "
" if (x < 0) {} \n "
" } \n " ;
ASSERT ( isNotKnownValues ( code , " < " ) ) ;
code = " void f() { \n "
" int x = 0; \n "
" dostuff(0 ? ptr : &x); \n "
" if (x < 0) {} \n "
" } \n " ;
ASSERT ( isNotKnownValues ( code , " < " ) ) ;
code = " void f() { \n "
" int x = 0; \n "
" dostuff(unknown ? ptr : &x); \n "
" if (x < 0) {} \n "
" } \n " ;
ASSERT ( isNotKnownValues ( code , " < " ) ) ;
2015-07-29 10:49:17 +02:00
code = " void f() { \n "
" int x = 0; \n "
" fred.dostuff(x); \n "
" if (x < 0) {} \n "
" } \n " ;
ASSERT ( isNotKnownValues ( code , " < " ) ) ;
2016-10-23 13:54:44 +02:00
code = " void dostuff(int x); \n "
" void f() { \n "
" int x = 0; \n "
" dostuff(x); \n "
" if (x < 0) {} \n "
" } \n " ;
value = valueOfTok ( code , " < " ) ;
ASSERT_EQUALS ( 0 , value . intvalue ) ;
ASSERT ( value . isKnown ( ) ) ;
code = " void dostuff(int & x); \n "
" void f() { \n "
" int x = 0; \n "
" dostuff(x); \n "
" if (x < 0) {} \n "
" } \n " ;
ASSERT ( isNotKnownValues ( code , " < " ) ) ;
code = " void dostuff(const int & x); \n "
" void f() { \n "
" int x = 0; \n "
" dostuff(x); \n "
" if (x < 0) {} \n "
" } \n " ;
value = valueOfTok ( code , " < " ) ;
ASSERT_EQUALS ( 0 , value . intvalue ) ;
ASSERT ( value . isKnown ( ) ) ;
2015-11-12 14:59:35 +01:00
code = " void f() { \n "
" int x = 0; \n "
" do { \n "
" if (x < 0) {} \n "
" fred.dostuff(x); \n "
" } while (abc); \n "
" } \n " ;
ASSERT ( isNotKnownValues ( code , " < " ) ) ;
2017-07-09 12:50:17 +02:00
code = " int x; \n "
" void f() { \n "
" x = 4; \n "
" while (1) { \n "
" a = x+2; \n "
" dostuff(); \n "
" } \n "
" } " ;
ASSERT ( isNotKnownValues ( code , " + " ) ) ;
2015-07-21 17:56:40 +02:00
code = " void f() { \n "
" int x = 0; \n "
" if (y) { dostuff(x); } \n "
" if (!x) {} \n "
" } \n " ;
ASSERT ( isNotKnownValues ( code , " ! " ) ) ;
2015-08-05 14:08:57 +02:00
code = " void f() { \n "
" int x = 0; \n "
" MACRO( v, { if (y) { x++; } } ); \n "
" if (!x) {} \n "
" } \n " ;
ASSERT ( isNotKnownValues ( code , " ! " ) ) ;
2015-07-16 21:08:32 +02:00
code = " void f() { \n "
" int x = 0; \n "
" for (int i = 0; i < 10; i++) { \n "
" if (cond) { \n "
" x = 1; \n "
" break; \n "
" } \n "
" } \n "
" if (!x) {} \n " // <- possible value
" } " ;
2015-07-20 09:36:56 +02:00
ASSERT ( isNotKnownValues ( code , " ! " ) ) ;
code = " void f() { \n "
" int x = 0; \n "
" switch (state) { \n "
" case 1: \n "
" x = 1; \n "
" break; \n "
" } \n "
" if (!x) {} \n " // <- possible value
" } " ;
ASSERT ( isNotKnownValues ( code , " ! " ) ) ;
2015-07-16 21:08:32 +02:00
2015-11-08 14:08:47 +01:00
code = " void f() { \n " // #7049
" int x = 0; \n "
" switch (a) { \n "
" case 1: \n "
" x = 1; \n "
" case 2: \n "
" if (!x) {} \n " // <- possible value
" } \n "
" } " ;
ASSERT ( isNotKnownValues ( code , " ! " ) ) ;
2015-07-17 10:24:24 +02:00
code = " void f() { \n "
" int x = 0; \n "
" while (!x) { \n " // <- possible value
2015-07-18 15:35:39 +02:00
" scanf( \" %d \" , &x); \n "
2015-07-17 10:24:24 +02:00
" } \n "
" } " ;
value = valueOfTok ( code , " ! " ) ;
ASSERT_EQUALS ( 1 , value . intvalue ) ;
2015-07-25 19:36:29 +02:00
ASSERT ( value . isPossible ( ) ) ;
2015-07-17 10:24:24 +02:00
2015-07-29 11:55:07 +02:00
code = " void f() { \n "
" int x = 0; \n "
" do { } while (++x < 12); \n " // <- possible value
" } " ;
ASSERT ( isNotKnownValues ( code , " < " ) ) ;
2015-07-17 20:30:34 +02:00
code = " void f() { \n "
2015-07-17 20:48:37 +02:00
" static int x = 0; \n "
2017-09-15 15:58:19 +02:00
" return x + 1; \n " // <- known value
2015-07-17 20:48:37 +02:00
" } \n " ;
value = valueOfTok ( code , " + " ) ;
ASSERT_EQUALS ( 1 , value . intvalue ) ;
2017-09-15 15:58:19 +02:00
ASSERT ( value . isKnown ( ) ) ;
2015-07-17 20:48:37 +02:00
2015-07-26 17:05:21 +02:00
code = " void f() { \n "
" int x = 0; \n "
" a: \n "
" a = x + 1; \n " // <- possible value
" } " ;
value = valueOfTok ( code , " + " ) ;
ASSERT_EQUALS ( 1 , value . intvalue ) ;
ASSERT ( value . isPossible ( ) ) ;
2017-03-03 01:29:34 +01:00
// in conditional code
code = " void f(int x) { \n "
" if (!x) { \n "
" a = x+1; \n " // <- known value
" } \n "
" } " ;
value = valueOfTok ( code , " + " ) ;
ASSERT_EQUALS ( 1 , value . intvalue ) ;
ASSERT ( value . isKnown ( ) ) ;
code = " void f(int x) { \n "
" if (a && 4==x && y) { \n "
" a = x+12; \n " // <- known value
" } \n "
" } " ;
value = valueOfTok ( code , " + " ) ;
ASSERT_EQUALS ( 16 , value . intvalue ) ;
ASSERT ( value . isKnown ( ) ) ;
2015-07-16 17:33:16 +02:00
// after condition
code = " int f(int x) { \n "
" if (x == 4) {} \n "
" return x + 1; \n " // <- possible value
" } " ;
value = valueOfTok ( code , " + " ) ;
ASSERT_EQUALS ( 5 , value . intvalue ) ;
2015-07-25 19:36:29 +02:00
ASSERT ( value . isPossible ( ) ) ;
2015-07-16 20:49:14 +02:00
2016-01-30 20:03:55 +01:00
code = " int f(int x) { \n "
" if (x < 2) {} \n "
" else if (x >= 2) {} \n " // <- known value
" } " ;
value = valueOfTok ( code , " >= " ) ;
ASSERT_EQUALS ( 1 , value . intvalue ) ;
ASSERT ( value . isKnown ( ) ) ;
2016-01-30 22:13:03 +01:00
code = " int f(int x) { \n "
" if (x < 2) {} \n "
" else if (x > 2) {} \n " // <- possible value
" } " ;
ASSERT ( isNotKnownValues ( code , " > " ) ) ;
2015-07-16 20:49:14 +02:00
// function
code = " int f(int x) { return x + 1; } \n " // <- possible value
2016-11-20 14:15:51 +01:00
" void a() { f(12); } " ;
2015-07-16 20:49:14 +02:00
value = valueOfTok ( code , " + " ) ;
ASSERT_EQUALS ( 13 , value . intvalue ) ;
2015-07-25 19:36:29 +02:00
ASSERT ( value . isPossible ( ) ) ;
2015-10-04 10:33:43 +02:00
// known and possible value
code = " void f() { \n "
" int x = 1; \n "
" int y = 2 + x; \n " // <- known value, don't care about condition
" if (x == 2) {} \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 1 ) ) ; // value of x can be 1
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 2 ) ) ; // value of x can't be 2
2016-01-26 10:07:42 +01:00
// calculation with known result
code = " int f(int x) { a = x & 0; } " ; // <- & is 0
value = valueOfTok ( code , " & " ) ;
ASSERT_EQUALS ( 0 , value . intvalue ) ;
ASSERT ( value . isKnown ( ) ) ;
2016-10-04 08:06:48 +02:00
2018-01-11 14:22:27 +01:00
// template parameters are not known
code = " template <int X> void f() { a = X; } \n "
" f<1>(); " ;
value = valueOfTok ( code , " 1 " ) ;
ASSERT_EQUALS ( 1 , value . intvalue ) ;
ASSERT_EQUALS ( false , value . isKnown ( ) ) ;
2015-07-16 17:33:16 +02:00
}
2016-10-26 10:36:02 +02:00
void valueFlowSizeofForwardDeclaredEnum ( ) {
const char * code = " enum E; sz=sizeof(E); " ;
valueOfTok ( code , " = " ) ; // Don't crash (#7775)
}
2017-01-09 15:53:08 +01:00
void valueFlowGlobalVar ( ) {
const char * code ;
code = " int x; \n "
" void f() { \n "
" x = 4; \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 4 ) ) ;
code = " int x; \n "
" void f() { \n "
" if (x == 4) {} \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 4U , 4 ) ) ;
code = " int x; \n "
" void f() { \n "
" x = 42; \n "
" unknownFunction(); \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , 42 ) ) ;
}
2017-03-23 20:01:16 +01:00
2017-09-15 15:58:19 +02:00
void valueFlowGlobalStaticVar ( ) {
const char * code ;
code = " static int x = 321; \n "
" void f() { \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( true , testValueOfX ( code , 3U , 321 ) ) ;
code = " static int x = 321; \n "
" void f() { \n "
" a = x; \n "
" } "
" void other() { x=a; } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 321 ) ) ;
code = " static int x = 321; \n "
" void f() { \n "
" a = x; \n "
" } "
" void other() { p = &x; } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 321 ) ) ;
code = " static int x = 321; \n "
" void f() { \n "
" a = x; \n "
" } "
" void other() { x++; } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 321 ) ) ;
code = " static int x = 321; \n "
" void f() { \n "
" a = x; \n "
" } "
" void other() { foo(x); } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 321 ) ) ;
2018-03-18 19:53:33 +01:00
code = " static int x = 1; \n " // compound assignment
" void f() { \n "
" a = x; \n "
" } "
" void other() { x += b; } \n " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 3U , 1 ) ) ;
2017-09-15 15:58:19 +02:00
}
2017-03-23 20:01:16 +01:00
void valueFlowInlineAssembly ( ) {
const char * code = " void f() { \n "
" int x = 42; \n "
" asm( \" \" ); \n "
" a = x; \n "
" } " ;
ASSERT_EQUALS ( false , testValueOfX ( code , 5U , 42 ) ) ;
}
2017-04-23 18:05:14 +02:00
void valueFlowUninit ( ) {
2017-04-24 18:27:16 +02:00
const char * code ;
2017-04-23 18:05:14 +02:00
std : : list < ValueFlow : : Value > values ;
2017-04-24 18:27:16 +02:00
code = " void f() { \n "
" int x; \n "
" switch (x) {} \n "
" } " ;
2017-04-23 18:05:14 +02:00
values = tokenValues ( code , " x ) " ) ;
2017-04-24 18:27:16 +02:00
ASSERT_EQUALS ( true , values . size ( ) = = 1U & & values . front ( ) . isUninitValue ( ) ) ;
code = " void f() { \n "
" C *c; \n "
" if (c->x() == 4) {} \n "
" } " ;
values = tokenValues ( code , " c . " ) ;
ASSERT_EQUALS ( true , values . size ( ) = = 1U & & values . front ( ) . isUninitValue ( ) ) ;
2017-04-29 08:25:55 +02:00
code = " void f() { \n "
" int **x; \n "
" y += 10; \n "
" x = dostuff(sizeof(*x)*y); \n "
" } " ;
ASSERT_EQUALS ( 0U , tokenValues ( code , " x ) " ) . size ( ) ) ;
2017-08-20 19:47:26 +02:00
// #8036
code = " void foo() { \n "
" int x; \n "
" f(x=3), return x+3; \n "
" } " ;
ASSERT_EQUALS ( 0U , tokenValues ( code , " x + " ) . size ( ) ) ;
2017-09-02 21:53:51 +02:00
// #8195
code = " void foo(std::istream &is) { \n "
" int x; \n "
" if (is >> x) { \n "
" a = x; \n "
" } \n "
" } " ;
values = tokenValues ( code , " x ; } " ) ;
ASSERT_EQUALS ( true , values . empty ( ) ) ;
2017-09-14 22:49:47 +02:00
// return (#8173)
code = " int repeat() { \n "
" const char *n; \n "
" return((n=42) && *n == 'A'); \n "
" } " ;
values = tokenValues ( code , " n == " ) ;
ASSERT_EQUALS ( true , values . size ( ) ! = 1U | | ! values . front ( ) . isUninitValue ( ) ) ;
2017-11-06 10:28:07 +01:00
// #8233
code = " void foo() { \n "
" int x; \n "
" int y = 1; \n "
" if (y>1) \n "
" x = 1; \n "
" else \n "
" x = 1; \n "
" if (x>1) {} \n "
" } " ;
values = tokenValues ( code , " x > " ) ;
ASSERT_EQUALS ( true , values . size ( ) = = 1U & & values . front ( ) . isIntValue ( ) ) ;
2018-02-11 22:14:44 +01:00
// #8348 - noreturn else
code = " int test_input_int(int a, int b) { \n "
" int x; \n "
" if (a == 1) \n "
" x = b; \n "
" else \n "
" abort(); \n "
" a = x + 1; \n "
" } \n " ;
values = tokenValues ( code , " x + " ) ;
ASSERT_EQUALS ( true , values . empty ( ) ) ;
2017-04-23 18:05:14 +02:00
}
2014-01-04 20:57:02 +01:00
} ;
REGISTER_TEST ( TestValueFlow )