diff --git a/src/engine/internal/llvm/llvmbuildutils.cpp b/src/engine/internal/llvm/llvmbuildutils.cpp index c8a70426..c873ed95 100644 --- a/src/engine/internal/llvm/llvmbuildutils.cpp +++ b/src/engine/internal/llvm/llvmbuildutils.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include "llvmbuildutils.h" #include "llvmfunctions.h" @@ -39,6 +41,35 @@ LLVMBuildUtils::LLVMBuildUtils(LLVMCompilerContext *ctx, llvm::IRBuilder<> &buil initTypes(); createVariableMap(); createListMap(); + + // Find unsafe numeric string constants in costume and sound names + if (m_target) { + IEngine *engine = m_target->engine(); + + if (engine) { + auto checkConstant = [this](const std::string &str) { + Value stringValue(str); + Value numberValue(stringValue.toDouble()); + + if (stringValue.isValidNumber() && str == numberValue.toString()) + m_unsafeConstants.insert(str); + }; + + const auto &targets = engine->targets(); + bool found = false; + + for (const auto &target : targets) { + const auto &costumes = target->costumes(); + const auto &sounds = target->sounds(); + + for (const auto &costume : costumes) + checkConstant(costume->name()); + + for (const auto &sound : sounds) + checkConstant(sound->name()); + } + } + } } void LLVMBuildUtils::init(llvm::Function *function, BlockPrototype *procedurePrototype, bool warp, const std::vector> ®s) @@ -429,13 +460,20 @@ std::vector &LLVMBuildUtils::loops() return m_loops; } -Compiler::StaticType LLVMBuildUtils::optimizeRegisterType(const LLVMRegister *reg) +Compiler::StaticType LLVMBuildUtils::optimizeRegisterType(const LLVMRegister *reg) const { Compiler::StaticType ret = reg->type(); // Optimize string constants that represent numbers - if (reg->isConst() && reg->type() == Compiler::StaticType::String && reg->constValue().isValidNumber()) - ret = Compiler::StaticType::Number; + if (reg->isConst() && reg->type() == Compiler::StaticType::String) { + const Value &value = reg->constValue(); + Value numberValue(value.toDouble()); + std::string str = value.toString(); + + // Apply this optimization only if the number matches the string and the constant is safe + if (value.isValidNumber() && numberValue.toString() == str && m_unsafeConstants.find(str) == m_unsafeConstants.cend()) + ret = Compiler::StaticType::Number; + } return ret; } diff --git a/src/engine/internal/llvm/llvmbuildutils.h b/src/engine/internal/llvm/llvmbuildutils.h index e6192ec9..35b77b78 100644 --- a/src/engine/internal/llvm/llvmbuildutils.h +++ b/src/engine/internal/llvm/llvmbuildutils.h @@ -83,7 +83,8 @@ class LLVMBuildUtils std::vector &ifStatements(); std::vector &loops(); - static Compiler::StaticType optimizeRegisterType(const LLVMRegister *reg); + Compiler::StaticType optimizeRegisterType(const LLVMRegister *reg) const; + static Compiler::StaticType mapType(ValueType type); static ValueType mapType(Compiler::StaticType type); static bool isSingleType(Compiler::StaticType type); @@ -161,6 +162,8 @@ class LLVMBuildUtils bool m_warp = false; Compiler::CodeType m_codeType = Compiler::CodeType::Script; + std::unordered_set m_unsafeConstants; + llvm::Value *m_executionContextPtr = nullptr; llvm::Value *m_targetPtr = nullptr; llvm::Value *m_targetVariables = nullptr; diff --git a/src/engine/internal/llvm/llvmcodeanalyzer.cpp b/src/engine/internal/llvm/llvmcodeanalyzer.cpp index f41b54eb..5bcc58b6 100644 --- a/src/engine/internal/llvm/llvmcodeanalyzer.cpp +++ b/src/engine/internal/llvm/llvmcodeanalyzer.cpp @@ -12,6 +12,11 @@ static const std::unordered_set BEGIN_LOOP_INSTRUCTIONS = static const std::unordered_set LIST_WRITE_INSTRUCTIONS = { LLVMInstruction::Type::AppendToList, LLVMInstruction::Type::InsertToList, LLVMInstruction::Type::ListReplace }; +LLVMCodeAnalyzer::LLVMCodeAnalyzer(const LLVMBuildUtils &utils) : + m_utils(utils) +{ +} + void LLVMCodeAnalyzer::analyzeScript(const LLVMInstructionList &script) const { std::unordered_set typeAssignedInstructions; @@ -289,5 +294,5 @@ Compiler::StaticType LLVMCodeAnalyzer::writeType(LLVMInstruction *ins) const } } - return LLVMBuildUtils::optimizeRegisterType(argReg); + return m_utils.optimizeRegisterType(argReg); } diff --git a/src/engine/internal/llvm/llvmcodeanalyzer.h b/src/engine/internal/llvm/llvmcodeanalyzer.h index 4c9b6a4a..94e8ef1d 100644 --- a/src/engine/internal/llvm/llvmcodeanalyzer.h +++ b/src/engine/internal/llvm/llvmcodeanalyzer.h @@ -8,12 +8,16 @@ namespace libscratchcpp { +class LLVMBuildUtils; class LLVMInstructionList; class LLVMInstruction; class LLVMCodeAnalyzer { public: + LLVMCodeAnalyzer(const LLVMBuildUtils &utils); + LLVMCodeAnalyzer(const LLVMCodeAnalyzer &) = delete; + void analyzeScript(const LLVMInstructionList &script) const; private: @@ -50,6 +54,8 @@ class LLVMCodeAnalyzer bool isProcedureCall(const LLVMInstruction *ins) const; Compiler::StaticType writeType(LLVMInstruction *ins) const; + + const LLVMBuildUtils &m_utils; }; } // namespace libscratchcpp diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp index 07dcf003..72dd67bf 100644 --- a/src/engine/internal/llvm/llvmcodebuilder.cpp +++ b/src/engine/internal/llvm/llvmcodebuilder.cpp @@ -28,6 +28,7 @@ LLVMCodeBuilder::LLVMCodeBuilder(LLVMCompilerContext *ctx, BlockPrototype *proce m_module(ctx->module()), m_builder(m_llvmCtx), m_utils(ctx, m_builder, codeType), + m_codeAnalyzer(m_utils), m_procedurePrototype(procedurePrototype), m_defaultWarp(procedurePrototype ? procedurePrototype->warp() : false), m_warp(m_defaultWarp), diff --git a/test/blocks/control_blocks_test.cpp b/test/blocks/control_blocks_test.cpp index 03b75fe5..c45812ec 100644 --- a/test/blocks/control_blocks_test.cpp +++ b/test/blocks/control_blocks_test.cpp @@ -23,6 +23,7 @@ using namespace libscratchcpp; using namespace libscratchcpp::test; using ::testing::Return; +using ::testing::ReturnRef; using ::testing::SaveArg; using ::testing::_; @@ -35,6 +36,8 @@ class ControlBlocksTest : public testing::Test m_engine = m_project.engine().get(); m_extension->registerBlocks(m_engine); registerBlocks(m_engine, m_extension.get()); + + EXPECT_CALL(m_engineMock, targets()).WillRepeatedly(ReturnRef(m_engine->targets())); } std::unique_ptr m_extension; diff --git a/test/blocks/event_blocks_test.cpp b/test/blocks/event_blocks_test.cpp index 03a354bd..299bd680 100644 --- a/test/blocks/event_blocks_test.cpp +++ b/test/blocks/event_blocks_test.cpp @@ -20,6 +20,7 @@ using namespace libscratchcpp; using namespace libscratchcpp::test; using ::testing::Return; +using ::testing::ReturnRef; class EventBlocksTest : public testing::Test { @@ -29,6 +30,8 @@ class EventBlocksTest : public testing::Test m_extension = std::make_unique(); m_engine = m_project.engine().get(); m_extension->registerBlocks(m_engine); + + EXPECT_CALL(m_engineMock, targets()).WillRepeatedly(ReturnRef(m_engine->targets())); } std::unique_ptr m_extension; diff --git a/test/blocks/looks_blocks_test.cpp b/test/blocks/looks_blocks_test.cpp index 7caca7c5..55a0b463 100644 --- a/test/blocks/looks_blocks_test.cpp +++ b/test/blocks/looks_blocks_test.cpp @@ -23,6 +23,7 @@ using namespace libscratchcpp; using namespace libscratchcpp::test; using ::testing::Return; +using ::testing::ReturnRef; using ::testing::ReturnArg; using ::testing::_; @@ -36,6 +37,8 @@ class LooksBlocksTest : public testing::Test m_extension->registerBlocks(m_engine); m_extension->onInit(m_engine); + EXPECT_CALL(m_engineMock, targets()).WillRepeatedly(ReturnRef(m_engine->targets())); + // Create and register fake graphic effects auto colorEffect = std::make_shared(); auto fisheyeEffect = std::make_shared(); diff --git a/test/blocks/motion_blocks_test.cpp b/test/blocks/motion_blocks_test.cpp index a6788c57..b5758bae 100644 --- a/test/blocks/motion_blocks_test.cpp +++ b/test/blocks/motion_blocks_test.cpp @@ -20,6 +20,7 @@ using namespace libscratchcpp; using namespace libscratchcpp::test; using ::testing::Return; +using ::testing::ReturnRef; class MotionBlocksTest : public testing::Test { @@ -29,6 +30,8 @@ class MotionBlocksTest : public testing::Test m_extension = std::make_unique(); m_engine = m_project.engine().get(); m_extension->registerBlocks(m_engine); + + EXPECT_CALL(m_engineMock, targets()).WillRepeatedly(ReturnRef(m_engine->targets())); } std::unique_ptr m_extension; diff --git a/test/blocks/sensing_blocks_test.cpp b/test/blocks/sensing_blocks_test.cpp index 356b94ac..88305621 100644 --- a/test/blocks/sensing_blocks_test.cpp +++ b/test/blocks/sensing_blocks_test.cpp @@ -47,6 +47,8 @@ class SensingBlocksTest : public testing::Test EXPECT_CALL(m_audioInput, audioLoudness()).WillRepeatedly(Return(m_audioLoudness)); SensingBlocks::clock = &m_clock; + + EXPECT_CALL(m_engineMock, targets()).WillRepeatedly(ReturnRef(m_engine->targets())); } void TearDown() override diff --git a/test/llvm/code_analyzer/list_type_analysis.cpp b/test/llvm/code_analyzer/list_type_analysis.cpp index 05e76b13..45d479fb 100644 --- a/test/llvm/code_analyzer/list_type_analysis.cpp +++ b/test/llvm/code_analyzer/list_type_analysis.cpp @@ -1,15 +1,60 @@ +#include +#include +#include +#include +#include #include #include +#include +#include #include #include #include +#include #include using namespace libscratchcpp; -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, FirstListWrite) +class LLVMCodeAnalyzer_ListTypeAnalysis : public testing::Test +{ + public: + void SetUp() override + { + auto engine = m_project.engine(); + m_target = std::make_shared(); + m_spriteWithUnsafeConstants = std::make_shared(); + + auto costume = std::make_shared(m_unsafeCostumeNumConstant, "", ""); + m_spriteWithUnsafeConstants->addCostume(costume); + + auto sound = std::make_shared(m_unsafeSoundNumConstant, "", ""); + m_spriteWithUnsafeConstants->addSound(sound); + + engine->setTargets({ m_target, m_spriteWithUnsafeConstants }); + + m_ctx = std::make_unique(engine.get(), m_target.get()); + m_builder = std::make_unique>(*m_ctx->llvmCtx()); + m_utils = std::make_unique(m_ctx.get(), *m_builder, Compiler::CodeType::Script); + m_analyzer = std::make_unique(*m_utils); + } + + std::unique_ptr m_analyzer; + + const std::string m_safeNumConstant = "3.14"; + const std::string m_unsafeCostumeNumConstant = "12"; + const std::string m_unsafeSoundNumConstant = "-27.672"; + + private: + Project m_project; + std::shared_ptr m_target; + std::shared_ptr m_spriteWithUnsafeConstants; + std::unique_ptr m_ctx; + std::unique_ptr> m_builder; + std::unique_ptr m_utils; +}; + +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, FirstListWrite) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList("", ""); @@ -19,15 +64,14 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, FirstListWrite) appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); list.addInstruction(appendList); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // First write should have Unknown targetType (no previous type) ASSERT_EQ(appendList->targetType, Compiler::StaticType::Unknown); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, SecondListWrite) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, SecondListWrite) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList("", ""); @@ -43,7 +87,7 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, SecondListWrite) appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); list.addInstruction(appendList2); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // First write has no previous type ASSERT_EQ(appendList1->targetType, Compiler::StaticType::Unknown); @@ -52,9 +96,8 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, SecondListWrite) ASSERT_EQ(appendList2->targetType, Compiler::StaticType::Unknown); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, MultipleWritesSameType_AfterClear) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, MultipleWritesSameType_AfterClear) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList("", ""); @@ -80,16 +123,15 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, MultipleWritesSameType_AfterClear) appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); list.addInstruction(appendList3); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(appendList1->targetType, Compiler::StaticType::Void); ASSERT_EQ(appendList2->targetType, Compiler::StaticType::String); ASSERT_EQ(appendList3->targetType, Compiler::StaticType::String); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, MultipleWritesDifferentTypes_AfterClear) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, MultipleWritesDifferentTypes_AfterClear) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList("", ""); @@ -115,16 +157,15 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, MultipleWritesDifferentTypes_AfterClear) appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); list.addInstruction(appendList3); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(appendList1->targetType, Compiler::StaticType::Void); ASSERT_EQ(appendList2->targetType, Compiler::StaticType::Number); ASSERT_EQ(appendList3->targetType, Compiler::StaticType::Number | Compiler::StaticType::String); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, StringOptimization_AfterClear) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, StringOptimization_AfterClear) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList("", ""); @@ -133,7 +174,7 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, StringOptimization_AfterClear) list.addInstruction(clearList); auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, false); - LLVMConstantRegister value1(Compiler::StaticType::String, "3.14"); + LLVMConstantRegister value1(Compiler::StaticType::String, m_safeNumConstant); appendList1->targetList = &targetList; appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); list.addInstruction(appendList1); @@ -144,17 +185,103 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, StringOptimization_AfterClear) appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); list.addInstruction(appendList2); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(appendList1->targetType, Compiler::StaticType::Void); - // String "3.14" optimized to Number, so second write sees Number type + // String gets optimized to Number, so second write sees Number type ASSERT_EQ(appendList2->targetType, Compiler::StaticType::Number); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, ClearListOperation) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, StringOptimization_AfterClear_DifferentString) +{ + LLVMInstructionList list; + List targetList("", ""); + + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, false); + clearList->targetList = &targetList; + list.addInstruction(clearList); + + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "1.0"); + appendList1->targetList = &targetList; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(appendList1); + + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, false); + LLVMConstantRegister value2(Compiler::StaticType::Bool, true); + appendList2->targetList = &targetList; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(appendList2); + + m_analyzer->analyzeScript(list); + + ASSERT_EQ(appendList1->targetType, Compiler::StaticType::Void); + + // String "1.0" does NOT get optimized to Number because it would convert to "1" + ASSERT_EQ(appendList2->targetType, Compiler::StaticType::String); +} + +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, StringOptimization_AfterClear_UnsafeCostumeConstant) +{ + LLVMInstructionList list; + List targetList("", ""); + + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, false); + clearList->targetList = &targetList; + list.addInstruction(clearList); + + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, false); + LLVMConstantRegister value1(Compiler::StaticType::String, m_unsafeCostumeNumConstant); + appendList1->targetList = &targetList; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(appendList1); + + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, false); + LLVMConstantRegister value2(Compiler::StaticType::Bool, true); + appendList2->targetList = &targetList; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(appendList2); + + m_analyzer->analyzeScript(list); + + ASSERT_EQ(appendList1->targetType, Compiler::StaticType::Void); + + // String does NOT get optimized to Number because there's a costume with the same name + ASSERT_EQ(appendList2->targetType, Compiler::StaticType::String); +} + +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, StringOptimization_AfterClear_UnsafeSoundConstant) +{ + LLVMInstructionList list; + List targetList("", ""); + + auto clearList = std::make_shared(LLVMInstruction::Type::ClearList, false); + clearList->targetList = &targetList; + list.addInstruction(clearList); + + auto appendList1 = std::make_shared(LLVMInstruction::Type::AppendToList, false); + LLVMConstantRegister value1(Compiler::StaticType::String, m_unsafeSoundNumConstant); + appendList1->targetList = &targetList; + appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(appendList1); + + auto appendList2 = std::make_shared(LLVMInstruction::Type::AppendToList, false); + LLVMConstantRegister value2(Compiler::StaticType::Bool, true); + appendList2->targetList = &targetList; + appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(appendList2); + + m_analyzer->analyzeScript(list); + + ASSERT_EQ(appendList1->targetType, Compiler::StaticType::Void); + + // String does NOT get optimized to Number because there's a sound with the same name + ASSERT_EQ(appendList2->targetType, Compiler::StaticType::String); +} + +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, ClearListOperation) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList("", ""); @@ -174,7 +301,7 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, ClearListOperation) appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); list.addInstruction(appendList2); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(appendList1->targetType, Compiler::StaticType::Unknown); @@ -182,9 +309,8 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, ClearListOperation) ASSERT_EQ(appendList2->targetType, Compiler::StaticType::Void); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, ProcedureCall) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, ProcedureCall) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList("", ""); @@ -207,7 +333,7 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, ProcedureCall) appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); list.addInstruction(appendList2); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(appendList1->targetType, Compiler::StaticType::Void); @@ -215,9 +341,8 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, ProcedureCall) ASSERT_EQ(appendList2->targetType, Compiler::StaticType::Unknown); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, MixedWriteOperationsSameType_AfterClear) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, MixedWriteOperationsSameType_AfterClear) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList("", ""); @@ -247,16 +372,15 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, MixedWriteOperationsSameType_AfterClear) replaceList->args.push_back({ Compiler::StaticType::Unknown, &value3 }); list.addInstruction(replaceList); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(appendList->targetType, Compiler::StaticType::Void); ASSERT_EQ(insertList->targetType, Compiler::StaticType::String); ASSERT_EQ(replaceList->targetType, Compiler::StaticType::String); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, MixedWriteOperationsDifferentTypes_AfterClear) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, MixedWriteOperationsDifferentTypes_AfterClear) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList("", ""); @@ -292,7 +416,7 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, MixedWriteOperationsDifferentTypes_After appendList2->args.push_back({ Compiler::StaticType::Unknown, &value4 }); list.addInstruction(appendList2); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(appendList->targetType, Compiler::StaticType::Void); ASSERT_EQ(insertList->targetType, Compiler::StaticType::String); @@ -300,9 +424,8 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, MixedWriteOperationsDifferentTypes_After ASSERT_EQ(appendList2->targetType, Compiler::StaticType::Unknown); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, LoopSingleWrite) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, LoopSingleWrite) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList("", ""); @@ -318,15 +441,14 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, LoopSingleWrite) auto loopEnd = std::make_shared(LLVMInstruction::Type::EndLoop, false); list.addInstruction(loopEnd); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // Loop convergence: first iteration Unknown, subsequent iterations Number ASSERT_EQ(appendList->targetType, Compiler::StaticType::Unknown); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, LoopSingleWrite_AfterClear) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, LoopSingleWrite_AfterClear) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList("", ""); @@ -346,14 +468,13 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, LoopSingleWrite_AfterClear) auto loopEnd = std::make_shared(LLVMInstruction::Type::EndLoop, false); list.addInstruction(loopEnd); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(appendList->targetType, Compiler::StaticType::Number); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, ClearAndWriteInIfStatement_IfBranch) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, ClearAndWriteInIfStatement_IfBranch) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList("", ""); @@ -379,7 +500,7 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, ClearAndWriteInIfStatement_IfBranch) appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); list.addInstruction(appendList2); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(appendList1->targetType, Compiler::StaticType::Void); @@ -387,9 +508,8 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, ClearAndWriteInIfStatement_IfBranch) ASSERT_EQ(appendList2->targetType, Compiler::StaticType::Unknown); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, ClearAndWriteInIfStatement_ElseBranch) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, ClearAndWriteInIfStatement_ElseBranch) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList("", ""); @@ -418,7 +538,7 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, ClearAndWriteInIfStatement_ElseBranch) appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); list.addInstruction(appendList2); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(appendList1->targetType, Compiler::StaticType::Void); @@ -426,9 +546,8 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, ClearAndWriteInIfStatement_ElseBranch) ASSERT_EQ(appendList2->targetType, Compiler::StaticType::Unknown); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, ClearAndWriteInIfElse) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, ClearAndWriteInIfElse) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList("", ""); @@ -467,7 +586,7 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, ClearAndWriteInIfElse) appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); list.addInstruction(appendList3); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(appendList1->targetType, Compiler::StaticType::Void); ASSERT_EQ(appendList2->targetType, Compiler::StaticType::Void); @@ -476,9 +595,8 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, ClearAndWriteInIfElse) ASSERT_EQ(appendList3->targetType, Compiler::StaticType::Number | Compiler::StaticType::String); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, ClearAndWriteInLoop) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, ClearAndWriteInLoop) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList("", ""); @@ -504,7 +622,7 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, ClearAndWriteInLoop) appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); list.addInstruction(appendList2); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(appendList1->targetType, Compiler::StaticType::Void); @@ -512,9 +630,8 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, ClearAndWriteInLoop) ASSERT_EQ(appendList2->targetType, Compiler::StaticType::Unknown); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, ClearAfterWriteInLoop) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, ClearAfterWriteInLoop) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList("", ""); @@ -545,14 +662,13 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, ClearAfterWriteInLoop) auto loopEnd = std::make_shared(LLVMInstruction::Type::EndLoop, false); list.addInstruction(loopEnd); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(appendList1->targetType, Compiler::StaticType::Bool); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, WhileLoop) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, WhileLoop) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList("", ""); @@ -595,15 +711,14 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, WhileLoop) auto loopEnd = std::make_shared(LLVMInstruction::Type::EndLoop, false); list.addInstruction(loopEnd); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(getItem->targetType, Compiler::StaticType::Number | Compiler::StaticType::Bool); ASSERT_EQ(appendList1->targetType, Compiler::StaticType::Number | Compiler::StaticType::Bool); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, RepeatUntilLoop) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, RepeatUntilLoop) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList("", ""); @@ -646,15 +761,14 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, RepeatUntilLoop) auto loopEnd = std::make_shared(LLVMInstruction::Type::EndLoop, false); list.addInstruction(loopEnd); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(getItem->targetType, Compiler::StaticType::Number | Compiler::StaticType::Bool); ASSERT_EQ(appendList1->targetType, Compiler::StaticType::Number | Compiler::StaticType::Bool); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, LoopMultipleWrites_UnknownType) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, LoopMultipleWrites_UnknownType) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList("", ""); @@ -676,7 +790,7 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, LoopMultipleWrites_UnknownType) auto loopEnd = std::make_shared(LLVMInstruction::Type::EndLoop, false); list.addInstruction(loopEnd); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // First write: Unknown (unknown before loop) ASSERT_EQ(appendList1->targetType, Compiler::StaticType::Unknown); @@ -685,9 +799,8 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, LoopMultipleWrites_UnknownType) ASSERT_EQ(appendList2->targetType, Compiler::StaticType::Unknown); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, LoopMultipleWrites_AfterClear) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, LoopMultipleWrites_AfterClear) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList("", ""); @@ -714,16 +827,15 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, LoopMultipleWrites_AfterClear) auto loopEnd = std::make_shared(LLVMInstruction::Type::EndLoop, false); list.addInstruction(loopEnd); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // Number | String (from loop iterations) ASSERT_EQ(appendList1->targetType, Compiler::StaticType::Number | Compiler::StaticType::String); ASSERT_EQ(appendList2->targetType, Compiler::StaticType::Number | Compiler::StaticType::String); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, IfElseStatementDifferentTypes) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, IfElseStatementDifferentTypes) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList("", ""); @@ -754,7 +866,7 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, IfElseStatementDifferentTypes) appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); list.addInstruction(appendList3); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // Both writes see Unknown before the if-else ASSERT_EQ(appendList1->targetType, Compiler::StaticType::Unknown); @@ -764,9 +876,8 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, IfElseStatementDifferentTypes) ASSERT_EQ(appendList3->targetType, Compiler::StaticType::Unknown); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, IfElseStatementDifferentTypes_AfterClear) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, IfElseStatementDifferentTypes_AfterClear) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList("", ""); @@ -801,7 +912,7 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, IfElseStatementDifferentTypes_AfterClear appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); list.addInstruction(appendList3); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // Both writes see Void (empty list) before the if-else ASSERT_EQ(appendList1->targetType, Compiler::StaticType::Void); @@ -811,9 +922,8 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, IfElseStatementDifferentTypes_AfterClear ASSERT_EQ(appendList3->targetType, Compiler::StaticType::Number | Compiler::StaticType::String); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, IfElseStatementDifferentType_IfBranch_AfterClear) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, IfElseStatementDifferentType_IfBranch_AfterClear) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList("", ""); @@ -845,7 +955,7 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, IfElseStatementDifferentType_IfBranch_Af appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); list.addInstruction(appendList3); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(appendList1->targetType, Compiler::StaticType::Void); ASSERT_EQ(appendList2->targetType, Compiler::StaticType::Number); @@ -854,9 +964,8 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, IfElseStatementDifferentType_IfBranch_Af ASSERT_EQ(appendList3->targetType, Compiler::StaticType::Number | Compiler::StaticType::String); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, IfElseStatementDifferentType_ElseBranch_AfterClear) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, IfElseStatementDifferentType_ElseBranch_AfterClear) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList("", ""); @@ -891,7 +1000,7 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, IfElseStatementDifferentType_ElseBranch_ appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); list.addInstruction(appendList3); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(appendList1->targetType, Compiler::StaticType::Void); ASSERT_EQ(appendList2->targetType, Compiler::StaticType::Number); @@ -900,9 +1009,8 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, IfElseStatementDifferentType_ElseBranch_ ASSERT_EQ(appendList3->targetType, Compiler::StaticType::Number | Compiler::StaticType::String); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, WriteBeforeLoop_AfterClear) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, WriteBeforeLoop_AfterClear) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList("", ""); @@ -934,14 +1042,13 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, WriteBeforeLoop_AfterClear) appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); list.addInstruction(appendList); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(appendList->targetType, Compiler::StaticType::String | Compiler::StaticType::Number); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, WriteBeforeIfStatement_IfBranch_AfterClear) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, WriteBeforeIfStatement_IfBranch_AfterClear) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList("", ""); @@ -973,14 +1080,13 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, WriteBeforeIfStatement_IfBranch_AfterCle appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); list.addInstruction(appendList); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(appendList->targetType, Compiler::StaticType::String | Compiler::StaticType::Number); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, WriteBeforeIfStatement_ElseBranch_AfterClear) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, WriteBeforeIfStatement_ElseBranch_AfterClear) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList("", ""); @@ -1015,14 +1121,13 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, WriteBeforeIfStatement_ElseBranch_AfterC appendList->args.push_back({ Compiler::StaticType::Unknown, &value }); list.addInstruction(appendList); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(appendList->targetType, Compiler::StaticType::String | Compiler::StaticType::Number); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, WriteBeforeIfElse_AfterClear) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, WriteBeforeIfElse_AfterClear) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList("", ""); @@ -1063,7 +1168,7 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, WriteBeforeIfElse_AfterClear) appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); list.addInstruction(appendList3); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // Write before if-else establishes Bool type ASSERT_EQ(appendListBefore->targetType, Compiler::StaticType::Void); @@ -1076,9 +1181,8 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, WriteBeforeIfElse_AfterClear) ASSERT_EQ(appendList3->targetType, Compiler::StaticType::Unknown); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, ComplexNestedControlFlow_AfterClear) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, ComplexNestedControlFlow_AfterClear) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList("", ""); @@ -1131,7 +1235,7 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, ComplexNestedControlFlow_AfterClear) appendList4->args.push_back({ Compiler::StaticType::Unknown, &value4 }); list.addInstruction(appendList4); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // Complex analysis with multiple execution paths and loop convergence ASSERT_EQ(appendList1->targetType, Compiler::StaticType::Unknown); @@ -1140,9 +1244,8 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, ComplexNestedControlFlow_AfterClear) ASSERT_EQ(appendList4->targetType, Compiler::StaticType::Unknown); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, MultipleListsSeparateAnalysis) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, MultipleListsSeparateAnalysis) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List targetList1("", ""), targetList2("", ""); @@ -1162,16 +1265,15 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, MultipleListsSeparateAnalysis) appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); list.addInstruction(appendList2); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // Both are first writes for their respective lists ASSERT_EQ(appendList1->targetType, Compiler::StaticType::Void); ASSERT_EQ(appendList2->targetType, Compiler::StaticType::Unknown); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, CrossListDependency_SingleType) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, CrossListDependency_SingleType) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List sourceList("", ""), targetList("", ""); @@ -1211,7 +1313,7 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, CrossListDependency_SingleType) appendList1_2->args.push_back({ Compiler::StaticType::Unknown, &sourceValue }); list.addInstruction(appendList1_2); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // sourceList first write has no previous type ASSERT_EQ(appendList2->targetType, Compiler::StaticType::Void); @@ -1226,9 +1328,8 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, CrossListDependency_SingleType) ASSERT_EQ(appendList1_2->targetType, Compiler::StaticType::Number | Compiler::StaticType::String); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, CrossListDependency_MultipleTypes) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, CrossListDependency_MultipleTypes) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List sourceList("", ""), targetList("", ""); @@ -1275,7 +1376,7 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, CrossListDependency_MultipleTypes) appendList4->args.push_back({ Compiler::StaticType::Unknown, &sourceValue }); list.addInstruction(appendList4); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // sourceList has Number or Bool type at read operation ASSERT_EQ(getItem->targetType, Compiler::StaticType::Number | Compiler::StaticType::Bool); @@ -1287,9 +1388,8 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, CrossListDependency_MultipleTypes) ASSERT_EQ(appendList4->targetType, Compiler::StaticType::Unknown); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, ChainedAssignmentsInLoop) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, ChainedAssignmentsInLoop) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List listA("a", ""), listB("b", ""), listC("c", ""); @@ -1412,7 +1512,7 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, ChainedAssignmentsInLoop) appendA3->args.push_back({ Compiler::StaticType::Unknown, &cValue2 }); list.addInstruction(appendA3); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // Check the type of 'a' before the final clear operation // 'a' could be Number (from initial assignment) or String (from loop iterations) @@ -1425,9 +1525,8 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, ChainedAssignmentsInLoop) ASSERT_EQ(getC2->targetType, expectedCType); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, ListReadReturnRegType) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, ListReadReturnRegType) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List sourceList("", ""), targetList("", ""); @@ -1461,15 +1560,14 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, ListReadReturnRegType) appendList1_1->args.push_back({ Compiler::StaticType::Unknown, &sourceValue }); list.addInstruction(appendList1_1); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // sourceList read return register has Number | String type (get list item can always return string) ASSERT_EQ(sourceValue.type(), Compiler::StaticType::Number | Compiler::StaticType::String); } -TEST(LLVMCodeAnalyzer_ListTypeAnalysis, CrossListWriteArgType) +TEST_F(LLVMCodeAnalyzer_ListTypeAnalysis, CrossListWriteArgType) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List sourceList("", ""), targetList("", ""); @@ -1503,7 +1601,7 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, CrossListWriteArgType) appendList1_1->args.push_back({ Compiler::StaticType::Unknown, &sourceValue }); list.addInstruction(appendList1_1); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // last write argument has Number | String type (get list item can always return string) ASSERT_EQ(appendList1_1->args.back().first, Compiler::StaticType::Number | Compiler::StaticType::String); diff --git a/test/llvm/code_analyzer/mixed_type_analysis.cpp b/test/llvm/code_analyzer/mixed_type_analysis.cpp index b1dbde86..a082ee92 100644 --- a/test/llvm/code_analyzer/mixed_type_analysis.cpp +++ b/test/llvm/code_analyzer/mixed_type_analysis.cpp @@ -1,35 +1,59 @@ +#include +#include #include #include #include +#include +#include #include #include #include +#include #include using namespace libscratchcpp; -TEST(LLVMCodeAnalyzer_MixedTypeAnalysis, EmptyScript) +class LLVMCodeAnalyzer_MixedTypeAnalysis : public testing::Test +{ + public: + void SetUp() override + { + auto engine = m_project.engine(); + m_ctx = std::make_unique(engine.get(), &m_target); + m_builder = std::make_unique>(*m_ctx->llvmCtx()); + m_utils = std::make_unique(m_ctx.get(), *m_builder, Compiler::CodeType::Script); + m_analyzer = std::make_unique(*m_utils); + } + + std::unique_ptr m_analyzer; + + private: + Project m_project; + Target m_target; + std::unique_ptr m_ctx; + std::unique_ptr> m_builder; + std::unique_ptr m_utils; +}; + +TEST_F(LLVMCodeAnalyzer_MixedTypeAnalysis, EmptyScript) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); } -TEST(LLVMCodeAnalyzer_MixedTypeAnalysis, NoOperations) +TEST_F(LLVMCodeAnalyzer_MixedTypeAnalysis, NoOperations) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; auto funcCall = std::make_shared(LLVMInstruction::Type::FunctionCall, false); list.addInstruction(funcCall); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); } -TEST(LLVMCodeAnalyzer_MixedTypeAnalysis, VariableToList_SimpleTransfer) +TEST_F(LLVMCodeAnalyzer_MixedTypeAnalysis, VariableToList_SimpleTransfer) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable sourceVar("sourceVar", ""); List targetList("targetList", ""); @@ -60,7 +84,7 @@ TEST(LLVMCodeAnalyzer_MixedTypeAnalysis, VariableToList_SimpleTransfer) appendList->args.push_back({ Compiler::StaticType::Unknown, &readVarReg }); list.addInstruction(appendList); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // Variable write should see Unknown (first write) ASSERT_EQ(writeVar->targetType, Compiler::StaticType::Unknown); @@ -75,9 +99,8 @@ TEST(LLVMCodeAnalyzer_MixedTypeAnalysis, VariableToList_SimpleTransfer) ASSERT_EQ(readVarReg.type(), Compiler::StaticType::String); } -TEST(LLVMCodeAnalyzer_MixedTypeAnalysis, ListToVariable_SimpleTransfer) +TEST_F(LLVMCodeAnalyzer_MixedTypeAnalysis, ListToVariable_SimpleTransfer) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List sourceList("sourceList", ""); Variable targetVar("targetVar", ""); @@ -110,7 +133,7 @@ TEST(LLVMCodeAnalyzer_MixedTypeAnalysis, ListToVariable_SimpleTransfer) writeVar->args.push_back({ Compiler::StaticType::Unknown, &readListReg }); list.addInstruction(writeVar); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // List append should see Void (empty list after clear) ASSERT_EQ(appendList->targetType, Compiler::StaticType::Void); @@ -125,9 +148,8 @@ TEST(LLVMCodeAnalyzer_MixedTypeAnalysis, ListToVariable_SimpleTransfer) ASSERT_EQ(readListReg.type(), Compiler::StaticType::Bool | Compiler::StaticType::String); } -TEST(LLVMCodeAnalyzer_MixedTypeAnalysis, CircularVarListDependency) +TEST_F(LLVMCodeAnalyzer_MixedTypeAnalysis, CircularVarListDependency) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var("var", ""); List targetList("list", ""); @@ -176,7 +198,7 @@ TEST(LLVMCodeAnalyzer_MixedTypeAnalysis, CircularVarListDependency) writeVar2->args.push_back({ Compiler::StaticType::Unknown, &readListReg }); list.addInstruction(writeVar2); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // Should handle circular dependency gracefully ASSERT_EQ(writeVar1->targetType, Compiler::StaticType::Unknown); @@ -186,9 +208,8 @@ TEST(LLVMCodeAnalyzer_MixedTypeAnalysis, CircularVarListDependency) ASSERT_EQ(writeVar2->targetType, Compiler::StaticType::Number); } -TEST(LLVMCodeAnalyzer_MixedTypeAnalysis, LoopWithVarListInteraction_TypeConflict) +TEST_F(LLVMCodeAnalyzer_MixedTypeAnalysis, LoopWithVarListInteraction_TypeConflict) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var("var", ""); List targetList("list", ""); @@ -232,7 +253,7 @@ TEST(LLVMCodeAnalyzer_MixedTypeAnalysis, LoopWithVarListInteraction_TypeConflict auto loopEnd = std::make_shared(LLVMInstruction::Type::EndLoop, false); list.addInstruction(loopEnd); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // Should show type accumulation through loop iterations ASSERT_EQ(writeVar1->targetType, Compiler::StaticType::Unknown); @@ -241,9 +262,8 @@ TEST(LLVMCodeAnalyzer_MixedTypeAnalysis, LoopWithVarListInteraction_TypeConflict ASSERT_EQ(writeVar2->targetType, Compiler::StaticType::String | Compiler::StaticType::Number); } -TEST(LLVMCodeAnalyzer_MixedTypeAnalysis, ConditionalVarListTransfer_TypeConflict) +TEST_F(LLVMCodeAnalyzer_MixedTypeAnalysis, ConditionalVarListTransfer_TypeConflict) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var("var", ""); List targetList("list", ""); @@ -303,7 +323,7 @@ TEST(LLVMCodeAnalyzer_MixedTypeAnalysis, ConditionalVarListTransfer_TypeConflict auto ifEnd = std::make_shared(LLVMInstruction::Type::EndIf, false); list.addInstruction(ifEnd); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // Should show type conflicts from conditional branches ASSERT_EQ(writeVar1->targetType, Compiler::StaticType::Unknown); @@ -312,9 +332,8 @@ TEST(LLVMCodeAnalyzer_MixedTypeAnalysis, ConditionalVarListTransfer_TypeConflict ASSERT_EQ(appendList2->targetType, Compiler::StaticType::Void); } -TEST(LLVMCodeAnalyzer_MixedTypeAnalysis, MultipleVarsToSingleList_TypePropagation) +TEST_F(LLVMCodeAnalyzer_MixedTypeAnalysis, MultipleVarsToSingleList_TypePropagation) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var1("var1", ""); Variable var2("var2", ""); @@ -368,16 +387,15 @@ TEST(LLVMCodeAnalyzer_MixedTypeAnalysis, MultipleVarsToSingleList_TypePropagatio appendList2->args.push_back({ Compiler::StaticType::Unknown, &readVar2Reg }); list.addInstruction(appendList2); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // List should have Bool type from both variables ASSERT_EQ(appendList1->targetType, Compiler::StaticType::Void); ASSERT_EQ(appendList2->targetType, Compiler::StaticType::Bool); } -TEST(LLVMCodeAnalyzer_MixedTypeAnalysis, SingleListToMultipleVars_TypePropagation) +TEST_F(LLVMCodeAnalyzer_MixedTypeAnalysis, SingleListToMultipleVars_TypePropagation) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; List sourceList("sourceList", ""); Variable var1("var1", ""); @@ -434,7 +452,7 @@ TEST(LLVMCodeAnalyzer_MixedTypeAnalysis, SingleListToMultipleVars_TypePropagatio writeVar2->args.push_back({ Compiler::StaticType::Unknown, &readList2Reg }); list.addInstruction(writeVar2); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // Both variables should have String type from the list ASSERT_EQ(writeVar1->targetType, Compiler::StaticType::Unknown); @@ -443,9 +461,8 @@ TEST(LLVMCodeAnalyzer_MixedTypeAnalysis, SingleListToMultipleVars_TypePropagatio ASSERT_EQ(readList2Reg.type(), Compiler::StaticType::String); } -TEST(LLVMCodeAnalyzer_MixedTypeAnalysis, ComplexChain_VarToListToVar_TypePropagation) +TEST_F(LLVMCodeAnalyzer_MixedTypeAnalysis, ComplexChain_VarToListToVar_TypePropagation) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable sourceVar("sourceVar", ""); List intermediateList("intermediateList", ""); @@ -494,7 +511,7 @@ TEST(LLVMCodeAnalyzer_MixedTypeAnalysis, ComplexChain_VarToListToVar_TypePropaga writeTargetVar->args.push_back({ Compiler::StaticType::Unknown, &readListReg }); list.addInstruction(writeTargetVar); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // Type should propagate through the chain: sourceVar -> intermediateList -> targetVar ASSERT_EQ(writeSourceVar->targetType, Compiler::StaticType::Unknown); diff --git a/test/llvm/code_analyzer/variable_type_analysis.cpp b/test/llvm/code_analyzer/variable_type_analysis.cpp index a09c4eb0..1546c87c 100644 --- a/test/llvm/code_analyzer/variable_type_analysis.cpp +++ b/test/llvm/code_analyzer/variable_type_analysis.cpp @@ -1,15 +1,60 @@ +#include +#include +#include +#include +#include #include #include +#include +#include #include #include #include +#include #include using namespace libscratchcpp; -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, FirstVariableWrite) +class LLVMCodeAnalyzer_VariableTypeAnalysis : public testing::Test +{ + public: + void SetUp() override + { + auto engine = m_project.engine(); + m_target = std::make_shared(); + m_spriteWithUnsafeConstants = std::make_shared(); + + auto costume = std::make_shared(m_unsafeCostumeNumConstant, "", ""); + m_spriteWithUnsafeConstants->addCostume(costume); + + auto sound = std::make_shared(m_unsafeSoundNumConstant, "", ""); + m_spriteWithUnsafeConstants->addSound(sound); + + engine->setTargets({ m_target, m_spriteWithUnsafeConstants }); + + m_ctx = std::make_unique(engine.get(), m_target.get()); + m_builder = std::make_unique>(*m_ctx->llvmCtx()); + m_utils = std::make_unique(m_ctx.get(), *m_builder, Compiler::CodeType::Script); + m_analyzer = std::make_unique(*m_utils); + } + + std::unique_ptr m_analyzer; + + const std::string m_safeNumConstant = "3.14"; + const std::string m_unsafeCostumeNumConstant = "12"; + const std::string m_unsafeSoundNumConstant = "-27.672"; + + private: + Project m_project; + std::shared_ptr m_target; + std::shared_ptr m_spriteWithUnsafeConstants; + std::unique_ptr m_ctx; + std::unique_ptr> m_builder; + std::unique_ptr m_utils; +}; + +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, FirstVariableWrite) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var("", ""); @@ -19,15 +64,14 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, FirstVariableWrite) setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); list.addInstruction(setVar); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // First write should have Unknown targetType (no previous type) ASSERT_EQ(setVar->targetType, Compiler::StaticType::Unknown); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, SecondVariableWrite) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, SecondVariableWrite) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var("", ""); @@ -43,7 +87,7 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, SecondVariableWrite) setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); list.addInstruction(setVar2); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // First write has no previous type ASSERT_EQ(setVar1->targetType, Compiler::StaticType::Unknown); @@ -51,9 +95,8 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, SecondVariableWrite) ASSERT_EQ(setVar2->targetType, Compiler::StaticType::Number); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, MultipleWritesSameType) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, MultipleWritesSameType) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var("", ""); @@ -75,21 +118,20 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, MultipleWritesSameType) setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); list.addInstruction(setVar3); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(setVar1->targetType, Compiler::StaticType::Unknown); ASSERT_EQ(setVar2->targetType, Compiler::StaticType::String); ASSERT_EQ(setVar3->targetType, Compiler::StaticType::String); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, StringOptimization) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, StringOptimization) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var("", ""); auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, false); - LLVMConstantRegister value1(Compiler::StaticType::String, "3.14"); + LLVMConstantRegister value1(Compiler::StaticType::String, m_safeNumConstant); setVar1->targetVariable = &var; setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); list.addInstruction(setVar1); @@ -100,16 +142,87 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, StringOptimization) setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); list.addInstruction(setVar2); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(setVar1->targetType, Compiler::StaticType::Unknown); - // String "3.14" optimized to Number, so second write sees Number type + // String gets optimized to Number, so second write sees Number type ASSERT_EQ(setVar2->targetType, Compiler::StaticType::Number); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, LoopSingleWrite) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, StringOptimization_DifferentString) +{ + LLVMInstructionList list; + Variable var("", ""); + + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, false); + LLVMConstantRegister value1(Compiler::StaticType::String, "1.0"); + setVar1->targetVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, false); + LLVMConstantRegister value2(Compiler::StaticType::Bool, true); + setVar2->targetVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + m_analyzer->analyzeScript(list); + + ASSERT_EQ(setVar1->targetType, Compiler::StaticType::Unknown); + // String "1.0" does NOT get optimized to Number because it would convert to "1" + ASSERT_EQ(setVar2->targetType, Compiler::StaticType::String); +} + +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, StringOptimization_UnsafeCostumeConstant) +{ + LLVMInstructionList list; + Variable var("", ""); + + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, false); + LLVMConstantRegister value1(Compiler::StaticType::String, m_unsafeCostumeNumConstant); + setVar1->targetVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, false); + LLVMConstantRegister value2(Compiler::StaticType::Bool, true); + setVar2->targetVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + m_analyzer->analyzeScript(list); + + ASSERT_EQ(setVar1->targetType, Compiler::StaticType::Unknown); + // String does NOT get optimized to Number because there's a costume with the same name + ASSERT_EQ(setVar2->targetType, Compiler::StaticType::String); +} + +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, StringOptimization_UnsafeSoundConstant) +{ + LLVMInstructionList list; + Variable var("", ""); + + auto setVar1 = std::make_shared(LLVMInstruction::Type::WriteVariable, false); + LLVMConstantRegister value1(Compiler::StaticType::String, m_unsafeSoundNumConstant); + setVar1->targetVariable = &var; + setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 }); + list.addInstruction(setVar1); + + auto setVar2 = std::make_shared(LLVMInstruction::Type::WriteVariable, false); + LLVMConstantRegister value2(Compiler::StaticType::Bool, true); + setVar2->targetVariable = &var; + setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); + list.addInstruction(setVar2); + + m_analyzer->analyzeScript(list); + + ASSERT_EQ(setVar1->targetType, Compiler::StaticType::Unknown); + // String does NOT get optimized to Number because there's a sound with the same name + ASSERT_EQ(setVar2->targetType, Compiler::StaticType::String); +} + +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, LoopSingleWrite) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var("", ""); @@ -125,15 +238,14 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, LoopSingleWrite) auto loopEnd = std::make_shared(LLVMInstruction::Type::EndLoop, false); list.addInstruction(loopEnd); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // Loop convergence: first iteration Unknown, subsequent iterations Number ASSERT_EQ(setVar->targetType, Compiler::StaticType::Unknown); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, WhileLoop) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, WhileLoop) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var("", ""); @@ -170,15 +282,14 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, WhileLoop) auto loopEnd = std::make_shared(LLVMInstruction::Type::EndLoop, false); list.addInstruction(loopEnd); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(readVar->targetType, Compiler::StaticType::Number | Compiler::StaticType::Bool); ASSERT_EQ(setVar1->targetType, Compiler::StaticType::Number | Compiler::StaticType::Bool); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, RepeatUntilLoop) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, RepeatUntilLoop) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var("", ""); @@ -215,15 +326,14 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, RepeatUntilLoop) auto loopEnd = std::make_shared(LLVMInstruction::Type::EndLoop, false); list.addInstruction(loopEnd); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(readVar->targetType, Compiler::StaticType::Number | Compiler::StaticType::Bool); ASSERT_EQ(setVar1->targetType, Compiler::StaticType::Number | Compiler::StaticType::Bool); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, ProcedureCallInLoop) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, ProcedureCallInLoop) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var("", ""); @@ -248,7 +358,7 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, ProcedureCallInLoop) auto loopEnd = std::make_shared(LLVMInstruction::Type::EndLoop, false); list.addInstruction(loopEnd); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(setVar1->targetType, Compiler::StaticType::Unknown); @@ -256,9 +366,8 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, ProcedureCallInLoop) ASSERT_EQ(setVar2->targetType, Compiler::StaticType::Unknown); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, LoopMultipleWrites_UnknownType) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, LoopMultipleWrites_UnknownType) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var("", ""); @@ -280,7 +389,7 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, LoopMultipleWrites_UnknownType) auto loopEnd = std::make_shared(LLVMInstruction::Type::EndLoop, false); list.addInstruction(loopEnd); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // First write: Unknown (unknown before loop) ASSERT_EQ(setVar1->targetType, Compiler::StaticType::Unknown); @@ -289,9 +398,8 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, LoopMultipleWrites_UnknownType) ASSERT_EQ(setVar2->targetType, Compiler::StaticType::Number); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, LoopMultipleWrites_KnownType) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, LoopMultipleWrites_KnownType) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var("", ""); @@ -320,7 +428,7 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, LoopMultipleWrites_KnownType) auto loopEnd = std::make_shared(LLVMInstruction::Type::EndLoop, false); list.addInstruction(loopEnd); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // First write: Bool | String (from loop iterations) ASSERT_EQ(setVar1->targetType, Compiler::StaticType::Bool | Compiler::StaticType::String); @@ -329,9 +437,8 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, LoopMultipleWrites_KnownType) ASSERT_EQ(setVar2->targetType, Compiler::StaticType::Number); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, IfElseStatementSameTypes) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, IfElseStatementSameTypes) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var("", ""); @@ -362,7 +469,7 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, IfElseStatementSameTypes) setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); list.addInstruction(setVar3); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // Both writes see Unknown before the if-else ASSERT_EQ(setVar1->targetType, Compiler::StaticType::Unknown); @@ -372,9 +479,8 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, IfElseStatementSameTypes) ASSERT_EQ(setVar3->targetType, Compiler::StaticType::Number); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, IfElseStatementDifferentTypes) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, IfElseStatementDifferentTypes) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var("", ""); @@ -405,7 +511,7 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, IfElseStatementDifferentTypes) setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); list.addInstruction(setVar3); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // Both writes see Unknown before the if-else ASSERT_EQ(setVar1->targetType, Compiler::StaticType::Unknown); @@ -415,9 +521,8 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, IfElseStatementDifferentTypes) ASSERT_EQ(setVar3->targetType, Compiler::StaticType::Number | Compiler::StaticType::String); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, IfElseStatementDifferentType_IfBranch) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, IfElseStatementDifferentType_IfBranch) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var("", ""); @@ -445,7 +550,7 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, IfElseStatementDifferentType_IfBranc setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); list.addInstruction(setVar3); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(setVar1->targetType, Compiler::StaticType::Unknown); ASSERT_EQ(setVar2->targetType, Compiler::StaticType::Number); @@ -454,9 +559,8 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, IfElseStatementDifferentType_IfBranc ASSERT_EQ(setVar3->targetType, Compiler::StaticType::Number | Compiler::StaticType::String); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, IfElseStatementDifferentType_ElseBranch) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, IfElseStatementDifferentType_ElseBranch) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var("", ""); @@ -487,7 +591,7 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, IfElseStatementDifferentType_ElseBra setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); list.addInstruction(setVar3); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(setVar1->targetType, Compiler::StaticType::Unknown); ASSERT_EQ(setVar2->targetType, Compiler::StaticType::Number); @@ -496,9 +600,8 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, IfElseStatementDifferentType_ElseBra ASSERT_EQ(setVar3->targetType, Compiler::StaticType::Number | Compiler::StaticType::String); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, WriteBeforeLoop) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, WriteBeforeLoop) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var("", ""); @@ -526,15 +629,14 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, WriteBeforeLoop) setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); list.addInstruction(setVar); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // The type might be String or Number because the loop might or might not run ASSERT_EQ(setVar->targetType, Compiler::StaticType::String | Compiler::StaticType::Number); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, WriteBeforeIfStatement_IfBranch) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, WriteBeforeIfStatement_IfBranch) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var("", ""); @@ -562,15 +664,14 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, WriteBeforeIfStatement_IfBranch) setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); list.addInstruction(setVar); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // The type might be String or Number because the if statement might or might not run ASSERT_EQ(setVar->targetType, Compiler::StaticType::String | Compiler::StaticType::Number); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, WriteBeforeIfStatement_ElseBranch) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, WriteBeforeIfStatement_ElseBranch) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var("", ""); @@ -601,15 +702,14 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, WriteBeforeIfStatement_ElseBranch) setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); list.addInstruction(setVar); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // The type might be String or Number because the else branch might or might not run ASSERT_EQ(setVar->targetType, Compiler::StaticType::String | Compiler::StaticType::Number); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, WriteBeforeIfElse) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, WriteBeforeIfElse) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var("", ""); @@ -646,7 +746,7 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, WriteBeforeIfElse) setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); list.addInstruction(setVar3); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // Write before if-else establishes Bool type ASSERT_EQ(setVarBefore->targetType, Compiler::StaticType::Unknown); @@ -659,9 +759,8 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, WriteBeforeIfElse) ASSERT_EQ(setVar3->targetType, Compiler::StaticType::Number | Compiler::StaticType::String); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, WriteInIfStatement_IfBranch) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, WriteInIfStatement_IfBranch) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var("", ""); @@ -683,7 +782,7 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, WriteInIfStatement_IfBranch) setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); list.addInstruction(setVar); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(setVarInIfStatement->targetType, Compiler::StaticType::Unknown); @@ -691,9 +790,8 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, WriteInIfStatement_IfBranch) ASSERT_EQ(setVar->targetType, Compiler::StaticType::Unknown); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, WriteInIfStatement_ElseBranch) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, WriteInIfStatement_ElseBranch) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var("", ""); @@ -718,7 +816,7 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, WriteInIfStatement_ElseBranch) setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); list.addInstruction(setVar); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(setVarInIfStatement->targetType, Compiler::StaticType::Unknown); @@ -726,9 +824,8 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, WriteInIfStatement_ElseBranch) ASSERT_EQ(setVar->targetType, Compiler::StaticType::Unknown); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, WriteInIfElse) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, WriteInIfElse) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var("", ""); @@ -759,7 +856,7 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, WriteInIfElse) setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); list.addInstruction(setVar3); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(setVar1->targetType, Compiler::StaticType::Unknown); ASSERT_EQ(setVar2->targetType, Compiler::StaticType::Unknown); @@ -768,9 +865,8 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, WriteInIfElse) ASSERT_EQ(setVar3->targetType, Compiler::StaticType::Number | Compiler::StaticType::String); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, WriteInLoop) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, WriteInLoop) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var("", ""); @@ -792,7 +888,7 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, WriteInLoop) setVar->args.push_back({ Compiler::StaticType::Unknown, &value }); list.addInstruction(setVar); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); ASSERT_EQ(setVarInLoop->targetType, Compiler::StaticType::Unknown); @@ -800,9 +896,8 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, WriteInLoop) ASSERT_EQ(setVar->targetType, Compiler::StaticType::Unknown); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, ComplexNestedControlFlow) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, ComplexNestedControlFlow) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var("", ""); @@ -851,7 +946,7 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, ComplexNestedControlFlow) setVar4->args.push_back({ Compiler::StaticType::Unknown, &value4 }); list.addInstruction(setVar4); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // Complex analysis with multiple execution paths and loop convergence ASSERT_EQ(setVar1->targetType, Compiler::StaticType::Unknown); @@ -860,9 +955,8 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, ComplexNestedControlFlow) ASSERT_EQ(setVar4->targetType, Compiler::StaticType::Unknown); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, MultipleVariablesSeparateAnalysis) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, MultipleVariablesSeparateAnalysis) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var1("", ""), var2("", ""); @@ -878,16 +972,15 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, MultipleVariablesSeparateAnalysis) setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 }); list.addInstruction(setVar2); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // Both are first writes for their respective variables ASSERT_EQ(setVar1->targetType, Compiler::StaticType::Unknown); ASSERT_EQ(setVar2->targetType, Compiler::StaticType::Unknown); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, CrossVariableDependency_SingleType) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, CrossVariableDependency_SingleType) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var1("", ""), var2("", ""); @@ -917,7 +1010,7 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, CrossVariableDependency_SingleType) setVar1_2->args.push_back({ Compiler::StaticType::Unknown, &var2Value }); list.addInstruction(setVar1_2); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // var2 first write has no previous type ASSERT_EQ(setVar2->targetType, Compiler::StaticType::Unknown); @@ -932,9 +1025,8 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, CrossVariableDependency_SingleType) ASSERT_EQ(setVar1_2->targetType, Compiler::StaticType::Number); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, CrossVariableDependency_MultipleTypes) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, CrossVariableDependency_MultipleTypes) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var1("", ""), var2("", ""); @@ -980,7 +1072,7 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, CrossVariableDependency_MultipleType setVar4->args.push_back({ Compiler::StaticType::Unknown, &var2Value }); list.addInstruction(setVar4); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // var2 has Number or Bool type at read operation ASSERT_EQ(readVar2->targetType, Compiler::StaticType::Number | Compiler::StaticType::Bool); @@ -992,9 +1084,8 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, CrossVariableDependency_MultipleType ASSERT_EQ(setVar4->targetType, Compiler::StaticType::Number | Compiler::StaticType::Bool); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, ChainedAssignmentsInLoop) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, ChainedAssignmentsInLoop) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable varA("a", ""), varB("b", ""), varC("c", ""); @@ -1079,7 +1170,7 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, ChainedAssignmentsInLoop) setA3->args.push_back({ Compiler::StaticType::Unknown, &cValue2 }); list.addInstruction(setA3); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // Check the type of 'a' before the final a = c assignment // 'a' could be Number (from initial assignment) or String (from loop iterations where a=b, b=c, c="test") @@ -1094,9 +1185,8 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, ChainedAssignmentsInLoop) ASSERT_EQ(readC2->targetType, expectedCType); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, SelfAssignment) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, SelfAssignment) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var("", ""); @@ -1129,7 +1219,7 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, SelfAssignment) setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 }); list.addInstruction(setVar3); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // First write should have Unknown targetType (no previous type) ASSERT_EQ(setVar1->targetType, Compiler::StaticType::Unknown); @@ -1141,9 +1231,8 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, SelfAssignment) ASSERT_EQ(setVar3->targetType, Compiler::StaticType::Number); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, SelfAssignmentInLoop) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, SelfAssignmentInLoop) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var("", ""); @@ -1168,16 +1257,15 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, SelfAssignmentInLoop) auto loopEnd = std::make_shared(LLVMInstruction::Type::EndLoop, false); list.addInstruction(loopEnd); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // Self-assignment in loop should maintain Unknown type since it's a no-op // and doesn't change the variable's type across iterations ASSERT_EQ(setVar->targetType, Compiler::StaticType::Unknown); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, VariableReadReturnRegType) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, VariableReadReturnRegType) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var1("", ""), var2("", ""); @@ -1201,15 +1289,14 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, VariableReadReturnRegType) setVar1_1->args.push_back({ Compiler::StaticType::Unknown, &var2Value }); list.addInstruction(setVar1_1); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // var2 read return register has Number type ASSERT_EQ(var2Value.type(), Compiler::StaticType::Number); } -TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, CrossVariableWriteArgType) +TEST_F(LLVMCodeAnalyzer_VariableTypeAnalysis, CrossVariableWriteArgType) { - LLVMCodeAnalyzer analyzer; LLVMInstructionList list; Variable var1("", ""), var2("", ""); @@ -1233,7 +1320,7 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, CrossVariableWriteArgType) setVar1_1->args.push_back({ Compiler::StaticType::Unknown, &var2Value }); list.addInstruction(setVar1_1); - analyzer.analyzeScript(list); + m_analyzer->analyzeScript(list); // last write argument has Number type ASSERT_EQ(setVar1_1->args.front().first, Compiler::StaticType::Number); diff --git a/test/llvm/llvmtestutils.cpp b/test/llvm/llvmtestutils.cpp index 2089493f..d5cc21f6 100644 --- a/test/llvm/llvmtestutils.cpp +++ b/test/llvm/llvmtestutils.cpp @@ -14,9 +14,13 @@ using namespace libscratchcpp; +using ::testing::ReturnRef; + LLVMTestUtils::LLVMTestUtils() { test_function(nullptr, nullptr, nullptr, nullptr, nullptr); // force dependency + + EXPECT_CALL(m_engine, targets()).WillRepeatedly(ReturnRef(m_emptyTargets)); } LLVMCodeBuilder *LLVMTestUtils::createBuilder(Target *target, BlockPrototype *procedurePrototype, Compiler::CodeType codeType) diff --git a/test/llvm/llvmtestutils.h b/test/llvm/llvmtestutils.h index afbc3c52..64380bc7 100644 --- a/test/llvm/llvmtestutils.h +++ b/test/llvm/llvmtestutils.h @@ -102,6 +102,7 @@ class LLVMTestUtils EngineMock m_engine; TargetMock m_target; // NOTE: isStage() is used for call expectations RandomGeneratorMock m_rng; + const std::vector> m_emptyTargets; }; } // namespace libscratchcpp