@@ -57,6 +57,7 @@ class TestValueFlow : public TestFixture {
5757
5858 TEST_CASE (valueFlowNumber);
5959 TEST_CASE (valueFlowString);
60+ TEST_CASE (valueFlowTypeTraits);
6061 TEST_CASE (valueFlowPointerAlias);
6162 TEST_CASE (valueFlowLifetime);
6263 TEST_CASE (valueFlowArrayElement);
@@ -532,6 +533,21 @@ class TestValueFlow : public TestFixture {
532533 return values.size () == 1U && !values.front ().isTokValue () ? values.front () : ValueFlow::Value ();
533534 }
534535
536+ #define testKnownValueOfTok (...) testKnownValueOfTok_(__FILE__, __LINE__, __VA_ARGS__)
537+ bool testKnownValueOfTok_ (const char * file,
538+ int line,
539+ const char code[],
540+ const char tokstr[],
541+ int value,
542+ const Settings* s = nullptr ,
543+ bool cpp = true )
544+ {
545+ std::list<ValueFlow::Value> values = removeImpossible (tokenValues_ (file, line, code, tokstr, s, cpp));
546+ return std::any_of (values.begin (), values.end (), [&](const ValueFlow::Value& v) {
547+ return v.isKnown () && v.isIntValue () && v.intvalue == value;
548+ });
549+ }
550+
535551 static std::list<ValueFlow::Value> removeSymbolicTok (std::list<ValueFlow::Value> values)
536552 {
537553 values.remove_if ([](const ValueFlow::Value& v) {
@@ -596,6 +612,136 @@ class TestValueFlow : public TestFixture {
596612 ASSERT_EQUALS (true , testValueOfX (code, 2 , " \" abc\" " , ValueFlow::Value::ValueType::TOK));
597613 }
598614
615+ void valueFlowTypeTraits ()
616+ {
617+ ASSERT_EQUALS (true , testKnownValueOfTok (" std::is_void<void>{};" , " {" , 1 ));
618+ ASSERT_EQUALS (true , testKnownValueOfTok (" std::is_void<void>::value;" , " :: value" , 1 ));
619+ ASSERT_EQUALS (true , testKnownValueOfTok (" std::is_void_v<void>;" , " ::" , 1 ));
620+
621+ // is_void
622+ ASSERT_EQUALS (true , testKnownValueOfTok (" std::is_void<int>{};" , " {" , 0 ));
623+ ASSERT_EQUALS (true , testKnownValueOfTok (" std::is_void<void*>{};" , " {" , 0 ));
624+ ASSERT_EQUALS (true , testKnownValueOfTok (" std::is_void<const void>{};" , " {" , 1 ));
625+ ASSERT_EQUALS (true , testKnownValueOfTok (" std::is_void<volatile void>{};" , " {" , 1 ));
626+
627+ // is_lvalue_reference
628+ ASSERT_EQUALS (true , testKnownValueOfTok (" std::is_lvalue_reference<int>{};" , " {" , 0 ));
629+ ASSERT_EQUALS (true , testKnownValueOfTok (" std::is_lvalue_reference<int&>{};" , " {" , 1 ));
630+ ASSERT_EQUALS (true , testKnownValueOfTok (" std::is_lvalue_reference<int&&>{};" , " {" , 0 ));
631+
632+ // is_rvalue_reference
633+ ASSERT_EQUALS (true , testKnownValueOfTok (" std::is_rvalue_reference<int>{};" , " {" , 0 ));
634+ ASSERT_EQUALS (true , testKnownValueOfTok (" std::is_rvalue_reference<int&>{};" , " {" , 0 ));
635+ ASSERT_EQUALS (true , testKnownValueOfTok (" std::is_rvalue_reference<int&&>{};" , " {" , 1 ));
636+
637+ // is_reference
638+ ASSERT_EQUALS (true , testKnownValueOfTok (" std::is_reference<int>{};" , " {" , 0 ));
639+ ASSERT_EQUALS (true , testKnownValueOfTok (" std::is_reference<int&>{};" , " {" , 1 ));
640+ ASSERT_EQUALS (true , testKnownValueOfTok (" std::is_reference<int&&>{};" , " {" , 1 ));
641+
642+ {
643+ const char * code;
644+ code = " void bar();\n "
645+ " void foo() { std::is_void<decltype(bar())>::value; }" ;
646+ ASSERT_EQUALS (true , testKnownValueOfTok (code, " :: value" , 1 ));
647+
648+ code = " int bar();\n "
649+ " void foo() { std::is_void<decltype(bar())>::value; }" ;
650+ ASSERT_EQUALS (true , testKnownValueOfTok (code, " :: value" , 0 ));
651+
652+ code = " void bar();\n "
653+ " void foo() { std::is_void<decltype(bar)>::value; }" ;
654+ ASSERT_EQUALS (true , testKnownValueOfTok (code, " :: value" , 0 ));
655+
656+ code = " class A;\n "
657+ " void foo() { std::is_lvalue_reference<A>::value; }" ;
658+ ASSERT_EQUALS (true , testKnownValueOfTok (code, " :: value" , 0 ));
659+
660+ code = " class A;\n "
661+ " void foo() { std::is_lvalue_reference<A&>::value; }" ;
662+ ASSERT_EQUALS (true , testKnownValueOfTok (code, " :: value" , 1 ));
663+
664+ code = " class A;\n "
665+ " void foo() { std::is_lvalue_reference<A&&>::value; }" ;
666+ ASSERT_EQUALS (true , testKnownValueOfTok (code, " :: value" , 0 ));
667+
668+ code = " class A;\n "
669+ " void foo() { std::is_rvalue_reference<A>::value; }" ;
670+ ASSERT_EQUALS (true , testKnownValueOfTok (code, " :: value" , 0 ));
671+
672+ code = " class A;\n "
673+ " void foo() { std::is_rvalue_reference<A&>::value; }" ;
674+ ASSERT_EQUALS (true , testKnownValueOfTok (code, " :: value" , 0 ));
675+
676+ code = " class A;\n "
677+ " void foo() { std::is_rvalue_reference<A&&>::value; }" ;
678+ ASSERT_EQUALS (true , testKnownValueOfTok (code, " :: value" , 1 ));
679+
680+ code = " class A;\n "
681+ " void foo() { std::is_reference<A>::value; }" ;
682+ ASSERT_EQUALS (true , testKnownValueOfTok (code, " :: value" , 0 ));
683+
684+ code = " class A;\n "
685+ " void foo() { std::is_reference<A&>::value; }" ;
686+ ASSERT_EQUALS (true , testKnownValueOfTok (code, " :: value" , 1 ));
687+
688+ code = " class A;\n "
689+ " void foo() { std::is_reference<A&&>::value; }" ;
690+ ASSERT_EQUALS (true , testKnownValueOfTok (code, " :: value" , 1 ));
691+
692+ code = " void foo() {\n "
693+ " int bar;\n "
694+ " std::is_void<decltype(bar)>::value;\n "
695+ " }\n " ;
696+ ASSERT_EQUALS (true , testKnownValueOfTok (code, " :: value" , 0 ));
697+
698+ code = " void foo(int bar) {\n "
699+ " std::is_lvalue_reference<decltype(bar)>::value;\n "
700+ " }\n " ;
701+ ASSERT_EQUALS (true , testKnownValueOfTok (code, " :: value" , 0 ));
702+
703+ code = " void foo(int& bar) {\n "
704+ " std::is_lvalue_reference<decltype(bar)>::value;\n "
705+ " }\n " ;
706+ ASSERT_EQUALS (true , testKnownValueOfTok (code, " :: value" , 1 ));
707+
708+ code = " void foo(int&& bar) {\n "
709+ " std::is_lvalue_reference<decltype(bar)>::value;\n "
710+ " }\n " ;
711+ ASSERT_EQUALS (true , testKnownValueOfTok (code, " :: value" , 0 ));
712+
713+ code = " void foo(int bar) {\n "
714+ " std::is_rvalue_reference<decltype(bar)>::value;\n "
715+ " }\n " ;
716+ ASSERT_EQUALS (true , testKnownValueOfTok (code, " :: value" , 0 ));
717+
718+ code = " void foo(int& bar) {\n "
719+ " std::is_rvalue_reference<decltype(bar)>::value;\n "
720+ " }\n " ;
721+ ASSERT_EQUALS (true , testKnownValueOfTok (code, " :: value" , 0 ));
722+
723+ code = " void foo(int&& bar) {\n "
724+ " std::is_rvalue_reference<decltype(bar)>::value;\n "
725+ " }\n " ;
726+ ASSERT_EQUALS (true , testKnownValueOfTok (code, " :: value" , 1 ));
727+
728+ code = " void foo(int bar) {\n "
729+ " std::is_reference<decltype(bar)>::value;\n "
730+ " }\n " ;
731+ ASSERT_EQUALS (true , testKnownValueOfTok (code, " :: value" , 0 ));
732+
733+ code = " void foo(int& bar) {\n "
734+ " std::is_reference<decltype(bar)>::value;\n "
735+ " }\n " ;
736+ ASSERT_EQUALS (true , testKnownValueOfTok (code, " :: value" , 1 ));
737+
738+ code = " void foo(int&& bar) {\n "
739+ " std::is_reference<decltype(bar)>::value;\n "
740+ " }\n " ;
741+ ASSERT_EQUALS (true , testKnownValueOfTok (code, " :: value" , 1 ));
742+ }
743+ }
744+
599745 void valueFlowPointerAlias () {
600746 const char *code;
601747 std::list<ValueFlow::Value> values;
0 commit comments