2015-08-02 21:57:32 +02:00
|
|
|
/*
|
|
|
|
* Cppcheck - A tool for static C/C++ code analysis
|
2022-02-05 11:45:17 +01:00
|
|
|
* Copyright (C) 2007-2022 Cppcheck team.
|
2015-08-02 21:57:32 +02: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/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
#ifndef astutilsH
|
|
|
|
#define astutilsH
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2018-11-23 06:53:43 +01:00
|
|
|
#include <functional>
|
2020-04-13 13:44:48 +02:00
|
|
|
#include <set>
|
2022-02-13 20:46:01 +01:00
|
|
|
#include <stack>
|
2015-08-03 09:20:50 +02:00
|
|
|
#include <string>
|
2022-08-14 12:44:19 +02:00
|
|
|
#include <type_traits>
|
|
|
|
#include <utility>
|
2017-04-20 19:57:39 +02:00
|
|
|
#include <vector>
|
2015-08-02 21:57:32 +02:00
|
|
|
|
2022-02-11 19:44:08 +01:00
|
|
|
#include "config.h"
|
2020-05-23 07:16:49 +02:00
|
|
|
#include "errortypes.h"
|
2022-08-14 12:44:19 +02:00
|
|
|
#include "library.h"
|
2022-09-29 21:41:32 +02:00
|
|
|
#include "smallvector.h"
|
2022-03-22 21:50:46 +01:00
|
|
|
#include "symboldatabase.h"
|
2018-08-07 09:32:16 +02:00
|
|
|
|
2017-05-27 04:33:47 +02:00
|
|
|
class Settings;
|
2015-08-03 09:20:50 +02:00
|
|
|
class Token;
|
|
|
|
|
2018-11-23 06:53:43 +01:00
|
|
|
enum class ChildrenToVisit {
|
|
|
|
none,
|
|
|
|
op1,
|
|
|
|
op2,
|
|
|
|
op1_and_op2,
|
|
|
|
done // found what we looked for, don't visit any more children
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Visit AST nodes recursively. The order is not "well defined"
|
|
|
|
*/
|
2022-02-13 20:46:01 +01:00
|
|
|
template<class T, class TFunc, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
|
|
|
|
void visitAstNodes(T *ast, const TFunc &visitor)
|
|
|
|
{
|
|
|
|
if (!ast)
|
|
|
|
return;
|
|
|
|
|
2022-06-03 19:21:17 +02:00
|
|
|
// the size of 8 was determined in tests to be sufficient to avoid excess allocations. also add 1 as a buffer.
|
|
|
|
// we might need to increase that value in the future.
|
2022-09-29 21:52:42 +02:00
|
|
|
std::stack<T *, SmallVector<T *, 8 + 1>> tokens;
|
2022-02-13 20:46:01 +01:00
|
|
|
T *tok = ast;
|
|
|
|
do {
|
2022-10-02 07:12:40 +02:00
|
|
|
const ChildrenToVisit c = visitor(tok);
|
2022-02-13 20:46:01 +01:00
|
|
|
|
|
|
|
if (c == ChildrenToVisit::done)
|
|
|
|
break;
|
|
|
|
if (c == ChildrenToVisit::op2 || c == ChildrenToVisit::op1_and_op2) {
|
|
|
|
T *t2 = tok->astOperand2();
|
|
|
|
if (t2)
|
|
|
|
tokens.push(t2);
|
|
|
|
}
|
|
|
|
if (c == ChildrenToVisit::op1 || c == ChildrenToVisit::op1_and_op2) {
|
|
|
|
T *t1 = tok->astOperand1();
|
|
|
|
if (t1)
|
|
|
|
tokens.push(t1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tokens.empty())
|
|
|
|
break;
|
|
|
|
|
|
|
|
tok = tokens.top();
|
|
|
|
tokens.pop();
|
|
|
|
} while (true);
|
|
|
|
}
|
2018-11-23 06:53:43 +01:00
|
|
|
|
2022-05-31 13:37:21 +02:00
|
|
|
template<class TFunc>
|
|
|
|
const Token* findAstNode(const Token* ast, const TFunc& pred)
|
|
|
|
{
|
|
|
|
const Token* result = nullptr;
|
|
|
|
visitAstNodes(ast, [&](const Token* tok) {
|
|
|
|
if (pred(tok)) {
|
|
|
|
result = tok;
|
|
|
|
return ChildrenToVisit::done;
|
|
|
|
}
|
|
|
|
return ChildrenToVisit::op1_and_op2;
|
|
|
|
});
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-01-27 19:49:13 +01:00
|
|
|
const Token* findExpression(const nonneg int exprid,
|
2021-01-23 17:52:01 +01:00
|
|
|
const Token* start,
|
|
|
|
const Token* end,
|
|
|
|
const std::function<bool(const Token*)>& pred);
|
2021-08-23 09:03:48 +02:00
|
|
|
const Token* findExpression(const Token* start, const nonneg int exprid);
|
2020-12-03 07:15:31 +01:00
|
|
|
|
2019-08-23 06:23:21 +02:00
|
|
|
std::vector<const Token*> astFlatten(const Token* tok, const char* op);
|
2021-10-15 10:58:16 +02:00
|
|
|
std::vector<Token*> astFlatten(Token* tok, const char* op);
|
2019-08-23 06:23:21 +02:00
|
|
|
|
2022-05-13 06:51:07 +02:00
|
|
|
nonneg int astCount(const Token* tok, const char* op, int depth = 100);
|
|
|
|
|
2019-08-29 08:38:50 +02:00
|
|
|
bool astHasToken(const Token* root, const Token * tok);
|
|
|
|
|
|
|
|
bool astHasVar(const Token * tok, nonneg int varid);
|
|
|
|
|
2021-11-07 18:19:56 +01:00
|
|
|
bool astIsPrimitive(const Token* tok);
|
2015-08-03 09:20:50 +02:00
|
|
|
/** Is expression a 'signed char' if no promotion is used */
|
|
|
|
bool astIsSignedChar(const Token *tok);
|
2016-02-08 08:08:35 +01:00
|
|
|
/** Is expression a 'char' if no promotion is used? */
|
|
|
|
bool astIsUnknownSignChar(const Token *tok);
|
2021-10-02 23:09:49 +02:00
|
|
|
/** Is expression a char according to valueType? */
|
|
|
|
bool astIsGenericChar(const Token* tok);
|
2015-08-02 21:57:32 +02:00
|
|
|
/** Is expression of integral type? */
|
|
|
|
bool astIsIntegral(const Token *tok, bool unknown);
|
2021-03-30 14:02:28 +02:00
|
|
|
bool astIsUnsigned(const Token* tok);
|
2015-08-02 21:57:32 +02:00
|
|
|
/** Is expression of floating point type? */
|
|
|
|
bool astIsFloat(const Token *tok, bool unknown);
|
2016-02-05 15:48:51 +01:00
|
|
|
/** Is expression of boolean type? */
|
|
|
|
bool astIsBool(const Token *tok);
|
2015-08-02 21:57:32 +02:00
|
|
|
|
2018-11-12 10:08:17 +01:00
|
|
|
bool astIsPointer(const Token *tok);
|
|
|
|
|
2019-09-30 21:04:43 +02:00
|
|
|
bool astIsSmartPointer(const Token* tok);
|
2021-11-11 08:00:05 +01:00
|
|
|
bool astIsUniqueSmartPointer(const Token* tok);
|
2019-09-30 21:04:43 +02:00
|
|
|
|
2018-11-17 09:41:59 +01:00
|
|
|
bool astIsIterator(const Token *tok);
|
|
|
|
|
|
|
|
bool astIsContainer(const Token *tok);
|
|
|
|
|
2021-10-05 08:28:19 +02:00
|
|
|
bool astIsContainerView(const Token* tok);
|
|
|
|
bool astIsContainerOwned(const Token* tok);
|
|
|
|
|
2022-06-19 08:17:05 +02:00
|
|
|
Library::Container::Action astContainerAction(const Token* tok, const Token** ftok = nullptr);
|
|
|
|
Library::Container::Yield astContainerYield(const Token* tok, const Token** ftok = nullptr);
|
2022-06-16 17:40:09 +02:00
|
|
|
|
2022-06-03 19:24:59 +02:00
|
|
|
/** Is given token a range-declaration in a range-based for loop */
|
|
|
|
bool astIsRangeBasedForDecl(const Token* tok);
|
|
|
|
|
2015-08-10 09:41:06 +02:00
|
|
|
/**
|
|
|
|
* Get canonical type of expression. const/static/etc are not included and neither *&.
|
|
|
|
* For example:
|
|
|
|
* Expression type Return
|
|
|
|
* std::string std::string
|
|
|
|
* int * int
|
|
|
|
* static const int int
|
|
|
|
* std::vector<T> std::vector
|
|
|
|
*/
|
|
|
|
std::string astCanonicalType(const Token *expr);
|
|
|
|
|
2015-08-03 09:20:50 +02:00
|
|
|
/** Is given syntax tree a variable comparison against value */
|
|
|
|
const Token * astIsVariableComparison(const Token *tok, const std::string &comp, const std::string &rhs, const Token **vartok=nullptr);
|
|
|
|
|
2022-02-28 18:54:55 +01:00
|
|
|
bool isVariableDecl(const Token* tok);
|
2022-08-20 20:52:10 +02:00
|
|
|
bool isStlStringType(const Token* tok);
|
2022-02-28 18:54:55 +01:00
|
|
|
|
2020-02-10 18:01:11 +01:00
|
|
|
bool isTemporary(bool cpp, const Token* tok, const Library* library, bool unknown = false);
|
2019-10-08 09:28:39 +02:00
|
|
|
|
2020-11-10 16:00:55 +01:00
|
|
|
const Token* previousBeforeAstLeftmostLeaf(const Token* tok);
|
|
|
|
Token* previousBeforeAstLeftmostLeaf(Token* tok);
|
|
|
|
|
2018-10-18 11:56:23 +02:00
|
|
|
const Token * nextAfterAstRightmostLeaf(const Token * tok);
|
2020-02-13 16:27:06 +01:00
|
|
|
Token* nextAfterAstRightmostLeaf(Token* tok);
|
2018-10-18 11:56:23 +02:00
|
|
|
|
2019-08-15 21:14:27 +02:00
|
|
|
Token* astParentSkipParens(Token* tok);
|
|
|
|
const Token* astParentSkipParens(const Token* tok);
|
|
|
|
|
2019-11-05 07:10:32 +01:00
|
|
|
const Token* getParentMember(const Token * tok);
|
|
|
|
|
2020-05-31 10:10:10 +02:00
|
|
|
const Token* getParentLifetime(const Token* tok);
|
2022-02-24 06:50:34 +01:00
|
|
|
const Token* getParentLifetime(bool cpp, const Token* tok, const Library* library);
|
2020-05-31 10:10:10 +02:00
|
|
|
|
2022-09-04 10:24:45 +02:00
|
|
|
std::vector<ValueType> getParentValueTypes(const Token* tok,
|
|
|
|
const Settings* settings = nullptr,
|
|
|
|
const Token** parent = nullptr);
|
|
|
|
|
2020-02-11 11:45:10 +01:00
|
|
|
bool astIsLHS(const Token* tok);
|
|
|
|
bool astIsRHS(const Token* tok);
|
|
|
|
|
2020-02-13 16:27:06 +01:00
|
|
|
Token* getCondTok(Token* tok);
|
|
|
|
const Token* getCondTok(const Token* tok);
|
|
|
|
|
2021-11-14 18:30:36 +01:00
|
|
|
Token* getInitTok(Token* tok);
|
|
|
|
const Token* getInitTok(const Token* tok);
|
|
|
|
|
|
|
|
Token* getStepTok(Token* tok);
|
|
|
|
const Token* getStepTok(const Token* tok);
|
|
|
|
|
2020-02-13 16:27:06 +01:00
|
|
|
Token* getCondTokFromEnd(Token* endBlock);
|
|
|
|
const Token* getCondTokFromEnd(const Token* endBlock);
|
|
|
|
|
2020-12-25 08:43:14 +01:00
|
|
|
/// For a "break" token, locate the next token to execute. The token will
|
|
|
|
/// be either a "}" or a ";".
|
|
|
|
const Token *findNextTokenFromBreak(const Token *breakToken);
|
2020-12-24 22:58:19 +01:00
|
|
|
|
2020-06-28 13:41:27 +02:00
|
|
|
/**
|
|
|
|
* Extract for loop values: loopvar varid, init value, step value, last value (inclusive)
|
|
|
|
*/
|
|
|
|
bool extractForLoopValues(const Token *forToken,
|
|
|
|
nonneg int * const varid,
|
2020-06-29 21:01:43 +02:00
|
|
|
bool * const knownInitValue,
|
2020-06-28 13:41:27 +02:00
|
|
|
long long * const initValue,
|
2020-06-29 21:53:14 +02:00
|
|
|
bool * const partialCond,
|
2020-06-28 13:41:27 +02:00
|
|
|
long long * const stepValue,
|
|
|
|
long long * const lastValue);
|
|
|
|
|
2018-11-11 16:43:54 +01:00
|
|
|
bool precedes(const Token * tok1, const Token * tok2);
|
2022-01-13 17:24:26 +01:00
|
|
|
bool succeeds(const Token* tok1, const Token* tok2);
|
2018-11-11 16:43:54 +01:00
|
|
|
|
2021-10-23 14:47:10 +02:00
|
|
|
bool exprDependsOnThis(const Token* expr, bool onVar = true, nonneg int depth = 0);
|
2019-09-30 21:04:43 +02:00
|
|
|
|
2021-02-09 15:27:46 +01:00
|
|
|
struct ReferenceToken {
|
|
|
|
const Token* token;
|
|
|
|
ErrorPath errors;
|
|
|
|
};
|
|
|
|
|
2022-09-29 21:41:32 +02:00
|
|
|
SmallVector<ReferenceToken> followAllReferences(const Token* tok,
|
2021-09-05 07:35:33 +02:00
|
|
|
bool temporary = true,
|
|
|
|
bool inconclusive = true,
|
|
|
|
ErrorPath errors = ErrorPath{},
|
|
|
|
int depth = 20);
|
2021-02-09 15:27:46 +01:00
|
|
|
const Token* followReferences(const Token* tok, ErrorPath* errors = nullptr);
|
|
|
|
|
2018-09-28 08:38:24 +02:00
|
|
|
bool isSameExpression(bool cpp, bool macro, const Token *tok1, const Token *tok2, const Library& library, bool pure, bool followVar, ErrorPath* errors=nullptr);
|
2015-08-03 09:20:50 +02:00
|
|
|
|
2018-03-24 07:58:37 +01:00
|
|
|
bool isEqualKnownValue(const Token * const tok1, const Token * const tok2);
|
|
|
|
|
2022-05-29 17:06:33 +02:00
|
|
|
bool isStructuredBindingVariable(const Variable* var);
|
|
|
|
|
2021-01-25 17:23:47 +01:00
|
|
|
/**
|
|
|
|
* Is token used a boolean, that is to say cast to a bool, or used as a condition in a if/while/for
|
|
|
|
*/
|
|
|
|
bool isUsedAsBool(const Token * const tok);
|
|
|
|
|
2015-08-03 09:20:50 +02:00
|
|
|
/**
|
|
|
|
* Are two conditions opposite
|
|
|
|
* @param isNot do you want to know if cond1 is !cond2 or if cond1 and cond2 are non-overlapping. true: cond1==!cond2 false: cond1==true => cond2==false
|
|
|
|
* @param cpp c++ file
|
|
|
|
* @param cond1 condition1
|
|
|
|
* @param cond2 condition2
|
2017-05-06 11:57:02 +02:00
|
|
|
* @param library files data
|
2019-06-30 09:17:42 +02:00
|
|
|
* @param pure boolean
|
2015-08-03 09:20:50 +02:00
|
|
|
*/
|
2018-09-28 08:38:24 +02:00
|
|
|
bool isOppositeCond(bool isNot, bool cpp, const Token * const cond1, const Token * const cond2, const Library& library, bool pure, bool followVar, ErrorPath* errors=nullptr);
|
2015-08-03 09:20:50 +02:00
|
|
|
|
2018-09-28 08:38:24 +02:00
|
|
|
bool isOppositeExpression(bool cpp, const Token * const tok1, const Token * const tok2, const Library& library, bool pure, bool followVar, ErrorPath* errors=nullptr);
|
2018-05-02 06:32:33 +02:00
|
|
|
|
2021-07-18 07:46:31 +02:00
|
|
|
bool isConstFunctionCall(const Token* ftok, const Library& library);
|
|
|
|
|
2018-10-21 07:09:20 +02:00
|
|
|
bool isConstExpression(const Token *tok, const Library& library, bool pure, bool cpp);
|
2015-08-03 09:20:50 +02:00
|
|
|
|
2022-03-27 07:59:29 +02:00
|
|
|
bool isWithoutSideEffects(bool cpp, const Token* tok, bool checkArrayAccess = false, bool checkReference = true);
|
2015-08-03 09:20:50 +02:00
|
|
|
|
2018-05-13 20:20:55 +02:00
|
|
|
bool isUniqueExpression(const Token* tok);
|
|
|
|
|
2020-02-13 16:27:06 +01:00
|
|
|
bool isEscapeFunction(const Token* ftok, const Library* library);
|
|
|
|
|
2016-01-16 18:52:34 +01:00
|
|
|
/** Is scope a return scope (scope will unconditionally return) */
|
2020-02-13 16:27:06 +01:00
|
|
|
bool isReturnScope(const Token* const endToken,
|
|
|
|
const Library* library = nullptr,
|
|
|
|
const Token** unknownFunc = nullptr,
|
|
|
|
bool functionScope = false);
|
2016-01-16 18:52:34 +01:00
|
|
|
|
2022-03-22 21:50:46 +01:00
|
|
|
/** Is tok within a scope of the given type, nested within var's scope? */
|
|
|
|
bool isWithinScope(const Token* tok,
|
|
|
|
const Variable* var,
|
|
|
|
Scope::ScopeType type);
|
|
|
|
|
2019-09-06 21:18:45 +02:00
|
|
|
/// Return the token to the function and the argument number
|
|
|
|
const Token * getTokenArgumentFunction(const Token * tok, int& argn);
|
2021-11-25 22:34:00 +01:00
|
|
|
Token* getTokenArgumentFunction(Token* tok, int& argn);
|
2019-09-06 21:18:45 +02:00
|
|
|
|
2021-06-03 07:31:46 +02:00
|
|
|
std::vector<const Variable*> getArgumentVars(const Token* tok, int argnr);
|
|
|
|
|
2017-11-18 11:02:52 +01:00
|
|
|
/** Is variable changed by function call?
|
|
|
|
* In case the answer of the question is inconclusive, e.g. because the function declaration is not known
|
|
|
|
* the return value is false and the output parameter inconclusive is set to true
|
|
|
|
*
|
|
|
|
* @param tok ast tree
|
|
|
|
* @param varid Variable Id
|
|
|
|
* @param settings program settings
|
|
|
|
* @param inconclusive pointer to output variable which indicates that the answer of the question is inconclusive
|
|
|
|
*/
|
2019-08-30 18:32:45 +02:00
|
|
|
bool isVariableChangedByFunctionCall(const Token *tok, int indirect, nonneg int varid, const Settings *settings, bool *inconclusive);
|
2017-11-18 11:02:52 +01:00
|
|
|
|
2016-10-23 13:54:44 +02:00
|
|
|
/** Is variable changed by function call?
|
2016-11-04 15:01:05 +01:00
|
|
|
* In case the answer of the question is inconclusive, e.g. because the function declaration is not known
|
2016-10-23 13:54:44 +02:00
|
|
|
* the return value is false and the output parameter inconclusive is set to true
|
|
|
|
*
|
2016-11-04 15:01:05 +01:00
|
|
|
* @param tok token of variable in function call
|
2016-10-23 13:54:44 +02:00
|
|
|
* @param settings program settings
|
|
|
|
* @param inconclusive pointer to output variable which indicates that the answer of the question is inconclusive
|
|
|
|
*/
|
2019-08-30 18:32:45 +02:00
|
|
|
bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Settings *settings, bool *inconclusive);
|
2016-10-23 13:54:44 +02:00
|
|
|
|
2015-11-11 13:45:28 +01:00
|
|
|
/** Is variable changed in block of code? */
|
2020-09-14 09:17:29 +02:00
|
|
|
bool isVariableChanged(const Token *start, const Token *end, const nonneg int exprid, bool globalvar, const Settings *settings, bool cpp, int depth = 20);
|
|
|
|
bool isVariableChanged(const Token *start, const Token *end, int indirect, const nonneg int exprid, bool globalvar, const Settings *settings, bool cpp, int depth = 20);
|
2015-11-11 13:45:28 +01:00
|
|
|
|
2019-08-30 18:32:45 +02:00
|
|
|
bool isVariableChanged(const Token *tok, int indirect, const Settings *settings, bool cpp, int depth = 20);
|
2019-08-15 10:44:55 +02:00
|
|
|
|
2019-07-26 07:03:21 +02:00
|
|
|
bool isVariableChanged(const Variable * var, const Settings *settings, bool cpp, int depth = 20);
|
2019-08-16 07:48:54 +02:00
|
|
|
|
2019-09-26 10:32:25 +02:00
|
|
|
bool isVariablesChanged(const Token* start,
|
|
|
|
const Token* end,
|
|
|
|
int indirect,
|
|
|
|
std::vector<const Variable*> vars,
|
|
|
|
const Settings* settings,
|
|
|
|
bool cpp);
|
|
|
|
|
2021-07-18 07:46:31 +02:00
|
|
|
bool isThisChanged(const Token* tok, int indirect, const Settings* settings, bool cpp);
|
2020-07-13 20:55:45 +02:00
|
|
|
bool isThisChanged(const Token* start, const Token* end, int indirect, const Settings* settings, bool cpp);
|
2020-07-13 19:40:01 +02:00
|
|
|
|
2020-09-14 09:17:29 +02:00
|
|
|
const Token* findVariableChanged(const Token *start, const Token *end, int indirect, const nonneg int exprid, bool globalvar, const Settings *settings, bool cpp, int depth = 20);
|
|
|
|
Token* findVariableChanged(Token *start, const Token *end, int indirect, const nonneg int exprid, bool globalvar, const Settings *settings, bool cpp, int depth = 20);
|
2018-10-18 21:01:47 +02:00
|
|
|
|
2020-12-03 07:15:31 +01:00
|
|
|
bool isExpressionChanged(const Token* expr,
|
|
|
|
const Token* start,
|
|
|
|
const Token* end,
|
|
|
|
const Settings* settings,
|
|
|
|
bool cpp,
|
|
|
|
int depth = 20);
|
|
|
|
|
2021-08-23 09:03:48 +02:00
|
|
|
bool isExpressionChangedAt(const Token* expr,
|
|
|
|
const Token* tok,
|
|
|
|
int indirect,
|
|
|
|
bool globalvar,
|
|
|
|
const Settings* settings,
|
|
|
|
bool cpp,
|
|
|
|
int depth = 20);
|
|
|
|
|
2019-09-11 19:25:09 +02:00
|
|
|
/// If token is an alias if another variable
|
2020-09-20 14:27:09 +02:00
|
|
|
bool isAliasOf(const Token *tok, nonneg int varid, bool* inconclusive = nullptr);
|
2019-09-11 19:25:09 +02:00
|
|
|
|
2022-06-28 22:40:59 +02:00
|
|
|
bool isAliasOf(const Token* tok, const Token* expr, bool* inconclusive = nullptr);
|
|
|
|
|
2019-07-24 09:59:01 +02:00
|
|
|
bool isAliased(const Variable *var);
|
|
|
|
|
2022-05-13 06:51:07 +02:00
|
|
|
const Token* getArgumentStart(const Token* ftok);
|
|
|
|
|
2015-12-06 12:50:05 +01:00
|
|
|
/** Determines the number of arguments - if token is a function call or macro
|
2022-05-15 12:42:29 +02:00
|
|
|
* @param ftok start token which is supposed to be the function/macro name.
|
|
|
|
* @return Number of arguments
|
2015-12-06 12:50:05 +01:00
|
|
|
*/
|
2022-05-13 06:51:07 +02:00
|
|
|
int numberOfArguments(const Token* ftok);
|
|
|
|
|
|
|
|
/// Get number of arguments without using AST
|
|
|
|
int numberOfArgumentsWithoutAst(const Token* start);
|
2015-12-06 12:50:05 +01:00
|
|
|
|
2017-04-20 19:57:39 +02:00
|
|
|
/**
|
|
|
|
* Get arguments (AST)
|
|
|
|
*/
|
|
|
|
std::vector<const Token *> getArguments(const Token *ftok);
|
|
|
|
|
2021-01-11 18:47:38 +01:00
|
|
|
int getArgumentPos(const Variable* var, const Function* f);
|
|
|
|
|
2021-10-04 07:55:17 +02:00
|
|
|
/**
|
|
|
|
* Are the arguments a pair of iterators/pointers?
|
|
|
|
*/
|
|
|
|
bool isIteratorPair(std::vector<const Token*> args);
|
|
|
|
|
2019-04-15 06:37:27 +02:00
|
|
|
const Token *findLambdaStartToken(const Token *last);
|
|
|
|
|
2017-08-29 22:35:55 +02:00
|
|
|
/**
|
|
|
|
* find lambda function end token
|
|
|
|
* \param first The [ token
|
|
|
|
* \return nullptr or the }
|
|
|
|
*/
|
|
|
|
const Token *findLambdaEndToken(const Token *first);
|
2020-02-13 16:27:06 +01:00
|
|
|
Token* findLambdaEndToken(Token* first);
|
2017-08-29 22:35:55 +02:00
|
|
|
|
2019-07-24 09:59:01 +02:00
|
|
|
bool isLikelyStream(bool cpp, const Token *stream);
|
|
|
|
|
2018-04-17 14:23:04 +02:00
|
|
|
/**
|
|
|
|
* do we see a likely write of rhs through overloaded operator
|
|
|
|
* s >> x;
|
|
|
|
* a & x;
|
|
|
|
*/
|
|
|
|
bool isLikelyStreamRead(bool cpp, const Token *op);
|
|
|
|
|
2019-02-07 14:59:09 +01:00
|
|
|
bool isCPPCast(const Token* tok);
|
|
|
|
|
2022-08-07 19:06:19 +02:00
|
|
|
bool isConstVarExpression(const Token* tok, std::function<bool(const Token*)> skipPredicate = nullptr);
|
2018-12-17 06:04:24 +01:00
|
|
|
|
2022-09-11 12:32:01 +02:00
|
|
|
enum class ExprUsage { None, NotUsed, PassedByReference, Used, Inconclusive };
|
|
|
|
|
|
|
|
ExprUsage getExprUsage(const Token* tok, int indirect, const Settings* settings);
|
|
|
|
|
2019-07-07 10:16:19 +02:00
|
|
|
const Variable *getLHSVariable(const Token *tok);
|
|
|
|
|
2021-06-03 07:31:46 +02:00
|
|
|
const Token* getLHSVariableToken(const Token* tok);
|
|
|
|
|
2020-02-13 16:27:06 +01:00
|
|
|
std::vector<const Variable*> getLHSVariables(const Token* tok);
|
|
|
|
|
2021-05-13 20:21:02 +02:00
|
|
|
/** Find a allocation function call in expression, so result of expression is allocated memory/resource. */
|
|
|
|
const Token* findAllocFuncCallToken(const Token *expr, const Library &library);
|
|
|
|
|
2019-09-10 19:41:35 +02:00
|
|
|
bool isScopeBracket(const Token* tok);
|
|
|
|
|
2020-02-09 11:16:08 +01:00
|
|
|
bool isNullOperand(const Token *expr);
|
2020-02-16 16:02:22 +01:00
|
|
|
|
|
|
|
bool isGlobalData(const Token *expr, bool cpp);
|
2018-12-25 11:56:06 +01:00
|
|
|
/**
|
2018-12-31 18:00:47 +01:00
|
|
|
* Forward data flow analysis for checks
|
2018-12-25 11:56:06 +01:00
|
|
|
* - unused value
|
|
|
|
* - redundant assignment
|
2018-12-31 18:00:47 +01:00
|
|
|
* - valueflow analysis
|
2018-12-25 11:56:06 +01:00
|
|
|
*/
|
2018-12-31 18:00:47 +01:00
|
|
|
class FwdAnalysis {
|
2018-12-02 17:01:52 +01:00
|
|
|
public:
|
2019-01-01 18:23:47 +01:00
|
|
|
FwdAnalysis(bool cpp, const Library &library) : mCpp(cpp), mLibrary(library), mWhat(What::Reassign), mValueFlowKnown(true) {}
|
2018-12-02 17:01:52 +01:00
|
|
|
|
2018-12-02 18:29:16 +01:00
|
|
|
bool hasOperand(const Token *tok, const Token *lhs) const;
|
2018-12-02 17:01:52 +01:00
|
|
|
|
2018-12-02 17:42:18 +01:00
|
|
|
/**
|
2018-12-02 18:29:16 +01:00
|
|
|
* Check if "expr" is reassigned. The "expr" can be a tree (x.y[12]).
|
2018-12-02 17:42:18 +01:00
|
|
|
* @param expr Symbolic expression to perform forward analysis for
|
|
|
|
* @param startToken First token in forward analysis
|
|
|
|
* @param endToken Last token in forward analysis
|
2018-12-02 18:29:16 +01:00
|
|
|
* @return Token where expr is reassigned. If it's not reassigned then nullptr is returned.
|
2018-12-02 17:42:18 +01:00
|
|
|
*/
|
2018-12-02 18:29:16 +01:00
|
|
|
const Token *reassign(const Token *expr, const Token *startToken, const Token *endToken);
|
2018-12-02 17:01:52 +01:00
|
|
|
|
2018-12-13 18:52:56 +01:00
|
|
|
/**
|
|
|
|
* Check if "expr" is used. The "expr" can be a tree (x.y[12]).
|
|
|
|
* @param expr Symbolic expression to perform forward analysis for
|
|
|
|
* @param startToken First token in forward analysis
|
|
|
|
* @param endToken Last token in forward analysis
|
|
|
|
* @return true if expr is used.
|
|
|
|
*/
|
|
|
|
bool unusedValue(const Token *expr, const Token *startToken, const Token *endToken);
|
|
|
|
|
2019-01-01 18:23:47 +01:00
|
|
|
struct KnownAndToken {
|
|
|
|
bool known;
|
|
|
|
const Token *token;
|
|
|
|
};
|
|
|
|
|
2018-12-13 18:52:56 +01:00
|
|
|
/** Is there some possible alias for given expression */
|
|
|
|
bool possiblyAliased(const Token *expr, const Token *startToken) const;
|
|
|
|
|
2021-01-27 19:49:13 +01:00
|
|
|
std::set<nonneg int> getExprVarIds(const Token* expr, bool* localOut = nullptr, bool* unknownVarIdOut = nullptr) const;
|
2018-12-02 17:01:52 +01:00
|
|
|
private:
|
2019-06-29 07:46:25 +02:00
|
|
|
static bool isEscapedAlias(const Token* expr);
|
|
|
|
|
2018-12-02 18:29:16 +01:00
|
|
|
/** Result of forward analysis */
|
|
|
|
struct Result {
|
|
|
|
enum class Type { NONE, READ, WRITE, BREAK, RETURN, BAILOUT } type;
|
2018-12-04 18:46:23 +01:00
|
|
|
explicit Result(Type type) : type(type), token(nullptr) {}
|
2018-12-02 18:29:16 +01:00
|
|
|
Result(Type type, const Token *token) : type(type), token(token) {}
|
|
|
|
const Token *token;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Result check(const Token *expr, const Token *startToken, const Token *endToken);
|
2021-01-27 19:49:13 +01:00
|
|
|
struct Result checkRecursive(const Token *expr, const Token *startToken, const Token *endToken, const std::set<nonneg int> &exprVarIds, bool local, bool inInnerClass, int depth=0);
|
2018-12-02 17:01:52 +01:00
|
|
|
|
2018-12-13 18:52:56 +01:00
|
|
|
// Is expression a l-value global data?
|
|
|
|
bool isGlobalData(const Token *expr) const;
|
|
|
|
|
2018-12-02 17:01:52 +01:00
|
|
|
const bool mCpp;
|
|
|
|
const Library &mLibrary;
|
2018-12-31 17:05:46 +01:00
|
|
|
enum class What { Reassign, UnusedValue, ValueFlow } mWhat;
|
2019-01-01 18:23:47 +01:00
|
|
|
std::vector<KnownAndToken> mValueFlow;
|
|
|
|
bool mValueFlowKnown;
|
2018-12-02 17:01:52 +01:00
|
|
|
};
|
|
|
|
|
2021-10-03 18:12:29 +02:00
|
|
|
bool isSizeOfEtc(const Token *tok);
|
|
|
|
|
2015-08-02 21:57:32 +02:00
|
|
|
#endif // astutilsH
|