| 1471 | } |
| 1472 | |
| 1473 | Action isWritable(const Token* tok, Direction /*d*/) const override |
| 1474 | { |
| 1475 | if (astIsIterator(tok)) |
| 1476 | return Action::None; |
| 1477 | if (!getValue(tok)) |
| 1478 | return Action::None; |
| 1479 | if (!tok->valueType()) |
| 1480 | return Action::None; |
| 1481 | if (!astIsContainer(tok)) |
| 1482 | return Action::None; |
| 1483 | const Token* parent = tok->astParent(); |
| 1484 | const Library::Container* container = getLibraryContainer(tok); |
| 1485 | |
| 1486 | if (container->stdStringLike && Token::simpleMatch(parent, "+=") && astIsLHS(tok) && parent->astOperand2()) { |
| 1487 | const Token* rhs = parent->astOperand2(); |
| 1488 | if (rhs->tokType() == Token::eString) |
| 1489 | return Action::Read | Action::Write | Action::Incremental; |
| 1490 | const Library::Container* rhsContainer = getLibraryContainer(rhs); |
| 1491 | if (rhsContainer && rhsContainer->stdStringLike) { |
| 1492 | if (std::any_of(rhs->values().cbegin(), rhs->values().cend(), [&](const ValueFlow::Value &rhsval) { |
| 1493 | return rhsval.isKnown() && rhsval.isContainerSizeValue(); |
| 1494 | })) |
| 1495 | return Action::Read | Action::Write | Action::Incremental; |
| 1496 | } |
| 1497 | } else if (astIsLHS(tok) && Token::Match(tok->astParent(), ". %name% (")) { |
| 1498 | const Library::Container::Action action = container->getAction(tok->astParent()->strAt(1)); |
| 1499 | if (action == Library::Container::Action::PUSH || action == Library::Container::Action::POP || action == Library::Container::Action::APPEND) { // TODO: handle more actions? |
| 1500 | std::vector<const Token*> args = getArguments(tok->tokAt(3)); |
| 1501 | bool isVariadic = false; |
| 1502 | if (const Library::Function* libFunc = settings.library.getFunction(tok->tokAt(2))) { |
| 1503 | const auto& argChecks = libFunc->argumentChecks; |
| 1504 | isVariadic = argChecks.find(-1) != argChecks.end() && argChecks.at(-1).variadic; |
| 1505 | } |
| 1506 | if (args.size() < 2 || action == Library::Container::Action::APPEND || isVariadic) |
| 1507 | return Action::Read | Action::Write | Action::Incremental; |
| 1508 | } |
| 1509 | } |
| 1510 | return Action::None; |
| 1511 | } |
| 1512 | |
| 1513 | void writeValue(ValueFlow::Value* val, const Token* tok, Direction d) const override { |
| 1514 | if (!val) |
nothing calls this directly
no test coverage detected