cppcheck/lib/analyzer.h

196 lines
5.6 KiB
C
Raw Normal View History

2020-11-10 16:00:55 +01:00
/*
* Cppcheck - A tool for static C/C++ code analysis
2023-01-28 10:16:34 +01:00
* Copyright (C) 2007-2023 Cppcheck team.
2020-11-10 16:00:55 +01: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 analyzerH
#define analyzerH
#include "config.h"
2021-10-11 19:10:37 +02:00
#include "mathlib.h"
2020-11-10 16:00:55 +01:00
#include <string>
#include <type_traits>
2020-11-10 16:00:55 +01:00
#include <vector>
class Token;
2021-08-07 20:51:18 +02:00
template<class T>
2020-11-10 16:00:55 +01:00
class ValuePtr;
struct Analyzer {
struct Action {
Action() = default;
Action(const Action&) = default;
Action& operator=(const Action& rhs) = default;
2020-11-10 16:00:55 +01:00
template<class T,
REQUIRES("T must be convertible to unsigned int", std::is_convertible<T, unsigned int> ),
REQUIRES("T must not be a bool", !std::is_same<T, bool> )>
// NOLINTNEXTLINE(google-explicit-constructor)
2021-08-09 09:55:24 +02:00
Action(T f) : mFlag(f) // cppcheck-suppress noExplicitConstructor
{}
2020-11-10 16:00:55 +01:00
enum {
None = 0,
Read = (1 << 0),
Write = (1 << 1),
Invalid = (1 << 2),
Inconclusive = (1 << 3),
Match = (1 << 4),
Idempotent = (1 << 5),
Incremental = (1 << 6),
SymbolicMatch = (1 << 7),
Internal = (1 << 8),
2020-11-10 16:00:55 +01:00
};
2020-11-11 09:15:36 +01:00
void set(unsigned int f, bool state = true) {
mFlag = state ? mFlag | f : mFlag & ~f;
}
2020-11-10 16:00:55 +01:00
2020-11-11 09:15:36 +01:00
bool get(unsigned int f) const {
return ((mFlag & f) != 0);
}
2020-11-10 16:00:55 +01:00
2020-11-11 09:15:36 +01:00
bool isRead() const {
return get(Read);
}
2020-11-10 16:00:55 +01:00
2020-11-11 09:15:36 +01:00
bool isWrite() const {
return get(Write);
}
2020-11-10 16:00:55 +01:00
2020-11-11 09:15:36 +01:00
bool isInvalid() const {
return get(Invalid);
}
2020-11-10 16:00:55 +01:00
2020-11-11 09:15:36 +01:00
bool isInconclusive() const {
return get(Inconclusive);
}
2020-11-10 16:00:55 +01:00
2020-11-11 09:15:36 +01:00
bool isNone() const {
return mFlag == None;
}
2020-11-10 16:00:55 +01:00
2020-11-11 09:15:36 +01:00
bool isModified() const {
return isWrite() || isInvalid();
}
2020-11-10 16:00:55 +01:00
2020-11-11 09:15:36 +01:00
bool isIdempotent() const {
return get(Idempotent);
}
2020-11-10 16:00:55 +01:00
bool isIncremental() const {
return get(Incremental);
}
2021-08-07 20:51:18 +02:00
bool isSymbolicMatch() const {
return get(SymbolicMatch);
}
bool isInternal() const {
return get(Internal);
}
2020-11-11 09:15:36 +01:00
bool matches() const {
return get(Match);
}
2020-11-10 16:00:55 +01:00
2020-11-11 09:15:36 +01:00
Action& operator|=(Action a) {
2020-11-10 16:00:55 +01:00
set(a.mFlag);
return *this;
}
2020-11-11 09:15:36 +01:00
friend Action operator|(Action a, Action b) {
2020-11-10 16:00:55 +01:00
a |= b;
return a;
}
2020-11-11 09:15:36 +01:00
friend bool operator==(Action a, Action b) {
return a.mFlag == b.mFlag;
}
2020-11-10 16:00:55 +01:00
2020-11-11 09:15:36 +01:00
friend bool operator!=(Action a, Action b) {
return a.mFlag != b.mFlag;
}
2020-11-10 16:00:55 +01:00
2020-11-11 09:15:36 +01:00
private:
unsigned int mFlag{};
2020-11-10 16:00:55 +01:00
};
enum class Terminate { None, Bail, Escape, Modified, Inconclusive, Conditional };
struct Result {
explicit Result(Action action = Action::None, Terminate terminate = Terminate::None)
: action(action), terminate(terminate)
{}
Action action;
Terminate terminate;
2021-07-18 10:01:22 +02:00
void update(Result rhs) {
if (terminate == Terminate::None)
terminate = rhs.terminate;
action |= rhs.action;
}
};
2020-11-10 16:00:55 +01:00
enum class Direction { Forward, Reverse };
struct Assume {
enum Flags {
None = 0,
Quiet = (1 << 0),
Absolute = (1 << 1),
ContainerEmpty = (1 << 2),
};
};
enum class Evaluate { Integral, ContainerEmpty };
2020-11-10 16:00:55 +01:00
/// Analyze a token
virtual Action analyze(const Token* tok, Direction d) const = 0;
/// Update the state of the value
virtual void update(Token* tok, Action a, Direction d) = 0;
/// Try to evaluate the value of a token(most likely a condition)
2021-10-11 19:10:37 +02:00
virtual std::vector<MathLib::bigint> evaluate(Evaluate e, const Token* tok, const Token* ctx = nullptr) const = 0;
std::vector<MathLib::bigint> evaluate(const Token* tok, const Token* ctx = nullptr) const
{
return evaluate(Evaluate::Integral, tok, ctx);
}
2020-11-10 16:00:55 +01:00
/// Lower any values to possible
virtual bool lowerToPossible() = 0;
/// Lower any values to inconclusive
virtual bool lowerToInconclusive() = 0;
/// If the analysis is unsure whether to update a scope, this will return true if the analysis should bifurcate the scope
virtual bool updateScope(const Token* endBlock, bool modified) const = 0;
/// If the value is conditional
virtual bool isConditional() const = 0;
/// If analysis should stop on the condition
virtual bool stopOnCondition(const Token* condTok) const = 0;
2020-11-10 16:00:55 +01:00
/// The condition that will be assumed during analysis
virtual void assume(const Token* tok, bool state, unsigned int flags = 0) = 0;
2020-11-10 16:00:55 +01:00
/// Return analyzer for expression at token
virtual ValuePtr<Analyzer> reanalyze(Token* tok, const std::string& msg = emptyString) const = 0;
virtual bool invalid() const {
return false;
}
virtual ~Analyzer() = default;
Analyzer(const Analyzer&) = default;
protected:
Analyzer() = default;
2020-11-10 16:00:55 +01:00
};
#endif