oneraynyday updated this revision to Diff 299470. oneraynyday added a comment.
- Address clang-tidy - Address using C++17 left-fold expression in C++14 - Address minor style issues Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D89765/new/ https://reviews.llvm.org/D89765 Files: clang-tools-extra/CMakeLists.txt clang-tools-extra/clang-cast/CMakeLists.txt clang-tools-extra/clang-cast/Cast.h clang-tools-extra/clang-cast/CastOptions.h clang-tools-extra/clang-cast/CastUtils.h clang-tools-extra/clang-cast/ClangCast.cpp clang-tools-extra/clang-cast/Consumer.h clang-tools-extra/clang-cast/Matcher.h clang-tools-extra/unittests/CMakeLists.txt clang-tools-extra/unittests/clang-cast/CMakeLists.txt clang-tools-extra/unittests/clang-cast/ClangCXXCastTestCases.h clang-tools-extra/unittests/clang-cast/ClangCastTests.cpp clang-tools-extra/unittests/clang-cast/ClangChangeQualifierTestCases.h clang-tools-extra/unittests/clang-cast/ClangFunctionPtrTestCases.h clang-tools-extra/unittests/clang-cast/ClangQualifierTestCases.h
Index: clang-tools-extra/unittests/clang-cast/ClangQualifierTestCases.h =================================================================== --- /dev/null +++ clang-tools-extra/unittests/clang-cast/ClangQualifierTestCases.h @@ -0,0 +1,603 @@ +//===-- ClangQualifierTestCases.h - clang-cast ------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains test cases for +/// CStyleCastOperation::requireConstCast (defined in Cast.h) +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANG_CAST_CLANGQUALIFIERTESTCASES_H +#define LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANG_CAST_CLANGQUALIFIERTESTCASES_H + +namespace testcases { + +namespace constcheck { +/// No-op +static const char QualNoOp[] = R"( +void f() { + (bool) 0; +} +)"; + +/// Const +/// Adding const doesn't require const_cast +static const char QualAddConst[] = R"( +void f() { + int x = 0; + (const int) x; +} +)"; +static const char QualAddPtrToConst[] = R"( +void f() { + int* x = nullptr; + const int* y = (const int*) x; +} +)"; +static const char QualAddConstPtr[] = R"( +void f() { + int* x = nullptr; + int* const y = (int* const) x; +} +)"; +static const char QualAddConstDoublePtr[] = R"( +void f() { + int** x = nullptr; + int* const * const y = (int* const * const) x; +} +)"; +static const char QualAddConstDiffLevelPtr[] = R"( +void f() { + int*** x = nullptr; + const int** y = (const int**) x; +} +)"; +static const char QualAddMemberPtrToConst[] = R"( +struct t{}; +void f() { + int t::* x = nullptr; + const int t::* y = (const int t::*) x; +} +)"; +static const char QualAddConstMemberPtr[] = R"( +struct t{}; +void f() { + int t::* x = nullptr; + int t::* const y = (int t::* const) x; +} +)"; +static const char QualAddConstDoubleMemberPtr[] = R"( +struct t{}; +void f() { + int t::* t::* x = nullptr; + int t::* const t::* const y = (int t::* const t::* const) x; +} +)"; +static const char QualAddConstDiffLevelMemberPtr[] = R"( +struct t{}; +void f() { + int t::* t::* t::* x = nullptr; + const int t::* t::* y = (const int t::* t::*) x; +} +)"; +static const char QualAddConstRef[] = R"( +void f() { + int x = 1; + int& y = x; + const int& z = (const int&) y; +} +)"; +static const char QualAddConstArr[] = R"( +void f() { + double a[2] {1, 2}; + const double* ca = (const double*) a; +} +)"; +static const char QualAddConstPtrToArr[] = R"( +void f() { + double (*a)[2] {}; + (double(* const)[2]) a; +} +)"; +static const char QualAddConstPtrToArrOfConstPtrs[] = R"( +void f() { + double* (*a)[2] {}; + (double * const (* const)[2]) a; +} +)"; +static const char QualAddArrPtrConstData[] = R"( +void f() { + double (*a)[2] {}; + (const double(*)[2]) a; +} +)"; +static const char QualAddDiffLevelArrPtrConstData[] = R"( +void f() { + double (*a)[2] {}; + (const double* (*)[2]) a; +} +)"; +static const char QualAddConstMixedPtrTypes[] = R"( +struct t {}; +void f() { + double * t::* (t::* *a) [2]; + (const double * const t::* const (t::* const * const) [2]) a; +} +)"; +static const char QualAddConstUnknownArrPtr[] = R"( +void f() { + int* (*x) [] {}; + (const int* const (*)[]) x; +} +)"; +static const char QualAddConstUnknownArrPtrToKnownArrPtr[] = R"( +void f() { + int* (*x) [] {}; + (const int* const (*)[2]) x; +} +)"; + +/// Removing const MIGHT require const_cast +static const char QualRemoveConst[] = R"( +void f() { + const int x = 0; + (int) x; +} +)"; +static const char QualRemovePtrToConst[] = R"( +void f() { + const int* x = nullptr; + int* y = (int*) x; +} +)"; +static const char QualRemoveConstPtr[] = R"( +void f() { + int* const x = nullptr; + int* y = (int*) x; +} +)"; +static const char QualRemoveConstDoublePtr[] = R"( +void f() { + int* const * const x = nullptr; + int** y = (int**) x; +} +)"; +static const char QualRemoveConstDiffLevelPtr[] = R"( +void f() { + const int*** x = nullptr; + int** y = (int**) x; +} +)"; +static const char QualRemoveMemberPtrToConst[] = R"( +struct t{}; +void f() { + const int t::* x = nullptr; + int t::* y = (int t::*) x; +} +)"; +static const char QualRemoveConstMemberPtr[] = R"( +struct t{}; +void f() { + int t::* const x = nullptr; + int t::* y = (int t::*) x; +} +)"; +static const char QualRemoveConstDoubleMemberPtr[] = R"( +struct t{}; +void f() { + int t::* const t::* const x = nullptr; + int t::* t::* y = (int t::* t::*) x; +} +)"; +static const char QualRemoveConstDiffLevelMemberPtr[] = R"( +struct t{}; +void f() { + const int t::* t::* t::* x = nullptr; + int t::* t::* y = (int t::* t::*) x; +} +)"; +static const char QualRemoveConstRef[] = R"( +void f() { + int x = 1; + const int& y = x; + int& z = (int&) y; +} +)"; +static const char QualRemoveConstArr[] = R"( +void f() { + const double a[2] {1, 2}; + double* ca = (double*) a; +} +)"; +static const char QualRemoveConstPtrToArr[] = R"( +void f() { + double (* const a)[2] {}; + (double(*)[2]) a; +} +)"; +static const char QualRemoveConstPtrToArrOfConstPtrs[] = R"( +void f() { + double* const (* const a)[2] {}; + (double* (*)[2]) a; +} +)"; +static const char QualRemoveArrPtrConstData[] = R"( +void f() { + const double (*a)[2] {}; + (double(*)[2]) a; +} +)"; +static const char QualRemoveDiffLevelArrPtrConstData[] = R"( +void f() { + const double* (*a)[2] {}; + (double (*)[2]) a; +} +)"; +static const char QualRemoveSimilarPtrsBeyondArrConstData[] = R"( +void f() { + const double* const (* const a)[2] {}; + (double* const (* const)[2]) a; +} +)"; +static const char QualRemoveConstMixedPtrTypes[] = R"( +struct t {}; +void f() { + const double * const t::* const (t::* const * const a) [2] {}; + (double * t::* (t::* *) [2]) a; +} +)"; +static const char QualRemoveConstUnknownArrPtr[] = R"( +void f() { + const int* const (*x) [] {}; + (int* (*)[]) x; +} +)"; +static const char QualRemoveConstUnknownArrPtrToKnownArrPtr[] = R"( +void f() { + const int* const (*x) [] {}; + (int* (*)[2]) x; +} +)"; + +/// Volatile +/// add +static const char QualAddVolatile[] = R"( +void f() { + int x = 0; + (volatile int) x; +} +)"; +static const char QualAddPtrToVolatile[] = R"( +void f() { + int* x = nullptr; + volatile int* y = (volatile int*) x; +} +)"; +static const char QualAddVolatilePtr[] = R"( +void f() { + int* x = nullptr; + int* volatile y = (int* volatile) x; +} +)"; +static const char QualAddVolatileDoublePtr[] = R"( +void f() { + int** x = nullptr; + int* volatile * volatile y = (int* volatile * volatile) x; +} +)"; +static const char QualAddVolatileDiffLevelPtr[] = R"( +void f() { + int*** x = nullptr; + volatile int** y = (volatile int**) x; +} +)"; +static const char QualAddVolatileRef[] = R"( +void f() { + int x = 1; + int& y = x; + volatile int& z = (volatile int&) y; +} +)"; +static const char QualAddVolatileArr[] = R"( +void f() { + double a[2] {1, 2}; + volatile double* ca = (volatile double*) a; +} +)"; +static const char QualAddVolatilePtrToArr[] = R"( +void f() { + double (*a)[2] {}; + (double(* volatile)[2]) a; +} +)"; +static const char QualAddVolatilePtrToArrOfVolatilePtrs[] = R"( +void f() { + double* (*a)[2] {}; + (double * volatile (* volatile)[2]) a; +} +)"; +static const char QualAddArrPtrVolatileData[] = R"( +void f() { + double (*a)[2] {}; + (volatile double(*)[2]) a; +} +)"; +static const char QualAddDiffLevelArrPtrVolatileData[] = R"( +void f() { + double (*a)[2] {}; + (volatile double* (*)[2]) a; +} +)"; +static const char QualRemoveSimilarPtrsBeyondArrVolatileData[] = R"( +void f() { + volatile double* volatile (* volatile a)[2] {}; + (double* volatile (* volatile)[2]) a; +} +)"; +static const char QualAddVolatileMixedPtrTypes[] = R"( +struct t {}; +void f() { + double * t::* (t::* *a) [2]; + (volatile double * volatile t::* volatile (t::* volatile * volatile) [2]) a; +} +)"; +static const char QualAddVolatileUnknownArrPtr[] = R"( +void f() { + int* (*x) [] {}; + (volatile int* volatile (*)[]) x; +} +)"; +static const char QualAddVolatileUnknownArrPtrToKnownArrPtr[] = R"( +void f() { + int* (*x) [] {}; + (volatile int* volatile (*)[2]) x; +} +)"; + +/// remove +static const char QualRemoveVolatile[] = R"( +void f() { + volatile int x = 0; + (int) x; +} +)"; +static const char QualRemovePtrToVolatile[] = R"( +void f() { + volatile int* x = nullptr; + int* y = (int*) x; +} +)"; +static const char QualRemoveVolatilePtr[] = R"( +void f() { + int* volatile x = nullptr; + int* y = (int*) x; +} +)"; +static const char QualRemoveVolatileDoublePtr[] = R"( +void f() { + int* volatile * volatile x = nullptr; + int** y = (int**) x; +} +)"; +static const char QualRemoveVolatileDiffLevelPtr[] = R"( +void f() { + volatile int*** x = nullptr; + int** y = (int**) x; +} +)"; +static const char QualRemoveVolatileRef[] = R"( +void f() { + int x = 1; + volatile int& y = x; + int& z = (int&) y; +} +)"; +static const char QualRemoveVolatileArr[] = R"( +void f() { + volatile double a[2] {1, 2}; + double* ca = (double*) a; +} +)"; +static const char QualRemoveVolatilePtrToArr[] = R"( +void f() { + double (* volatile a)[2] {}; + (double(*)[2]) a; +} +)"; +static const char QualRemoveVolatilePtrToArrOfVolatilePtrs[] = R"( +void f() { + double* volatile (* volatile a)[2] {}; + (double* (*)[2]) a; +} +)"; +static const char QualRemoveArrPtrVolatileData[] = R"( +void f() { + volatile double (*a)[2] {}; + (double(*)[2]) a; +} +)"; +static const char QualRemoveDiffLevelArrPtrVolatileData[] = R"( +void f() { + volatile double* (*a)[2] {}; + (double (*)[2]) a; +} +)"; +static const char QualRemoveVolatileMixedPtrTypes[] = R"( +struct t {}; +void f() { + volatile double * volatile t::* volatile (t::* volatile * volatile a) [2] {}; + (double * t::* (t::* *) [2]) a; +} +)"; +static const char QualRemoveVolatileUnknownArrPtr[] = R"( +void f() { + volatile int* volatile (*x) [] {}; + (int* (*)[]) x; +} +)"; +static const char QualRemoveVolatileUnknownArrPtrToKnownArrPtr[] = R"( +void f() { + volatile int* volatile (*x) [] {}; + (int* (*)[2]) x; +} +)"; + +/// Restricted +/// add +static const char QualAddRestrictPtr[] = R"( +void f() { + int* x = nullptr; + int* __restrict y = (int* __restrict) x; +} +)"; +static const char QualAddRestrictDoublePtr[] = R"( +void f() { + int** x = nullptr; + int* __restrict * __restrict y = (int* __restrict * __restrict) x; +} +)"; +// Add another layer of pointers to decorate __restrict on +static const char QualAddRestrictDiffLevelPtr[] = R"( +void f() { + int** x = nullptr; + int* __restrict *** y = (int* __restrict ***) x; +} +)"; +// Add another layers of pointers to decorate __restrict on +static const char QualAddRestrictArr[] = R"( +void f() { + double* a[2] {}; + double* __restrict * ca = (double* __restrict *) a; +} +)"; +static const char QualAddRestrictPtrToArr[] = R"( +void f() { + double (*a)[2] {}; + (double(* __restrict)[2]) a; +} +)"; +static const char QualAddRestrictPtrToArrOfRestrictPtrs[] = R"( +void f() { + double* (*a)[2] {}; + (double* __restrict (* __restrict)[2]) a; +} +)"; +// Add another layer of pointers to decorate __restrict on +static const char QualAddArrPtrRestrictData[] = R"( +void f() { + double* (*a)[2] {}; + (double* __restrict (*)[2]) a; +} +)"; +// Add another layer of pointers to decorate __restrict on +static const char QualAddDiffLevelArrPtrRestrictData[] = R"( +void f() { + double (*a)[2] {}; + (double* __restrict *(*)[2]) a; +} +)"; +static const char QualAddRestrictMixedPtrTypes[] = R"( +struct t {}; +void f() { + double * t::* (t::* *a) [2]; + (double * __restrict t::* __restrict (t::* __restrict * __restrict) [2]) a; +} +)"; +static const char QualAddRestrictUnknownArrPtr[] = R"( +void f() { + int* (*x) [] {}; + (int* __restrict (*)[]) x; +} +)"; +static const char QualAddRestrictUnknownArrPtrToKnownArrPtr[] = R"( +void f() { + int* (*x) [] {}; + (int* __restrict (*)[2]) x; +} +)"; + +/// remove +static const char QualRemoveRestrictPtr[] = R"( +void f() { + int* __restrict x = nullptr; + int* y = (int*) x; +} +)"; +static const char QualRemoveRestrictDoublePtr[] = R"( +void f() { + int* __restrict * __restrict x = nullptr; + int** y = (int**) x; +} +)"; +static const char QualRemoveRestrictDiffLevelPtr[] = R"( +void f() { + int* __restrict *** x = nullptr; + int** y = (int**) x; +} +)"; +static const char QualRemoveRestrictArr[] = R"( +void f() { + double* __restrict a[2] {}; + double** ca = (double**) a; +} +)"; +static const char QualRemoveRestrictPtrToArr[] = R"( +void f() { + double (* __restrict a)[2] {}; + (double(*)[2]) a; +} +)"; +static const char QualRemoveRestrictPtrToArrOfRestrictPtrs[] = R"( +void f() { + double* __restrict (* __restrict a)[2] {}; + (double* (*)[2]) a; +} +)"; +static const char QualRemoveArrPtrRestrictData[] = R"( +void f() { + double* __restrict (*a)[2] {}; + (double* (*)[2]) a; +} +)"; +static const char QualRemoveDiffLevelArrPtrRestrictData[] = R"( +void f() { + double* __restrict *(*a)[2] {}; + (double (*)[2]) a; +} +)"; +static const char QualRemoveSimilarPtrsBeyondArrRestrictData[] = R"( +void f() { + double* __restrict * __restrict (* __restrict a)[2] {}; + (double* * __restrict (* __restrict)[2]) a; +} +)"; +static const char QualRemoveRestrictMixedPtrTypes[] = R"( +struct t {}; +void f() { + double * __restrict t::* __restrict (t::* __restrict * __restrict a) [2] {}; + (double * t::* (t::* *) [2]) a; +} +)"; +static const char QualRemoveRestrictUnknownArrPtr[] = R"( +void f() { + int* __restrict (*x) [] {}; + (int* (*)[]) x; +} +)"; +static const char QualRemoveRestrictUnknownArrPtrToKnownArrPtr[] = R"( +void f() { + int* __restrict (*x) [] {}; + (int* (*)[2]) x; +} +)"; + +} // namespace constcheck + +} // namespace testcases + +#endif // LLVM_PROJECT_CLANGQUALIFIERTESTCASES_H Index: clang-tools-extra/unittests/clang-cast/ClangFunctionPtrTestCases.h =================================================================== --- /dev/null +++ clang-tools-extra/unittests/clang-cast/ClangFunctionPtrTestCases.h @@ -0,0 +1,71 @@ +//===-- ClangFunctionPtrTestCases.h - clang-cast ----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains test cases for +/// details::isFunctionPtr (defined in CastUtils.h) +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_PROJECT_CLANGFUNCTIONPTRTESTCASES_H +#define LLVM_PROJECT_CLANGFUNCTIONPTRTESTCASES_H + +namespace testcases { +namespace funcptr { + +// Out of all of these tests, we should ideally only identify the cases of +// FreeFunction and MemberFunction. + +static const char Scalar[] = R"( +void f() { + bool a {}; +} +)"; + +static const char ArrOfFreeFunctionPtr[] = R"( +void f() { + void (*a[2])(void){}; +} +)"; + +static const char NestedFreeFunctionPtr[] = R"( +void f() { + void (**a)(void) {}; +} +)"; + +static const char FreeFunction[] = R"( +void f() { + void (*a)(void) {}; +} +)"; + +static const char ArrOfMemberFunction[] = R"( +struct t{}; +void f() { + void (t::* a[2])(void) const {}; +} +)"; + +static const char NestedMemberFunction[] = R"( +struct t{}; +void f() { + void (t::** a)(void) const {}; +} +)"; + +static const char MemberFunction[] = R"( +struct t{}; +void f() { + void (t::* a)(void) const {}; +} +)"; +} // namespace funcptr +} // namespace testcases + +#endif // LLVM_PROJECT_CLANGFUNCTIONPTRTESTCASES_H Index: clang-tools-extra/unittests/clang-cast/ClangChangeQualifierTestCases.h =================================================================== --- /dev/null +++ clang-tools-extra/unittests/clang-cast/ClangChangeQualifierTestCases.h @@ -0,0 +1,199 @@ +//===-- ClangChangeQualifierTestCases.h - clang-cast ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains test cases for +/// CStyleCast::changeQualifiers (defined in Cast.h) +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_PROJECT_CLANGCHANGEQUALIFIERTESTCASES_H +#define LLVM_PROJECT_CLANGCHANGEQUALIFIERTESTCASES_H + +/// NOTE: We are not performing an implicit cast conversion, so the types +/// are exactly decltype(p) when we pass it into changeQualifiers(). +namespace testcases { +namespace changequal { +namespace extension { +static const char NoQualifierChange[] = R"( +void f() { + const int * const p {}; + (const int * const) p; + // Expected type + const int * const x {}; +} +)"; +static const char NoQualifierChangeReinterpret[] = R"( +void f() { + const int * const p {}; + (const double * const) p; + // Expected type + const double * const x {}; +} +)"; + +// Change all of these pointer qualifiers down +static const char ChangeNestedPointers[] = R"( +void f() { + const int * const * volatile * __restrict p {}; + (int***) p; + // Expected type + const int* const * volatile * __restrict x {}; +} +)"; +static const char ChangeNestedPointersReinterpret[] = R"( +void f() { + const int * const * volatile * __restrict p {}; + (double****) p; + // Expected type (note how we have 1 more layer of ptr) + double* const * const * volatile * __restrict x {}; +} +)"; + +// Stop the const cast up to an array type +static const char ChangeNestedPointersUntilArray[] = R"( +void f() { + int * const * volatile * __restrict (* const * volatile * __restrict p) [2] {}; + (int*** (***)[2]) p; + // Expected type + int * const * volatile * __restrict (* const * volatile * __restrict x) [2] {}; +} +)"; +static const char ChangeNestedPointersUntilArrayReinterpret[] = R"( +void f() { + int * const * volatile * __restrict (* const * volatile * __restrict p) [2] {}; + (double**** (***)[2]) p; + // Expected type + double ** const * volatile * __restrict (* const * volatile * __restrict x) [2] {}; +} +)"; +static const char NoModificationToMixedPtrTypes[] = R"( +struct t{}; +void f() { + double * __restrict t::* __restrict (t::* __restrict * __restrict a) [2]; + (double * t::* (t::* *) [2]) a; + // Expected type + double * __restrict t::* __restrict (t::* __restrict * __restrict x) [2]; +} +)"; + +// The member function dropped const, but const_cast can't perform this +// operation. It's up to reinterpret_cast to perform this. +static const char DontChangeMemberFuncPtr[] = R"( +struct t{}; +void f() { + void (t::* p)(void) const {}; + (void (t::*)(void)) p; + // Expected type + void (t::* x)(void) {}; +} +)"; + +static const char ChangeNestedPointersUntilMemberVsNot[] = R"( +struct t{}; +void f() { + const int* const t::* const t::* const p {}; + (int** t::*) p; + // Expected type + int** const t::* const x {}; +} +)"; +} // namespace extension + +namespace pedantic { + +static const char NoQualifierChange[] = R"( +void f() { + const int * const p {}; + (const int * const) p; + // Expected type + const int * const x {}; +} +)"; +static const char NoQualifierChangeReinterpret[] = R"( +void f() { + const int * const p {}; + (const double * const) p; + // Expected type + const double * const x {}; +} +)"; + +// Change all of these pointer qualifiers down +static const char ChangeNestedPointers[] = R"( +void f() { + const int * const * volatile * __restrict p {}; + (int***) p; + // Expected type + const int* const * volatile * __restrict x {}; +} +)"; +static const char ChangeNestedPointersReinterpret[] = R"( +void f() { + const int * const * volatile * __restrict p {}; + (double****) p; + // Expected type (note how we have 1 more layer of ptr) + double* const * const * volatile * __restrict x {}; +} +)"; + +// Stop the const cast up to an array type +static const char ChangeNestedPointersUntilArray[] = R"( +void f() { + int * const * volatile * __restrict (* const * volatile * __restrict p) [2] {}; + (int*** (***)[2]) p; + // Expected type + int * const * volatile * __restrict (* const * volatile * __restrict x) [2] {}; +} +)"; +static const char ChangeNestedPointersUntilArrayReinterpret[] = R"( +void f() { + int * const * volatile * __restrict (* const * volatile * __restrict p) [2] {}; + (double**** (***)[2]) p; + // Expected type + double ** const * volatile * __restrict (* const * volatile * __restrict x) [2] {}; +} +)"; +static const char NoModificationToMixedPtrTypes[] = R"( +struct t{}; +void f() { + double * __restrict t::* __restrict (t::* __restrict * __restrict a) [2]; + (double * t::* (t::* *) [2]) a; + // Expected type + double * __restrict t::* __restrict (t::* __restrict * __restrict x) [2]; +} +)"; + +// The member function dropped const, but const_cast can't perform this +// operation. It's up to reinterpret_cast to perform this. +static const char DontChangeMemberFuncPtr[] = R"( +struct t{}; +void f() { + void (t::* p)(void) const {}; + (void (t::*)(void)) p; + // Expected type + void (t::* x)(void) {}; +} +)"; + +static const char ChangeNestedPointersUntilMemberVsNot[] = R"( +struct t{}; +void f() { + const int* const t::* const t::* const p {}; + (int** t::*) p; + // Expected type + const int* const* const t::* const x {}; +} +)"; + +} // namespace pedantic + +} // namespace changequal +} // namespace testcases + +#endif // LLVM_PROJECT_CLANGCHANGEQUALIFIERTESTCASES_H Index: clang-tools-extra/unittests/clang-cast/ClangCastTests.cpp =================================================================== --- /dev/null +++ clang-tools-extra/unittests/clang-cast/ClangCastTests.cpp @@ -0,0 +1,509 @@ +//===-- ClangCastTests.cpp - clang-cast -------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains tests of: +/// - Getting the correct non-const cast type from a C style cast +/// - Correctly determing whether an expression is casting +/// away constness +/// - Checking edge cases (function ptrs, private access +/// inheritance, etc) +/// +//===----------------------------------------------------------------------===// + +#include "Cast.h" +#include "ClangCXXCastTestCases.h" +#include "ClangChangeQualifierTestCases.h" +#include "ClangFunctionPtrTestCases.h" +#include "ClangQualifierTestCases.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Tooling/Tooling.h" +#include "gtest/gtest.h" +#include <iostream> +#include <set> +#include <vector> + +#define CLANG_CXX_CAST_CHECK(cast_kind, cxx_cast) \ + { \ + auto res = parse(cast_kind); \ + ASSERT_GE(res.first.size(), 1ul); \ + ASSERT_EQ(res.second.size(), 1ul); \ + ASSERT_TRUE(res.first.find(CastKind::CK_##cast_kind) != res.first.end()); \ + ASSERT_EQ(res.second[0], CXXCast::CC_##cxx_cast); \ + } + +#define CLANG_QUAL_CHECK(test_case, req_const, pedantic) \ + { \ + auto res = parse(test_case, pedantic); \ + ASSERT_EQ(res, req_const); \ + } + +#define CLANG_FUNC_PTR_CHECK(test_case, detected) \ + { \ + auto res = parse(test_case); \ + ASSERT_EQ(res, detected); \ + } + +using namespace testcases; +using namespace testcases::constcheck; +using namespace testcases::funcptr; +using namespace testcases::changequal; +using namespace clang; +using namespace clang::tooling; +using namespace clang::ast_matchers; +using namespace clang::cppcast; + +static constexpr auto CastVar = "cast"; +static constexpr auto DeclVar = "varDecl"; + +/// Uses CStyleCastCollector to collect all CXXCast enums obtained +/// and CastKinds encountered. +class ClangCXXCastTest : public ::testing::Test { + using CastKindSet = std::set<CastKind>; + using CXXCastVector = std::vector<CXXCast>; + StatementMatcher CStyleCastMatcher; + + struct CStyleCastCollector : MatchFinder::MatchCallback { + std::vector<CXXCast> Casts; + std::set<CastKind> CastKinds; + CStyleCastCollector() = default; + + virtual void run(const MatchFinder::MatchResult &Result) override { + ASTContext *Context = Result.Context; + const CStyleCastExpr *Expr = + Result.Nodes.getNodeAs<CStyleCastExpr>(CastVar); + assert(Expr && Context); + CStyleCastOperation Op(*Expr, *Context, /*Pedantic*/ false); + + const CastExpr *GenericCastExpr = dyn_cast<CastExpr>(Expr); + // traverse the expr tree and set current expr + // node to GenericCastExpr. + while (GenericCastExpr) { + CastKinds.insert(GenericCastExpr->getCastKind()); + GenericCastExpr = dyn_cast<CastExpr>(GenericCastExpr->getSubExpr()); + } + + Casts.push_back(Op.getCastKindFromCStyleCast()); + } + }; + +protected: + ClangCXXCastTest() : CStyleCastMatcher(cStyleCastExpr().bind(CastVar)) {} + + std::pair<CastKindSet, CXXCastVector> parse(const StringRef Code) { + // Parses a single translation unit (from text) + // and returns the CXXCasts in order of traversed. + std::unique_ptr<clang::ASTUnit> ast(clang::tooling::buildASTFromCode(Code)); + CStyleCastCollector Collector; + MatchFinder Finder; + Finder.addMatcher(CStyleCastMatcher, &Collector); + Finder.matchAST(ast->getASTContext()); + return {Collector.CastKinds, Collector.Casts}; + } +}; + +class ClangQualifierModificationTest : public ::testing::Test { + StatementMatcher CStyleCastMatcher; + + struct QualifierChecker : MatchFinder::MatchCallback { + bool RequireConstCast; + bool Pedantic; + + QualifierChecker(const bool Pedantic) : Pedantic(Pedantic){}; + + virtual void run(const MatchFinder::MatchResult &Result) override { + ASTContext *Context = Result.Context; + const CStyleCastExpr *CastExpression = + Result.Nodes.getNodeAs<CStyleCastExpr>(CastVar); + assert(CastExpression && Context); + CStyleCastOperation Op(*CastExpression, *Context, Pedantic); + + RequireConstCast = Op.requireConstCast(); + } + }; + +protected: + ClangQualifierModificationTest() + : CStyleCastMatcher(cStyleCastExpr().bind(CastVar)) {} + + bool parse(const StringRef Code, bool Pedantic) { + std::unique_ptr<clang::ASTUnit> ast(clang::tooling::buildASTFromCode(Code)); + QualifierChecker Checker(Pedantic); + MatchFinder Finder; + Finder.addMatcher(CStyleCastMatcher, &Checker); + Finder.matchAST(ast->getASTContext()); + return Checker.RequireConstCast; + } +}; + +class ClangFunctionPtrDetectionTest : public ::testing::Test { + DeclarationMatcher VarDeclMatcher; + + struct FunctionPtrDetector : MatchFinder::MatchCallback { + bool FoundFunctionPtr; + FunctionPtrDetector() = default; + + virtual void run(const MatchFinder::MatchResult &Result) override { + const VarDecl *DeclExpr = Result.Nodes.getNodeAs<VarDecl>(DeclVar); + assert(DeclExpr); + QualType CanonicalDeclType = DeclExpr->getType().getCanonicalType(); + FoundFunctionPtr = details::isFunctionPtr(CanonicalDeclType); + } + }; + +protected: + ClangFunctionPtrDetectionTest() : VarDeclMatcher(varDecl().bind(DeclVar)) {} + + bool parse(const StringRef Code) { + std::unique_ptr<clang::ASTUnit> ast(clang::tooling::buildASTFromCode(Code)); + FunctionPtrDetector Detector; + MatchFinder Finder; + Finder.addMatcher(VarDeclMatcher, &Detector); + Finder.matchAST(ast->getASTContext()); + return Detector.FoundFunctionPtr; + } +}; + +class ChangeQualifierTest : public ::testing::Test { + StatementMatcher CStyleCastMatcher; + DeclarationMatcher DeclMatcher; + + struct QualifierChanger : MatchFinder::MatchCallback { + QualType ChangedCanonicalType; + bool Pedantic; + QualifierChanger(const bool Pedantic) : Pedantic(Pedantic) {} + + virtual void run(const MatchFinder::MatchResult &Result) override { + ASTContext *Context = Result.Context; + const CStyleCastExpr *CastExpression = + Result.Nodes.getNodeAs<CStyleCastExpr>(CastVar); + assert(CastExpression && Context); + CStyleCastOperation Op(*CastExpression, *Context, Pedantic); + + ChangedCanonicalType = Op.changeQualifiers().getCanonicalType(); + } + }; + + struct DeclTypeMatcher : MatchFinder::MatchCallback { + QualType FoundCanonicalType; + DeclTypeMatcher() = default; + + virtual void run(const MatchFinder::MatchResult &Result) override { + const VarDecl *DeclExpr = Result.Nodes.getNodeAs<VarDecl>(DeclVar); + assert(DeclExpr); + + FoundCanonicalType = DeclExpr->getType().getCanonicalType(); + } + }; + +protected: + ChangeQualifierTest() + : CStyleCastMatcher(cStyleCastExpr().bind(CastVar)), + DeclMatcher(varDecl().bind(DeclVar)) {} + + bool parse(const StringRef CastCode, bool Pedantic) { + std::unique_ptr<clang::ASTUnit> CastAst( + clang::tooling::buildASTFromCode(CastCode)); + std::unique_ptr<clang::ASTUnit> TypeAst( + clang::tooling::buildASTFromCode(CastCode)); + QualifierChanger Changer(Pedantic); + DeclTypeMatcher TypeMatcher; + { + MatchFinder Finder; + Finder.addMatcher(CStyleCastMatcher, &Changer); + Finder.matchAST(CastAst->getASTContext()); + } + { + MatchFinder Finder; + Finder.addMatcher(DeclMatcher, &TypeMatcher); + Finder.matchAST(TypeAst->getASTContext()); + } + return Changer.ChangedCanonicalType.getAsString() == + TypeMatcher.FoundCanonicalType.getAsString(); + } +}; + +TEST_F(ClangCXXCastTest, TestNoOpCastTypes) { + CLANG_CXX_CAST_CHECK(NoOp, NoOpCast); + CLANG_CXX_CAST_CHECK(ArrayToPointerDecay, NoOpCast); + // Unchecked: CLANG_CXX_CAST_CHECK(LValueToRValue, ConstCast); +} + +TEST_F(ClangCXXCastTest, TestReinterpretCastTypes) { + CLANG_CXX_CAST_CHECK(BitCast, ReinterpretCast); + CLANG_CXX_CAST_CHECK(LValueBitCast, ReinterpretCast); + CLANG_CXX_CAST_CHECK(IntegralToPointer, ReinterpretCast); + CLANG_CXX_CAST_CHECK(ReinterpretMemberPointer, ReinterpretCast); + CLANG_CXX_CAST_CHECK(PointerToIntegral, ReinterpretCast); +} + +TEST_F(ClangCXXCastTest, TestStaticCastTypes) { + CLANG_CXX_CAST_CHECK(BaseToDerived, StaticCast); + CLANG_CXX_CAST_CHECK(DerivedToBase, StaticCast); + // Unchecked: CLANG_CXX_CAST_CHECK(UncheckedDerivedToBase, StaticCast); + CLANG_CXX_CAST_CHECK(FunctionToPointerDecay, StaticCast); + CLANG_CXX_CAST_CHECK(NullToPointer, StaticCast); + CLANG_CXX_CAST_CHECK(NullToMemberPointer, StaticCast); + CLANG_CXX_CAST_CHECK(BaseToDerivedMemberPointer, StaticCast); + CLANG_CXX_CAST_CHECK(DerivedToBaseMemberPointer, StaticCast); + CLANG_CXX_CAST_CHECK(MemberPointerToBoolean, StaticCast); + CLANG_CXX_CAST_CHECK(UserDefinedConversion, StaticCast); + CLANG_CXX_CAST_CHECK(ConstructorConversion, StaticCast); + CLANG_CXX_CAST_CHECK(PointerToBoolean, StaticCast); + CLANG_CXX_CAST_CHECK(ToVoid, StaticCast); + CLANG_CXX_CAST_CHECK(VectorSplat, StaticCast); + CLANG_CXX_CAST_CHECK(IntegralCast, StaticCast); + CLANG_CXX_CAST_CHECK(IntegralToBoolean, StaticCast); + CLANG_CXX_CAST_CHECK(IntegralToFloating, StaticCast); + CLANG_CXX_CAST_CHECK(FloatingToIntegral, StaticCast); + CLANG_CXX_CAST_CHECK(FloatingToBoolean, StaticCast); + CLANG_CXX_CAST_CHECK(FloatingCast, StaticCast); + CLANG_CXX_CAST_CHECK(FloatingRealToComplex, StaticCast); + CLANG_CXX_CAST_CHECK(FloatingComplexToReal, StaticCast); + CLANG_CXX_CAST_CHECK(FloatingComplexToBoolean, StaticCast); + CLANG_CXX_CAST_CHECK(FloatingComplexCast, StaticCast); + CLANG_CXX_CAST_CHECK(FloatingComplexToIntegralComplex, StaticCast); + CLANG_CXX_CAST_CHECK(IntegralRealToComplex, StaticCast); + CLANG_CXX_CAST_CHECK(IntegralComplexToReal, StaticCast); + CLANG_CXX_CAST_CHECK(IntegralComplexToBoolean, StaticCast); + CLANG_CXX_CAST_CHECK(IntegralComplexCast, StaticCast); + CLANG_CXX_CAST_CHECK(IntegralComplexToFloatingComplex, StaticCast); + CLANG_CXX_CAST_CHECK(AtomicToNonAtomic, StaticCast); + CLANG_CXX_CAST_CHECK(NonAtomicToAtomic, StaticCast); +} + +TEST_F(ClangCXXCastTest, TestCStyleCastTypes) { + CLANG_CXX_CAST_CHECK(Dependent, CStyleCast); +} + +TEST_F(ClangCXXCastTest, TestEdgeCases) { + using namespace edgecases; + { + auto res = parse(DerivedToBasePrivateSpecifier); + ASSERT_GE(res.first.size(), 1ul); + ASSERT_GE(res.second.size(), 1ul); + ASSERT_TRUE(res.first.find(CastKind::CK_DerivedToBase) != res.first.end()); + ASSERT_EQ(res.second[0], CXXCast::CC_CStyleCast); + } + { + auto res = parse(BaseToDerivedPrivateSpecifier); + ASSERT_GE(res.first.size(), 1ul); + ASSERT_GE(res.second.size(), 1ul); + ASSERT_TRUE(res.first.find(CastKind::CK_BaseToDerived) != res.first.end()); + ASSERT_EQ(res.second[0], CXXCast::CC_CStyleCast); + } + CLANG_CXX_CAST_CHECK(Dependent, CStyleCast); +} + +/// These tests mean: +/// Does the C-style cast in <test case> require a const_cast? +TEST_F(ClangQualifierModificationTest, TestConstCases) { + CLANG_QUAL_CHECK(QualNoOp, false, false); + // add + // we perform these operations in order to first do a sanity check that + // 1. const cast isn't needed for upcasting + // 2. there will be no segmentation faults before we run the removal tests + CLANG_QUAL_CHECK(QualAddConst, false, false); + CLANG_QUAL_CHECK(QualAddPtrToConst, false, false); + CLANG_QUAL_CHECK(QualAddConstPtr, false, false); + CLANG_QUAL_CHECK(QualAddConstDoublePtr, false, false); + CLANG_QUAL_CHECK(QualAddConstDiffLevelPtr, false, false); + CLANG_QUAL_CHECK(QualAddMemberPtrToConst, false, false); + CLANG_QUAL_CHECK(QualAddConstMemberPtr, false, false); + CLANG_QUAL_CHECK(QualAddConstDoubleMemberPtr, false, false); + CLANG_QUAL_CHECK(QualAddConstDiffLevelMemberPtr, false, false); + CLANG_QUAL_CHECK(QualAddConstRef, false, false); + CLANG_QUAL_CHECK(QualAddConstArr, false, false); + CLANG_QUAL_CHECK(QualAddConstPtrToArr, false, false); + CLANG_QUAL_CHECK(QualAddConstPtrToArrOfConstPtrs, false, false); + CLANG_QUAL_CHECK(QualAddArrPtrConstData, false, false); + CLANG_QUAL_CHECK(QualAddDiffLevelArrPtrConstData, false, false); + CLANG_QUAL_CHECK(QualAddConstMixedPtrTypes, false, false); + CLANG_QUAL_CHECK(QualAddConstUnknownArrPtr, false, false); + CLANG_QUAL_CHECK(QualAddConstUnknownArrPtrToKnownArrPtr, false, false); + + // remove + // we perform these operations in order to check the positive cases, along + // with negative edge cases. + // does not require const cast - implicit + CLANG_QUAL_CHECK(QualRemoveConst, false, false); + // does require const cast, base type downcast + CLANG_QUAL_CHECK(QualRemovePtrToConst, true, false); + // does not - implicit + CLANG_QUAL_CHECK(QualRemoveConstPtr, false, false); + // does - downcast + CLANG_QUAL_CHECK(QualRemoveConstDoublePtr, true, false); + // does not - level truncated + CLANG_QUAL_CHECK(QualRemoveConstDiffLevelPtr, false, false); + + // Same as the above 4 + CLANG_QUAL_CHECK(QualRemoveMemberPtrToConst, true, false); + CLANG_QUAL_CHECK(QualRemoveConstMemberPtr, false, false); + CLANG_QUAL_CHECK(QualRemoveConstDoubleMemberPtr, true, false); + CLANG_QUAL_CHECK(QualRemoveConstDiffLevelMemberPtr, false, false); + + // does - downcast + CLANG_QUAL_CHECK(QualRemoveConstRef, true, false); + // does - downcast + CLANG_QUAL_CHECK(QualRemoveConstArr, true, false); + // does not - implicit + CLANG_QUAL_CHECK(QualRemoveConstPtrToArr, false, false); + // does - downcast + CLANG_QUAL_CHECK(QualRemoveConstPtrToArrOfConstPtrs, true, false); + // does - downcast + CLANG_QUAL_CHECK(QualRemoveArrPtrConstData, true, false); + // does not - level truncated + CLANG_QUAL_CHECK(QualRemoveDiffLevelArrPtrConstData, false, false); + // does - similar types going down + CLANG_QUAL_CHECK(QualRemoveSimilarPtrsBeyondArrConstData, true, false); + // does - All pointer-like types are downcasted + CLANG_QUAL_CHECK(QualRemoveConstMixedPtrTypes, true, false); + // does - Unknown size array is similar to unknown size array + CLANG_QUAL_CHECK(QualRemoveConstUnknownArrPtr, true, false); + // does - Unknown size array is similar to known size array + CLANG_QUAL_CHECK(QualRemoveConstUnknownArrPtrToKnownArrPtr, true, false); + + // Checking for pedantic changes + CLANG_QUAL_CHECK(QualNoOp, false, false); + CLANG_QUAL_CHECK(QualAddConst, false, false); + CLANG_QUAL_CHECK(QualAddPtrToConst, false, false); + CLANG_QUAL_CHECK(QualAddConstPtr, false, false); + CLANG_QUAL_CHECK(QualAddConstDoublePtr, false, false); + CLANG_QUAL_CHECK(QualAddConstDiffLevelPtr, false, false); + CLANG_QUAL_CHECK(QualAddMemberPtrToConst, false, false); + CLANG_QUAL_CHECK(QualAddConstMemberPtr, false, false); + CLANG_QUAL_CHECK(QualAddConstDoubleMemberPtr, false, false); + CLANG_QUAL_CHECK(QualAddConstDiffLevelMemberPtr, false, false); + CLANG_QUAL_CHECK(QualAddConstRef, false, false); + CLANG_QUAL_CHECK(QualAddConstArr, false, false); + CLANG_QUAL_CHECK(QualAddConstPtrToArr, false, false); + CLANG_QUAL_CHECK(QualAddConstPtrToArrOfConstPtrs, false, false); + CLANG_QUAL_CHECK(QualAddArrPtrConstData, false, false); + CLANG_QUAL_CHECK(QualAddDiffLevelArrPtrConstData, false, false); + CLANG_QUAL_CHECK(QualAddConstMixedPtrTypes, false, false); + CLANG_QUAL_CHECK(QualAddConstUnknownArrPtr, false, false); + CLANG_QUAL_CHECK(QualAddConstUnknownArrPtrToKnownArrPtr, false, false); + + CLANG_QUAL_CHECK(QualRemoveConst, false, false); + CLANG_QUAL_CHECK(QualRemovePtrToConst, true, false); + CLANG_QUAL_CHECK(QualRemoveConstPtr, false, false); + CLANG_QUAL_CHECK(QualRemoveConstDoublePtr, true, false); + CLANG_QUAL_CHECK(QualRemoveConstDiffLevelPtr, false, false); + CLANG_QUAL_CHECK(QualRemoveMemberPtrToConst, true, false); + CLANG_QUAL_CHECK(QualRemoveConstMemberPtr, false, false); + CLANG_QUAL_CHECK(QualRemoveConstDoubleMemberPtr, true, false); + CLANG_QUAL_CHECK(QualRemoveConstDiffLevelMemberPtr, false, false); + CLANG_QUAL_CHECK(QualRemoveConstRef, true, false); + CLANG_QUAL_CHECK(QualRemoveConstArr, true, false); + CLANG_QUAL_CHECK(QualRemoveConstPtrToArr, false, false); + CLANG_QUAL_CHECK(QualRemoveConstPtrToArrOfConstPtrs, true, false); + CLANG_QUAL_CHECK(QualRemoveArrPtrConstData, true, false); + CLANG_QUAL_CHECK(QualRemoveDiffLevelArrPtrConstData, false, false); + CLANG_QUAL_CHECK(QualRemoveSimilarPtrsBeyondArrConstData, true, false); + CLANG_QUAL_CHECK(QualRemoveConstMixedPtrTypes, true, false); + CLANG_QUAL_CHECK(QualRemoveConstUnknownArrPtr, true, false); + CLANG_QUAL_CHECK(QualRemoveConstUnknownArrPtrToKnownArrPtr, true, false); +} + +TEST_F(ClangQualifierModificationTest, TestVolatileCases) { + // add + CLANG_QUAL_CHECK(QualAddVolatile, false, false); + CLANG_QUAL_CHECK(QualAddPtrToVolatile, false, false); + CLANG_QUAL_CHECK(QualAddVolatilePtr, false, false); + CLANG_QUAL_CHECK(QualAddVolatileDoublePtr, false, false); + CLANG_QUAL_CHECK(QualAddVolatileDiffLevelPtr, false, false); + CLANG_QUAL_CHECK(QualAddVolatileRef, false, false); + CLANG_QUAL_CHECK(QualAddVolatileArr, false, false); + CLANG_QUAL_CHECK(QualAddVolatilePtrToArr, false, false); + CLANG_QUAL_CHECK(QualAddVolatilePtrToArrOfVolatilePtrs, false, false); + CLANG_QUAL_CHECK(QualAddArrPtrVolatileData, false, false); + CLANG_QUAL_CHECK(QualAddDiffLevelArrPtrVolatileData, false, false); + CLANG_QUAL_CHECK(QualAddVolatileMixedPtrTypes, false, false); + CLANG_QUAL_CHECK(QualAddVolatileUnknownArrPtr, false, false); + CLANG_QUAL_CHECK(QualAddVolatileUnknownArrPtrToKnownArrPtr, false, false); + + // remove + CLANG_QUAL_CHECK(QualRemoveVolatile, false, false); + CLANG_QUAL_CHECK(QualRemovePtrToVolatile, true, false); + CLANG_QUAL_CHECK(QualRemoveVolatilePtr, false, false); + CLANG_QUAL_CHECK(QualRemoveVolatileDoublePtr, true, false); + CLANG_QUAL_CHECK(QualRemoveVolatileDiffLevelPtr, false, false); + CLANG_QUAL_CHECK(QualRemoveVolatileRef, true, false); + CLANG_QUAL_CHECK(QualRemoveVolatileArr, true, false); + CLANG_QUAL_CHECK(QualRemoveVolatilePtrToArr, false, false); + CLANG_QUAL_CHECK(QualRemoveVolatilePtrToArrOfVolatilePtrs, true, false); + CLANG_QUAL_CHECK(QualRemoveArrPtrVolatileData, true, false); + CLANG_QUAL_CHECK(QualRemoveDiffLevelArrPtrVolatileData, false, false); + CLANG_QUAL_CHECK(QualRemoveSimilarPtrsBeyondArrVolatileData, true, false); + CLANG_QUAL_CHECK(QualRemoveVolatileMixedPtrTypes, true, false); + CLANG_QUAL_CHECK(QualRemoveVolatileUnknownArrPtr, true, false); + CLANG_QUAL_CHECK(QualRemoveVolatileUnknownArrPtrToKnownArrPtr, true, false); +} + +TEST_F(ClangQualifierModificationTest, TestRestrictCases) { + // add + CLANG_QUAL_CHECK(QualAddRestrictPtr, false, false); + CLANG_QUAL_CHECK(QualAddRestrictDoublePtr, false, false); + CLANG_QUAL_CHECK(QualAddRestrictDiffLevelPtr, false, false); + CLANG_QUAL_CHECK(QualAddRestrictArr, false, false); + CLANG_QUAL_CHECK(QualAddRestrictPtrToArr, false, false); + CLANG_QUAL_CHECK(QualAddRestrictPtrToArrOfRestrictPtrs, false, false); + CLANG_QUAL_CHECK(QualAddArrPtrRestrictData, false, false); + CLANG_QUAL_CHECK(QualAddDiffLevelArrPtrRestrictData, false, false); + CLANG_QUAL_CHECK(QualAddRestrictMixedPtrTypes, false, false); + CLANG_QUAL_CHECK(QualAddRestrictUnknownArrPtr, false, false); + CLANG_QUAL_CHECK(QualAddRestrictUnknownArrPtrToKnownArrPtr, false, false); + + // remove + CLANG_QUAL_CHECK(QualRemoveRestrictPtr, false, false); + CLANG_QUAL_CHECK(QualRemoveRestrictDoublePtr, true, false); + CLANG_QUAL_CHECK(QualRemoveRestrictDiffLevelPtr, false, false); + CLANG_QUAL_CHECK(QualRemoveRestrictArr, true, false); + CLANG_QUAL_CHECK(QualRemoveRestrictPtrToArr, false, false); + CLANG_QUAL_CHECK(QualRemoveRestrictPtrToArrOfRestrictPtrs, true, false); + CLANG_QUAL_CHECK(QualRemoveArrPtrRestrictData, true, false); + CLANG_QUAL_CHECK(QualRemoveDiffLevelArrPtrRestrictData, false, false); + CLANG_QUAL_CHECK(QualRemoveSimilarPtrsBeyondArrRestrictData, true, false); + CLANG_QUAL_CHECK(QualRemoveRestrictMixedPtrTypes, true, false); + CLANG_QUAL_CHECK(QualRemoveRestrictUnknownArrPtr, true, false); + CLANG_QUAL_CHECK(QualRemoveRestrictUnknownArrPtrToKnownArrPtr, true, false); +} + +TEST_F(ClangFunctionPtrDetectionTest, TestFuncPtrs) { + CLANG_FUNC_PTR_CHECK(Scalar, false); + CLANG_FUNC_PTR_CHECK(ArrOfFreeFunctionPtr, false); + CLANG_FUNC_PTR_CHECK(NestedFreeFunctionPtr, false); + CLANG_FUNC_PTR_CHECK(FreeFunction, true); + CLANG_FUNC_PTR_CHECK(ArrOfMemberFunction, false); + CLANG_FUNC_PTR_CHECK(NestedMemberFunction, false); + CLANG_FUNC_PTR_CHECK(MemberFunction, true); +} + +TEST_F(ChangeQualifierTest, TestChangeQualifiers) { + ASSERT_TRUE(parse(extension::NoQualifierChange, false)); + ASSERT_TRUE(parse(extension::NoQualifierChangeReinterpret, false)); + ASSERT_TRUE(parse(extension::ChangeNestedPointers, false)); + ASSERT_TRUE(parse(extension::ChangeNestedPointersReinterpret, false)); + ASSERT_TRUE(parse(extension::ChangeNestedPointersUntilArray, false)); + ASSERT_TRUE( + parse(extension::ChangeNestedPointersUntilArrayReinterpret, false)); + ASSERT_TRUE(parse(extension::NoModificationToMixedPtrTypes, false)); + ASSERT_TRUE(parse(extension::DontChangeMemberFuncPtr, false)); + ASSERT_TRUE(parse(extension::ChangeNestedPointersUntilMemberVsNot, false)); + + ASSERT_TRUE(parse(pedantic::NoQualifierChange, true)); + ASSERT_TRUE(parse(pedantic::NoQualifierChangeReinterpret, true)); + ASSERT_TRUE(parse(pedantic::ChangeNestedPointers, true)); + ASSERT_TRUE(parse(pedantic::ChangeNestedPointersReinterpret, true)); + ASSERT_TRUE(parse(pedantic::ChangeNestedPointersUntilArray, true)); + ASSERT_TRUE(parse(pedantic::ChangeNestedPointersUntilArrayReinterpret, true)); + ASSERT_TRUE(parse(pedantic::NoModificationToMixedPtrTypes, true)); + ASSERT_TRUE(parse(pedantic::DontChangeMemberFuncPtr, true)); + ASSERT_TRUE(parse(pedantic::ChangeNestedPointersUntilMemberVsNot, true)); +} Index: clang-tools-extra/unittests/clang-cast/ClangCXXCastTestCases.h =================================================================== --- /dev/null +++ clang-tools-extra/unittests/clang-cast/ClangCXXCastTestCases.h @@ -0,0 +1,339 @@ +//===-- ClangCXXCastTestCases.h - clang-cast --------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains test cases for +/// CStyleCastOperation::getCastKindFromCStyleCast (defined in Cast.h) +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANG_CAST_CLANGCXXCASTTESTCASES_H +#define LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANG_CAST_CLANGCXXCASTTESTCASES_H + +namespace testcases { + +/// NoOp cast types - these are conversions +/// that can be done implicitly. +static const char NoOp[] = R"( +void f() { + (int&&) 0; +} +)"; +static const char ArrayToPointerDecay[] = R"( +void f() { + char x[] = ""; + (char*) x; +} +)"; +// NOTE: Unused, as C style casts cannot +// perform this. It must be done implicitly. +// (int&&) x is a NoOp, and std::move(x) is +// FunctionToPointerDecay. +static const char LValueToRValue[] = R"( +void f() { + int x; + int y = x; +} +)"; + +/// Static cast types +static const char BaseToDerived[] = R"( +class A {}; +class B: public A {}; +class C: public B {}; + +void f() { + A* a = nullptr; + (C*) a; +} +)"; +static const char DerivedToBase[] = R"( +class A {}; +class B: public A {}; +class C: public B {}; + +void f() { + C* c = nullptr; + (A*) c; +} +)"; +// NOTE: Unused, as C style casts cannot +// perform this. It must be done implicitly. +static const char UncheckedDerivedToBase[] = R"( +class A { public: void a(){} }; +class B : public A {}; + +void f() { + B *b; + b->a(); +} +)"; +static const char FunctionToPointerDecay[] = R"( +void g() {} + +void f() { + (void (*)()) g; +} +)"; +static const char NullToPointer[] = R"( +void f() { + (void*) 0; +} +)"; +static const char NullToMemberPointer[] = R"( +struct A {}; +void f() { + (int A::*) 0; +} +)"; +static const char BaseToDerivedMemberPointer[] = R"( +struct A { int m; }; +struct B : A {}; +void f() { + (int B::*) &A::m; +} +)"; +static const char DerivedToBaseMemberPointer[] = R"( +struct A {}; +struct B : A { int m; }; +void f() { + (int A::*) &B::m; +} +)"; +static const char MemberPointerToBoolean[] = R"( +struct A { int m; }; +void f() { + (bool) &A::m; +} +)"; +static const char UserDefinedConversion[] = R"( +struct A { operator int(); }; + +void f() { + (int) A(); +} +)"; +static const char ConstructorConversion[] = R"( +struct A { A(int); }; + +void f() { + (A) 10; +} +)"; +static const char PointerToBoolean[] = R"( +void f() { + (bool) nullptr; +} +)"; +static const char ToVoid[] = R"( +void f() { + (void) 0; +} +)"; +static const char VectorSplat[] = R"( +void f() { + typedef float float4 __attribute__((ext_vector_type(4))); + using type = float4; + (type) 0.0f; +} +)"; +static const char IntegralCast[] = R"( +void f() { + (long long int) 0u; +} +)"; +static const char IntegralToBoolean[] = R"( +void f() { + (bool) 10l; +} +)"; +static const char IntegralToFloating[] = R"( +void f() { + (float) 10l; +} +)"; + +// NOTE: Unused, as fixed points are not yet introduced into C++ standard. +// nor the clang extensions. +static const char FixedPointCast[] = R"()"; +// NOTE: Unused, as fixed points are not yet introduced into C++ standard. +// nor the clang extensions. +static const char FixedPointToIntegral[] = R"()"; +// NOTE: Unused, as fixed points are not yet introduced into C++ standard. +// nor the clang extensions. +static const char IntegralToFixedPoint[] = R"()"; +// NOTE: Unused, as fixed points are not yet introduced into C++ standard. +// nor the clang extensions. +static const char FixedPointToBoolean[] = R"()"; + +static const char FloatingToIntegral[] = R"( +void f() { + (int) 0.0f; +} +)"; +static const char FloatingToBoolean[] = R"( +void f() { + (bool) 0.0f; +} +)"; +// TODO: Ask question +// NOTE: Unused, because AFAIK this is not possible, according to +// the comments it will cast to -1/0 for true/false. +static const char BooleanToSignedIntegral[] = R"( +void f() { + (int) true; +} +)"; +static const char FloatingCast[] = R"( +void f() { + (double) 0.0f; +} +)"; +static const char FloatingRealToComplex[] = R"( +void f() { + (_Complex long double) 1.0; +} +)"; +static const char FloatingComplexToReal[] = R"( +void f() { + _Complex long double c; + (long double) c; +} +)"; +static const char FloatingComplexToBoolean[] = R"( +void f() { + _Complex long double c; + (bool) c; +} +)"; +static const char FloatingComplexCast[] = R"( +void f() { + _Complex long double c; + (_Complex float) c; +} +)"; +static const char FloatingComplexToIntegralComplex[] = R"( +void f() { + _Complex long double c; + (_Complex int) c; +} +)"; +static const char IntegralRealToComplex[] = R"( +void f() { + (_Complex long long) 10l; +} +)"; +static const char IntegralComplexToReal[] = R"( +void f() { + _Complex long long c; + (int) c; +} +)"; +static const char IntegralComplexToBoolean[] = R"( +void f() { + _Complex long long c; + (bool) c; +} +)"; +static const char IntegralComplexCast[] = R"( +void f() { + _Complex long long c; + (_Complex int) c; +} +)"; +static const char IntegralComplexToFloatingComplex[] = R"( +void f() { + _Complex long long c; + (_Complex float) c; +} +)"; +static const char AtomicToNonAtomic[] = R"( +void f() { + _Atomic(int) c; + (int) c; +} +)"; +static const char NonAtomicToAtomic[] = R"( +void f() { + int c; + (_Atomic(int)) c; +} +)"; + +/// Reinterpret cast types +const char BitCast[] = R"( +void f() { + char* x; + (int *) x; +} +)"; +const char LValueBitCast[] = R"( +void f() { + char c; + (bool&) c; +} +)"; +static const char IntegralToPointer[] = R"( +void f() { + (int*) 10l; +} +)"; +// NOTE: Unused, as C style casts cannot +// perform this. It must be done by bit_cast. +const char LValueToRValueBitCast[] = R"( +void f() { + int i; + std::bit_cast<float>(i); +} +)"; +static const char ReinterpretMemberPointer[] = R"( +struct A { int val; }; + +void f() { + int A::* ptr = &A::val; + (bool A::*) ptr; +} +)"; +static const char PointerToIntegral[] = R"( +#include <stdint.h> +void f() { + (intptr_t) nullptr; +} +)"; + +/// C-style cast types +static const char Dependent[] = R"( +template <typename T> +void foo() { + (T) 0; +} +)"; + +namespace edgecases { + +static const char BaseToDerivedPrivateSpecifier[] = R"( +struct A { int i; }; +struct Pad { int i; }; +class B: Pad, A {}; + +B* foo(A *a) { return (B*)(a); } +)"; + +static const char DerivedToBasePrivateSpecifier[] = R"( +struct A { int i; }; +struct Pad { int i; }; +class B: Pad, A {}; + +A* foo(B *b) { return (A*)(b); } +)"; + +} // namespace edgecases + +} // namespace testcases + +#endif // LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANG_CAST_CLANGCXXCASTTESTCASES_H Index: clang-tools-extra/unittests/clang-cast/CMakeLists.txt =================================================================== --- /dev/null +++ clang-tools-extra/unittests/clang-cast/CMakeLists.txt @@ -0,0 +1,30 @@ +set(LLVM_LINK_COMPONENTS Support) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/../../clang-cast +) + +add_extra_unittest(ClangCastTests + ClangCastTests.cpp +) + +clang_target_link_libraries(ClangCastTests + PRIVATE + clangAST + clangASTMatchers + clangBasic + clangFormat + clangFrontend + clangRewrite + clangSerialization + clangTooling + clangToolingCore +) + +target_link_libraries(ClangCastTests + PRIVATE + clangTooling + clangBasic + clangASTMatchers +) + Index: clang-tools-extra/unittests/CMakeLists.txt =================================================================== --- clang-tools-extra/unittests/CMakeLists.txt +++ clang-tools-extra/unittests/CMakeLists.txt @@ -6,6 +6,7 @@ endfunction() add_subdirectory(clang-apply-replacements) +add_subdirectory(clang-cast) add_subdirectory(clang-change-namespace) add_subdirectory(clang-doc) add_subdirectory(clang-include-fixer) Index: clang-tools-extra/clang-cast/Matcher.h =================================================================== --- /dev/null +++ clang-tools-extra/clang-cast/Matcher.h @@ -0,0 +1 @@ +/home/ray/home/clang-cast/Matcher.h \ No newline at end of file Index: clang-tools-extra/clang-cast/Consumer.h =================================================================== --- /dev/null +++ clang-tools-extra/clang-cast/Consumer.h @@ -0,0 +1 @@ +/home/ray/home/clang-cast/Consumer.h \ No newline at end of file Index: clang-tools-extra/clang-cast/ClangCast.cpp =================================================================== --- /dev/null +++ clang-tools-extra/clang-cast/ClangCast.cpp @@ -0,0 +1 @@ +/home/ray/home/clang-cast/ClangCast.cpp \ No newline at end of file Index: clang-tools-extra/clang-cast/CastUtils.h =================================================================== --- /dev/null +++ clang-tools-extra/clang-cast/CastUtils.h @@ -0,0 +1 @@ +/home/ray/home/clang-cast/CastUtils.h \ No newline at end of file Index: clang-tools-extra/clang-cast/CastOptions.h =================================================================== --- /dev/null +++ clang-tools-extra/clang-cast/CastOptions.h @@ -0,0 +1 @@ +/home/ray/home/clang-cast/CastOptions.h \ No newline at end of file Index: clang-tools-extra/clang-cast/Cast.h =================================================================== --- /dev/null +++ clang-tools-extra/clang-cast/Cast.h @@ -0,0 +1 @@ +/home/ray/home/clang-cast/Cast.h \ No newline at end of file Index: clang-tools-extra/clang-cast/CMakeLists.txt =================================================================== --- /dev/null +++ clang-tools-extra/clang-cast/CMakeLists.txt @@ -0,0 +1,14 @@ +set(LLVM_LINK_COMPONENTS + support) + +add_clang_tool(clang-cast + ClangCast.cpp + ) + +target_link_libraries(clang-cast + PRIVATE + clangTooling + clangBasic + clangRewriteFrontend + clangASTMatchers + ) Index: clang-tools-extra/CMakeLists.txt =================================================================== --- clang-tools-extra/CMakeLists.txt +++ clang-tools-extra/CMakeLists.txt @@ -8,6 +8,7 @@ add_subdirectory(modularize) add_subdirectory(clang-tidy) +add_subdirectory(clang-cast) add_subdirectory(clang-change-namespace) add_subdirectory(clang-doc) add_subdirectory(clang-include-fixer)
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits