ast: Replace IsValid() with TINT_ASSERT()
The readers must not produce invalid ASTs. If readers cannot produce a valid AST, then they should error instead. If a reader does produce an invalid AST, this change catches this bad behavior early, significantly helping identify the root of the broken logic. IsValid() made a bit more sense in the days where the AST was mutable, and was constructed by calling setters on the nodes to build up the tree. In order to detect bad ASTs, IsValid() would have to perform an entire AST traversal and give a yes / no answer for the entire tree. Not only was this slow, an answer of 'no' didn't tell you *where* the AST was invalid, resulting in a lot of manual debugging. Now that the AST is fully immutable, all child nodes need to be built before their parents. The AST node constructors now become a perfect place to perform pointer sanity checking. The argument for attempting to catch and handle invalid ASTs is not a compelling one. Invalid ASTs are invalid compiler behavior, not something that should ever happen with a correctly functioning compiler. If this were to happen in production, the user would be utterly clueless to _why_ the program is invalid, or _how_ to fix it. Attempting to handle invalid ASTs is just masking a much larger problem. Let's just let the fuzzers do their job to catch any of these cases early. Fixed: chromium:1185569 Change-Id: I6496426a3a9da9d42627d2c1ca23917bfd04cc5c Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/44048 Commit-Queue: Ben Clayton <bclayton@chromium.org> Reviewed-by: David Neto <dneto@google.com>
This commit is contained in:
parent
6ce58becd2
commit
8454d824d4
|
@ -24,7 +24,10 @@ namespace ast {
|
|||
ArrayAccessorExpression::ArrayAccessorExpression(const Source& source,
|
||||
Expression* array,
|
||||
Expression* idx_expr)
|
||||
: Base(source), array_(array), idx_expr_(idx_expr) {}
|
||||
: Base(source), array_(array), idx_expr_(idx_expr) {
|
||||
TINT_ASSERT(array_);
|
||||
TINT_ASSERT(idx_expr_);
|
||||
}
|
||||
|
||||
ArrayAccessorExpression::ArrayAccessorExpression(ArrayAccessorExpression&&) =
|
||||
default;
|
||||
|
@ -40,15 +43,6 @@ ArrayAccessorExpression* ArrayAccessorExpression::Clone(
|
|||
return ctx->dst->create<ArrayAccessorExpression>(src, arr, idx);
|
||||
}
|
||||
|
||||
bool ArrayAccessorExpression::IsValid() const {
|
||||
if (array_ == nullptr || !array_->IsValid())
|
||||
return false;
|
||||
if (idx_expr_ == nullptr || !idx_expr_->IsValid())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ArrayAccessorExpression::to_str(const semantic::Info& sem,
|
||||
std::ostream& out,
|
||||
size_t indent) const {
|
||||
|
|
|
@ -47,9 +47,6 @@ class ArrayAccessorExpression
|
|||
/// @return the newly cloned node
|
||||
ArrayAccessorExpression* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
/// Writes a representation of the node to the output stream
|
||||
/// @param sem the semantic info for the program
|
||||
/// @param out the stream to write to
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "gtest/gtest-spi.h"
|
||||
#include "src/ast/test_helper.h"
|
||||
|
||||
namespace tint {
|
||||
|
@ -48,40 +49,22 @@ TEST_F(ArrayAccessorExpressionTest, IsArrayAccessor) {
|
|||
EXPECT_TRUE(exp->Is<ArrayAccessorExpression>());
|
||||
}
|
||||
|
||||
TEST_F(ArrayAccessorExpressionTest, IsValid) {
|
||||
auto* ary = Expr("ary");
|
||||
auto* idx = Expr("idx");
|
||||
|
||||
auto* exp = create<ArrayAccessorExpression>(ary, idx);
|
||||
EXPECT_TRUE(exp->IsValid());
|
||||
TEST_F(ArrayAccessorExpressionTest, Assert_NullArray) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.create<ArrayAccessorExpression>(nullptr, b.Expr("idx"));
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(ArrayAccessorExpressionTest, IsValid_MissingArray) {
|
||||
auto* idx = Expr("idx");
|
||||
|
||||
auto* exp = create<ArrayAccessorExpression>(nullptr, idx);
|
||||
EXPECT_FALSE(exp->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ArrayAccessorExpressionTest, IsValid_MissingIndex) {
|
||||
auto* ary = Expr("ary");
|
||||
|
||||
auto* exp = create<ArrayAccessorExpression>(ary, nullptr);
|
||||
EXPECT_FALSE(exp->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ArrayAccessorExpressionTest, IsValid_InvalidArray) {
|
||||
auto* ary = Expr("");
|
||||
auto* idx = Expr("idx");
|
||||
auto* exp = create<ArrayAccessorExpression>(ary, idx);
|
||||
EXPECT_FALSE(exp->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ArrayAccessorExpressionTest, IsValid_InvalidIndex) {
|
||||
auto* ary = Expr("ary");
|
||||
auto* idx = Expr("");
|
||||
auto* exp = create<ArrayAccessorExpression>(ary, idx);
|
||||
EXPECT_FALSE(exp->IsValid());
|
||||
TEST_F(ArrayAccessorExpressionTest, Assert_NullIndex) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.create<ArrayAccessorExpression>(b.Expr("arr"), nullptr);
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(ArrayAccessorExpressionTest, ToStr) {
|
||||
|
|
|
@ -24,7 +24,10 @@ namespace ast {
|
|||
AssignmentStatement::AssignmentStatement(const Source& source,
|
||||
Expression* lhs,
|
||||
Expression* rhs)
|
||||
: Base(source), lhs_(lhs), rhs_(rhs) {}
|
||||
: Base(source), lhs_(lhs), rhs_(rhs) {
|
||||
TINT_ASSERT(lhs_);
|
||||
TINT_ASSERT(rhs_);
|
||||
}
|
||||
|
||||
AssignmentStatement::AssignmentStatement(AssignmentStatement&&) = default;
|
||||
|
||||
|
@ -38,15 +41,6 @@ AssignmentStatement* AssignmentStatement::Clone(CloneContext* ctx) const {
|
|||
return ctx->dst->create<AssignmentStatement>(src, l, r);
|
||||
}
|
||||
|
||||
bool AssignmentStatement::IsValid() const {
|
||||
if (lhs_ == nullptr || !lhs_->IsValid())
|
||||
return false;
|
||||
if (rhs_ == nullptr || !rhs_->IsValid())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AssignmentStatement::to_str(const semantic::Info& sem,
|
||||
std::ostream& out,
|
||||
size_t indent) const {
|
||||
|
|
|
@ -44,9 +44,6 @@ class AssignmentStatement : public Castable<AssignmentStatement, Statement> {
|
|||
/// @return the newly cloned node
|
||||
AssignmentStatement* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
/// Writes a representation of the node to the output stream
|
||||
/// @param sem the semantic info for the program
|
||||
/// @param out the stream to write to
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "src/ast/assignment_statement.h"
|
||||
|
||||
#include "gtest/gtest-spi.h"
|
||||
#include "src/ast/test_helper.h"
|
||||
|
||||
namespace tint {
|
||||
|
@ -50,40 +51,22 @@ TEST_F(AssignmentStatementTest, IsAssign) {
|
|||
EXPECT_TRUE(stmt->Is<AssignmentStatement>());
|
||||
}
|
||||
|
||||
TEST_F(AssignmentStatementTest, IsValid) {
|
||||
auto* lhs = Expr("lhs");
|
||||
auto* rhs = Expr("rhs");
|
||||
|
||||
auto* stmt = create<AssignmentStatement>(lhs, rhs);
|
||||
EXPECT_TRUE(stmt->IsValid());
|
||||
TEST_F(AssignmentStatementTest, Assert_NullLHS) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.create<AssignmentStatement>(nullptr, b.Expr(1));
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(AssignmentStatementTest, IsValid_MissingLHS) {
|
||||
auto* rhs = Expr("rhs");
|
||||
|
||||
auto* stmt = create<AssignmentStatement>(nullptr, rhs);
|
||||
EXPECT_FALSE(stmt->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(AssignmentStatementTest, IsValid_MissingRHS) {
|
||||
auto* lhs = Expr("lhs");
|
||||
|
||||
auto* stmt = create<AssignmentStatement>(lhs, nullptr);
|
||||
EXPECT_FALSE(stmt->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(AssignmentStatementTest, IsValid_InvalidLHS) {
|
||||
auto* lhs = Expr("");
|
||||
auto* rhs = Expr("rhs");
|
||||
auto* stmt = create<AssignmentStatement>(lhs, rhs);
|
||||
EXPECT_FALSE(stmt->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(AssignmentStatementTest, IsValid_InvalidRHS) {
|
||||
auto* lhs = Expr("lhs");
|
||||
auto* rhs = Expr("");
|
||||
auto* stmt = create<AssignmentStatement>(lhs, rhs);
|
||||
EXPECT_FALSE(stmt->IsValid());
|
||||
TEST_F(AssignmentStatementTest, Assert_NullRHS) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.create<AssignmentStatement>(b.Expr(1), nullptr);
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(AssignmentStatementTest, ToStr) {
|
||||
|
|
|
@ -25,7 +25,11 @@ BinaryExpression::BinaryExpression(const Source& source,
|
|||
BinaryOp op,
|
||||
Expression* lhs,
|
||||
Expression* rhs)
|
||||
: Base(source), op_(op), lhs_(lhs), rhs_(rhs) {}
|
||||
: Base(source), op_(op), lhs_(lhs), rhs_(rhs) {
|
||||
TINT_ASSERT(lhs_);
|
||||
TINT_ASSERT(rhs_);
|
||||
TINT_ASSERT(op_ != BinaryOp::kNone);
|
||||
}
|
||||
|
||||
BinaryExpression::BinaryExpression(BinaryExpression&&) = default;
|
||||
|
||||
|
@ -39,16 +43,6 @@ BinaryExpression* BinaryExpression::Clone(CloneContext* ctx) const {
|
|||
return ctx->dst->create<BinaryExpression>(src, op_, l, r);
|
||||
}
|
||||
|
||||
bool BinaryExpression::IsValid() const {
|
||||
if (lhs_ == nullptr || !lhs_->IsValid()) {
|
||||
return false;
|
||||
}
|
||||
if (rhs_ == nullptr || !rhs_->IsValid()) {
|
||||
return false;
|
||||
}
|
||||
return op_ != BinaryOp::kNone;
|
||||
}
|
||||
|
||||
void BinaryExpression::to_str(const semantic::Info& sem,
|
||||
std::ostream& out,
|
||||
size_t indent) const {
|
||||
|
|
|
@ -110,9 +110,6 @@ class BinaryExpression : public Castable<BinaryExpression, Expression> {
|
|||
/// @return the newly cloned node
|
||||
BinaryExpression* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
/// Writes a representation of the node to the output stream
|
||||
/// @param sem the semantic info for the program
|
||||
/// @param out the stream to write to
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "gtest/gtest-spi.h"
|
||||
#include "src/ast/test_helper.h"
|
||||
|
||||
namespace tint {
|
||||
|
@ -49,50 +50,22 @@ TEST_F(BinaryExpressionTest, IsBinary) {
|
|||
EXPECT_TRUE(r->Is<BinaryExpression>());
|
||||
}
|
||||
|
||||
TEST_F(BinaryExpressionTest, IsValid) {
|
||||
auto* lhs = Expr("lhs");
|
||||
auto* rhs = Expr("rhs");
|
||||
|
||||
auto* r = create<BinaryExpression>(BinaryOp::kEqual, lhs, rhs);
|
||||
EXPECT_TRUE(r->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(BinaryExpressionTest, IsValid_Null_LHS) {
|
||||
auto* rhs = Expr("rhs");
|
||||
|
||||
auto* r = create<BinaryExpression>(BinaryOp::kEqual, nullptr, rhs);
|
||||
EXPECT_FALSE(r->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(BinaryExpressionTest, IsValid_Invalid_LHS) {
|
||||
auto* lhs = Expr("");
|
||||
auto* rhs = Expr("rhs");
|
||||
|
||||
auto* r = create<BinaryExpression>(BinaryOp::kEqual, lhs, rhs);
|
||||
EXPECT_FALSE(r->IsValid());
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.create<BinaryExpression>(BinaryOp::kEqual, nullptr, b.Expr("rhs"));
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(BinaryExpressionTest, IsValid_Null_RHS) {
|
||||
auto* lhs = Expr("lhs");
|
||||
|
||||
auto* r = create<BinaryExpression>(BinaryOp::kEqual, lhs, nullptr);
|
||||
EXPECT_FALSE(r->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(BinaryExpressionTest, IsValid_Invalid_RHS) {
|
||||
auto* lhs = Expr("lhs");
|
||||
auto* rhs = Expr("");
|
||||
|
||||
auto* r = create<BinaryExpression>(BinaryOp::kEqual, lhs, rhs);
|
||||
EXPECT_FALSE(r->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(BinaryExpressionTest, IsValid_Binary_None) {
|
||||
auto* lhs = Expr("lhs");
|
||||
auto* rhs = Expr("rhs");
|
||||
|
||||
auto* r = create<BinaryExpression>(BinaryOp::kNone, lhs, rhs);
|
||||
EXPECT_FALSE(r->IsValid());
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.create<BinaryExpression>(BinaryOp::kEqual, b.Expr("lhs"), nullptr);
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(BinaryExpressionTest, ToStr) {
|
||||
|
|
|
@ -24,7 +24,10 @@ namespace ast {
|
|||
BitcastExpression::BitcastExpression(const Source& source,
|
||||
type::Type* type,
|
||||
Expression* expr)
|
||||
: Base(source), type_(type), expr_(expr) {}
|
||||
: Base(source), type_(type), expr_(expr) {
|
||||
TINT_ASSERT(type_);
|
||||
TINT_ASSERT(expr_);
|
||||
}
|
||||
|
||||
BitcastExpression::BitcastExpression(BitcastExpression&&) = default;
|
||||
BitcastExpression::~BitcastExpression() = default;
|
||||
|
@ -37,12 +40,6 @@ BitcastExpression* BitcastExpression::Clone(CloneContext* ctx) const {
|
|||
return ctx->dst->create<BitcastExpression>(src, ty, e);
|
||||
}
|
||||
|
||||
bool BitcastExpression::IsValid() const {
|
||||
if (expr_ == nullptr || !expr_->IsValid())
|
||||
return false;
|
||||
return type_ != nullptr;
|
||||
}
|
||||
|
||||
void BitcastExpression::to_str(const semantic::Info& sem,
|
||||
std::ostream& out,
|
||||
size_t indent) const {
|
||||
|
|
|
@ -43,9 +43,6 @@ class BitcastExpression : public Castable<BitcastExpression, Expression> {
|
|||
/// @return the newly cloned node
|
||||
BitcastExpression* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
/// Writes a representation of the node to the output stream
|
||||
/// @param sem the semantic info for the program
|
||||
/// @param out the stream to write to
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "src/ast/bitcast_expression.h"
|
||||
|
||||
#include "gtest/gtest-spi.h"
|
||||
#include "src/ast/test_helper.h"
|
||||
|
||||
namespace tint {
|
||||
|
@ -47,29 +48,22 @@ TEST_F(BitcastExpressionTest, IsBitcast) {
|
|||
EXPECT_TRUE(exp->Is<BitcastExpression>());
|
||||
}
|
||||
|
||||
TEST_F(BitcastExpressionTest, IsValid) {
|
||||
auto* expr = Expr("expr");
|
||||
|
||||
auto* exp = create<BitcastExpression>(ty.f32(), expr);
|
||||
EXPECT_TRUE(exp->IsValid());
|
||||
TEST_F(BitcastExpressionTest, Assert_NullType) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.create<BitcastExpression>(nullptr, b.Expr("idx"));
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(BitcastExpressionTest, IsValid_MissingType) {
|
||||
auto* expr = Expr("expr");
|
||||
|
||||
auto* exp = create<BitcastExpression>(nullptr, expr);
|
||||
EXPECT_FALSE(exp->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(BitcastExpressionTest, IsValid_MissingExpr) {
|
||||
auto* exp = create<BitcastExpression>(ty.f32(), nullptr);
|
||||
EXPECT_FALSE(exp->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(BitcastExpressionTest, IsValid_InvalidExpr) {
|
||||
auto* expr = Expr("");
|
||||
auto* e = create<BitcastExpression>(ty.f32(), expr);
|
||||
EXPECT_FALSE(e->IsValid());
|
||||
TEST_F(BitcastExpressionTest, Assert_NullExpr) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.create<BitcastExpression>(b.ty.f32(), nullptr);
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(BitcastExpressionTest, ToStr) {
|
||||
|
|
|
@ -23,7 +23,11 @@ namespace ast {
|
|||
|
||||
BlockStatement::BlockStatement(const Source& source,
|
||||
const StatementList& statements)
|
||||
: Base(source), statements_(std::move(statements)) {}
|
||||
: Base(source), statements_(std::move(statements)) {
|
||||
for (auto* stmt : *this) {
|
||||
TINT_ASSERT(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
BlockStatement::BlockStatement(BlockStatement&&) = default;
|
||||
|
||||
|
@ -36,15 +40,6 @@ BlockStatement* BlockStatement::Clone(CloneContext* ctx) const {
|
|||
return ctx->dst->create<BlockStatement>(src, stmts);
|
||||
}
|
||||
|
||||
bool BlockStatement::IsValid() const {
|
||||
for (auto* stmt : *this) {
|
||||
if (stmt == nullptr || !stmt->IsValid()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void BlockStatement::to_str(const semantic::Info& sem,
|
||||
std::ostream& out,
|
||||
size_t indent) const {
|
||||
|
|
|
@ -71,9 +71,6 @@ class BlockStatement : public Castable<BlockStatement, Statement> {
|
|||
/// @return the newly cloned node
|
||||
BlockStatement* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
/// Writes a representation of the node to the output stream
|
||||
/// @param sem the semantic info for the program
|
||||
/// @param out the stream to write to
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "gtest/gtest-spi.h"
|
||||
#include "src/ast/discard_statement.h"
|
||||
#include "src/ast/if_statement.h"
|
||||
#include "src/ast/test_helper.h"
|
||||
|
@ -45,35 +46,13 @@ TEST_F(BlockStatementTest, IsBlock) {
|
|||
EXPECT_TRUE(b->Is<BlockStatement>());
|
||||
}
|
||||
|
||||
TEST_F(BlockStatementTest, IsValid) {
|
||||
auto* b = create<BlockStatement>(ast::StatementList{
|
||||
create<DiscardStatement>(),
|
||||
});
|
||||
EXPECT_TRUE(b->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(BlockStatementTest, IsValid_Empty) {
|
||||
auto* b = create<BlockStatement>(ast::StatementList{});
|
||||
EXPECT_TRUE(b->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(BlockStatementTest, IsValid_NullBodyStatement) {
|
||||
auto* b = create<BlockStatement>(ast::StatementList{
|
||||
create<DiscardStatement>(),
|
||||
nullptr,
|
||||
});
|
||||
|
||||
EXPECT_FALSE(b->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(BlockStatementTest, IsValid_InvalidBodyStatement) {
|
||||
auto* b = create<BlockStatement>(
|
||||
|
||||
ast::StatementList{
|
||||
create<IfStatement>(nullptr, create<BlockStatement>(StatementList{}),
|
||||
ElseStatementList{}),
|
||||
});
|
||||
EXPECT_FALSE(b->IsValid());
|
||||
TEST_F(BlockStatementTest, Assert_NullStatement) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.create<BlockStatement>(ast::StatementList{nullptr});
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(BlockStatementTest, ToStr) {
|
||||
|
|
|
@ -33,10 +33,6 @@ BreakStatement* BreakStatement::Clone(CloneContext* ctx) const {
|
|||
return ctx->dst->create<BreakStatement>(src);
|
||||
}
|
||||
|
||||
bool BreakStatement::IsValid() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void BreakStatement::to_str(const semantic::Info&,
|
||||
std::ostream& out,
|
||||
size_t indent) const {
|
||||
|
|
|
@ -36,9 +36,6 @@ class BreakStatement : public Castable<BreakStatement, Statement> {
|
|||
/// @return the newly cloned node
|
||||
BreakStatement* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
/// Writes a representation of the node to the output stream
|
||||
/// @param sem the semantic info for the program
|
||||
/// @param out the stream to write to
|
||||
|
|
|
@ -34,11 +34,6 @@ TEST_F(BreakStatementTest, IsBreak) {
|
|||
EXPECT_TRUE(stmt->Is<BreakStatement>());
|
||||
}
|
||||
|
||||
TEST_F(BreakStatementTest, IsValid) {
|
||||
auto* stmt = create<BreakStatement>();
|
||||
EXPECT_TRUE(stmt->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(BreakStatementTest, ToStr) {
|
||||
auto* stmt = create<BreakStatement>();
|
||||
EXPECT_EQ(str(stmt), R"(Break{}
|
||||
|
|
|
@ -24,7 +24,12 @@ namespace ast {
|
|||
CallExpression::CallExpression(const Source& source,
|
||||
Expression* func,
|
||||
ExpressionList params)
|
||||
: Base(source), func_(func), params_(params) {}
|
||||
: Base(source), func_(func), params_(params) {
|
||||
TINT_ASSERT(func_);
|
||||
for (auto* param : params_) {
|
||||
TINT_ASSERT(param);
|
||||
}
|
||||
}
|
||||
|
||||
CallExpression::CallExpression(CallExpression&&) = default;
|
||||
|
||||
|
@ -38,18 +43,6 @@ CallExpression* CallExpression::Clone(CloneContext* ctx) const {
|
|||
return ctx->dst->create<CallExpression>(src, fn, p);
|
||||
}
|
||||
|
||||
bool CallExpression::IsValid() const {
|
||||
if (func_ == nullptr || !func_->IsValid())
|
||||
return false;
|
||||
|
||||
// All params must be valid
|
||||
for (auto* param : params_) {
|
||||
if (param == nullptr || !param->IsValid())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CallExpression::to_str(const semantic::Info& sem,
|
||||
std::ostream& out,
|
||||
size_t indent) const {
|
||||
|
|
|
@ -43,9 +43,6 @@ class CallExpression : public Castable<CallExpression, Expression> {
|
|||
/// @return the newly cloned node
|
||||
CallExpression* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
/// Writes a representation of the node to the output stream
|
||||
/// @param sem the semantic info for the program
|
||||
/// @param out the stream to write to
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "gtest/gtest-spi.h"
|
||||
#include "src/ast/test_helper.h"
|
||||
|
||||
namespace tint {
|
||||
|
@ -50,44 +51,26 @@ TEST_F(CallExpressionTest, IsCall) {
|
|||
EXPECT_TRUE(stmt->Is<CallExpression>());
|
||||
}
|
||||
|
||||
TEST_F(CallExpressionTest, IsValid) {
|
||||
auto* func = Expr("func");
|
||||
auto* stmt = create<CallExpression>(func, ExpressionList{});
|
||||
EXPECT_TRUE(stmt->IsValid());
|
||||
TEST_F(CallExpressionTest, Assert_NullFunction) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.create<CallExpression>(nullptr, ExpressionList{});
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(CallExpressionTest, IsValid_MissingFunction) {
|
||||
auto* stmt = create<CallExpression>(nullptr, ExpressionList{});
|
||||
EXPECT_FALSE(stmt->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(CallExpressionTest, IsValid_NullParam) {
|
||||
auto* func = Expr("func");
|
||||
TEST_F(CallExpressionTest, Assert_NullParam) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
ExpressionList params;
|
||||
params.push_back(Expr("param1"));
|
||||
params.push_back(b.Expr("param1"));
|
||||
params.push_back(nullptr);
|
||||
params.push_back(Expr("param2"));
|
||||
|
||||
auto* stmt = create<CallExpression>(func, params);
|
||||
EXPECT_FALSE(stmt->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(CallExpressionTest, IsValid_InvalidFunction) {
|
||||
auto* func = Expr("");
|
||||
ExpressionList params;
|
||||
params.push_back(Expr("param1"));
|
||||
|
||||
auto* stmt = create<CallExpression>(func, params);
|
||||
EXPECT_FALSE(stmt->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(CallExpressionTest, IsValid_InvalidParam) {
|
||||
auto* func = Expr("func");
|
||||
ExpressionList params;
|
||||
params.push_back(Expr(""));
|
||||
|
||||
auto* stmt = create<CallExpression>(func, params);
|
||||
EXPECT_FALSE(stmt->IsValid());
|
||||
params.push_back(b.Expr("param2"));
|
||||
b.create<CallExpression>(b.Expr("func"), params);
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(CallExpressionTest, ToStr_NoParams) {
|
||||
|
|
|
@ -22,7 +22,9 @@ namespace tint {
|
|||
namespace ast {
|
||||
|
||||
CallStatement::CallStatement(const Source& source, CallExpression* call)
|
||||
: Base(source), call_(call) {}
|
||||
: Base(source), call_(call) {
|
||||
TINT_ASSERT(call_);
|
||||
}
|
||||
|
||||
CallStatement::CallStatement(CallStatement&&) = default;
|
||||
|
||||
|
@ -35,10 +37,6 @@ CallStatement* CallStatement::Clone(CloneContext* ctx) const {
|
|||
return ctx->dst->create<CallStatement>(src, call);
|
||||
}
|
||||
|
||||
bool CallStatement::IsValid() const {
|
||||
return call_ != nullptr && call_->IsValid();
|
||||
}
|
||||
|
||||
void CallStatement::to_str(const semantic::Info& sem,
|
||||
std::ostream& out,
|
||||
size_t indent) const {
|
||||
|
|
|
@ -41,9 +41,6 @@ class CallStatement : public Castable<CallStatement, Statement> {
|
|||
/// @return the newly cloned node
|
||||
CallStatement* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
/// Writes a representation of the node to the output stream
|
||||
/// @param sem the semantic info for the program
|
||||
/// @param out the stream to write to
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "src/ast/call_statement.h"
|
||||
|
||||
#include "gtest/gtest-spi.h"
|
||||
#include "src/ast/test_helper.h"
|
||||
|
||||
namespace tint {
|
||||
|
@ -30,25 +31,17 @@ TEST_F(CallStatementTest, Creation) {
|
|||
}
|
||||
|
||||
TEST_F(CallStatementTest, IsCall) {
|
||||
auto* c = create<CallStatement>(nullptr);
|
||||
auto* c = create<CallStatement>(Call("f"));
|
||||
EXPECT_TRUE(c->Is<CallStatement>());
|
||||
}
|
||||
|
||||
TEST_F(CallStatementTest, IsValid) {
|
||||
auto* c = create<CallStatement>(
|
||||
create<CallExpression>(Expr("func"), ExpressionList{}));
|
||||
EXPECT_TRUE(c->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(CallStatementTest, IsValid_MissingExpr) {
|
||||
auto* c = create<CallStatement>(nullptr);
|
||||
EXPECT_FALSE(c->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(CallStatementTest, IsValid_InvalidExpr) {
|
||||
auto* c = create<CallStatement>(
|
||||
create<CallExpression>(nullptr, ast::ExpressionList{}));
|
||||
EXPECT_FALSE(c->IsValid());
|
||||
TEST_F(CallStatementTest, Assert_NullCall) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.create<CallStatement>(nullptr);
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(CallStatementTest, ToStr) {
|
||||
|
|
|
@ -24,7 +24,9 @@ namespace ast {
|
|||
CaseStatement::CaseStatement(const Source& source,
|
||||
CaseSelectorList selectors,
|
||||
BlockStatement* body)
|
||||
: Base(source), selectors_(selectors), body_(body) {}
|
||||
: Base(source), selectors_(selectors), body_(body) {
|
||||
TINT_ASSERT(body_);
|
||||
}
|
||||
|
||||
CaseStatement::CaseStatement(CaseStatement&&) = default;
|
||||
|
||||
|
@ -38,10 +40,6 @@ CaseStatement* CaseStatement::Clone(CloneContext* ctx) const {
|
|||
return ctx->dst->create<CaseStatement>(src, sel, b);
|
||||
}
|
||||
|
||||
bool CaseStatement::IsValid() const {
|
||||
return body_ != nullptr && body_->IsValid();
|
||||
}
|
||||
|
||||
void CaseStatement::to_str(const semantic::Info& sem,
|
||||
std::ostream& out,
|
||||
size_t indent) const {
|
||||
|
|
|
@ -56,9 +56,6 @@ class CaseStatement : public Castable<CaseStatement, Statement> {
|
|||
/// @return the newly cloned node
|
||||
CaseStatement* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
/// Writes a representation of the node to the output stream
|
||||
/// @param sem the semantic info for the program
|
||||
/// @param out the stream to write to
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "src/ast/case_statement.h"
|
||||
|
||||
#include "gtest/gtest-spi.h"
|
||||
#include "src/ast/discard_statement.h"
|
||||
#include "src/ast/if_statement.h"
|
||||
#include "src/ast/test_helper.h"
|
||||
|
@ -89,36 +90,13 @@ TEST_F(CaseStatementTest, IsCase) {
|
|||
EXPECT_TRUE(c->Is<CaseStatement>());
|
||||
}
|
||||
|
||||
TEST_F(CaseStatementTest, IsValid) {
|
||||
auto* c = create<CaseStatement>(CaseSelectorList{},
|
||||
create<BlockStatement>(StatementList{}));
|
||||
EXPECT_TRUE(c->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(CaseStatementTest, IsValid_NullBodyStatement) {
|
||||
CaseSelectorList b;
|
||||
b.push_back(create<SintLiteral>(ty.i32(), 2));
|
||||
|
||||
auto* body = create<BlockStatement>(StatementList{
|
||||
create<DiscardStatement>(),
|
||||
nullptr,
|
||||
});
|
||||
auto* c = create<CaseStatement>(b, body);
|
||||
EXPECT_FALSE(c->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(CaseStatementTest, IsValid_InvalidBodyStatement) {
|
||||
CaseSelectorList b;
|
||||
b.push_back(create<SintLiteral>(ty.i32(), 2));
|
||||
|
||||
auto* body = create<BlockStatement>(
|
||||
|
||||
StatementList{
|
||||
create<IfStatement>(nullptr, create<BlockStatement>(StatementList{}),
|
||||
ElseStatementList{}),
|
||||
});
|
||||
auto* c = create<CaseStatement>(CaseSelectorList{b}, body);
|
||||
EXPECT_FALSE(c->IsValid());
|
||||
TEST_F(CaseStatementTest, Assert_NullBody) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.create<CaseStatement>(CaseSelectorList{}, nullptr);
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(CaseStatementTest, ToStr_WithSelectors_i32) {
|
||||
|
|
|
@ -33,10 +33,6 @@ ContinueStatement* ContinueStatement::Clone(CloneContext* ctx) const {
|
|||
return ctx->dst->create<ContinueStatement>(src);
|
||||
}
|
||||
|
||||
bool ContinueStatement::IsValid() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void ContinueStatement::to_str(const semantic::Info&,
|
||||
std::ostream& out,
|
||||
size_t indent) const {
|
||||
|
|
|
@ -36,9 +36,6 @@ class ContinueStatement : public Castable<ContinueStatement, Statement> {
|
|||
/// @return the newly cloned node
|
||||
ContinueStatement* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
/// Writes a representation of the node to the output stream
|
||||
/// @param sem the semantic info for the program
|
||||
/// @param out the stream to write to
|
||||
|
|
|
@ -34,11 +34,6 @@ TEST_F(ContinueStatementTest, IsContinue) {
|
|||
EXPECT_TRUE(stmt->Is<ContinueStatement>());
|
||||
}
|
||||
|
||||
TEST_F(ContinueStatementTest, IsValid) {
|
||||
auto* stmt = create<ContinueStatement>();
|
||||
EXPECT_TRUE(stmt->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ContinueStatementTest, ToStr) {
|
||||
auto* stmt = create<ContinueStatement>();
|
||||
EXPECT_EQ(str(stmt), R"(Continue{}
|
||||
|
|
|
@ -39,9 +39,5 @@ std::ostream& operator<<(std::ostream& out, DecorationKind data) {
|
|||
return out << "<unknown>";
|
||||
}
|
||||
|
||||
bool Decoration::IsValid() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ast
|
||||
} // namespace tint
|
||||
|
|
|
@ -42,9 +42,6 @@ class Decoration : public Castable<Decoration, Node> {
|
|||
/// @return the decoration kind
|
||||
virtual DecorationKind GetKind() const = 0;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
protected:
|
||||
/// Constructor
|
||||
/// @param source the source of this decoration
|
||||
|
|
|
@ -33,10 +33,6 @@ DiscardStatement* DiscardStatement::Clone(CloneContext* ctx) const {
|
|||
return ctx->dst->create<DiscardStatement>(src);
|
||||
}
|
||||
|
||||
bool DiscardStatement::IsValid() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void DiscardStatement::to_str(const semantic::Info&,
|
||||
std::ostream& out,
|
||||
size_t indent) const {
|
||||
|
|
|
@ -36,9 +36,6 @@ class DiscardStatement : public Castable<DiscardStatement, Statement> {
|
|||
/// @return the newly cloned node
|
||||
DiscardStatement* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
/// Writes a representation of the node to the output stream
|
||||
/// @param sem the semantic info for the program
|
||||
/// @param out the stream to write to
|
||||
|
|
|
@ -44,11 +44,6 @@ TEST_F(DiscardStatementTest, IsDiscard) {
|
|||
EXPECT_TRUE(stmt->Is<DiscardStatement>());
|
||||
}
|
||||
|
||||
TEST_F(DiscardStatementTest, IsValid) {
|
||||
auto* stmt = create<DiscardStatement>();
|
||||
EXPECT_TRUE(stmt->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(DiscardStatementTest, ToStr) {
|
||||
auto* stmt = create<DiscardStatement>();
|
||||
EXPECT_EQ(str(stmt), R"(Discard{}
|
||||
|
|
|
@ -24,7 +24,9 @@ namespace ast {
|
|||
ElseStatement::ElseStatement(const Source& source,
|
||||
Expression* condition,
|
||||
BlockStatement* body)
|
||||
: Base(source), condition_(condition), body_(body) {}
|
||||
: Base(source), condition_(condition), body_(body) {
|
||||
TINT_ASSERT(body_);
|
||||
}
|
||||
|
||||
ElseStatement::ElseStatement(ElseStatement&&) = default;
|
||||
|
||||
|
@ -38,13 +40,6 @@ ElseStatement* ElseStatement::Clone(CloneContext* ctx) const {
|
|||
return ctx->dst->create<ElseStatement>(src, cond, b);
|
||||
}
|
||||
|
||||
bool ElseStatement::IsValid() const {
|
||||
if (body_ == nullptr || !body_->IsValid()) {
|
||||
return false;
|
||||
}
|
||||
return condition_ == nullptr || condition_->IsValid();
|
||||
}
|
||||
|
||||
void ElseStatement::to_str(const semantic::Info& sem,
|
||||
std::ostream& out,
|
||||
size_t indent) const {
|
||||
|
|
|
@ -53,9 +53,6 @@ class ElseStatement : public Castable<ElseStatement, Statement> {
|
|||
/// @return the newly cloned node
|
||||
ElseStatement* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
/// Writes a representation of the node to the output stream
|
||||
/// @param sem the semantic info for the program
|
||||
/// @param out the stream to write to
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "gtest/gtest-spi.h"
|
||||
#include "src/ast/discard_statement.h"
|
||||
#include "src/ast/if_statement.h"
|
||||
#include "src/ast/test_helper.h"
|
||||
|
@ -36,7 +37,7 @@ TEST_F(ElseStatementTest, Creation) {
|
|||
}
|
||||
|
||||
TEST_F(ElseStatementTest, Creation_WithSource) {
|
||||
auto* e = create<ElseStatement>(Source{Source::Location{20, 2}}, nullptr,
|
||||
auto* e = create<ElseStatement>(Source{Source::Location{20, 2}}, Expr(true),
|
||||
create<BlockStatement>(StatementList{}));
|
||||
auto src = e->source();
|
||||
EXPECT_EQ(src.range.begin.line, 20u);
|
||||
|
@ -62,45 +63,13 @@ TEST_F(ElseStatementTest, HasContition_NullCondition) {
|
|||
EXPECT_FALSE(e->HasCondition());
|
||||
}
|
||||
|
||||
TEST_F(ElseStatementTest, IsValid) {
|
||||
auto* e =
|
||||
create<ElseStatement>(nullptr, create<BlockStatement>(StatementList{}));
|
||||
EXPECT_TRUE(e->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ElseStatementTest, IsValid_WithBody) {
|
||||
auto* body = create<BlockStatement>(StatementList{
|
||||
create<DiscardStatement>(),
|
||||
});
|
||||
auto* e = create<ElseStatement>(nullptr, body);
|
||||
EXPECT_TRUE(e->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ElseStatementTest, IsValid_WithNullBodyStatement) {
|
||||
auto* body = create<BlockStatement>(StatementList{
|
||||
create<DiscardStatement>(),
|
||||
nullptr,
|
||||
});
|
||||
auto* e = create<ElseStatement>(nullptr, body);
|
||||
EXPECT_FALSE(e->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ElseStatementTest, IsValid_InvalidCondition) {
|
||||
auto* cond = create<ScalarConstructorExpression>(nullptr);
|
||||
auto* e =
|
||||
create<ElseStatement>(cond, create<BlockStatement>(StatementList{}));
|
||||
EXPECT_FALSE(e->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ElseStatementTest, IsValid_InvalidBodyStatement) {
|
||||
auto* body = create<BlockStatement>(
|
||||
|
||||
StatementList{
|
||||
create<IfStatement>(nullptr, create<BlockStatement>(StatementList{}),
|
||||
ElseStatementList{}),
|
||||
});
|
||||
auto* e = create<ElseStatement>(nullptr, body);
|
||||
EXPECT_FALSE(e->IsValid());
|
||||
TEST_F(ElseStatementTest, Assert_NullBody) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.create<ElseStatement>(b.Expr(true), nullptr);
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(ElseStatementTest, ToStr) {
|
||||
|
|
|
@ -34,10 +34,6 @@ FallthroughStatement* FallthroughStatement::Clone(CloneContext* ctx) const {
|
|||
return ctx->dst->create<FallthroughStatement>(src);
|
||||
}
|
||||
|
||||
bool FallthroughStatement::IsValid() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void FallthroughStatement::to_str(const semantic::Info&,
|
||||
std::ostream& out,
|
||||
size_t indent) const {
|
||||
|
|
|
@ -36,9 +36,6 @@ class FallthroughStatement : public Castable<FallthroughStatement, Statement> {
|
|||
/// @return the newly cloned node
|
||||
FallthroughStatement* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
/// Writes a representation of the node to the output stream
|
||||
/// @param sem the semantic info for the program
|
||||
/// @param out the stream to write to
|
||||
|
|
|
@ -42,11 +42,6 @@ TEST_F(FallthroughStatementTest, IsFallthrough) {
|
|||
EXPECT_TRUE(stmt->Is<FallthroughStatement>());
|
||||
}
|
||||
|
||||
TEST_F(FallthroughStatementTest, IsValid) {
|
||||
auto* stmt = create<FallthroughStatement>();
|
||||
EXPECT_TRUE(stmt->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(FallthroughStatementTest, ToStr) {
|
||||
auto* stmt = create<FallthroughStatement>();
|
||||
EXPECT_EQ(str(stmt), R"(Fallthrough{}
|
||||
|
|
|
@ -34,7 +34,14 @@ Function::Function(const Source& source,
|
|||
params_(std::move(params)),
|
||||
return_type_(return_type),
|
||||
body_(body),
|
||||
decorations_(std::move(decorations)) {}
|
||||
decorations_(std::move(decorations)) {
|
||||
for (auto* param : params_) {
|
||||
TINT_ASSERT(param);
|
||||
}
|
||||
TINT_ASSERT(body_);
|
||||
TINT_ASSERT(symbol_.IsValid());
|
||||
TINT_ASSERT(return_type_);
|
||||
}
|
||||
|
||||
Function::Function(Function&&) = default;
|
||||
|
||||
|
@ -73,23 +80,6 @@ Function* Function::Clone(CloneContext* ctx) const {
|
|||
return ctx->dst->create<Function>(src, sym, p, ret, b, decos);
|
||||
}
|
||||
|
||||
bool Function::IsValid() const {
|
||||
for (auto* param : params_) {
|
||||
if (param == nullptr || !param->IsValid())
|
||||
return false;
|
||||
}
|
||||
if (body_ == nullptr || !body_->IsValid()) {
|
||||
return false;
|
||||
}
|
||||
if (!symbol_.IsValid()) {
|
||||
return false;
|
||||
}
|
||||
if (return_type_ == nullptr) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Function::to_str(const semantic::Info& sem,
|
||||
std::ostream& out,
|
||||
size_t indent) const {
|
||||
|
|
|
@ -89,9 +89,6 @@ class Function : public Castable<Function, Node> {
|
|||
/// @return the newly cloned node
|
||||
Function* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the symbol and type are both present
|
||||
bool IsValid() const override;
|
||||
|
||||
/// Writes a representation of the node to the output stream
|
||||
/// @param sem the semantic info for the program
|
||||
/// @param out the stream to write to
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "gtest/gtest-spi.h"
|
||||
#include "src/ast/discard_statement.h"
|
||||
#include "src/ast/stage_decoration.h"
|
||||
#include "src/ast/test_helper.h"
|
||||
|
@ -47,80 +48,38 @@ TEST_F(FunctionTest, Creation_WithSource) {
|
|||
EXPECT_EQ(src.range.begin.column, 2u);
|
||||
}
|
||||
|
||||
TEST_F(FunctionTest, IsValid) {
|
||||
VariableList params;
|
||||
params.push_back(Var("var", ty.i32(), StorageClass::kNone));
|
||||
|
||||
auto* f = Func("func", params, ty.void_(),
|
||||
StatementList{
|
||||
create<DiscardStatement>(),
|
||||
},
|
||||
TEST_F(FunctionTest, Assert_InvalidName) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.Func("", VariableList{}, b.ty.void_(), StatementList{},
|
||||
FunctionDecorationList{});
|
||||
EXPECT_TRUE(f->IsValid());
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(FunctionTest, IsValid_InvalidName) {
|
||||
VariableList params;
|
||||
params.push_back(Var("var", ty.i32(), StorageClass::kNone));
|
||||
|
||||
auto* f =
|
||||
Func("", params, ty.void_(), StatementList{}, FunctionDecorationList{});
|
||||
EXPECT_FALSE(f->IsValid());
|
||||
TEST_F(FunctionTest, Assert_NullReturnType) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.Func("f", VariableList{}, nullptr, StatementList{},
|
||||
FunctionDecorationList{});
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(FunctionTest, IsValid_MissingReturnType) {
|
||||
TEST_F(FunctionTest, Assert_NullParam) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
VariableList params;
|
||||
params.push_back(Var("var", ty.i32(), StorageClass::kNone));
|
||||
|
||||
auto* f =
|
||||
Func("func", params, nullptr, StatementList{}, FunctionDecorationList{});
|
||||
EXPECT_FALSE(f->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(FunctionTest, IsValid_NullParam) {
|
||||
VariableList params;
|
||||
params.push_back(Var("var", ty.i32(), StorageClass::kNone));
|
||||
params.push_back(b.Var("var", b.ty.i32(), StorageClass::kNone));
|
||||
params.push_back(nullptr);
|
||||
|
||||
auto* f = Func("func", params, ty.void_(), StatementList{},
|
||||
b.Func("f", params, b.ty.void_(), StatementList{},
|
||||
FunctionDecorationList{});
|
||||
EXPECT_FALSE(f->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(FunctionTest, IsValid_InvalidParam) {
|
||||
VariableList params;
|
||||
params.push_back(Var("var", nullptr, StorageClass::kNone));
|
||||
|
||||
auto* f = Func("func", params, ty.void_(), StatementList{},
|
||||
FunctionDecorationList{});
|
||||
EXPECT_FALSE(f->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(FunctionTest, IsValid_NullBodyStatement) {
|
||||
VariableList params;
|
||||
params.push_back(Var("var", ty.i32(), StorageClass::kNone));
|
||||
|
||||
auto* f = Func("func", params, ty.void_(),
|
||||
StatementList{
|
||||
create<DiscardStatement>(),
|
||||
nullptr,
|
||||
},
|
||||
FunctionDecorationList{});
|
||||
|
||||
EXPECT_FALSE(f->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(FunctionTest, IsValid_InvalidBodyStatement) {
|
||||
VariableList params;
|
||||
params.push_back(Var("var", ty.i32(), StorageClass::kNone));
|
||||
|
||||
auto* f = Func("func", params, ty.void_(),
|
||||
StatementList{
|
||||
create<DiscardStatement>(),
|
||||
nullptr,
|
||||
},
|
||||
FunctionDecorationList{});
|
||||
EXPECT_FALSE(f->IsValid());
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(FunctionTest, ToStr) {
|
||||
|
|
|
@ -22,7 +22,9 @@ namespace tint {
|
|||
namespace ast {
|
||||
|
||||
IdentifierExpression::IdentifierExpression(const Source& source, Symbol sym)
|
||||
: Base(source), sym_(sym) {}
|
||||
: Base(source), sym_(sym) {
|
||||
TINT_ASSERT(sym_.IsValid());
|
||||
}
|
||||
|
||||
IdentifierExpression::IdentifierExpression(IdentifierExpression&&) = default;
|
||||
|
||||
|
@ -35,10 +37,6 @@ IdentifierExpression* IdentifierExpression::Clone(CloneContext* ctx) const {
|
|||
return ctx->dst->create<IdentifierExpression>(src, sym);
|
||||
}
|
||||
|
||||
bool IdentifierExpression::IsValid() const {
|
||||
return sym_.IsValid();
|
||||
}
|
||||
|
||||
void IdentifierExpression::to_str(const semantic::Info& sem,
|
||||
std::ostream& out,
|
||||
size_t indent) const {
|
||||
|
|
|
@ -41,9 +41,6 @@ class IdentifierExpression : public Castable<IdentifierExpression, Expression> {
|
|||
/// @return the newly cloned node
|
||||
IdentifierExpression* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
/// Writes a representation of the node to the output stream
|
||||
/// @param sem the semantic info for the program
|
||||
/// @param out the stream to write to
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "gtest/gtest-spi.h"
|
||||
#include "src/ast/test_helper.h"
|
||||
|
||||
namespace tint {
|
||||
|
@ -39,9 +40,13 @@ TEST_F(IdentifierExpressionTest, IsIdentifier) {
|
|||
EXPECT_TRUE(i->Is<IdentifierExpression>());
|
||||
}
|
||||
|
||||
TEST_F(IdentifierExpressionTest, IsValid) {
|
||||
auto* i = Expr("ident");
|
||||
EXPECT_TRUE(i->IsValid());
|
||||
TEST_F(IdentifierExpressionTest, Assert_InvalidSymbol) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.Expr("");
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(IdentifierExpressionTest, ToStr) {
|
||||
|
|
|
@ -28,7 +28,13 @@ IfStatement::IfStatement(const Source& source,
|
|||
: Base(source),
|
||||
condition_(condition),
|
||||
body_(body),
|
||||
else_statements_(std::move(else_stmts)) {}
|
||||
else_statements_(std::move(else_stmts)) {
|
||||
TINT_ASSERT(condition_);
|
||||
TINT_ASSERT(body);
|
||||
for (auto* el : else_statements_) {
|
||||
TINT_ASSERT(el);
|
||||
}
|
||||
}
|
||||
|
||||
IfStatement::IfStatement(IfStatement&&) = default;
|
||||
|
||||
|
@ -43,30 +49,6 @@ IfStatement* IfStatement::Clone(CloneContext* ctx) const {
|
|||
return ctx->dst->create<IfStatement>(src, cond, b, el);
|
||||
}
|
||||
|
||||
bool IfStatement::IsValid() const {
|
||||
if (condition_ == nullptr || !condition_->IsValid()) {
|
||||
return false;
|
||||
}
|
||||
if (body_ == nullptr || !body_->IsValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool found_else = false;
|
||||
for (auto* el : else_statements_) {
|
||||
// Else statement must be last
|
||||
if (found_else)
|
||||
return false;
|
||||
|
||||
if (el == nullptr || !el->IsValid())
|
||||
return false;
|
||||
|
||||
if (el->condition() == nullptr)
|
||||
found_else = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void IfStatement::to_str(const semantic::Info& sem,
|
||||
std::ostream& out,
|
||||
size_t indent) const {
|
||||
|
|
|
@ -57,9 +57,6 @@ class IfStatement : public Castable<IfStatement, Statement> {
|
|||
/// @return the newly cloned node
|
||||
IfStatement* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
/// Writes a representation of the node to the output stream
|
||||
/// @param sem the semantic info for the program
|
||||
/// @param out the stream to write to
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "src/ast/if_statement.h"
|
||||
|
||||
#include "gtest/gtest-spi.h"
|
||||
#include "src/ast/discard_statement.h"
|
||||
#include "src/ast/test_helper.h"
|
||||
|
||||
|
@ -36,128 +37,37 @@ TEST_F(IfStatementTest, Creation) {
|
|||
|
||||
TEST_F(IfStatementTest, IsIf) {
|
||||
auto* stmt = create<IfStatement>(
|
||||
nullptr, create<BlockStatement>(StatementList{}), ElseStatementList{});
|
||||
Expr(true), create<BlockStatement>(StatementList{}), ElseStatementList{});
|
||||
EXPECT_TRUE(stmt->Is<IfStatement>());
|
||||
}
|
||||
|
||||
TEST_F(IfStatementTest, IsValid) {
|
||||
auto* cond = Expr("cond");
|
||||
auto* body =
|
||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
||||
auto* stmt = create<IfStatement>(cond, body, ElseStatementList{});
|
||||
EXPECT_TRUE(stmt->IsValid());
|
||||
TEST_F(IfStatementTest, Assert_NullCondition) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
auto* body = b.create<BlockStatement>(StatementList{});
|
||||
b.create<IfStatement>(nullptr, body, ElseStatementList{});
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(IfStatementTest, IsValid_WithElseStatements) {
|
||||
auto* cond = Expr("cond");
|
||||
auto* body =
|
||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
||||
auto* stmt = create<IfStatement>(
|
||||
cond, body,
|
||||
ElseStatementList{
|
||||
create<ElseStatement>(Expr("Ident"),
|
||||
create<BlockStatement>(StatementList{})),
|
||||
create<ElseStatement>(nullptr,
|
||||
create<BlockStatement>(StatementList{})),
|
||||
});
|
||||
EXPECT_TRUE(stmt->IsValid());
|
||||
TEST_F(IfStatementTest, Assert_NullBody) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.create<IfStatement>(b.Expr(true), nullptr, ElseStatementList{});
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(IfStatementTest, IsValid_MissingCondition) {
|
||||
auto* body =
|
||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
||||
auto* stmt = create<IfStatement>(nullptr, body, ElseStatementList{});
|
||||
EXPECT_FALSE(stmt->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(IfStatementTest, IsValid_InvalidCondition) {
|
||||
auto* cond = Expr("");
|
||||
auto* body =
|
||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
||||
auto* stmt = create<IfStatement>(cond, body, ElseStatementList{});
|
||||
EXPECT_FALSE(stmt->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(IfStatementTest, IsValid_NullBodyStatement) {
|
||||
auto* cond = Expr("cond");
|
||||
auto* body = create<BlockStatement>(StatementList{
|
||||
create<DiscardStatement>(),
|
||||
nullptr,
|
||||
});
|
||||
auto* stmt = create<IfStatement>(cond, body, ElseStatementList{});
|
||||
EXPECT_FALSE(stmt->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(IfStatementTest, IsValid_InvalidBodyStatement) {
|
||||
auto* cond = Expr("cond");
|
||||
auto* body = create<BlockStatement>(
|
||||
|
||||
StatementList{
|
||||
create<DiscardStatement>(),
|
||||
create<IfStatement>(nullptr, create<BlockStatement>(StatementList{}),
|
||||
ast::ElseStatementList{}),
|
||||
});
|
||||
auto* stmt = create<IfStatement>(cond, body, ElseStatementList{});
|
||||
EXPECT_FALSE(stmt->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(IfStatementTest, IsValid_NullElseStatement) {
|
||||
auto* cond = Expr("cond");
|
||||
auto* body =
|
||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
||||
auto* stmt = create<IfStatement>(
|
||||
cond, body,
|
||||
ElseStatementList{
|
||||
create<ElseStatement>(Expr("Ident"),
|
||||
create<BlockStatement>(StatementList{})),
|
||||
create<ElseStatement>(nullptr,
|
||||
create<BlockStatement>(StatementList{})),
|
||||
nullptr,
|
||||
});
|
||||
EXPECT_FALSE(stmt->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(IfStatementTest, IsValid_InvalidElseStatement) {
|
||||
auto* cond = Expr("cond");
|
||||
auto* body =
|
||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
||||
auto* stmt = create<IfStatement>(
|
||||
cond, body,
|
||||
ElseStatementList{
|
||||
create<ElseStatement>(Expr(""),
|
||||
create<BlockStatement>(StatementList{})),
|
||||
});
|
||||
EXPECT_FALSE(stmt->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(IfStatementTest, IsValid_MultipleElseWiththoutCondition) {
|
||||
auto* cond = Expr("cond");
|
||||
auto* body =
|
||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
||||
auto* stmt = create<IfStatement>(
|
||||
cond, body,
|
||||
ElseStatementList{
|
||||
create<ElseStatement>(nullptr,
|
||||
create<BlockStatement>(StatementList{})),
|
||||
create<ElseStatement>(nullptr,
|
||||
create<BlockStatement>(StatementList{})),
|
||||
});
|
||||
EXPECT_FALSE(stmt->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(IfStatementTest, IsValid_ElseNotLast) {
|
||||
auto* cond = Expr("cond");
|
||||
auto* body =
|
||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
||||
auto* stmt = create<IfStatement>(
|
||||
cond, body,
|
||||
ElseStatementList{
|
||||
create<ElseStatement>(nullptr,
|
||||
create<BlockStatement>(StatementList{})),
|
||||
create<ElseStatement>(Expr("Ident"),
|
||||
create<BlockStatement>(StatementList{})),
|
||||
});
|
||||
EXPECT_FALSE(stmt->IsValid());
|
||||
TEST_F(IfStatementTest, Assert_NullElseStatement) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
auto* body = b.create<BlockStatement>(StatementList{});
|
||||
b.create<IfStatement>(b.Expr(true), body, ElseStatementList{nullptr});
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(IfStatementTest, ToStr) {
|
||||
|
|
|
@ -24,10 +24,6 @@ Literal::Literal(const Source& source, type::Type* type)
|
|||
|
||||
Literal::~Literal() = default;
|
||||
|
||||
bool Literal::IsValid() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void Literal::to_str(const semantic::Info& sem,
|
||||
std::ostream& out,
|
||||
size_t indent) const {
|
||||
|
|
|
@ -30,9 +30,6 @@ class Literal : public Castable<Literal, Node> {
|
|||
/// @returns the type of the literal
|
||||
type::Type* type() const { return type_; }
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
/// Writes a representation of the node to the output stream
|
||||
/// @param sem the semantic info for the program
|
||||
/// @param out the stream to write to
|
||||
|
|
|
@ -24,7 +24,9 @@ namespace ast {
|
|||
LoopStatement::LoopStatement(const Source& source,
|
||||
BlockStatement* body,
|
||||
BlockStatement* continuing)
|
||||
: Base(source), body_(body), continuing_(continuing) {}
|
||||
: Base(source), body_(body), continuing_(continuing) {
|
||||
TINT_ASSERT(body_);
|
||||
}
|
||||
|
||||
LoopStatement::LoopStatement(LoopStatement&&) = default;
|
||||
|
||||
|
@ -38,16 +40,6 @@ LoopStatement* LoopStatement::Clone(CloneContext* ctx) const {
|
|||
return ctx->dst->create<LoopStatement>(src, b, cont);
|
||||
}
|
||||
|
||||
bool LoopStatement::IsValid() const {
|
||||
if (body_ == nullptr || !body_->IsValid()) {
|
||||
return false;
|
||||
}
|
||||
if (continuing_ == nullptr || !continuing_->IsValid()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void LoopStatement::to_str(const semantic::Info& sem,
|
||||
std::ostream& out,
|
||||
size_t indent) const {
|
||||
|
|
|
@ -54,9 +54,6 @@ class LoopStatement : public Castable<LoopStatement, Statement> {
|
|||
/// @return the newly cloned node
|
||||
LoopStatement* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
/// Writes a representation of the node to the output stream
|
||||
/// @param sem the semantic info for the program
|
||||
/// @param out the stream to write to
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "src/ast/loop_statement.h"
|
||||
|
||||
#include "gtest/gtest-spi.h"
|
||||
#include "src/ast/discard_statement.h"
|
||||
#include "src/ast/if_statement.h"
|
||||
#include "src/ast/test_helper.h"
|
||||
|
@ -78,88 +79,13 @@ TEST_F(LoopStatementTest, HasContinuing_WithContinuing) {
|
|||
EXPECT_TRUE(l->has_continuing());
|
||||
}
|
||||
|
||||
TEST_F(LoopStatementTest, IsValid) {
|
||||
auto* body =
|
||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
||||
|
||||
auto* continuing =
|
||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
||||
|
||||
auto* l = create<LoopStatement>(body, continuing);
|
||||
EXPECT_TRUE(l->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(LoopStatementTest, IsValid_WithoutContinuing) {
|
||||
auto* body =
|
||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
||||
|
||||
auto* l =
|
||||
create<LoopStatement>(body, create<BlockStatement>(StatementList{}));
|
||||
EXPECT_TRUE(l->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(LoopStatementTest, IsValid_WithoutBody) {
|
||||
auto* l = create<LoopStatement>(create<BlockStatement>(StatementList{}),
|
||||
create<BlockStatement>(StatementList{}));
|
||||
EXPECT_TRUE(l->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(LoopStatementTest, IsValid_NullBodyStatement) {
|
||||
auto* body = create<BlockStatement>(StatementList{
|
||||
create<DiscardStatement>(),
|
||||
nullptr,
|
||||
});
|
||||
|
||||
auto* continuing =
|
||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
||||
|
||||
auto* l = create<LoopStatement>(body, continuing);
|
||||
EXPECT_FALSE(l->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(LoopStatementTest, IsValid_InvalidBodyStatement) {
|
||||
auto* body = create<BlockStatement>(
|
||||
|
||||
StatementList{
|
||||
create<DiscardStatement>(),
|
||||
create<IfStatement>(nullptr, create<BlockStatement>(StatementList{}),
|
||||
ElseStatementList{}),
|
||||
});
|
||||
|
||||
auto* continuing =
|
||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
||||
|
||||
auto* l = create<LoopStatement>(body, continuing);
|
||||
EXPECT_FALSE(l->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(LoopStatementTest, IsValid_NullContinuingStatement) {
|
||||
auto* body =
|
||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
||||
|
||||
auto* continuing = create<BlockStatement>(StatementList{
|
||||
create<DiscardStatement>(),
|
||||
nullptr,
|
||||
});
|
||||
|
||||
auto* l = create<LoopStatement>(body, continuing);
|
||||
EXPECT_FALSE(l->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(LoopStatementTest, IsValid_InvalidContinuingStatement) {
|
||||
auto* body =
|
||||
create<BlockStatement>(StatementList{create<DiscardStatement>()});
|
||||
|
||||
auto* continuing = create<BlockStatement>(
|
||||
|
||||
StatementList{
|
||||
create<DiscardStatement>(),
|
||||
create<IfStatement>(nullptr, create<BlockStatement>(StatementList{}),
|
||||
ElseStatementList{}),
|
||||
});
|
||||
|
||||
auto* l = create<LoopStatement>(body, continuing);
|
||||
EXPECT_FALSE(l->IsValid());
|
||||
TEST_F(LoopStatementTest, Assert_NullBody) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.create<LoopStatement>(nullptr, nullptr);
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(LoopStatementTest, ToStr) {
|
||||
|
|
|
@ -24,7 +24,10 @@ namespace ast {
|
|||
MemberAccessorExpression::MemberAccessorExpression(const Source& source,
|
||||
Expression* structure,
|
||||
IdentifierExpression* member)
|
||||
: Base(source), struct_(structure), member_(member) {}
|
||||
: Base(source), struct_(structure), member_(member) {
|
||||
TINT_ASSERT(structure);
|
||||
TINT_ASSERT(member);
|
||||
}
|
||||
|
||||
MemberAccessorExpression::MemberAccessorExpression(MemberAccessorExpression&&) =
|
||||
default;
|
||||
|
@ -40,16 +43,6 @@ MemberAccessorExpression* MemberAccessorExpression::Clone(
|
|||
return ctx->dst->create<MemberAccessorExpression>(src, str, mem);
|
||||
}
|
||||
|
||||
bool MemberAccessorExpression::IsValid() const {
|
||||
if (struct_ == nullptr || !struct_->IsValid()) {
|
||||
return false;
|
||||
}
|
||||
if (member_ == nullptr || !member_->IsValid()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void MemberAccessorExpression::to_str(const semantic::Info& sem,
|
||||
std::ostream& out,
|
||||
size_t indent) const {
|
||||
|
|
|
@ -46,9 +46,6 @@ class MemberAccessorExpression
|
|||
/// @return the newly cloned node
|
||||
MemberAccessorExpression* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
/// Writes a representation of the node to the output stream
|
||||
/// @param sem the semantic info for the program
|
||||
/// @param out the stream to write to
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "gtest/gtest-spi.h"
|
||||
#include "src/ast/test_helper.h"
|
||||
|
||||
namespace tint {
|
||||
|
@ -43,30 +44,22 @@ TEST_F(MemberAccessorExpressionTest, IsMemberAccessor) {
|
|||
EXPECT_TRUE(stmt->Is<MemberAccessorExpression>());
|
||||
}
|
||||
|
||||
TEST_F(MemberAccessorExpressionTest, IsValid) {
|
||||
auto* stmt =
|
||||
create<MemberAccessorExpression>(Expr("structure"), Expr("member"));
|
||||
EXPECT_TRUE(stmt->IsValid());
|
||||
TEST_F(MemberAccessorExpressionTest, Assert_NullStruct) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.create<MemberAccessorExpression>(nullptr, b.Expr("member"));
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(MemberAccessorExpressionTest, IsValid_NullStruct) {
|
||||
auto* stmt = create<MemberAccessorExpression>(nullptr, Expr("member"));
|
||||
EXPECT_FALSE(stmt->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(MemberAccessorExpressionTest, IsValid_InvalidStruct) {
|
||||
auto* stmt = create<MemberAccessorExpression>(Expr(""), Expr("member"));
|
||||
EXPECT_FALSE(stmt->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(MemberAccessorExpressionTest, IsValid_NullMember) {
|
||||
auto* stmt = create<MemberAccessorExpression>(Expr("structure"), nullptr);
|
||||
EXPECT_FALSE(stmt->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(MemberAccessorExpressionTest, IsValid_InvalidMember) {
|
||||
auto* stmt = create<MemberAccessorExpression>(Expr("structure"), Expr(""));
|
||||
EXPECT_FALSE(stmt->IsValid());
|
||||
TEST_F(MemberAccessorExpressionTest, Assert_NullMember) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.create<MemberAccessorExpression>(b.Expr("struct"), nullptr);
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(MemberAccessorExpressionTest, ToStr) {
|
||||
|
|
|
@ -47,46 +47,6 @@ Module::Module(const Source& source, std::vector<CastableBase*> global_decls)
|
|||
|
||||
Module::~Module() = default;
|
||||
|
||||
bool Module::IsValid() const {
|
||||
for (auto* decl : global_declarations_) {
|
||||
if (decl == nullptr) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (auto* var : global_variables_) {
|
||||
if (var == nullptr || !var->IsValid()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (auto* const ty : constructed_types_) {
|
||||
if (ty == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (auto* alias = ty->As<type::Alias>()) {
|
||||
if (alias->type() == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (auto* str = alias->type()->As<type::Struct>()) {
|
||||
if (!str->symbol().IsValid()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (auto* str = ty->As<type::Struct>()) {
|
||||
if (!str->symbol().IsValid()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (auto* func : functions_) {
|
||||
if (func == nullptr || !func->IsValid()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Module* Module::Clone(CloneContext* ctx) const {
|
||||
auto* out = ctx->dst->create<Module>();
|
||||
out->Copy(ctx, this);
|
||||
|
|
|
@ -48,6 +48,7 @@ class Module : public Castable<Module, Node> {
|
|||
/// Add a global variable to the Builder
|
||||
/// @param var the variable to add
|
||||
void AddGlobalVariable(ast::Variable* var) {
|
||||
TINT_ASSERT(var);
|
||||
global_variables_.push_back(var);
|
||||
global_declarations_.push_back(var);
|
||||
}
|
||||
|
@ -62,6 +63,7 @@ class Module : public Castable<Module, Node> {
|
|||
/// The type must be an alias or a struct.
|
||||
/// @param type the constructed type to add
|
||||
void AddConstructedType(type::Type* type) {
|
||||
TINT_ASSERT(type);
|
||||
constructed_types_.push_back(type);
|
||||
global_declarations_.push_back(type);
|
||||
}
|
||||
|
@ -74,6 +76,7 @@ class Module : public Castable<Module, Node> {
|
|||
/// Add a function to the Builder
|
||||
/// @param func the function to add
|
||||
void AddFunction(ast::Function* func) {
|
||||
TINT_ASSERT(func);
|
||||
functions_.push_back(func);
|
||||
global_declarations_.push_back(func);
|
||||
}
|
||||
|
@ -81,9 +84,6 @@ class Module : public Castable<Module, Node> {
|
|||
/// @returns the functions declared in the translation unit
|
||||
const FunctionList& Functions() const { return functions_; }
|
||||
|
||||
/// @returns true if all required fields in the AST are present.
|
||||
bool IsValid() const override;
|
||||
|
||||
/// Clones this node and all transitive child nodes using the `CloneContext`
|
||||
/// `ctx`.
|
||||
/// @param ctx the clone context
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "gtest/gtest-spi.h"
|
||||
#include "src/ast/test_helper.h"
|
||||
|
||||
namespace tint {
|
||||
|
@ -45,78 +46,40 @@ TEST_F(ModuleTest, LookupFunctionMissing) {
|
|||
program.AST().Functions().Find(program.Symbols().Get("Missing")));
|
||||
}
|
||||
|
||||
TEST_F(ModuleTest, IsValid_Empty) {
|
||||
Program program(std::move(*this));
|
||||
EXPECT_TRUE(program.AST().IsValid());
|
||||
TEST_F(ModuleTest, Assert_Null_GlobalVariable) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder builder;
|
||||
builder.AST().AddGlobalVariable(nullptr);
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(ModuleTest, IsValid_GlobalVariable) {
|
||||
Global("var", ty.f32(), StorageClass::kInput);
|
||||
Program program(std::move(*this));
|
||||
EXPECT_TRUE(program.AST().IsValid());
|
||||
TEST_F(ModuleTest, Assert_Invalid_GlobalVariable) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder builder;
|
||||
builder.Global("var", nullptr, StorageClass::kInput);
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(ModuleTest, IsValid_Null_GlobalVariable) {
|
||||
AST().AddGlobalVariable(nullptr);
|
||||
Program program(std::move(*this));
|
||||
EXPECT_FALSE(program.AST().IsValid());
|
||||
TEST_F(ModuleTest, Assert_Null_ConstructedType) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder builder;
|
||||
builder.AST().AddConstructedType(nullptr);
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(ModuleTest, IsValid_Invalid_GlobalVariable) {
|
||||
Global("var", nullptr, StorageClass::kInput);
|
||||
Program program(std::move(*this));
|
||||
EXPECT_FALSE(program.AST().IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ModuleTest, IsValid_Alias) {
|
||||
auto* alias = ty.alias("alias", ty.f32());
|
||||
AST().AddConstructedType(alias);
|
||||
Program program(std::move(*this));
|
||||
EXPECT_TRUE(program.AST().IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ModuleTest, IsValid_Null_Alias) {
|
||||
AST().AddConstructedType(nullptr);
|
||||
Program program(std::move(*this));
|
||||
EXPECT_FALSE(program.AST().IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ModuleTest, IsValid_Struct) {
|
||||
auto* st = ty.struct_("name", {});
|
||||
auto* alias = ty.alias("name", st);
|
||||
AST().AddConstructedType(alias);
|
||||
Program program(std::move(*this));
|
||||
EXPECT_TRUE(program.AST().IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ModuleTest, IsValid_Struct_EmptyName) {
|
||||
auto* st = ty.struct_("", {});
|
||||
auto* alias = ty.alias("name", st);
|
||||
AST().AddConstructedType(alias);
|
||||
Program program(std::move(*this));
|
||||
EXPECT_FALSE(program.AST().IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ModuleTest, IsValid_Function) {
|
||||
Func("main", VariableList(), ty.f32(), StatementList{},
|
||||
ast::FunctionDecorationList{});
|
||||
|
||||
Program program(std::move(*this));
|
||||
EXPECT_TRUE(program.AST().IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ModuleTest, IsValid_Null_Function) {
|
||||
AST().AddFunction(nullptr);
|
||||
Program program(std::move(*this));
|
||||
EXPECT_FALSE(program.AST().IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ModuleTest, IsValid_Invalid_Function) {
|
||||
Func("main", VariableList{}, nullptr, StatementList{},
|
||||
ast::FunctionDecorationList{});
|
||||
|
||||
Program program(std::move(*this));
|
||||
EXPECT_FALSE(program.AST().IsValid());
|
||||
TEST_F(ModuleTest, Assert_Null_Function) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder builder;
|
||||
builder.AST().AddFunction(nullptr);
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -40,9 +40,6 @@ class Node : public Castable<Node, Cloneable> {
|
|||
/// @returns the node source data
|
||||
const Source& source() const { return source_; }
|
||||
|
||||
/// @returns true if the node is valid
|
||||
virtual bool IsValid() const = 0;
|
||||
|
||||
/// Writes a representation of the node to the output stream
|
||||
/// @param sem the semantic info for the program
|
||||
/// @param out the stream to write to
|
||||
|
|
|
@ -38,13 +38,6 @@ ReturnStatement* ReturnStatement::Clone(CloneContext* ctx) const {
|
|||
return ctx->dst->create<ReturnStatement>(src, ret);
|
||||
}
|
||||
|
||||
bool ReturnStatement::IsValid() const {
|
||||
if (value_ != nullptr) {
|
||||
return value_->IsValid();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ReturnStatement::to_str(const semantic::Info& sem,
|
||||
std::ostream& out,
|
||||
size_t indent) const {
|
||||
|
|
|
@ -46,9 +46,6 @@ class ReturnStatement : public Castable<ReturnStatement, Statement> {
|
|||
/// @return the newly cloned node
|
||||
ReturnStatement* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
/// Writes a representation of the node to the output stream
|
||||
/// @param sem the semantic info for the program
|
||||
/// @param out the stream to write to
|
||||
|
|
|
@ -52,23 +52,6 @@ TEST_F(ReturnStatementTest, HasValue_WithValue) {
|
|||
EXPECT_TRUE(r->has_value());
|
||||
}
|
||||
|
||||
TEST_F(ReturnStatementTest, IsValid_WithoutValue) {
|
||||
auto* r = create<ReturnStatement>();
|
||||
EXPECT_TRUE(r->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ReturnStatementTest, IsValid_WithValue) {
|
||||
auto* expr = Expr("expr");
|
||||
auto* r = create<ReturnStatement>(expr);
|
||||
EXPECT_TRUE(r->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ReturnStatementTest, IsValid_InvalidValue) {
|
||||
auto* expr = Expr("");
|
||||
auto* r = create<ReturnStatement>(expr);
|
||||
EXPECT_FALSE(r->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ReturnStatementTest, ToStr_WithValue) {
|
||||
auto* expr = Expr("expr");
|
||||
auto* r = create<ReturnStatement>(expr);
|
||||
|
|
|
@ -22,8 +22,10 @@ namespace tint {
|
|||
namespace ast {
|
||||
|
||||
ScalarConstructorExpression::ScalarConstructorExpression(const Source& source,
|
||||
Literal* litearl)
|
||||
: Base(source), literal_(litearl) {}
|
||||
Literal* literal)
|
||||
: Base(source), literal_(literal) {
|
||||
TINT_ASSERT(literal);
|
||||
}
|
||||
|
||||
ScalarConstructorExpression::ScalarConstructorExpression(
|
||||
ScalarConstructorExpression&&) = default;
|
||||
|
@ -38,10 +40,6 @@ ScalarConstructorExpression* ScalarConstructorExpression::Clone(
|
|||
return ctx->dst->create<ScalarConstructorExpression>(src, lit);
|
||||
}
|
||||
|
||||
bool ScalarConstructorExpression::IsValid() const {
|
||||
return literal_ != nullptr;
|
||||
}
|
||||
|
||||
void ScalarConstructorExpression::to_str(const semantic::Info& sem,
|
||||
std::ostream& out,
|
||||
size_t indent) const {
|
||||
|
|
|
@ -42,9 +42,6 @@ class ScalarConstructorExpression
|
|||
/// @return the newly cloned node
|
||||
ScalarConstructorExpression* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
/// Writes a representation of the node to the output stream
|
||||
/// @param sem the semantic info for the program
|
||||
/// @param out the stream to write to
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "gtest/gtest-spi.h"
|
||||
#include "src/ast/test_helper.h"
|
||||
|
||||
namespace tint {
|
||||
|
@ -33,14 +34,13 @@ TEST_F(ScalarConstructorExpressionTest, Creation_WithSource) {
|
|||
EXPECT_EQ(src.range.begin.column, 2u);
|
||||
}
|
||||
|
||||
TEST_F(ScalarConstructorExpressionTest, IsValid) {
|
||||
auto* c = Expr(true);
|
||||
EXPECT_TRUE(c->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ScalarConstructorExpressionTest, IsValid_MissingLiteral) {
|
||||
auto* c = create<ScalarConstructorExpression>(nullptr);
|
||||
EXPECT_FALSE(c->IsValid());
|
||||
TEST_F(ScalarConstructorExpressionTest, Assert_NullLiteral) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.create<ScalarConstructorExpression>(nullptr);
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(ScalarConstructorExpressionTest, ToStr) {
|
||||
|
|
|
@ -27,7 +27,14 @@ Struct::Struct(const Source& source,
|
|||
StructDecorationList decorations)
|
||||
: Base(source),
|
||||
members_(std::move(members)),
|
||||
decorations_(std::move(decorations)) {}
|
||||
decorations_(std::move(decorations)) {
|
||||
for (auto* mem : members_) {
|
||||
TINT_ASSERT(mem);
|
||||
}
|
||||
for (auto* deco : decorations_) {
|
||||
TINT_ASSERT(deco);
|
||||
}
|
||||
}
|
||||
|
||||
Struct::Struct(Struct&&) = default;
|
||||
|
||||
|
@ -59,15 +66,6 @@ Struct* Struct::Clone(CloneContext* ctx) const {
|
|||
return ctx->dst->create<Struct>(src, mem, decos);
|
||||
}
|
||||
|
||||
bool Struct::IsValid() const {
|
||||
for (auto* mem : members_) {
|
||||
if (mem == nullptr || !mem->IsValid()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Struct::to_str(const semantic::Info& sem,
|
||||
std::ostream& out,
|
||||
size_t indent) const {
|
||||
|
|
|
@ -58,9 +58,6 @@ class Struct : public Castable<Struct, Node> {
|
|||
/// @return the newly cloned node
|
||||
Struct* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
/// Writes a representation of the node to the output stream
|
||||
/// @param sem the semantic info for the program
|
||||
/// @param out the stream to write to
|
||||
|
|
|
@ -28,7 +28,13 @@ StructMember::StructMember(const Source& source,
|
|||
: Base(source),
|
||||
symbol_(sym),
|
||||
type_(type),
|
||||
decorations_(std::move(decorations)) {}
|
||||
decorations_(std::move(decorations)) {
|
||||
TINT_ASSERT(type);
|
||||
TINT_ASSERT(symbol_.IsValid());
|
||||
for (auto* deco : decorations_) {
|
||||
TINT_ASSERT(deco);
|
||||
}
|
||||
}
|
||||
|
||||
StructMember::StructMember(StructMember&&) = default;
|
||||
|
||||
|
@ -61,18 +67,6 @@ StructMember* StructMember::Clone(CloneContext* ctx) const {
|
|||
return ctx->dst->create<StructMember>(src, sym, ty, decos);
|
||||
}
|
||||
|
||||
bool StructMember::IsValid() const {
|
||||
if (type_ == nullptr || !symbol_.IsValid()) {
|
||||
return false;
|
||||
}
|
||||
for (auto* deco : decorations_) {
|
||||
if (deco == nullptr) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void StructMember::to_str(const semantic::Info& sem,
|
||||
std::ostream& out,
|
||||
size_t indent) const {
|
||||
|
|
|
@ -59,9 +59,6 @@ class StructMember : public Castable<StructMember, Node> {
|
|||
/// @return the newly cloned node
|
||||
StructMember* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
/// Writes a representation of the node to the output stream
|
||||
/// @param sem the semantic info for the program
|
||||
/// @param out the stream to write to
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "gtest/gtest-spi.h"
|
||||
#include "src/ast/test_helper.h"
|
||||
|
||||
namespace tint {
|
||||
|
@ -45,24 +46,31 @@ TEST_F(StructMemberTest, CreationWithSource) {
|
|||
EXPECT_EQ(st->source().range.end.column, 8u);
|
||||
}
|
||||
|
||||
TEST_F(StructMemberTest, IsValid) {
|
||||
auto* st = Member("a", ty.i32());
|
||||
EXPECT_TRUE(st->IsValid());
|
||||
TEST_F(StructMemberTest, Assert_EmptySymbol) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.Member("", b.ty.i32());
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(StructMemberTest, IsValid_EmptySymbol) {
|
||||
auto* st = Member("", ty.i32());
|
||||
EXPECT_FALSE(st->IsValid());
|
||||
TEST_F(StructMemberTest, Assert_NullType) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.Member("a", nullptr);
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(StructMemberTest, IsValid_NullType) {
|
||||
auto* st = Member("a", nullptr);
|
||||
EXPECT_FALSE(st->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(StructMemberTest, IsValid_Null_Decoration) {
|
||||
auto* st = Member("a", ty.i32(), {MemberOffset(4), nullptr});
|
||||
EXPECT_FALSE(st->IsValid());
|
||||
TEST_F(StructMemberTest, Assert_NullDecoration) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.Member("a", b.ty.i32(), {b.MemberOffset(4), nullptr});
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(StructMemberTest, ToStr) {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "gtest/gtest-spi.h"
|
||||
#include "src/ast/struct_block_decoration.h"
|
||||
#include "src/ast/test_helper.h"
|
||||
|
||||
|
@ -62,21 +63,24 @@ TEST_F(StructTest, CreationWithSourceAndDecorations) {
|
|||
EXPECT_EQ(s->source().range.end.column, 8u);
|
||||
}
|
||||
|
||||
TEST_F(StructTest, IsValid) {
|
||||
auto* s = create<Struct>(StructMemberList{}, StructDecorationList{});
|
||||
EXPECT_TRUE(s->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(StructTest, IsValid_Null_StructMember) {
|
||||
auto* s = create<Struct>(StructMemberList{Member("a", ty.i32()), nullptr},
|
||||
TEST_F(StructTest, Assert_Null_StructMember) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.create<Struct>(StructMemberList{b.Member("a", b.ty.i32()), nullptr},
|
||||
StructDecorationList{});
|
||||
EXPECT_FALSE(s->IsValid());
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(StructTest, IsValid_Invalid_StructMember) {
|
||||
auto* s = create<Struct>(StructMemberList{Member("", ty.i32())},
|
||||
ast::StructDecorationList{});
|
||||
EXPECT_FALSE(s->IsValid());
|
||||
TEST_F(StructTest, Assert_Null_Decoration) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.create<Struct>(StructMemberList{b.Member("a", b.ty.i32())},
|
||||
StructDecorationList{nullptr});
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(StructTest, ToStr) {
|
||||
|
|
|
@ -24,7 +24,12 @@ namespace ast {
|
|||
SwitchStatement::SwitchStatement(const Source& source,
|
||||
Expression* condition,
|
||||
CaseStatementList body)
|
||||
: Base(source), condition_(condition), body_(body) {}
|
||||
: Base(source), condition_(condition), body_(body) {
|
||||
TINT_ASSERT(condition_);
|
||||
for (auto* stmt : body_) {
|
||||
TINT_ASSERT(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
SwitchStatement::SwitchStatement(SwitchStatement&&) = default;
|
||||
|
||||
|
@ -38,18 +43,6 @@ SwitchStatement* SwitchStatement::Clone(CloneContext* ctx) const {
|
|||
return ctx->dst->create<SwitchStatement>(src, cond, b);
|
||||
}
|
||||
|
||||
bool SwitchStatement::IsValid() const {
|
||||
if (condition_ == nullptr || !condition_->IsValid()) {
|
||||
return false;
|
||||
}
|
||||
for (auto* stmt : body_) {
|
||||
if (stmt == nullptr || !stmt->IsValid()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SwitchStatement::to_str(const semantic::Info& sem,
|
||||
std::ostream& out,
|
||||
size_t indent) const {
|
||||
|
|
|
@ -49,9 +49,6 @@ class SwitchStatement : public Castable<SwitchStatement, Statement> {
|
|||
/// @return the newly cloned node
|
||||
SwitchStatement* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
/// Writes a representation of the node to the output stream
|
||||
/// @param sem the semantic info for the program
|
||||
/// @param out the stream to write to
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "src/ast/switch_statement.h"
|
||||
|
||||
#include "gtest/gtest-spi.h"
|
||||
#include "src/ast/test_helper.h"
|
||||
|
||||
namespace tint {
|
||||
|
@ -61,69 +62,26 @@ TEST_F(SwitchStatementTest, IsSwitch) {
|
|||
EXPECT_TRUE(stmt->Is<SwitchStatement>());
|
||||
}
|
||||
|
||||
TEST_F(SwitchStatementTest, IsValid) {
|
||||
CaseSelectorList lit;
|
||||
lit.push_back(create<SintLiteral>(ty.i32(), 2));
|
||||
|
||||
auto* ident = Expr("ident");
|
||||
CaseStatementList body;
|
||||
body.push_back(
|
||||
create<CaseStatement>(lit, create<BlockStatement>(StatementList{})));
|
||||
|
||||
auto* stmt = create<SwitchStatement>(ident, body);
|
||||
EXPECT_TRUE(stmt->IsValid());
|
||||
TEST_F(SwitchStatementTest, Assert_Null_Condition) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
CaseStatementList cases;
|
||||
cases.push_back(
|
||||
b.create<CaseStatement>(CaseSelectorList{b.Literal(1)},
|
||||
b.create<BlockStatement>(StatementList{})));
|
||||
b.create<SwitchStatement>(nullptr, cases);
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(SwitchStatementTest, IsValid_Null_Condition) {
|
||||
CaseSelectorList lit;
|
||||
lit.push_back(create<SintLiteral>(ty.i32(), 2));
|
||||
|
||||
CaseStatementList body;
|
||||
body.push_back(
|
||||
create<CaseStatement>(lit, create<BlockStatement>(StatementList{})));
|
||||
|
||||
auto* stmt = create<SwitchStatement>(nullptr, body);
|
||||
EXPECT_FALSE(stmt->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(SwitchStatementTest, IsValid_Invalid_Condition) {
|
||||
CaseSelectorList lit;
|
||||
lit.push_back(create<SintLiteral>(ty.i32(), 2));
|
||||
|
||||
auto* ident = Expr("");
|
||||
CaseStatementList body;
|
||||
body.push_back(
|
||||
create<CaseStatement>(lit, create<BlockStatement>(StatementList{})));
|
||||
|
||||
auto* stmt = create<SwitchStatement>(ident, body);
|
||||
EXPECT_FALSE(stmt->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(SwitchStatementTest, IsValid_Null_BodyStatement) {
|
||||
CaseSelectorList lit;
|
||||
lit.push_back(create<SintLiteral>(ty.i32(), 2));
|
||||
|
||||
auto* ident = Expr("ident");
|
||||
CaseStatementList body;
|
||||
body.push_back(
|
||||
create<CaseStatement>(lit, create<BlockStatement>(StatementList{})));
|
||||
body.push_back(nullptr);
|
||||
|
||||
auto* stmt = create<SwitchStatement>(ident, body);
|
||||
EXPECT_FALSE(stmt->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(SwitchStatementTest, IsValid_Invalid_BodyStatement) {
|
||||
auto* ident = Expr("ident");
|
||||
|
||||
auto* case_body = create<BlockStatement>(StatementList{
|
||||
nullptr,
|
||||
});
|
||||
CaseStatementList body;
|
||||
body.push_back(create<CaseStatement>(CaseSelectorList{}, case_body));
|
||||
|
||||
auto* stmt = create<SwitchStatement>(ident, body);
|
||||
EXPECT_FALSE(stmt->IsValid());
|
||||
TEST_F(SwitchStatementTest, Assert_Null_CaseStatement) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.create<SwitchStatement>(b.Expr(true), CaseStatementList{nullptr});
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(SwitchStatementTest, ToStr_Empty) {
|
||||
|
|
|
@ -24,7 +24,12 @@ namespace ast {
|
|||
TypeConstructorExpression::TypeConstructorExpression(const Source& source,
|
||||
type::Type* type,
|
||||
ExpressionList values)
|
||||
: Base(source), type_(type), values_(std::move(values)) {}
|
||||
: Base(source), type_(type), values_(std::move(values)) {
|
||||
TINT_ASSERT(type);
|
||||
for (auto* val : values_) {
|
||||
TINT_ASSERT(val);
|
||||
}
|
||||
}
|
||||
|
||||
TypeConstructorExpression::TypeConstructorExpression(
|
||||
TypeConstructorExpression&&) = default;
|
||||
|
@ -40,21 +45,6 @@ TypeConstructorExpression* TypeConstructorExpression::Clone(
|
|||
return ctx->dst->create<TypeConstructorExpression>(src, ty, vals);
|
||||
}
|
||||
|
||||
bool TypeConstructorExpression::IsValid() const {
|
||||
if (values_.empty()) {
|
||||
return true;
|
||||
}
|
||||
if (type_ == nullptr) {
|
||||
return false;
|
||||
}
|
||||
for (auto* val : values_) {
|
||||
if (val == nullptr || !val->IsValid()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void TypeConstructorExpression::to_str(const semantic::Info& sem,
|
||||
std::ostream& out,
|
||||
size_t indent) const {
|
||||
|
|
|
@ -48,9 +48,6 @@ class TypeConstructorExpression
|
|||
/// @return the newly cloned node
|
||||
TypeConstructorExpression* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
/// Writes a representation of the node to the output stream
|
||||
/// @param sem the semantic info for the program
|
||||
/// @param out the stream to write to
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "gtest/gtest-spi.h"
|
||||
#include "src/ast/test_helper.h"
|
||||
|
||||
namespace tint {
|
||||
|
@ -49,44 +50,23 @@ TEST_F(TypeConstructorExpressionTest, IsTypeConstructor) {
|
|||
EXPECT_TRUE(t->Is<TypeConstructorExpression>());
|
||||
}
|
||||
|
||||
TEST_F(TypeConstructorExpressionTest, IsValid) {
|
||||
ExpressionList expr;
|
||||
expr.push_back(Expr("expr"));
|
||||
|
||||
auto* t = create<TypeConstructorExpression>(ty.f32(), expr);
|
||||
EXPECT_TRUE(t->IsValid());
|
||||
TEST_F(TypeConstructorExpressionTest, Assert_NullType) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.create<TypeConstructorExpression>(nullptr, ExpressionList{b.Expr(1)});
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(TypeConstructorExpressionTest, IsValid_EmptyValue) {
|
||||
ExpressionList expr;
|
||||
|
||||
auto* t = create<TypeConstructorExpression>(ty.f32(), expr);
|
||||
EXPECT_TRUE(t->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(TypeConstructorExpressionTest, IsValid_NullType) {
|
||||
ExpressionList expr;
|
||||
expr.push_back(Expr("expr"));
|
||||
|
||||
auto* t = create<TypeConstructorExpression>(nullptr, expr);
|
||||
EXPECT_FALSE(t->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(TypeConstructorExpressionTest, IsValid_NullValue) {
|
||||
ExpressionList expr;
|
||||
expr.push_back(Expr("expr"));
|
||||
expr.push_back(nullptr);
|
||||
|
||||
auto* t = create<TypeConstructorExpression>(ty.f32(), expr);
|
||||
EXPECT_FALSE(t->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(TypeConstructorExpressionTest, IsValid_InvalidValue) {
|
||||
ExpressionList expr;
|
||||
expr.push_back(Expr(""));
|
||||
|
||||
auto* t = create<TypeConstructorExpression>(ty.f32(), expr);
|
||||
EXPECT_FALSE(t->IsValid());
|
||||
TEST_F(TypeConstructorExpressionTest, Assert_NullValue) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.create<TypeConstructorExpression>(b.ty.i32(),
|
||||
ExpressionList{nullptr});
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(TypeConstructorExpressionTest, ToStr) {
|
||||
|
|
|
@ -24,7 +24,9 @@ namespace ast {
|
|||
UnaryOpExpression::UnaryOpExpression(const Source& source,
|
||||
UnaryOp op,
|
||||
Expression* expr)
|
||||
: Base(source), op_(op), expr_(expr) {}
|
||||
: Base(source), op_(op), expr_(expr) {
|
||||
TINT_ASSERT(expr_);
|
||||
}
|
||||
|
||||
UnaryOpExpression::UnaryOpExpression(UnaryOpExpression&&) = default;
|
||||
|
||||
|
@ -37,10 +39,6 @@ UnaryOpExpression* UnaryOpExpression::Clone(CloneContext* ctx) const {
|
|||
return ctx->dst->create<UnaryOpExpression>(src, op_, e);
|
||||
}
|
||||
|
||||
bool UnaryOpExpression::IsValid() const {
|
||||
return expr_ != nullptr && expr_->IsValid();
|
||||
}
|
||||
|
||||
void UnaryOpExpression::to_str(const semantic::Info& sem,
|
||||
std::ostream& out,
|
||||
size_t indent) const {
|
||||
|
|
|
@ -44,9 +44,6 @@ class UnaryOpExpression : public Castable<UnaryOpExpression, Expression> {
|
|||
/// @return the newly cloned node
|
||||
UnaryOpExpression* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
/// Writes a representation of the node to the output stream
|
||||
/// @param sem the semantic info for the program
|
||||
/// @param out the stream to write to
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "src/ast/unary_op_expression.h"
|
||||
|
||||
#include "gtest/gtest-spi.h"
|
||||
#include "src/ast/test_helper.h"
|
||||
|
||||
namespace tint {
|
||||
|
@ -45,21 +46,13 @@ TEST_F(UnaryOpExpressionTest, IsUnaryOp) {
|
|||
EXPECT_TRUE(u->Is<UnaryOpExpression>());
|
||||
}
|
||||
|
||||
TEST_F(UnaryOpExpressionTest, IsValid) {
|
||||
auto* ident = Expr("ident");
|
||||
auto* u = create<UnaryOpExpression>(UnaryOp::kNot, ident);
|
||||
EXPECT_TRUE(u->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(UnaryOpExpressionTest, IsValid_NullExpression) {
|
||||
auto* u = create<UnaryOpExpression>(UnaryOp::kNot, nullptr);
|
||||
EXPECT_FALSE(u->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(UnaryOpExpressionTest, IsValid_InvalidExpression) {
|
||||
auto* ident = Expr("");
|
||||
auto* u = create<UnaryOpExpression>(UnaryOp::kNot, ident);
|
||||
EXPECT_FALSE(u->IsValid());
|
||||
TEST_F(UnaryOpExpressionTest, Assert_NullExpression) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.create<UnaryOpExpression>(UnaryOp::kNot, nullptr);
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(UnaryOpExpressionTest, ToStr) {
|
||||
|
|
|
@ -36,7 +36,10 @@ Variable::Variable(const Source& source,
|
|||
is_const_(is_const),
|
||||
constructor_(constructor),
|
||||
decorations_(std::move(decorations)),
|
||||
declared_storage_class_(sc) {}
|
||||
declared_storage_class_(sc) {
|
||||
TINT_ASSERT(symbol_.IsValid());
|
||||
TINT_ASSERT(type_);
|
||||
}
|
||||
|
||||
Variable::Variable(Variable&&) = default;
|
||||
|
||||
|
@ -79,7 +82,7 @@ LocationDecoration* Variable::GetLocationDecoration() const {
|
|||
}
|
||||
|
||||
uint32_t Variable::constant_id() const {
|
||||
assert(HasConstantIdDecoration());
|
||||
TINT_ASSERT(HasConstantIdDecoration());
|
||||
for (auto* deco : decorations_) {
|
||||
if (auto* cid = deco->As<ConstantIdDecoration>()) {
|
||||
return cid->value();
|
||||
|
@ -98,19 +101,6 @@ Variable* Variable::Clone(CloneContext* ctx) const {
|
|||
is_const_, ctor, decos);
|
||||
}
|
||||
|
||||
bool Variable::IsValid() const {
|
||||
if (!symbol_.IsValid()) {
|
||||
return false;
|
||||
}
|
||||
if (type_ == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (constructor_ && !constructor_->IsValid()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Variable::info_to_str(const semantic::Info& sem,
|
||||
std::ostream& out,
|
||||
size_t indent) const {
|
||||
|
|
|
@ -137,9 +137,6 @@ class Variable : public Castable<Variable, Node> {
|
|||
/// @return the newly cloned node
|
||||
Variable* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the variable is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
/// Writes a representation of the node to the output stream
|
||||
/// @param sem the semantic info for the program
|
||||
/// @param out the stream to write to
|
||||
|
|
|
@ -23,7 +23,9 @@ namespace ast {
|
|||
|
||||
VariableDeclStatement::VariableDeclStatement(const Source& source,
|
||||
Variable* variable)
|
||||
: Base(source), variable_(variable) {}
|
||||
: Base(source), variable_(variable) {
|
||||
TINT_ASSERT(variable_);
|
||||
}
|
||||
|
||||
VariableDeclStatement::VariableDeclStatement(VariableDeclStatement&&) = default;
|
||||
|
||||
|
@ -36,10 +38,6 @@ VariableDeclStatement* VariableDeclStatement::Clone(CloneContext* ctx) const {
|
|||
return ctx->dst->create<VariableDeclStatement>(src, var);
|
||||
}
|
||||
|
||||
bool VariableDeclStatement::IsValid() const {
|
||||
return variable_ != nullptr && variable_->IsValid();
|
||||
}
|
||||
|
||||
void VariableDeclStatement::to_str(const semantic::Info& sem,
|
||||
std::ostream& out,
|
||||
size_t indent) const {
|
||||
|
|
|
@ -42,9 +42,6 @@ class VariableDeclStatement
|
|||
/// @return the newly cloned node
|
||||
VariableDeclStatement* Clone(CloneContext* ctx) const override;
|
||||
|
||||
/// @returns true if the node is valid
|
||||
bool IsValid() const override;
|
||||
|
||||
/// Writes a representation of the node to the output stream
|
||||
/// @param sem the semantic info for the program
|
||||
/// @param out the stream to write to
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "src/ast/variable_decl_statement.h"
|
||||
|
||||
#include "gtest/gtest-spi.h"
|
||||
#include "src/ast/test_helper.h"
|
||||
|
||||
namespace tint {
|
||||
|
@ -46,21 +47,13 @@ TEST_F(VariableDeclStatementTest, IsVariableDecl) {
|
|||
EXPECT_TRUE(stmt->Is<VariableDeclStatement>());
|
||||
}
|
||||
|
||||
TEST_F(VariableDeclStatementTest, IsValid) {
|
||||
auto* var = Var("a", ty.f32(), StorageClass::kNone);
|
||||
auto* stmt = create<VariableDeclStatement>(var);
|
||||
EXPECT_TRUE(stmt->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(VariableDeclStatementTest, IsValid_InvalidVariable) {
|
||||
auto* var = Var("", ty.f32(), StorageClass::kNone);
|
||||
auto* stmt = create<VariableDeclStatement>(var);
|
||||
EXPECT_FALSE(stmt->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(VariableDeclStatementTest, IsValid_NullVariable) {
|
||||
auto* stmt = create<VariableDeclStatement>(nullptr);
|
||||
EXPECT_FALSE(stmt->IsValid());
|
||||
TEST_F(VariableDeclStatementTest, Assert_NullVariable) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.create<VariableDeclStatement>(nullptr);
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(VariableDeclStatementTest, ToStr) {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "gtest/gtest-spi.h"
|
||||
#include "src/ast/constant_id_decoration.h"
|
||||
#include "src/ast/test_helper.h"
|
||||
|
||||
|
@ -62,34 +63,22 @@ TEST_F(VariableTest, CreationEmpty) {
|
|||
EXPECT_EQ(v->source().range.end.column, 7u);
|
||||
}
|
||||
|
||||
TEST_F(VariableTest, IsValid) {
|
||||
auto* v = Var("my_var", ty.i32(), StorageClass::kNone);
|
||||
EXPECT_TRUE(v->IsValid());
|
||||
TEST_F(VariableTest, Assert_MissingSymbol) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.Var("", b.ty.i32(), StorageClass::kNone);
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(VariableTest, IsValid_WithConstructor) {
|
||||
auto* v = Var("my_var", ty.i32(), StorageClass::kNone, Expr("ident"));
|
||||
EXPECT_TRUE(v->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(VariableTest, IsValid_MissingSymbol) {
|
||||
auto* v = Var("", ty.i32(), StorageClass::kNone);
|
||||
EXPECT_FALSE(v->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(VariableTest, IsValid_MissingType) {
|
||||
auto* v = Var("x", nullptr, StorageClass::kNone);
|
||||
EXPECT_FALSE(v->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(VariableTest, IsValid_MissingBoth) {
|
||||
auto* v = Var("", nullptr, StorageClass::kNone);
|
||||
EXPECT_FALSE(v->IsValid());
|
||||
}
|
||||
|
||||
TEST_F(VariableTest, IsValid_InvalidConstructor) {
|
||||
auto* v = Var("my_var", ty.i32(), StorageClass::kNone, Expr(""));
|
||||
EXPECT_FALSE(v->IsValid());
|
||||
TEST_F(VariableTest, Assert_NullType) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.Var("x", nullptr, StorageClass::kNone);
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(VariableTest, to_str) {
|
||||
|
|
|
@ -37,7 +37,6 @@ struct Node : public Castable<Node, ast::Node> {
|
|||
return out;
|
||||
}
|
||||
|
||||
bool IsValid() const override { return true; }
|
||||
void to_str(const semantic::Info&, std::ostream&, size_t) const override {}
|
||||
};
|
||||
|
||||
|
@ -55,7 +54,6 @@ struct NotANode : public Castable<NotANode, ast::Node> {
|
|||
return ctx->dst->create<NotANode>();
|
||||
}
|
||||
|
||||
bool IsValid() const override { return true; }
|
||||
void to_str(const semantic::Info&, std::ostream&, size_t) const override {}
|
||||
};
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ ProgramBuilder ProgramBuilder::Wrap(const Program* program) {
|
|||
}
|
||||
|
||||
bool ProgramBuilder::IsValid() const {
|
||||
return !diagnostics_.contains_errors() && ast_->IsValid();
|
||||
return !diagnostics_.contains_errors();
|
||||
}
|
||||
|
||||
std::string ProgramBuilder::str(const ast::Node* node) const {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "gtest/gtest-spi.h"
|
||||
#include "src/ast/return_statement.h"
|
||||
#include "src/ast/test_helper.h"
|
||||
|
||||
|
@ -37,109 +38,43 @@ TEST_F(ProgramTest, ToStrEmitsPreambleAndPostamble) {
|
|||
EXPECT_EQ(str, expected);
|
||||
}
|
||||
|
||||
TEST_F(ProgramTest, IsValid_Empty) {
|
||||
TEST_F(ProgramTest, EmptyIsValid) {
|
||||
Program program(std::move(*this));
|
||||
EXPECT_TRUE(program.IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ProgramTest, IsValid_GlobalVariable) {
|
||||
TEST_F(ProgramTest, Assert_GlobalVariable) {
|
||||
Global("var", ty.f32(), ast::StorageClass::kInput);
|
||||
|
||||
Program program(std::move(*this));
|
||||
EXPECT_TRUE(program.IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ProgramTest, IsValid_Null_GlobalVariable) {
|
||||
AST().AddGlobalVariable(nullptr);
|
||||
|
||||
Program program(std::move(*this));
|
||||
EXPECT_FALSE(program.IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ProgramTest, IsValid_Invalid_GlobalVariable) {
|
||||
Global("var", nullptr, ast::StorageClass::kInput);
|
||||
|
||||
Program program(std::move(*this));
|
||||
EXPECT_FALSE(program.IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ProgramTest, IsValid_Alias) {
|
||||
auto* alias = ty.alias("alias", ty.f32());
|
||||
AST().AddConstructedType(alias);
|
||||
|
||||
Program program(std::move(*this));
|
||||
EXPECT_TRUE(program.IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ProgramTest, IsValid_Null_Alias) {
|
||||
AST().AddConstructedType(nullptr);
|
||||
|
||||
Program program(std::move(*this));
|
||||
EXPECT_FALSE(program.IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ProgramTest, IsValid_Struct) {
|
||||
auto* st = ty.struct_("name", {});
|
||||
auto* alias = ty.alias("name", st);
|
||||
AST().AddConstructedType(alias);
|
||||
|
||||
Program program(std::move(*this));
|
||||
EXPECT_TRUE(program.IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ProgramTest, IsValid_Struct_EmptyName) {
|
||||
auto* st = ty.struct_("", {});
|
||||
auto* alias = ty.alias("name", st);
|
||||
AST().AddConstructedType(alias);
|
||||
|
||||
Program program(std::move(*this));
|
||||
EXPECT_FALSE(program.IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ProgramTest, IsValid_Function) {
|
||||
Func("main", ast::VariableList(), ty.f32(), ast::StatementList{},
|
||||
ast::FunctionDecorationList{});
|
||||
|
||||
Program program(std::move(*this));
|
||||
EXPECT_TRUE(program.IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ProgramTest, IsValid_Null_Function) {
|
||||
AST().AddFunction(nullptr);
|
||||
|
||||
Program program(std::move(*this));
|
||||
EXPECT_FALSE(program.IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ProgramTest, IsValid_Invalid_Function) {
|
||||
Func("main", ast::VariableList{}, nullptr, ast::StatementList{},
|
||||
ast::FunctionDecorationList{});
|
||||
|
||||
Program program(std::move(*this));
|
||||
EXPECT_FALSE(program.IsValid());
|
||||
}
|
||||
|
||||
TEST_F(ProgramTest, IsValid_Invalid_UnknownVar) {
|
||||
Func("main", ast::VariableList{}, nullptr,
|
||||
ast::StatementList{
|
||||
create<ast::ReturnStatement>(Expr("unknown_ident")),
|
||||
TEST_F(ProgramTest, Assert_NullGlobalVariable) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.AST().AddGlobalVariable(nullptr);
|
||||
},
|
||||
ast::FunctionDecorationList{});
|
||||
|
||||
Program program(std::move(*this));
|
||||
EXPECT_FALSE(program.IsValid());
|
||||
EXPECT_NE(program.Diagnostics().count(), 0u);
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(ProgramTest, IsValid_GeneratesError) {
|
||||
AST().AddGlobalVariable(nullptr);
|
||||
TEST_F(ProgramTest, Assert_NullConstructedType) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.AST().AddConstructedType(nullptr);
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
Program program(std::move(*this));
|
||||
EXPECT_FALSE(program.IsValid());
|
||||
EXPECT_EQ(program.Diagnostics().count(), 1u);
|
||||
EXPECT_EQ(program.Diagnostics().error_count(), 1u);
|
||||
EXPECT_EQ(program.Diagnostics().begin()->message,
|
||||
"invalid program generated");
|
||||
TEST_F(ProgramTest, Assert_Null_Function) {
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
ProgramBuilder b;
|
||||
b.AST().AddFunction(nullptr);
|
||||
},
|
||||
"internal compiler error");
|
||||
}
|
||||
|
||||
TEST_F(ProgramTest, DiagnosticsMove) {
|
||||
|
|
|
@ -684,9 +684,6 @@ DefInfo::DefInfo(const spvtools::opt::Instruction& def_inst,
|
|||
|
||||
DefInfo::~DefInfo() = default;
|
||||
|
||||
bool StatementBuilder::IsValid() const {
|
||||
return true;
|
||||
}
|
||||
ast::Node* StatementBuilder::Clone(CloneContext*) const {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -4117,6 +4114,9 @@ bool FunctionEmitter::EmitFunctionCall(const spvtools::opt::Instruction& inst) {
|
|||
for (uint32_t iarg = 1; iarg < inst.NumInOperands(); ++iarg) {
|
||||
params.emplace_back(MakeOperand(inst, iarg).expr);
|
||||
}
|
||||
if (failed()) {
|
||||
return false;
|
||||
}
|
||||
auto* call_expr =
|
||||
create<ast::CallExpression>(Source{}, function, std::move(params));
|
||||
auto* result_type = parser_impl_.ConvertType(inst.type_id());
|
||||
|
|
|
@ -368,7 +368,6 @@ class StatementBuilder : public Castable<StatementBuilder, ast::Statement> {
|
|||
virtual ast::Statement* Build(ProgramBuilder* builder) const = 0;
|
||||
|
||||
private:
|
||||
bool IsValid() const override;
|
||||
Node* Clone(CloneContext*) const override;
|
||||
void to_str(const semantic::Info& sem,
|
||||
std::ostream& out,
|
||||
|
|
|
@ -50,7 +50,6 @@ class FakeStmt : public ast::Statement {
|
|||
public:
|
||||
explicit FakeStmt(Source source) : ast::Statement(source) {}
|
||||
FakeStmt* Clone(CloneContext*) const override { return nullptr; }
|
||||
bool IsValid() const override { return true; }
|
||||
void to_str(const semantic::Info&, std::ostream& out, size_t) const override {
|
||||
out << "Fake";
|
||||
}
|
||||
|
@ -60,7 +59,6 @@ class FakeExpr : public ast::Expression {
|
|||
public:
|
||||
explicit FakeExpr(Source source) : ast::Expression(source) {}
|
||||
FakeExpr* Clone(CloneContext*) const override { return nullptr; }
|
||||
bool IsValid() const override { return true; }
|
||||
void to_str(const semantic::Info&, std::ostream&, size_t) const override {}
|
||||
};
|
||||
|
||||
|
|
|
@ -2715,9 +2715,11 @@ bool Builder::GenerateLoopStatement(ast::LoopStatement* stmt) {
|
|||
if (!GenerateLabel(continue_block_id)) {
|
||||
return false;
|
||||
}
|
||||
if (stmt->has_continuing()) {
|
||||
if (!GenerateBlockStatementWithoutScoping(stmt->continuing())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
scope_stack_.pop_scope();
|
||||
|
||||
|
|
Loading…
Reference in New Issue