diff options
Diffstat (limited to 'clang/unittests')
7 files changed, 302 insertions, 18 deletions
diff --git a/clang/unittests/Analysis/FlowSensitive/MockHeaders.cpp b/clang/unittests/Analysis/FlowSensitive/MockHeaders.cpp index d875542..2e528ed 100644 --- a/clang/unittests/Analysis/FlowSensitive/MockHeaders.cpp +++ b/clang/unittests/Analysis/FlowSensitive/MockHeaders.cpp @@ -1356,7 +1356,7 @@ bool operator==(const Status &lhs, const Status &rhs); bool operator!=(const Status &lhs, const Status &rhs); Status OkStatus(); -Status InvalidArgumentError(char *); +Status InvalidArgumentError(const char *); #endif // STATUS_H )cc"; diff --git a/clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp b/clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp index cae9265..4bb09d3 100644 --- a/clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp +++ b/clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp @@ -2614,6 +2614,263 @@ TEST_P(UncheckedStatusOrAccessModelTest, StatusUpdate) { )cc"); } +TEST_P(UncheckedStatusOrAccessModelTest, EqualityCheck) { + ExpectDiagnosticsFor( + R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(STATUSOR_INT x, STATUSOR_INT y) { + if (x.ok()) { + if (x == y) + y.value(); + else + y.value(); // [[unsafe]] + } + } + )cc"); + ExpectDiagnosticsFor( + R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(STATUSOR_INT x, STATUSOR_INT y) { + if (x.ok()) { + if (y == x) + y.value(); + else + y.value(); // [[unsafe]] + } + } + )cc"); + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(STATUSOR_INT x, STATUSOR_INT y) { + if (x.ok()) { + if (x != y) + y.value(); // [[unsafe]] + else + y.value(); + } + } + )cc"); + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(STATUSOR_INT x, STATUSOR_INT y) { + if (x.ok()) { + if (y != x) + y.value(); // [[unsafe]] + else + y.value(); + } + } + )cc"); + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(STATUSOR_INT x, STATUSOR_INT y) { + if (x.ok()) { + if (!(x == y)) + y.value(); // [[unsafe]] + else + y.value(); + } + } + )cc"); + ExpectDiagnosticsFor( + R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(STATUSOR_INT x, STATUSOR_INT y) { + if (x.ok()) { + if (!(x != y)) + y.value(); + else + y.value(); // [[unsafe]] + } + } + )cc"); + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(STATUSOR_INT x, STATUSOR_INT y) { + if (x == y) + if (x.ok()) y.value(); + } + )cc"); + ExpectDiagnosticsFor( + R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(STATUSOR_INT x, STATUSOR_INT y) { + if (x.ok()) { + if (x.status() == y.status()) + y.value(); + else + y.value(); // [[unsafe]] + } + } + )cc"); + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(STATUSOR_INT x, STATUSOR_INT y) { + if (x.ok()) { + if (x.status() != y.status()) + y.value(); // [[unsafe]] + else + y.value(); + } + } + )cc"); + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(STATUSOR_INT sor) { + if (sor.status() == absl::OkStatus()) + sor.value(); + else + sor.value(); // [[unsafe]] + } + )cc"); + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(STATUSOR_INT sor) { + if (sor.status() != absl::OkStatus()) + sor.value(); // [[unsafe]] + else + sor.value(); + } + )cc"); + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(STATUSOR_INT sor) { + if (sor.status() != absl::InvalidArgumentError("oh no")) + sor.value(); // [[unsafe]] + else + sor.value(); // [[unsafe]] + } + )cc"); + ExpectDiagnosticsFor( + R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(STATUSOR_INT x, STATUSOR_INT y) { + if (x.ok()) { + if (x.ok() == y.ok()) + y.value(); + else + y.value(); // [[unsafe]] + } + } + )cc"); + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(STATUSOR_INT x, STATUSOR_INT y) { + if (x.ok()) { + if (x.ok() != y.ok()) + y.value(); // [[unsafe]] + else + y.value(); + } + } + )cc"); + ExpectDiagnosticsFor( + R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(STATUSOR_INT x, STATUSOR_INT y) { + if (x.ok()) { + if (x.status().ok() == y.status().ok()) + y.value(); + else + y.value(); // [[unsafe]] + } + } + )cc"); + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(STATUSOR_INT x, STATUSOR_INT y) { + if (x.ok()) { + if (x.status().ok() != y.status().ok()) + y.value(); // [[unsafe]] + else + y.value(); + } + } + )cc"); + ExpectDiagnosticsFor( + R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(STATUSOR_INT x, STATUSOR_INT y) { + if (x.ok()) { + if (x.status().ok() == y.ok()) + y.value(); + else + y.value(); // [[unsafe]] + } + } + )cc"); + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(STATUSOR_INT x, STATUSOR_INT y) { + if (x.ok()) { + if (x.status().ok() != y.ok()) + y.value(); // [[unsafe]] + else + y.value(); + } + } + )cc"); + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(bool b, STATUSOR_INT sor) { + if (sor.ok() == b) { + if (b) sor.value(); + } + } + )cc"); + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(STATUSOR_INT sor) { + if (sor.ok() == true) sor.value(); + } + )cc"); + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(STATUSOR_INT sor) { + if (sor.ok() == false) sor.value(); // [[unsafe]] + } + )cc"); + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(bool b) { + STATUSOR_INT sor1; + STATUSOR_INT sor2 = Make<STATUSOR_INT>(); + if (sor1 == sor2) sor2.value(); // [[unsafe]] + } + )cc"); + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(bool b) { + STATUSOR_INT sor1 = Make<STATUSOR_INT>(); + STATUSOR_INT sor2; + if (sor1 == sor2) sor1.value(); // [[unsafe]] + } + )cc"); +} + } // namespace std::string diff --git a/clang/unittests/CIR/PointerLikeTest.cpp b/clang/unittests/CIR/PointerLikeTest.cpp index 22690f2..b3dfba7 100644 --- a/clang/unittests/CIR/PointerLikeTest.cpp +++ b/clang/unittests/CIR/PointerLikeTest.cpp @@ -76,7 +76,7 @@ protected: EXPECT_EQ(pltTy.getElementType(), ty); OwningOpRef<cir::AllocaOp> varPtrOp = - b.create<cir::AllocaOp>(loc, ptrTy, ty, "", getAlignOne(&context)); + cir::AllocaOp::create(b, loc, ptrTy, ty, "", getAlignOne(&context)); mlir::Value val = varPtrOp.get(); mlir::acc::VariableTypeCategory typeCategory = pltTy.getPointeeTypeCategory( @@ -110,7 +110,7 @@ protected: // Create an alloca for the array OwningOpRef<cir::AllocaOp> varPtrOp = - b.create<cir::AllocaOp>(loc, ptrTy, arrTy, "", getAlignOne(&context)); + cir::AllocaOp::create(b, loc, ptrTy, arrTy, "", getAlignOne(&context)); // Verify that the type category is array. mlir::Value val = varPtrOp.get(); @@ -121,8 +121,8 @@ protected: // Create an array-to-pointer decay cast. mlir::Type ptrToElemTy = cir::PointerType::get(ty); - OwningOpRef<cir::CastOp> decayPtr = b.create<cir::CastOp>( - loc, ptrToElemTy, cir::CastKind::array_to_ptrdecay, val); + OwningOpRef<cir::CastOp> decayPtr = cir::CastOp::create( + b, loc, ptrToElemTy, cir::CastKind::array_to_ptrdecay, val); mlir::Value decayVal = decayPtr.get(); // Verify that we still get the expected element type. @@ -141,9 +141,9 @@ protected: // Create an element access. mlir::Type i32Ty = cir::IntType::get(&context, 32, true); mlir::Value index = - b.create<cir::ConstantOp>(loc, cir::IntAttr::get(i32Ty, 2)); + cir::ConstantOp::create(b, loc, cir::IntAttr::get(i32Ty, 2)); OwningOpRef<cir::PtrStrideOp> accessPtr = - b.create<cir::PtrStrideOp>(loc, ptrToElemTy, decayVal, index); + cir::PtrStrideOp::create(b, loc, ptrToElemTy, decayVal, index); mlir::Value accessVal = accessPtr.get(); // Verify that we still get the expected element type. @@ -175,8 +175,8 @@ protected: EXPECT_EQ(pltTy.getElementType(), structTy); // Create an alloca for the array - OwningOpRef<cir::AllocaOp> varPtrOp = b.create<cir::AllocaOp>( - loc, ptrTy, structTy, "", getAlignOne(&context)); + OwningOpRef<cir::AllocaOp> varPtrOp = cir::AllocaOp::create( + b, loc, ptrTy, structTy, "", getAlignOne(&context)); // Verify that the type category is composite. mlir::Value val = varPtrOp.get(); @@ -186,8 +186,8 @@ protected: EXPECT_EQ(typeCategory, mlir::acc::VariableTypeCategory::composite); // Access the first element of the structure. - OwningOpRef<cir::GetMemberOp> access1 = b.create<cir::GetMemberOp>( - loc, cir::PointerType::get(ty1), val, b.getStringAttr("f1"), 0); + OwningOpRef<cir::GetMemberOp> access1 = cir::GetMemberOp::create( + b, loc, cir::PointerType::get(ty1), val, "f1", 0u); mlir::Value accessVal1 = access1.get(); // Verify that we get the expected element type. @@ -204,8 +204,8 @@ protected: EXPECT_EQ(access1TypeCategory, mlir::acc::VariableTypeCategory::composite); // Access the second element of the structure. - OwningOpRef<cir::GetMemberOp> access2 = b.create<cir::GetMemberOp>( - loc, cir::PointerType::get(ty2), val, b.getStringAttr("f2"), 1); + OwningOpRef<cir::GetMemberOp> access2 = cir::GetMemberOp::create( + b, loc, cir::PointerType::get(ty2), val, "f2", 1u); mlir::Value accessVal2 = access2.get(); // Verify that we get the expected element type. @@ -252,17 +252,17 @@ protected: mlir::Type structPptrTy = cir::PointerType::get(structTy); // Create an alloca for the struct. - OwningOpRef<cir::AllocaOp> varPtrOp = b.create<cir::AllocaOp>( - loc, structPptrTy, structTy, "S", getAlignOne(&context)); + OwningOpRef<cir::AllocaOp> varPtrOp = cir::AllocaOp::create( + b, loc, structPptrTy, structTy, "S", getAlignOne(&context)); mlir::Value val = varPtrOp.get(); // Get a pointer to the second member. - OwningOpRef<cir::GetMemberOp> access = b.create<cir::GetMemberOp>( - loc, cir::PointerType::get(ptrTy), val, b.getStringAttr("f2"), 1); + OwningOpRef<cir::GetMemberOp> access = cir::GetMemberOp::create( + b, loc, cir::PointerType::get(ptrTy), val, b.getStringAttr("f2"), 1); mlir::Value accessVal = access.get(); // Load the value of the second member. This is the pointer we want to test. - OwningOpRef<cir::LoadOp> loadOp = b.create<cir::LoadOp>(loc, accessVal); + OwningOpRef<cir::LoadOp> loadOp = cir::LoadOp::create(b, loc, accessVal); mlir::Value loadVal = loadOp.get(); // Verify that the type category is the expected type category. diff --git a/clang/unittests/Sema/HeuristicResolverTest.cpp b/clang/unittests/Sema/HeuristicResolverTest.cpp index a00632f..c592e74 100644 --- a/clang/unittests/Sema/HeuristicResolverTest.cpp +++ b/clang/unittests/Sema/HeuristicResolverTest.cpp @@ -524,6 +524,28 @@ TEST(HeuristicResolver, MemberExpr_HangIssue126536) { cxxDependentScopeMemberExpr(hasMemberName("foo")).bind("input")); } +TEST(HeuristicResolver, MemberExpr_HangOnLongCallChain) { + const size_t CallChainLength = 50; + std::string Code = R"cpp( + template <typename T> + void foo(T t) { + t + )cpp"; + for (size_t I = 0; I < CallChainLength; ++I) + Code.append(".method()\n"); + Code.append(R"cpp( + .lastMethod(); + } + )cpp"); + // Test that resolution of a name whose base is a long call chain + // does not hang. Note that the hang for which this is a regression + // test is finite (exponential runtime in the length of the chain), + // so a "failure" here manifests as abnormally long runtime. + expectResolution( + Code, &HeuristicResolver::resolveMemberExpr, + cxxDependentScopeMemberExpr(hasMemberName("lastMethod")).bind("input")); +} + TEST(HeuristicResolver, MemberExpr_DefaultTemplateArgument) { std::string Code = R"cpp( struct Default { diff --git a/clang/unittests/Tooling/DependencyScanning/DependencyScannerTest.cpp b/clang/unittests/Tooling/DependencyScanning/DependencyScannerTest.cpp index aa32bb3..4523af3 100644 --- a/clang/unittests/Tooling/DependencyScanning/DependencyScannerTest.cpp +++ b/clang/unittests/Tooling/DependencyScanning/DependencyScannerTest.cpp @@ -49,6 +49,8 @@ private: std::vector<std::string> &Deps; }; +// FIXME: Use the regular Service/Worker/Collector APIs instead of +// reimplementing the action. class TestDependencyScanningAction : public tooling::ToolAction { public: TestDependencyScanningAction(std::vector<std::string> &Deps) : Deps(Deps) {} @@ -59,6 +61,7 @@ public: DiagnosticConsumer *DiagConsumer) override { CompilerInstance Compiler(std::move(Invocation), std::move(PCHContainerOps)); + Compiler.setVirtualFileSystem(FileMgr->getVirtualFileSystemPtr()); Compiler.setFileManager(FileMgr); Compiler.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false); diff --git a/clang/unittests/Tooling/Syntax/TokensTest.cpp b/clang/unittests/Tooling/Syntax/TokensTest.cpp index 6094177..47184cb 100644 --- a/clang/unittests/Tooling/Syntax/TokensTest.cpp +++ b/clang/unittests/Tooling/Syntax/TokensTest.cpp @@ -134,6 +134,7 @@ public: FileName, llvm::MemoryBuffer::getMemBufferCopy(Code).release()); CompilerInstance Compiler(std::move(CI)); Compiler.setDiagnostics(Diags); + Compiler.setVirtualFileSystem(FS); Compiler.setFileManager(FileMgr); Compiler.setSourceManager(SourceMgr); diff --git a/clang/unittests/Tooling/Syntax/TreeTestBase.cpp b/clang/unittests/Tooling/Syntax/TreeTestBase.cpp index 400a0d5..b2be64f 100644 --- a/clang/unittests/Tooling/Syntax/TreeTestBase.cpp +++ b/clang/unittests/Tooling/Syntax/TreeTestBase.cpp @@ -153,6 +153,7 @@ SyntaxTreeTest::buildTree(StringRef Code, const TestClangConfig &ClangConfig) { FileName, llvm::MemoryBuffer::getMemBufferCopy(Code).release()); CompilerInstance Compiler(Invocation); Compiler.setDiagnostics(Diags); + Compiler.setVirtualFileSystem(FS); Compiler.setFileManager(FileMgr); Compiler.setSourceManager(SourceMgr); |