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

Reply via email to