| // |
| // Copyright 2015 The ANGLE Project Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| // IntermNode_test.cpp: |
| // Unit tests for the AST node classes. |
| // |
| |
| #include "compiler/translator/IntermNode.h" |
| #include "angle_gl.h" |
| #include "compiler/translator/InfoSink.h" |
| #include "compiler/translator/PoolAlloc.h" |
| #include "compiler/translator/StaticType.h" |
| #include "compiler/translator/SymbolTable.h" |
| #include "gtest/gtest.h" |
| |
| using namespace sh; |
| |
| class IntermNodeTest : public testing::Test |
| { |
| public: |
| IntermNodeTest() : mUniqueIndex(0) {} |
| |
| protected: |
| void SetUp() override |
| { |
| allocator.push(); |
| SetGlobalPoolAllocator(&allocator); |
| } |
| |
| void TearDown() override |
| { |
| SetGlobalPoolAllocator(nullptr); |
| allocator.pop(); |
| } |
| |
| TIntermSymbol *createTestSymbol(const TType &type) |
| { |
| std::stringstream symbolNameOut; |
| symbolNameOut << "test" << mUniqueIndex; |
| ImmutableString symbolName(symbolNameOut.str()); |
| ++mUniqueIndex; |
| |
| // We're using a dummy symbol table here, don't need to assign proper symbol ids to these |
| // nodes. |
| TSymbolTable symbolTable; |
| TType *variableType = new TType(type); |
| variableType->setQualifier(EvqTemporary); |
| TVariable *variable = |
| new TVariable(&symbolTable, symbolName, variableType, SymbolType::AngleInternal); |
| TIntermSymbol *node = new TIntermSymbol(variable); |
| node->setLine(createUniqueSourceLoc()); |
| return node; |
| } |
| |
| TIntermSymbol *createTestSymbol() |
| { |
| TType type(EbtFloat, EbpHigh); |
| return createTestSymbol(type); |
| } |
| |
| TFunction *createTestFunction(const TType &returnType, const TIntermSequence &args) |
| { |
| // We're using a dummy symbol table similarly as for creating symbol nodes. |
| const ImmutableString name("testFunc"); |
| TSymbolTable symbolTable; |
| TFunction *func = new TFunction(&symbolTable, name, SymbolType::UserDefined, |
| new TType(returnType), false); |
| for (TIntermNode *arg : args) |
| { |
| const TType *type = new TType(arg->getAsTyped()->getType()); |
| func->addParameter(new TVariable(&symbolTable, ImmutableString("param"), type, |
| SymbolType::UserDefined)); |
| } |
| return func; |
| } |
| |
| void checkTypeEqualWithQualifiers(const TType &original, const TType ©) |
| { |
| ASSERT_EQ(original, copy); |
| ASSERT_EQ(original.getPrecision(), copy.getPrecision()); |
| ASSERT_EQ(original.getQualifier(), copy.getQualifier()); |
| } |
| |
| void checkSymbolCopy(TIntermNode *aOriginal, TIntermNode *aCopy) |
| { |
| ASSERT_NE(aOriginal, aCopy); |
| TIntermSymbol *copy = aCopy->getAsSymbolNode(); |
| TIntermSymbol *original = aOriginal->getAsSymbolNode(); |
| ASSERT_NE(nullptr, copy); |
| ASSERT_NE(nullptr, original); |
| ASSERT_NE(original, copy); |
| ASSERT_EQ(&original->variable(), ©->variable()); |
| ASSERT_EQ(original->uniqueId(), copy->uniqueId()); |
| ASSERT_EQ(original->getName(), copy->getName()); |
| checkTypeEqualWithQualifiers(original->getType(), copy->getType()); |
| ASSERT_EQ(original->getLine().first_file, copy->getLine().first_file); |
| ASSERT_EQ(original->getLine().first_line, copy->getLine().first_line); |
| ASSERT_EQ(original->getLine().last_file, copy->getLine().last_file); |
| ASSERT_EQ(original->getLine().last_line, copy->getLine().last_line); |
| } |
| |
| TSourceLoc createUniqueSourceLoc() |
| { |
| TSourceLoc loc; |
| loc.first_file = mUniqueIndex; |
| loc.first_line = mUniqueIndex + 1; |
| loc.last_file = mUniqueIndex + 2; |
| loc.last_line = mUniqueIndex + 3; |
| ++mUniqueIndex; |
| return loc; |
| } |
| |
| static TSourceLoc getTestSourceLoc() |
| { |
| TSourceLoc loc; |
| loc.first_file = 1; |
| loc.first_line = 2; |
| loc.last_file = 3; |
| loc.last_line = 4; |
| return loc; |
| } |
| |
| static void checkTestSourceLoc(const TSourceLoc &loc) |
| { |
| ASSERT_EQ(1, loc.first_file); |
| ASSERT_EQ(2, loc.first_line); |
| ASSERT_EQ(3, loc.last_file); |
| ASSERT_EQ(4, loc.last_line); |
| } |
| |
| private: |
| angle::PoolAllocator allocator; |
| int mUniqueIndex; |
| }; |
| |
| // Check that the deep copy of a symbol node is an actual copy with the same attributes as the |
| // original. |
| TEST_F(IntermNodeTest, DeepCopySymbolNode) |
| { |
| const TType *type = StaticType::Get<EbtInt, EbpHigh, EvqTemporary, 1, 1>(); |
| |
| // We're using a dummy symbol table here, don't need to assign proper symbol ids to these nodes. |
| TSymbolTable symbolTable; |
| |
| TVariable *variable = |
| new TVariable(&symbolTable, ImmutableString("name"), type, SymbolType::AngleInternal); |
| TIntermSymbol *original = new TIntermSymbol(variable); |
| original->setLine(getTestSourceLoc()); |
| TIntermTyped *copy = original->deepCopy(); |
| checkSymbolCopy(original, copy); |
| checkTestSourceLoc(copy->getLine()); |
| } |
| |
| // Check that the deep copy of a constant union node is an actual copy with the same attributes as |
| // the original. |
| TEST_F(IntermNodeTest, DeepCopyConstantUnionNode) |
| { |
| TType type(EbtInt, EbpHigh); |
| TConstantUnion *constValue = new TConstantUnion[1]; |
| constValue[0].setIConst(101); |
| TIntermConstantUnion *original = new TIntermConstantUnion(constValue, type); |
| original->setLine(getTestSourceLoc()); |
| TIntermTyped *copyTyped = original->deepCopy(); |
| TIntermConstantUnion *copy = copyTyped->getAsConstantUnion(); |
| ASSERT_NE(nullptr, copy); |
| ASSERT_NE(original, copy); |
| checkTestSourceLoc(copy->getLine()); |
| checkTypeEqualWithQualifiers(original->getType(), copy->getType()); |
| ASSERT_EQ(101, copy->getIConst(0)); |
| } |
| |
| // Check that the deep copy of a binary node is an actual copy with the same attributes as the |
| // original. Child nodes also need to be copies with the same attributes as the original children. |
| TEST_F(IntermNodeTest, DeepCopyBinaryNode) |
| { |
| TType type(EbtFloat, EbpHigh); |
| |
| TIntermBinary *original = new TIntermBinary(EOpAdd, createTestSymbol(), createTestSymbol()); |
| original->setLine(getTestSourceLoc()); |
| TIntermTyped *copyTyped = original->deepCopy(); |
| TIntermBinary *copy = copyTyped->getAsBinaryNode(); |
| ASSERT_NE(nullptr, copy); |
| ASSERT_NE(original, copy); |
| checkTestSourceLoc(copy->getLine()); |
| checkTypeEqualWithQualifiers(original->getType(), copy->getType()); |
| |
| checkSymbolCopy(original->getLeft(), copy->getLeft()); |
| checkSymbolCopy(original->getRight(), copy->getRight()); |
| } |
| |
| // Check that the deep copy of a unary node is an actual copy with the same attributes as the |
| // original. The child node also needs to be a copy with the same attributes as the original child. |
| TEST_F(IntermNodeTest, DeepCopyUnaryNode) |
| { |
| TType type(EbtFloat, EbpHigh); |
| |
| TIntermUnary *original = new TIntermUnary(EOpPreIncrement, createTestSymbol(), nullptr); |
| original->setLine(getTestSourceLoc()); |
| TIntermTyped *copyTyped = original->deepCopy(); |
| TIntermUnary *copy = copyTyped->getAsUnaryNode(); |
| ASSERT_NE(nullptr, copy); |
| ASSERT_NE(original, copy); |
| checkTestSourceLoc(copy->getLine()); |
| checkTypeEqualWithQualifiers(original->getType(), copy->getType()); |
| |
| checkSymbolCopy(original->getOperand(), copy->getOperand()); |
| } |
| |
| // Check that the deep copy of an aggregate node is an actual copy with the same attributes as the |
| // original. Child nodes also need to be copies with the same attributes as the original children. |
| TEST_F(IntermNodeTest, DeepCopyAggregateNode) |
| { |
| TIntermSequence *originalSeq = new TIntermSequence(); |
| originalSeq->push_back(createTestSymbol()); |
| originalSeq->push_back(createTestSymbol()); |
| originalSeq->push_back(createTestSymbol()); |
| |
| TFunction *testFunc = |
| createTestFunction(originalSeq->back()->getAsTyped()->getType(), *originalSeq); |
| |
| TIntermAggregate *original = TIntermAggregate::CreateFunctionCall(*testFunc, originalSeq); |
| original->setLine(getTestSourceLoc()); |
| |
| TIntermTyped *copyTyped = original->deepCopy(); |
| TIntermAggregate *copy = copyTyped->getAsAggregate(); |
| ASSERT_NE(nullptr, copy); |
| ASSERT_NE(original, copy); |
| checkTestSourceLoc(copy->getLine()); |
| checkTypeEqualWithQualifiers(original->getType(), copy->getType()); |
| |
| ASSERT_EQ(original->getSequence()->size(), copy->getSequence()->size()); |
| TIntermSequence::size_type i = 0; |
| for (auto *copyChild : *copy->getSequence()) |
| { |
| TIntermNode *originalChild = original->getSequence()->at(i); |
| checkSymbolCopy(originalChild, copyChild); |
| ++i; |
| } |
| } |
| |
| // Check that the deep copy of a ternary node is an actual copy with the same attributes as the |
| // original. Child nodes also need to be copies with the same attributes as the original children. |
| TEST_F(IntermNodeTest, DeepCopyTernaryNode) |
| { |
| TType type(EbtFloat, EbpHigh); |
| |
| TIntermTernary *original = new TIntermTernary(createTestSymbol(TType(EbtBool, EbpUndefined)), |
| createTestSymbol(), createTestSymbol()); |
| original->setLine(getTestSourceLoc()); |
| TIntermTyped *copyTyped = original->deepCopy(); |
| TIntermTernary *copy = copyTyped->getAsTernaryNode(); |
| ASSERT_NE(nullptr, copy); |
| ASSERT_NE(original, copy); |
| checkTestSourceLoc(copy->getLine()); |
| checkTypeEqualWithQualifiers(original->getType(), copy->getType()); |
| |
| checkSymbolCopy(original->getCondition(), copy->getCondition()); |
| checkSymbolCopy(original->getTrueExpression(), copy->getTrueExpression()); |
| checkSymbolCopy(original->getFalseExpression(), copy->getFalseExpression()); |
| } |