| 793 | } |
| 794 | |
| 795 | void CheckOtherImpl::redundantBitwiseOperationInSwitchError() |
| 796 | { |
| 797 | if (!mSettings.severity.isEnabled(Severity::warning)) |
| 798 | return; |
| 799 | |
| 800 | logChecker("CheckOther::redundantBitwiseOperationInSwitch"); // warning |
| 801 | |
| 802 | const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); |
| 803 | |
| 804 | // Find the beginning of a switch. E.g.: |
| 805 | // switch (var) { ... |
| 806 | for (const Scope &switchScope : symbolDatabase->scopeList) { |
| 807 | if (switchScope.type != ScopeType::eSwitch || !switchScope.bodyStart) |
| 808 | continue; |
| 809 | |
| 810 | // Check the contents of the switch statement |
| 811 | std::map<int, const Token*> varsWithBitsSet; |
| 812 | std::map<int, std::string> bitOperations; |
| 813 | |
| 814 | for (const Token *tok2 = switchScope.bodyStart->next(); tok2 != switchScope.bodyEnd; tok2 = tok2->next()) { |
| 815 | if (tok2->str() == "{") { |
| 816 | // Inside a conditional or loop. Don't mark variable accesses as being redundant. E.g.: |
| 817 | // case 3: b = 1; |
| 818 | // case 4: if (a) { b = 2; } // Doesn't make the b=1 redundant because it's conditional |
| 819 | if (Token::Match(tok2->previous(), ")|else {") && tok2->link()) { |
| 820 | const Token* endOfConditional = tok2->link(); |
| 821 | for (const Token* tok3 = tok2; tok3 != endOfConditional; tok3 = tok3->next()) { |
| 822 | if (tok3->varId() != 0) { |
| 823 | varsWithBitsSet.erase(tok3->varId()); |
| 824 | bitOperations.erase(tok3->varId()); |
| 825 | } else if (isFunctionOrBreakPattern(tok3)) { |
| 826 | varsWithBitsSet.clear(); |
| 827 | bitOperations.clear(); |
| 828 | } |
| 829 | } |
| 830 | tok2 = endOfConditional; |
| 831 | } |
| 832 | } |
| 833 | |
| 834 | // Variable assignment. Report an error if it's assigned to twice before a break. E.g.: |
| 835 | // case 3: b = 1; // <== redundant |
| 836 | // case 4: b = 2; |
| 837 | |
| 838 | if (Token::Match(tok2->previous(), ";|{|}|: %var% = %any% ;")) { |
| 839 | varsWithBitsSet.erase(tok2->varId()); |
| 840 | bitOperations.erase(tok2->varId()); |
| 841 | } |
| 842 | |
| 843 | // Bitwise operation. Report an error if it's performed twice before a break. E.g.: |
| 844 | // case 3: b |= 1; // <== redundant |
| 845 | // case 4: b |= 1; |
| 846 | else if (Token::Match(tok2->previous(), ";|{|}|: %var% %assign% %num% ;") && |
| 847 | (tok2->strAt(1) == "|=" || tok2->strAt(1) == "&=") && |
| 848 | Token::Match(tok2->next()->astOperand2(), "%num%")) { |
| 849 | std::string bitOp = tok2->strAt(1)[0] + tok2->strAt(2); |
| 850 | const auto i2 = utils::as_const(varsWithBitsSet).find(tok2->varId()); |
| 851 | |
| 852 | // This variable has not had a bit operation performed on it yet, so just make a note of it |
no test coverage detected