blob: 4e285492d048de88ab895ef05766dfc77803628d [file] [log] [blame]
/* A state machine for use in DejaGnu tests, to check that
pattern-matching works as expected.
Copyright (C) 2019-2021 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
This file is part of GCC.
GCC 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, or (at your option)
any later version.
GCC 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 GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "function.h"
#include "basic-block.h"
#include "gimple.h"
#include "tree-pretty-print.h"
#include "diagnostic-path.h"
#include "diagnostic-metadata.h"
#include "function.h"
#include "json.h"
#include "analyzer/analyzer.h"
#include "diagnostic-event-id.h"
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
#include "tristate.h"
#include "selftest.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#if ENABLE_ANALYZER
namespace ana {
namespace {
/* A state machine for use in DejaGnu tests, to check that
pattern-matching works as expected. */
class pattern_test_state_machine : public state_machine
{
public:
pattern_test_state_machine (logger *logger);
bool inherited_state_p () const FINAL OVERRIDE { return false; }
bool on_stmt (sm_context *sm_ctxt,
const supernode *node,
const gimple *stmt) const FINAL OVERRIDE;
void on_condition (sm_context *sm_ctxt,
const supernode *node,
const gimple *stmt,
const svalue *lhs,
enum tree_code op,
const svalue *rhs) const FINAL OVERRIDE;
bool can_purge_p (state_t s) const FINAL OVERRIDE;
};
class pattern_match : public pending_diagnostic_subclass<pattern_match>
{
public:
pattern_match (tree lhs, enum tree_code op, tree rhs)
: m_lhs (lhs), m_op (op), m_rhs (rhs) {}
const char *get_kind () const FINAL OVERRIDE { return "pattern_match"; }
bool operator== (const pattern_match &other) const
{
return (same_tree_p (m_lhs, other.m_lhs)
&& m_op == other.m_op
&& same_tree_p (m_rhs, other.m_rhs));
}
bool emit (rich_location *rich_loc) FINAL OVERRIDE
{
return warning_at (rich_loc, 0, "pattern match on %<%E %s %E%>",
m_lhs, op_symbol_code (m_op), m_rhs);
}
private:
tree m_lhs;
enum tree_code m_op;
tree m_rhs;
};
pattern_test_state_machine::pattern_test_state_machine (logger *logger)
: state_machine ("pattern-test", logger)
{
}
bool
pattern_test_state_machine::on_stmt (sm_context *sm_ctxt ATTRIBUTE_UNUSED,
const supernode *node ATTRIBUTE_UNUSED,
const gimple *stmt ATTRIBUTE_UNUSED) const
{
return false;
}
/* Implementation of state_machine::on_condition vfunc for
pattern_test_state_machine.
Queue a pattern_match diagnostic for any comparison against a
constant. */
void
pattern_test_state_machine::on_condition (sm_context *sm_ctxt,
const supernode *node,
const gimple *stmt,
const svalue *lhs,
enum tree_code op,
const svalue *rhs) const
{
if (stmt == NULL)
return;
tree rhs_cst = rhs->maybe_get_constant ();
if (!rhs_cst)
return;
if (tree lhs_expr = sm_ctxt->get_diagnostic_tree (lhs))
{
pending_diagnostic *diag = new pattern_match (lhs_expr, op, rhs_cst);
sm_ctxt->warn (node, stmt, lhs_expr, diag);
}
}
bool
pattern_test_state_machine::can_purge_p (state_t s ATTRIBUTE_UNUSED) const
{
return true;
}
} // anonymous namespace
/* Internal interface to this file. */
state_machine *
make_pattern_test_state_machine (logger *logger)
{
return new pattern_test_state_machine (logger);
}
} // namespace ana
#endif /* #if ENABLE_ANALYZER */