8080#include " analyzer.h"
8181#include " astutils.h"
8282#include " errorlogger.h"
83+ #include " errortypes.h"
8384#include " forwardanalyzer.h"
8485#include " library.h"
8586#include " mathlib.h"
106107#include < map>
107108#include < set>
108109#include < stack>
110+ #include < stdexcept>
109111#include < string>
110112#include < tuple>
111113#include < vector>
@@ -341,6 +343,60 @@ static bool isComputableValue(const Token* parent, const ValueFlow::Value& value
341343 return true ;
342344}
343345
346+ template <class T >
347+ T asInt (T x)
348+ {
349+ return x;
350+ }
351+
352+ MathLib::bigint asInt (float x) { return x; }
353+
354+ MathLib::bigint asInt (double x) { return x; }
355+
356+ template <class T , class U >
357+ static T calculate (const std::string& s, T x, U y)
358+ {
359+ switch (MathLib::encodeMultiChar (s)) {
360+ case ' +' :
361+ return x + y;
362+ case ' -' :
363+ return x - y;
364+ case ' *' :
365+ return x * y;
366+ case ' /' :
367+ return x / y;
368+ case ' %' :
369+ return asInt (x) % asInt (y);
370+ case ' &' :
371+ return asInt (x) & asInt (y);
372+ case ' |' :
373+ return asInt (x) | asInt (y);
374+ case ' ^' :
375+ return asInt (x) ^ asInt (y);
376+ case ' >' :
377+ return x > y;
378+ case ' <' :
379+ return x < y;
380+ case ' <<' :
381+ return asInt (x) << asInt (y);
382+ case ' >>' :
383+ return asInt (x) >> asInt (y);
384+ case ' &&' :
385+ return x && y;
386+ case ' ||' :
387+ return x || y;
388+ case ' ==' :
389+ return x == y;
390+ case ' !=' :
391+ return x != y;
392+ case ' >=' :
393+ return x >= y;
394+ case ' <=' :
395+ return x <= y;
396+ }
397+ throw InternalError (nullptr , " Unknown operator: " + s);
398+ }
399+
344400/* * Set token value for cast */
345401static void setTokenValueCast (Token *parent, const ValueType &valueType, const ValueFlow::Value &value, const Settings *settings);
346402
@@ -359,31 +415,40 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value, const Setti
359415
360416 if (value.isContainerSizeValue ()) {
361417 // .empty, .size, +"abc", +'a'
362- if (parent-> str () == " + " && parent->astOperand1 () && parent->astOperand2 ()) {
418+ if (Token::Match (parent, " +|==|!= " ) && parent->astOperand1 () && parent->astOperand2 ()) {
363419 for (const ValueFlow::Value &value1 : parent->astOperand1 ()->values ()) {
364420 for (const ValueFlow::Value &value2 : parent->astOperand2 ()->values ()) {
365421 if (value1.path != value2.path )
366422 continue ;
367423 ValueFlow::Value result;
368- result.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
424+ if (Token::Match (parent, " %comp%" ))
425+ result.valueType = ValueFlow::Value::ValueType::INT;
426+ else
427+ result.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
428+
369429 if (value1.isContainerSizeValue () && value2.isContainerSizeValue ())
370- result.intvalue = value1.intvalue + value2.intvalue ;
430+ result.intvalue = calculate (parent-> str (), value1.intvalue , value2.intvalue ) ;
371431 else if (value1.isContainerSizeValue () && value2.isTokValue () && value2.tokvalue ->tokType () == Token::eString)
372- result.intvalue = value1.intvalue + Token::getStrLength (value2.tokvalue );
432+ result.intvalue = calculate (parent-> str (), value1.intvalue , Token::getStrLength (value2.tokvalue ) );
373433 else if (value2.isContainerSizeValue () && value1.isTokValue () && value1.tokvalue ->tokType () == Token::eString)
374- result.intvalue = Token::getStrLength (value1.tokvalue ) + value2.intvalue ;
434+ result.intvalue = calculate (parent-> str (), Token::getStrLength (value1.tokvalue ), value2.intvalue ) ;
375435 else
376436 continue ;
377437
378438 combineValueProperties (value1, value2, &result);
379439
440+ if (Token::simpleMatch (parent, " ==" ) && result.intvalue )
441+ continue ;
442+ if (Token::simpleMatch (parent, " !=" ) && !result.intvalue )
443+ continue ;
444+
380445 setTokenValue (parent, result, settings);
381446 }
382447 }
383448 }
384449
385-
386- else if ( Token::Match (parent, " . %name% ( " ) && parent-> astParent () == parent-> tokAt ( 2 ) && parent->astOperand1 () && parent->astOperand1 ()->valueType ()) {
450+ else if ( Token::Match (parent, " . %name% ( " ) && parent-> astParent () == parent-> tokAt ( 2 ) &&
451+ parent->astOperand1 () && parent->astOperand1 ()->valueType ()) {
387452 const Library::Container *c = parent->astOperand1 ()->valueType ()->container ;
388453 const Library::Container::Yield yields = c ? c->getYield (parent->strAt (1 )) : Library::Container::Yield::NO_YIELD;
389454 if (yields == Library::Container::Yield::SIZE) {
@@ -545,147 +610,48 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value, const Setti
545610 combineValueProperties (value1, value2, &result);
546611 const double floatValue1 = value1.isIntValue () ? value1.intvalue : value1.floatValue ;
547612 const double floatValue2 = value2.isIntValue () ? value2.intvalue : value2.floatValue ;
548- switch (parent->str ()[0 ]) {
549- case ' +' :
550- if (value1.isTokValue () || value2.isTokValue ())
551- break ;
552- if (value1.isFloatValue () || value2.isFloatValue ()) {
553- result.valueType = ValueFlow::Value::ValueType::FLOAT;
554- result.floatValue = floatValue1 + floatValue2;
613+ const bool isFloat = value1.isFloatValue () || value2.isFloatValue ();
614+ if (isFloat && Token::Match (parent, " &|^|%|<<|>>|%or%" ))
615+ continue ;
616+ if (Token::Match (parent, " <<|>>" ) &&
617+ !(value1.intvalue >= 0 && value2.intvalue >= 0 && value2.intvalue < MathLib::bigint_bits))
618+ continue ;
619+ if (Token::Match (parent, " /|%" ) && floatValue2 == 0 )
620+ continue ;
621+ if (Token::Match (parent, " ==|!=" )) {
622+ if ((value1.isIntValue () && value2.isTokValue ()) || (value1.isTokValue () && value2.isIntValue ())) {
623+ if (parent->str () == " ==" )
624+ result.intvalue = 0 ;
625+ else if (parent->str () == " !=" )
626+ result.intvalue = 1 ;
627+ } else if (value1.isIntValue () && value2.isIntValue ()) {
628+ result.intvalue = calculate (parent->str (), value1.intvalue , value2.intvalue );
555629 } else {
556- result. intvalue = value1. intvalue + value2. intvalue ;
630+ continue ;
557631 }
558632 setTokenValue (parent, result, settings);
559- break ;
560- case ' -' :
561- if (value1.isTokValue () || value2.isTokValue ())
562- break ;
563- if (value1.isFloatValue () || value2.isFloatValue ()) {
564- result.valueType = ValueFlow::Value::ValueType::FLOAT;
565- result.floatValue = floatValue1 - floatValue2;
566- } else {
567- // Avoid overflow
568- if (value1.intvalue < 0 && value2.intvalue > value1.intvalue - LLONG_MIN)
569- break ;
570-
571- result.intvalue = value1.intvalue - value2.intvalue ;
572- }
573- // If the bound comes from the second value then invert the bound
574- if (value2.bound == result.bound && value2.bound != ValueFlow::Value::Bound::Point)
575- result.invertBound ();
633+ } else if (Token::Match (parent, " %comp%" )) {
634+ if (!isFloat && !value1.isIntValue () && !value2.isIntValue ())
635+ continue ;
636+ if (isFloat)
637+ result.intvalue = calculate (parent->str (), floatValue1, floatValue2);
638+ else
639+ result.intvalue = calculate (parent->str (), value1.intvalue , value2.intvalue );
576640 setTokenValue (parent, result, settings);
577- break ;
578- case ' *' :
641+ } else if (Token::Match (parent, " %op%" )) {
579642 if (value1.isTokValue () || value2.isTokValue ())
580643 break ;
581- if (value1.isFloatValue () || value2.isFloatValue ()) {
582- result.valueType = ValueFlow::Value::ValueType::FLOAT;
583- result.floatValue = floatValue1 * floatValue2;
584- } else {
585- result.intvalue = value1.intvalue * value2.intvalue ;
586- }
587- setTokenValue (parent, result, settings);
588- break ;
589- case ' /' :
590- if (value1.isTokValue () || value2.isTokValue () || value2.intvalue == 0 )
591- break ;
592- if (value1.isFloatValue () || value2.isFloatValue ()) {
644+ if (isFloat) {
593645 result.valueType = ValueFlow::Value::ValueType::FLOAT;
594- result.floatValue = floatValue1 / floatValue2;
646+ result.floatValue = calculate (parent-> str (), floatValue1, floatValue2) ;
595647 } else {
596- result.intvalue = value1.intvalue / value2.intvalue ;
648+ result.intvalue = calculate (parent-> str (), value1.intvalue , value2.intvalue ) ;
597649 }
650+ // If the bound comes from the second value then invert the bound when subtracting
651+ if (Token::simpleMatch (parent, " -" ) && value2.bound == result.bound &&
652+ value2.bound != ValueFlow::Value::Bound::Point)
653+ result.invertBound ();
598654 setTokenValue (parent, result, settings);
599- break ;
600- case ' %' :
601- if (!value1.isIntValue () || !value2.isIntValue ())
602- break ;
603- if (value2.intvalue == 0 )
604- break ;
605- result.intvalue = value1.intvalue % value2.intvalue ;
606- setTokenValue (parent, result, settings);
607- break ;
608- case ' =' :
609- if (parent->str () == " ==" ) {
610- if ((value1.isIntValue () && value2.isTokValue ()) ||
611- (value1.isTokValue () && value2.isIntValue ())) {
612- result.intvalue = 0 ;
613- setTokenValue (parent, result, settings);
614- } else if (value1.isIntValue () && value2.isIntValue ()) {
615- result.intvalue = value1.intvalue == value2.intvalue ;
616- setTokenValue (parent, result, settings);
617- }
618- }
619- break ;
620- case ' !' :
621- if (parent->str () == " !=" ) {
622- if ((value1.isIntValue () && value2.isTokValue ()) ||
623- (value1.isTokValue () && value2.isIntValue ())) {
624- result.intvalue = 1 ;
625- setTokenValue (parent, result, settings);
626- } else if (value1.isIntValue () && value2.isIntValue ()) {
627- result.intvalue = value1.intvalue != value2.intvalue ;
628- setTokenValue (parent, result, settings);
629- }
630- }
631- break ;
632- case ' >' : {
633- const bool f = value1.isFloatValue () || value2.isFloatValue ();
634- if (!f && !value1.isIntValue () && !value2.isIntValue ())
635- break ;
636- if (parent->str () == " >" )
637- result.intvalue = f ? (floatValue1 > floatValue2) : (value1.intvalue > value2.intvalue );
638- else if (parent->str () == " >=" )
639- result.intvalue = f ? (floatValue1 >= floatValue2) : (value1.intvalue >= value2.intvalue );
640- else if (!f && parent->str () == " >>" && value1.intvalue >= 0 && value2.intvalue >= 0 && value2.intvalue < MathLib::bigint_bits)
641- result.intvalue = value1.intvalue >> value2.intvalue ;
642- else
643- break ;
644- setTokenValue (parent, result, settings);
645- break ;
646- }
647- case ' <' : {
648- const bool f = value1.isFloatValue () || value2.isFloatValue ();
649- if (!f && !value1.isIntValue () && !value2.isIntValue ())
650- break ;
651- if (parent->str () == " <" )
652- result.intvalue = f ? (floatValue1 < floatValue2) : (value1.intvalue < value2.intvalue );
653- else if (parent->str () == " <=" )
654- result.intvalue = f ? (floatValue1 <= floatValue2) : (value1.intvalue <= value2.intvalue );
655- else if (!f && parent->str () == " <<" && value1.intvalue >= 0 && value2.intvalue >= 0 && value2.intvalue < MathLib::bigint_bits)
656- result.intvalue = value1.intvalue << value2.intvalue ;
657- else
658- break ;
659- setTokenValue (parent, result, settings);
660- break ;
661- }
662- case ' &' :
663- if (!value1.isIntValue () || !value2.isIntValue ())
664- break ;
665- if (parent->str () == " &" )
666- result.intvalue = value1.intvalue & value2.intvalue ;
667- else
668- result.intvalue = value1.intvalue && value2.intvalue ;
669- setTokenValue (parent, result, settings);
670- break ;
671- case ' |' :
672- if (!value1.isIntValue () || !value2.isIntValue ())
673- break ;
674- if (parent->str () == " |" )
675- result.intvalue = value1.intvalue | value2.intvalue ;
676- else
677- result.intvalue = value1.intvalue || value2.intvalue ;
678- setTokenValue (parent, result, settings);
679- break ;
680- case ' ^' :
681- if (!value1.isIntValue () || !value2.isIntValue ())
682- break ;
683- result.intvalue = value1.intvalue ^ value2.intvalue ;
684- setTokenValue (parent, result, settings);
685- break ;
686- default :
687- // unhandled operator, do nothing
688- break ;
689655 }
690656 }
691657 }
0 commit comments