Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Clang] [NFC] Rename isAnyPointerType() and getPointeeOrArrayElementType(). #122938

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

Sirraide
Copy link
Member

Changes

tl;dr: The names are inaccurate and continue to cause confusion.

This pr currently makes the following changes:

  • Rename isAnyPointerType() to isPointerOrObjCObjectPointerType().
  • Rename getPointeeOrArrayElementType() to getPointerOrObjCPointerOrArrayElementType().
  • Introduce getPointerLikeOrArrayElementType() which actually is a superset of the functionality that getPointeeType() provides (I don’t think we can call this getPointeeOrArrayElementType() because that would effectively just mean that the behaviour of this function changes all of a sudden, which may cause even more confusion for people that are not aware that we’re making this change). A function like this that actually supports member pointers is needed for [Clang] FunctionEffects: Correctly navigate through array types in FunctionEffectsRef::get(). #121525.
  • Elaborate on what types getPointeeType() actually supports in a comment. getPointeeType() actually ends up being fine imo because it does actually handle anything that could reasonably be conceived of as having a ‘pointee’.

Open Questions

  • The names for the first two are rather verbose; I’m open to suggestions as to better names for these functions since that was the best that I managed to come up with...
  • I’ve already discussed this somewhat with @AaronBallman and @cor3ntin, and I think that we probably don’t want to introduce any new helpers like isAnyPointerType() that claim to handle ‘all pointer types’, mainly because a lot of the calls to isAnyPointerType() are currently of the form if (Ty->isAnyPointerType() || Ty->someOtherPredicate()), where someOtherPredicate() may check for ReferenceType, MemberPointerType, etc. It seems that nearly every call site is different in what ‘pointer-like types’ it cares about, so a general helper is unlikely to be of any use pretty much ever.
  • I’m planning to do a general clean-up pass and look at all call sites of what used to be isAnyPointerType() to see if there is anything weird—so far, two instances of rather obvious dead code have surfaced as a result of the renaming (see below)—but my plan is to do that as a follow-up pr.
  • Additionally, there are a few places we could probably clean up by either introducing or using newer helper functions, e.g. we now have isPointerOrReferenceType(), so it would be possible to replace every instance of Ty->isPointerType() || Ty->isReferenceType() with Ty->isPointerOrReferenceType() and additionally introduce new helpers for common combinations of these predicates. At the same time, that sounds a bit like a reformatting pass with extra steps, and we usually tend to eschew these because they interact poorly with git blame from what I recall, so I’m not sure if that’s a good idea.
  • @AaronBallman There is an AST matcher with the name isAnyPointer(), which uses isAnyPointerType(). I’m not sure what exactly we want to do with that one.

Background

In the Type class, we currently have the following function:

bool isAnyPointerType() const;

which, one might reasonably assume, ought to return true if this is ‘any pointer type’, whatever that means. It turns out that what that actually ends up meaning is:

// Any C pointer or ObjC object pointer

That is, it does not include

  • Member pointers,
  • Block pointers,
  • nullptr_t.

Of course, one might argue that e.g. member pointers aren’t actually pointers but offsets, which is true, but we still call them MemberPointerTypes, so by name alone, they are still ‘a kind of pointer’.

Searching for occurrences yields several cases where someone has fallen for this and misunderstood what ‘any pointer type’ was actually supposed to mean. I’ve renamed it to isPointerOrObjCObjectPointerType(), so these misuses end up being rather apparent. There seem to be at least two places that are currently in the code base where someone got confused about this:

  • Here, we end up checking if Pointee is a pointer or Objective-C pointer... or Objective-C pointer.

    return Pointee->isPointerOrObjCObjectPointerType() ||
    Pointee->isObjCObjectPointerType() || Pointee->isMemberPointerType();

  • Here, it would seem that both of these if statements together end up being functionally equivalent to
    if (!Ty->isObjectPointerType()) return false;

    static bool TypeIsInnerPointer(QualType T) {
    if (!T->isPointerOrObjCObjectPointerType())
    return false;
    if (T->isObjCObjectPointerType() || T->isObjCBuiltinType() ||
    T->isBlockPointerType() || T->isFunctionPointerType() ||
    ento::coreFoundation::isCFObjectRef(T))
    return false;

Additionally, I can recall several instances of me either reading or writing code that uses isAnyPointerType() and then getting confused why something wasn’t working properly, and I’ve heard similar sentiment from others.

Another possible instance of that might be getPointeeOrArrayElementType(). You’d think based on its name that it’s an extension of getPointeeType() that also handles arrays, but that’s wrong: the former calls isAnyPointerType() before delegating to getPointeeType(), which means that unlike getPointeeType(), this function does not handle block or member pointers at all. Confusion about this fact in particular just a few days ago is what prompted me to address this issue.

@llvmbot
Copy link
Member

llvmbot commented Jan 14, 2025

@llvm/pr-subscribers-backend-aarch64
@llvm/pr-subscribers-lldb
@llvm/pr-subscribers-backend-arm
@llvm/pr-subscribers-clang-codegen
@llvm/pr-subscribers-hlsl
@llvm/pr-subscribers-backend-systemz
@llvm/pr-subscribers-clang-tidy

@llvm/pr-subscribers-clang

Author: None (Sirraide)

Changes

Changes

tl;dr: The names are inaccurate and continue to cause confusion.

This pr currently makes the following changes:

  • Rename isAnyPointerType() to isPointerOrObjCObjectPointerType().
  • Rename getPointeeOrArrayElementType() to getPointerOrObjCPointerOrArrayElementType().
  • Introduce getPointerLikeOrArrayElementType() which actually is a superset of the functionality that getPointeeType() provides (I don’t think we can call this getPointeeOrArrayElementType() because that would effectively just mean that the behaviour of this function changes all of a sudden, which may cause even more confusion for people that are not aware that we’re making this change). A function like this that actually supports member pointers is needed for #121525.
  • Elaborate on what types getPointeeType() actually supports in a comment. getPointeeType() actually ends up being fine imo because it does actually handle anything that could reasonably be conceived of as having a ‘pointee’.

Open Questions

  • The names for the first two are rather verbose; I’m open to suggestions as to better names for these functions since that was the best that I managed to come up with...
  • I’ve already discussed this somewhat with @AaronBallman and @cor3ntin, and I think that we probably don’t want to introduce any new helpers like isAnyPointerType() that claim to handle ‘all pointer types’, mainly because a lot of the calls to isAnyPointerType() are currently of the form if (Ty->isAnyPointerType() || Ty->someOtherPredicate()), where someOtherPredicate() may check for ReferenceType, MemberPointerType, etc. It seems that nearly every call site is different in what ‘pointer-like types’ it cares about, so a general helper is unlikely to be of any use pretty much ever.
  • I’m planning to do a general clean-up pass and look at all call sites of what used to be isAnyPointerType() to see if there is anything weird—so far, two instances of rather obvious dead code have surfaced as a result of the renaming (see below)—but my plan is to do that as a follow-up pr.
  • Additionally, there are a few places we could probably clean up by either introducing or using newer helper functions, e.g. we now have isPointerOrReferenceType(), so it would be possible to replace every instance of Ty->isPointerType() || Ty->isReferenceType() with Ty->isPointerOrReferenceType() and additionally introduce new helpers for common combinations of these predicates. At the same time, that sounds a bit like a reformatting pass with extra steps, and we usually tend to eschew these because they interact poorly with git blame from what I recall, so I’m not sure if that’s a good idea.
  • @AaronBallman There is an AST matcher with the name isAnyPointer(), which uses isAnyPointerType(). I’m not sure what exactly we want to do with that one.

Background

In the Type class, we currently have the following function:

bool isAnyPointerType() const;

which, one might reasonably assume, ought to return true if this is ‘any pointer type’, whatever that means. It turns out that what that actually ends up meaning is:

// Any C pointer or ObjC object pointer

That is, it does not include

  • Member pointers,
  • Block pointers,
  • nullptr_t.

Of course, one might argue that e.g. member pointers aren’t actually pointers but offsets, which is true, but we still call them MemberPointerTypes, so by name alone, they are still ‘a kind of pointer’.

Searching for occurrences yields several cases where someone has fallen for this and misunderstood what ‘any pointer type’ was actually supposed to mean. I’ve renamed it to isPointerOrObjCObjectPointerType(), so these misuses end up being rather apparent. There seem to be at least two places that are currently in the code base where someone got confused about this:

  • Here, we end up checking if Pointee is a pointer or Objective-C pointer... or Objective-C pointer.

    return Pointee->isPointerOrObjCObjectPointerType() ||
    Pointee->isObjCObjectPointerType() || Pointee->isMemberPointerType();

  • Here, it would seem that both of these if statements together end up being functionally equivalent to
    if (!Ty->isObjectPointerType()) return false;

    static bool TypeIsInnerPointer(QualType T) {
    if (!T->isPointerOrObjCObjectPointerType())
    return false;
    if (T->isObjCObjectPointerType() || T->isObjCBuiltinType() ||
    T->isBlockPointerType() || T->isFunctionPointerType() ||
    ento::coreFoundation::isCFObjectRef(T))
    return false;

Additionally, I can recall several instances of me either reading or writing code that uses isAnyPointerType() and then getting confused why something wasn’t working properly, and I’ve heard similar sentiment from others.

Another possible instance of that might be getPointeeOrArrayElementType(). You’d think based on its name that it’s an extension of getPointeeType() that also handles arrays, but that’s wrong: the former calls isAnyPointerType() before delegating to getPointeeType(), which means that unlike getPointeeType(), this function does not handle block or member pointers at all. Confusion about this fact in particular just a few days ago is what prompted me to address this issue.


Patch is 96.82 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/122938.diff

69 Files Affected:

  • (modified) clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp (+1-1)
  • (modified) clang-tools-extra/clang-tidy/bugprone/SuspiciousMemoryComparisonCheck.cpp (+2-1)
  • (modified) clang-tools-extra/clang-tidy/cppcoreguidelines/InitVariablesCheck.cpp (+1-1)
  • (modified) clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp (+1-1)
  • (modified) clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp (+11-6)
  • (modified) clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp (+2-1)
  • (modified) clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp (+1-1)
  • (modified) clang-tools-extra/clangd/SemanticHighlighting.cpp (+1-1)
  • (modified) clang/include/clang/AST/CanonicalType.h (+1-1)
  • (modified) clang/include/clang/AST/Type.h (+25-10)
  • (modified) clang/include/clang/ASTMatchers/ASTMatchers.h (+2-2)
  • (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h (+1-1)
  • (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h (+11-6)
  • (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h (+1-2)
  • (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h (+1-1)
  • (modified) clang/lib/ARCMigrate/ObjCMT.cpp (+2-2)
  • (modified) clang/lib/AST/ASTContext.cpp (+5-5)
  • (modified) clang/lib/AST/ASTImporter.cpp (+1-1)
  • (modified) clang/lib/AST/Expr.cpp (+2-2)
  • (modified) clang/lib/AST/ExprCXX.cpp (+1-1)
  • (modified) clang/lib/AST/ExprConstant.cpp (+1-1)
  • (modified) clang/lib/AST/MicrosoftMangle.cpp (+3-2)
  • (modified) clang/lib/AST/Type.cpp (+6)
  • (modified) clang/lib/Analysis/ThreadSafetyCommon.cpp (+1-1)
  • (modified) clang/lib/Analysis/UninitializedValues.cpp (+2-1)
  • (modified) clang/lib/CodeGen/CGCall.cpp (+2-1)
  • (modified) clang/lib/CodeGen/CGExpr.cpp (+2-1)
  • (modified) clang/lib/CodeGen/CGHLSLRuntime.cpp (+1-1)
  • (modified) clang/lib/CodeGen/CGOpenMPRuntime.cpp (+21-16)
  • (modified) clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp (+4-2)
  • (modified) clang/lib/CodeGen/CGStmtOpenMP.cpp (+6-4)
  • (modified) clang/lib/CodeGen/CodeGenTypes.cpp (+2-1)
  • (modified) clang/lib/CodeGen/Targets/SystemZ.cpp (+1-1)
  • (modified) clang/lib/ExtractAPI/DeclarationFragments.cpp (+1-1)
  • (modified) clang/lib/Frontend/ASTUnit.cpp (+3-3)
  • (modified) clang/lib/Sema/SemaAPINotes.cpp (+2-2)
  • (modified) clang/lib/Sema/SemaARM.cpp (+12-10)
  • (modified) clang/lib/Sema/SemaCast.cpp (+22-15)
  • (modified) clang/lib/Sema/SemaChecking.cpp (+7-5)
  • (modified) clang/lib/Sema/SemaCodeComplete.cpp (+4-3)
  • (modified) clang/lib/Sema/SemaDecl.cpp (+7-6)
  • (modified) clang/lib/Sema/SemaDeclAttr.cpp (+7-6)
  • (modified) clang/lib/Sema/SemaExpr.cpp (+34-26)
  • (modified) clang/lib/Sema/SemaExprCXX.cpp (+5-5)
  • (modified) clang/lib/Sema/SemaInit.cpp (+4-2)
  • (modified) clang/lib/Sema/SemaLookup.cpp (+2-1)
  • (modified) clang/lib/Sema/SemaOpenACC.cpp (+1-1)
  • (modified) clang/lib/Sema/SemaOpenCL.cpp (+3-1)
  • (modified) clang/lib/Sema/SemaOpenMP.cpp (+19-15)
  • (modified) clang/lib/Sema/SemaOverload.cpp (+8-7)
  • (modified) clang/lib/Sema/SemaRISCV.cpp (+2-1)
  • (modified) clang/lib/Sema/SemaSYCL.cpp (+2-2)
  • (modified) clang/lib/Sema/SemaTemplateDeduction.cpp (+1-1)
  • (modified) clang/lib/Sema/SemaType.cpp (+4-4)
  • (modified) clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp (+1-1)
  • (modified) clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp (+2-1)
  • (modified) clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp (+1-1)
  • (modified) clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp (+1-1)
  • (modified) clang/lib/StaticAnalyzer/Checkers/TrustNonnullChecker.cpp (+1-1)
  • (modified) clang/lib/StaticAnalyzer/Checkers/TrustReturnsNonnullChecker.cpp (+1-1)
  • (modified) clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h (+1-1)
  • (modified) clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp (+2-2)
  • (modified) clang/lib/StaticAnalyzer/Core/CallEvent.cpp (+2-2)
  • (modified) clang/lib/StaticAnalyzer/Core/DynamicType.cpp (+3-2)
  • (modified) clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp (+1-1)
  • (modified) clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp (+1-1)
  • (modified) clang/lib/Tooling/Transformer/SourceCodeBuilders.cpp (+1-1)
  • (modified) clang/lib/Tooling/Transformer/Stencil.cpp (+2-2)
  • (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp (+1-1)
diff --git a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
index b7f0c08b2a7d4b..f4c5523184630f 100644
--- a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
@@ -93,7 +93,7 @@ static bool isVarThatIsPossiblyChanged(const Decl *Func, const Stmt *LoopStmt,
       if (T.isVolatileQualified())
         return true;
 
-      if (!T->isAnyPointerType() && !T->isReferenceType())
+      if (!T->isPointerOrObjCObjectPointerType() && !T->isReferenceType())
         break;
 
       T = T->getPointeeType();
diff --git a/clang-tools-extra/clang-tidy/bugprone/SuspiciousMemoryComparisonCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SuspiciousMemoryComparisonCheck.cpp
index 84957e0b8190c0..7779b6725673cb 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SuspiciousMemoryComparisonCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SuspiciousMemoryComparisonCheck.cpp
@@ -45,7 +45,8 @@ void SuspiciousMemoryComparisonCheck::check(
   for (unsigned int ArgIndex = 0; ArgIndex < 2; ++ArgIndex) {
     const Expr *ArgExpr = CE->getArg(ArgIndex);
     QualType ArgType = ArgExpr->IgnoreImplicit()->getType();
-    const Type *PointeeType = ArgType->getPointeeOrArrayElementType();
+    const Type *PointeeType =
+        ArgType->getPointerOrObjCPointerOrArrayElementType();
     assert(PointeeType != nullptr && "PointeeType should always be available.");
     QualType PointeeQualifiedType(PointeeType, 0);
 
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/InitVariablesCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/InitVariablesCheck.cpp
index 3eef2fd12cc8e5..be1673d5c08c98 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/InitVariablesCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/InitVariablesCheck.cpp
@@ -95,7 +95,7 @@ void InitVariablesCheck::check(const MatchFinder::MatchResult &Result) {
   else if (TypePtr->isFloatingType()) {
     InitializationString = " = NAN";
     AddMathInclude = true;
-  } else if (TypePtr->isAnyPointerType()) {
+  } else if (TypePtr->isPointerOrObjCObjectPointerType()) {
     if (getLangOpts().CPlusPlus11)
       InitializationString = " = nullptr";
     else
diff --git a/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp b/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp
index 5abe4f77d65984..36628d0fd84be5 100644
--- a/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp
+++ b/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp
@@ -229,7 +229,7 @@ static bool isTypedefTypeMatching(const TypedefType *const Typedef,
 /// \returns type of the argument
 static const Type *argumentType(const CallExpr *const CE, const size_t Idx) {
   const QualType QT = CE->getArg(Idx)->IgnoreImpCasts()->getType();
-  return QT.getTypePtr()->getPointeeOrArrayElementType();
+  return QT.getTypePtr()->getPointerOrObjCPointerOrArrayElementType();
 }
 
 void TypeMismatchCheck::registerMatchers(MatchFinder *Finder) {
diff --git a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
index 3f63eec2c51a8c..dc740377c4db14 100644
--- a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
@@ -1218,7 +1218,7 @@ StyleKind IdentifierNamingCheck::findStyleKind(
       return SK_ConstexprVariable;
 
     if (!Type.isNull() && Type.isConstQualified()) {
-      if (Type.getTypePtr()->isAnyPointerType() &&
+      if (Type.getTypePtr()->isPointerOrObjCObjectPointerType() &&
           NamingStyles[SK_ConstantPointerParameter])
         return SK_ConstantPointerParameter;
 
@@ -1232,7 +1232,8 @@ StyleKind IdentifierNamingCheck::findStyleKind(
     if (Decl->isParameterPack() && NamingStyles[SK_ParameterPack])
       return SK_ParameterPack;
 
-    if (!Type.isNull() && Type.getTypePtr()->isAnyPointerType() &&
+    if (!Type.isNull() &&
+        Type.getTypePtr()->isPointerOrObjCObjectPointerType() &&
         NamingStyles[SK_PointerParameter])
       return SK_PointerParameter;
 
@@ -1508,7 +1509,8 @@ StyleKind IdentifierNamingCheck::findStyleKindForVar(
     if (Var->isStaticDataMember() && NamingStyles[SK_ClassConstant])
       return SK_ClassConstant;
 
-    if (Var->isFileVarDecl() && Type.getTypePtr()->isAnyPointerType() &&
+    if (Var->isFileVarDecl() &&
+        Type.getTypePtr()->isPointerOrObjCObjectPointerType() &&
         NamingStyles[SK_GlobalConstantPointer])
       return SK_GlobalConstantPointer;
 
@@ -1518,7 +1520,8 @@ StyleKind IdentifierNamingCheck::findStyleKindForVar(
     if (Var->isStaticLocal() && NamingStyles[SK_StaticConstant])
       return SK_StaticConstant;
 
-    if (Var->isLocalVarDecl() && Type.getTypePtr()->isAnyPointerType() &&
+    if (Var->isLocalVarDecl() &&
+        Type.getTypePtr()->isPointerOrObjCObjectPointerType() &&
         NamingStyles[SK_LocalConstantPointer])
       return SK_LocalConstantPointer;
 
@@ -1535,7 +1538,8 @@ StyleKind IdentifierNamingCheck::findStyleKindForVar(
   if (Var->isStaticDataMember() && NamingStyles[SK_ClassMember])
     return SK_ClassMember;
 
-  if (Var->isFileVarDecl() && Type.getTypePtr()->isAnyPointerType() &&
+  if (Var->isFileVarDecl() &&
+      Type.getTypePtr()->isPointerOrObjCObjectPointerType() &&
       NamingStyles[SK_GlobalPointer])
     return SK_GlobalPointer;
 
@@ -1545,7 +1549,8 @@ StyleKind IdentifierNamingCheck::findStyleKindForVar(
   if (Var->isStaticLocal() && NamingStyles[SK_StaticVariable])
     return SK_StaticVariable;
 
-  if (Var->isLocalVarDecl() && Type.getTypePtr()->isAnyPointerType() &&
+  if (Var->isLocalVarDecl() &&
+      Type.getTypePtr()->isPointerOrObjCObjectPointerType() &&
       NamingStyles[SK_LocalPointer])
     return SK_LocalPointer;
 
diff --git a/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp b/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp
index c5eaff88e0ed3b..dc6b459e05bdfb 100644
--- a/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp
@@ -472,7 +472,8 @@ static bool areTypesCompatible(QualType ArgType, QualType ParamType,
 
   // Unless argument and param are both multilevel pointers, the types are not
   // convertible.
-  if (!(ParamType->isAnyPointerType() && ArgType->isAnyPointerType()))
+  if (!(ParamType->isPointerOrObjCObjectPointerType() &&
+        ArgType->isPointerOrObjCObjectPointerType()))
     return false;
 
   return arePointerTypesCompatible(ArgType, ParamType, IsParamContinuouslyConst,
diff --git a/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp b/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
index 0fea7946a59f95..eec39d97a94a72 100644
--- a/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
+++ b/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
@@ -84,7 +84,7 @@ inline bool isPointerOrPointerToMember(const Type *T) {
 }
 
 std::optional<QualType> getPointeeOrArrayElementQualType(QualType T) {
-  if (T->isAnyPointerType() || T->isMemberPointerType())
+  if (T->isPointerOrObjCObjectPointerType() || T->isMemberPointerType())
     return T->getPointeeType();
 
   if (T->isArrayType())
diff --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp b/clang-tools-extra/clangd/SemanticHighlighting.cpp
index e6d16af2495fec..238b28eb976960 100644
--- a/clang-tools-extra/clangd/SemanticHighlighting.cpp
+++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp
@@ -296,7 +296,7 @@ bool isDefaultLibrary(const Decl *D) {
 bool isDefaultLibrary(const Type *T) {
   if (!T)
     return false;
-  const Type *Underlying = T->getPointeeOrArrayElementType();
+  const Type *Underlying = T->getPointerOrObjCPointerOrArrayElementType();
   if (Underlying->isBuiltinType())
     return true;
   if (auto *TD = dyn_cast<TemplateTypeParmType>(Underlying))
diff --git a/clang/include/clang/AST/CanonicalType.h b/clang/include/clang/AST/CanonicalType.h
index 6699284d215bd0..8c0b9aa39df941 100644
--- a/clang/include/clang/AST/CanonicalType.h
+++ b/clang/include/clang/AST/CanonicalType.h
@@ -286,7 +286,7 @@ class CanProxyBase {
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isDerivedType)
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isScalarType)
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isAggregateType)
-  LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isAnyPointerType)
+  LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isPointerOrObjCObjectPointerType)
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVoidPointerType)
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isFunctionPointerType)
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isMemberFunctionPointerType)
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 78677df578c4bc..80602a85fbcff4 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -2536,7 +2536,8 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
   bool isPointerType() const;
   bool isPointerOrReferenceType() const;
   bool isSignableType() const;
-  bool isAnyPointerType() const;   // Any C pointer or ObjC object pointer
+  bool isPointerOrObjCObjectPointerType()
+      const; // Any C pointer or ObjC object pointer
   bool isCountAttributedType() const;
   bool isBlockPointerType() const;
   bool isVoidPointerType() const;
@@ -2862,15 +2863,29 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
   /// This should never be used when type qualifiers are meaningful.
   const Type *getArrayElementTypeNoTypeQual() const;
 
-  /// If this is a pointer type, return the pointee type.
+  /// If this is a C or ObjC pointer type, return the pointee type. Notably,
+  /// this does not handle things like member pointers or block pointers.
+  ///
   /// If this is an array type, return the array element type.
+  ///
   /// This should never be used when type qualifiers are meaningful.
-  const Type *getPointeeOrArrayElementType() const;
+  const Type *getPointerOrObjCPointerOrArrayElementType() const;
 
-  /// If this is a pointer, ObjC object pointer, or block
-  /// pointer, this returns the respective pointee.
+  /// Return the 'pointee type' for any of the following kinds of types,
+  /// and an empty QualType otherwise.
+  ///
+  ///   - PointerType
+  ///   - ObjCObjectPointerType
+  ///   - BlockPointerType
+  ///   - ReferenceType
+  ///   - MemberPointerType
+  ///   - DecayedType
   QualType getPointeeType() const;
 
+  /// Return getElementType() if this is an array type, and getPointeeType()
+  /// otherwise.
+  QualType getPointerLikeOrArrayElementType() const;
+
   /// Return the specified type with any "sugar" removed from the type,
   /// removing any typedefs, typeofs, etc., as well as any qualifiers.
   const Type *getUnqualifiedDesugaredType() const;
@@ -8196,7 +8211,7 @@ inline bool Type::isPointerOrReferenceType() const {
   return isPointerType() || isReferenceType();
 }
 
-inline bool Type::isAnyPointerType() const {
+inline bool Type::isPointerOrObjCObjectPointerType() const {
   return isPointerType() || isObjCObjectPointerType();
 }
 
@@ -8656,8 +8671,8 @@ inline bool Type::isUndeducedType() const {
 inline bool Type::isOverloadableType() const {
   if (!isDependentType())
     return isRecordType() || isEnumeralType();
-  return !isArrayType() && !isFunctionType() && !isAnyPointerType() &&
-         !isMemberPointerType();
+  return !isArrayType() && !isFunctionType() &&
+         !isPointerOrObjCObjectPointerType() && !isMemberPointerType();
 }
 
 /// Determines whether this type is written as a typedef-name.
@@ -8690,9 +8705,9 @@ inline const Type *Type::getBaseElementTypeUnsafe() const {
   return type;
 }
 
-inline const Type *Type::getPointeeOrArrayElementType() const {
+inline const Type *Type::getPointerOrObjCPointerOrArrayElementType() const {
   const Type *type = this;
-  if (type->isAnyPointerType())
+  if (type->isPointerOrObjCObjectPointerType())
     return type->getPointeeType().getTypePtr();
   else if (type->isArrayType())
     return type->getBaseElementTypeUnsafe();
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 239fcba4e5e057..d9f505c5645f06 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -4156,7 +4156,7 @@ AST_MATCHER_P(QualType, asString, std::string, Name) {
 AST_MATCHER_P(
     QualType, pointsTo, internal::Matcher<QualType>,
     InnerMatcher) {
-  return (!Node.isNull() && Node->isAnyPointerType() &&
+  return (!Node.isNull() && Node->isPointerOrObjCObjectPointerType() &&
           InnerMatcher.matches(Node->getPointeeType(), Finder, Builder));
 }
 
@@ -6605,7 +6605,7 @@ AST_MATCHER(QualType, isAnyCharacter) {
 /// varDecl(hasType(isAnyPointer()))
 ///   matches "int *i" and "Foo *f", but not "int j".
 AST_MATCHER(QualType, isAnyPointer) {
-  return Node->isAnyPointerType();
+  return Node->isPointerOrObjCObjectPointerType();
 }
 
 /// Matches QualType nodes that are const-qualified, i.e., that
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index f88bf70d72398c..15e01bdbcd6ed5 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -787,7 +787,7 @@ class SymbolicRegion : public SubRegion {
     // Because pointer arithmetic is represented by ElementRegion layers,
     // the base symbol here should not contain any arithmetic.
     assert(isa_and_nonnull<SymbolData>(s));
-    assert(s->getType()->isAnyPointerType() ||
+    assert(s->getType()->isPointerOrObjCObjectPointerType() ||
            s->getType()->isReferenceType() ||
            s->getType()->isBlockPointerType());
     assert(isa<UnknownSpaceRegion>(sreg) || isa<HeapSpaceRegion>(sreg) ||
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h
index fcc9c02999b3b0..d175b6d2886095 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h
@@ -264,7 +264,8 @@ class SMTConv {
                                           uint64_t FromBitWidth) {
     if ((FromTy->isIntegralOrEnumerationType() &&
          ToTy->isIntegralOrEnumerationType()) ||
-        (FromTy->isAnyPointerType() ^ ToTy->isAnyPointerType()) ||
+        (FromTy->isPointerOrObjCObjectPointerType() ^
+         ToTy->isPointerOrObjCObjectPointerType()) ||
         (FromTy->isBlockPointerType() ^ ToTy->isBlockPointerType()) ||
         (FromTy->isReferenceType() ^ ToTy->isReferenceType())) {
 
@@ -365,7 +366,8 @@ class SMTConv {
 
       // If the two operands are pointers and the operation is a subtraction,
       // the result is of type ptrdiff_t, which is signed
-      if (LTy->isAnyPointerType() && RTy->isAnyPointerType() && Op == BO_Sub) {
+      if (LTy->isPointerOrObjCObjectPointerType() &&
+          RTy->isPointerOrObjCObjectPointerType() && Op == BO_Sub) {
         *RetTy = Ctx.getPointerDiffType();
       }
     }
@@ -509,8 +511,9 @@ class SMTConv {
                             Solver->mkFloat(Zero));
     }
 
-    if (Ty->isIntegralOrEnumerationType() || Ty->isAnyPointerType() ||
-        Ty->isBlockPointerType() || Ty->isReferenceType()) {
+    if (Ty->isIntegralOrEnumerationType() ||
+        Ty->isPointerOrObjCObjectPointerType() || Ty->isBlockPointerType() ||
+        Ty->isReferenceType()) {
 
       // Skip explicit comparison for boolean types
       bool isSigned = Ty->isSignedIntegerOrEnumerationType();
@@ -613,7 +616,8 @@ class SMTConv {
       return;
     }
 
-    if ((LTy->isAnyPointerType() || RTy->isAnyPointerType()) ||
+    if ((LTy->isPointerOrObjCObjectPointerType() ||
+         RTy->isPointerOrObjCObjectPointerType()) ||
         (LTy->isBlockPointerType() || RTy->isBlockPointerType()) ||
         (LTy->isReferenceType() || RTy->isReferenceType())) {
       // TODO: Refactor to Sema::FindCompositePointerType(), and
@@ -624,7 +628,8 @@ class SMTConv {
 
       // Cast the non-pointer type to the pointer type.
       // TODO: Be more strict about this.
-      if ((LTy->isAnyPointerType() ^ RTy->isAnyPointerType()) ||
+      if ((LTy->isPointerOrObjCObjectPointerType() ^
+           RTy->isPointerOrObjCObjectPointerType()) ||
           (LTy->isBlockPointerType() ^ RTy->isBlockPointerType()) ||
           (LTy->isReferenceType() ^ RTy->isReferenceType())) {
         if (LTy->isNullPtrType() || LTy->isBlockPointerType() ||
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 54430d426a82a8..93e6b08644807a 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -356,8 +356,7 @@ class SValBuilder {
   /// space.
   /// \param type pointer type.
   loc::ConcreteInt makeNullWithType(QualType type) {
-    // We cannot use the `isAnyPointerType()`.
-    assert((type->isPointerType() || type->isObjCObjectPointerType() ||
+    assert((type->isPointerOrObjCObjectPointerType() ||
             type->isBlockPointerType() || type->isNullPtrType() ||
             type->isReferenceType()) &&
            "makeNullWithType must use pointer type");
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index aeb57b28077c61..c6c6951ba32198 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -260,7 +260,7 @@ class Loc : public DefinedSVal {
   void dumpToStream(raw_ostream &Out) const;
 
   static bool isLocType(QualType T) {
-    return T->isAnyPointerType() || T->isBlockPointerType() ||
+    return T->isPointerOrObjCObjectPointerType() || T->isBlockPointerType() ||
            T->isReferenceType() || T->isNullPtrType();
   }
 
diff --git a/clang/lib/ARCMigrate/ObjCMT.cpp b/clang/lib/ARCMigrate/ObjCMT.cpp
index c1bc7c762088f2..47c130379d5126 100644
--- a/clang/lib/ARCMigrate/ObjCMT.cpp
+++ b/clang/lib/ARCMigrate/ObjCMT.cpp
@@ -1042,7 +1042,7 @@ void ObjCMigrateASTConsumer::migrateMethodInstanceType(ASTContext &Ctx,
 }
 
 static bool TypeIsInnerPointer(QualType T) {
-  if (!T->isAnyPointerType())
+  if (!T->isPointerOrObjCObjectPointerType())
     return false;
   if (T->isObjCObjectPointerType() || T->isObjCBuiltinType() ||
       T->isBlockPointerType() || T->isFunctionPointerType() ||
@@ -1366,7 +1366,7 @@ static bool IsVoidStarType(QualType Ty) {
 /// CF object types or of the "void *" variety. It returns true if we don't care about the type
 /// such as a non-pointer or pointers which have no ownership issues (such as "int *").
 static bool AuditedType (QualType AT) {
-  if (!AT->isAnyPointerType() && !AT->isBlockPointerType())
+  if (!AT->isPointerOrObjCObjectPointerType() && !AT->isBlockPointerType())
     return true;
   // FIXME. There isn't much we can say about CF pointer type; or is there?
   if (ento::coreFoundation::isCFObjectRef(AT) ||
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index be1dd29d462788..9d4743bd0a0aa7 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -2980,9 +2980,9 @@ bool ASTContext::isSentinelNullExpr(const Expr *E) {
   // nullptr_t is always treated as null.
   if (E->getType()->isNullPtrType()) return true;
 
-  if (E->getType()->isAnyPointerType() &&
-      E->IgnoreParenCasts()->isNullPointerConstant(*this,
-                                                Expr::NPC_ValueDependentIsNull))
+  if (E->getType()->isPointerOrObjCObjectPointerType() &&
+      E->IgnoreParenCasts()->isNullPointerConstant(
+          *this, Expr::NPC_ValueDependentIsNull))
     return true;
 
   // Unfortunately, __null has type 'int'.
@@ -3518,7 +3518,7 @@ QualType ASTContext::getObjCGCQualType(QualType T,
 
   if (const auto *ptr = T->getAs<PointerType>()) {
     QualType Pointee = ptr->getPointeeType();
-    if (Pointee->isAnyPointerType()) {...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Jan 14, 2025

@llvm/pr-subscribers-clangd

Author: None (Sirraide)

Changes

Changes

tl;dr: The names are inaccurate and continue to cause confusion.

This pr currently makes the following changes:

  • Rename isAnyPointerType() to isPointerOrObjCObjectPointerType().
  • Rename getPointeeOrArrayElementType() to getPointerOrObjCPointerOrArrayElementType().
  • Introduce getPointerLikeOrArrayElementType() which actually is a superset of the functionality that getPointeeType() provides (I don’t think we can call this getPointeeOrArrayElementType() because that would effectively just mean that the behaviour of this function changes all of a sudden, which may cause even more confusion for people that are not aware that we’re making this change). A function like this that actually supports member pointers is needed for #121525.
  • Elaborate on what types getPointeeType() actually supports in a comment. getPointeeType() actually ends up being fine imo because it does actually handle anything that could reasonably be conceived of as having a ‘pointee’.

Open Questions

  • The names for the first two are rather verbose; I’m open to suggestions as to better names for these functions since that was the best that I managed to come up with...
  • I’ve already discussed this somewhat with @AaronBallman and @cor3ntin, and I think that we probably don’t want to introduce any new helpers like isAnyPointerType() that claim to handle ‘all pointer types’, mainly because a lot of the calls to isAnyPointerType() are currently of the form if (Ty-&gt;isAnyPointerType() || Ty-&gt;someOtherPredicate()), where someOtherPredicate() may check for ReferenceType, MemberPointerType, etc. It seems that nearly every call site is different in what ‘pointer-like types’ it cares about, so a general helper is unlikely to be of any use pretty much ever.
  • I’m planning to do a general clean-up pass and look at all call sites of what used to be isAnyPointerType() to see if there is anything weird—so far, two instances of rather obvious dead code have surfaced as a result of the renaming (see below)—but my plan is to do that as a follow-up pr.
  • Additionally, there are a few places we could probably clean up by either introducing or using newer helper functions, e.g. we now have isPointerOrReferenceType(), so it would be possible to replace every instance of Ty-&gt;isPointerType() || Ty-&gt;isReferenceType() with Ty-&gt;isPointerOrReferenceType() and additionally introduce new helpers for common combinations of these predicates. At the same time, that sounds a bit like a reformatting pass with extra steps, and we usually tend to eschew these because they interact poorly with git blame from what I recall, so I’m not sure if that’s a good idea.
  • @AaronBallman There is an AST matcher with the name isAnyPointer(), which uses isAnyPointerType(). I’m not sure what exactly we want to do with that one.

Background

In the Type class, we currently have the following function:

bool isAnyPointerType() const;

which, one might reasonably assume, ought to return true if this is ‘any pointer type’, whatever that means. It turns out that what that actually ends up meaning is:

// Any C pointer or ObjC object pointer

That is, it does not include

  • Member pointers,
  • Block pointers,
  • nullptr_t.

Of course, one might argue that e.g. member pointers aren’t actually pointers but offsets, which is true, but we still call them MemberPointerTypes, so by name alone, they are still ‘a kind of pointer’.

Searching for occurrences yields several cases where someone has fallen for this and misunderstood what ‘any pointer type’ was actually supposed to mean. I’ve renamed it to isPointerOrObjCObjectPointerType(), so these misuses end up being rather apparent. There seem to be at least two places that are currently in the code base where someone got confused about this:

  • Here, we end up checking if Pointee is a pointer or Objective-C pointer... or Objective-C pointer.

    return Pointee->isPointerOrObjCObjectPointerType() ||
    Pointee->isObjCObjectPointerType() || Pointee->isMemberPointerType();

  • Here, it would seem that both of these if statements together end up being functionally equivalent to
    if (!Ty-&gt;isObjectPointerType()) return false;

    static bool TypeIsInnerPointer(QualType T) {
    if (!T->isPointerOrObjCObjectPointerType())
    return false;
    if (T->isObjCObjectPointerType() || T->isObjCBuiltinType() ||
    T->isBlockPointerType() || T->isFunctionPointerType() ||
    ento::coreFoundation::isCFObjectRef(T))
    return false;

Additionally, I can recall several instances of me either reading or writing code that uses isAnyPointerType() and then getting confused why something wasn’t working properly, and I’ve heard similar sentiment from others.

Another possible instance of that might be getPointeeOrArrayElementType(). You’d think based on its name that it’s an extension of getPointeeType() that also handles arrays, but that’s wrong: the former calls isAnyPointerType() before delegating to getPointeeType(), which means that unlike getPointeeType(), this function does not handle block or member pointers at all. Confusion about this fact in particular just a few days ago is what prompted me to address this issue.


Patch is 96.82 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/122938.diff

69 Files Affected:

  • (modified) clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp (+1-1)
  • (modified) clang-tools-extra/clang-tidy/bugprone/SuspiciousMemoryComparisonCheck.cpp (+2-1)
  • (modified) clang-tools-extra/clang-tidy/cppcoreguidelines/InitVariablesCheck.cpp (+1-1)
  • (modified) clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp (+1-1)
  • (modified) clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp (+11-6)
  • (modified) clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp (+2-1)
  • (modified) clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp (+1-1)
  • (modified) clang-tools-extra/clangd/SemanticHighlighting.cpp (+1-1)
  • (modified) clang/include/clang/AST/CanonicalType.h (+1-1)
  • (modified) clang/include/clang/AST/Type.h (+25-10)
  • (modified) clang/include/clang/ASTMatchers/ASTMatchers.h (+2-2)
  • (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h (+1-1)
  • (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h (+11-6)
  • (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h (+1-2)
  • (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h (+1-1)
  • (modified) clang/lib/ARCMigrate/ObjCMT.cpp (+2-2)
  • (modified) clang/lib/AST/ASTContext.cpp (+5-5)
  • (modified) clang/lib/AST/ASTImporter.cpp (+1-1)
  • (modified) clang/lib/AST/Expr.cpp (+2-2)
  • (modified) clang/lib/AST/ExprCXX.cpp (+1-1)
  • (modified) clang/lib/AST/ExprConstant.cpp (+1-1)
  • (modified) clang/lib/AST/MicrosoftMangle.cpp (+3-2)
  • (modified) clang/lib/AST/Type.cpp (+6)
  • (modified) clang/lib/Analysis/ThreadSafetyCommon.cpp (+1-1)
  • (modified) clang/lib/Analysis/UninitializedValues.cpp (+2-1)
  • (modified) clang/lib/CodeGen/CGCall.cpp (+2-1)
  • (modified) clang/lib/CodeGen/CGExpr.cpp (+2-1)
  • (modified) clang/lib/CodeGen/CGHLSLRuntime.cpp (+1-1)
  • (modified) clang/lib/CodeGen/CGOpenMPRuntime.cpp (+21-16)
  • (modified) clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp (+4-2)
  • (modified) clang/lib/CodeGen/CGStmtOpenMP.cpp (+6-4)
  • (modified) clang/lib/CodeGen/CodeGenTypes.cpp (+2-1)
  • (modified) clang/lib/CodeGen/Targets/SystemZ.cpp (+1-1)
  • (modified) clang/lib/ExtractAPI/DeclarationFragments.cpp (+1-1)
  • (modified) clang/lib/Frontend/ASTUnit.cpp (+3-3)
  • (modified) clang/lib/Sema/SemaAPINotes.cpp (+2-2)
  • (modified) clang/lib/Sema/SemaARM.cpp (+12-10)
  • (modified) clang/lib/Sema/SemaCast.cpp (+22-15)
  • (modified) clang/lib/Sema/SemaChecking.cpp (+7-5)
  • (modified) clang/lib/Sema/SemaCodeComplete.cpp (+4-3)
  • (modified) clang/lib/Sema/SemaDecl.cpp (+7-6)
  • (modified) clang/lib/Sema/SemaDeclAttr.cpp (+7-6)
  • (modified) clang/lib/Sema/SemaExpr.cpp (+34-26)
  • (modified) clang/lib/Sema/SemaExprCXX.cpp (+5-5)
  • (modified) clang/lib/Sema/SemaInit.cpp (+4-2)
  • (modified) clang/lib/Sema/SemaLookup.cpp (+2-1)
  • (modified) clang/lib/Sema/SemaOpenACC.cpp (+1-1)
  • (modified) clang/lib/Sema/SemaOpenCL.cpp (+3-1)
  • (modified) clang/lib/Sema/SemaOpenMP.cpp (+19-15)
  • (modified) clang/lib/Sema/SemaOverload.cpp (+8-7)
  • (modified) clang/lib/Sema/SemaRISCV.cpp (+2-1)
  • (modified) clang/lib/Sema/SemaSYCL.cpp (+2-2)
  • (modified) clang/lib/Sema/SemaTemplateDeduction.cpp (+1-1)
  • (modified) clang/lib/Sema/SemaType.cpp (+4-4)
  • (modified) clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp (+1-1)
  • (modified) clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp (+2-1)
  • (modified) clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp (+1-1)
  • (modified) clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp (+1-1)
  • (modified) clang/lib/StaticAnalyzer/Checkers/TrustNonnullChecker.cpp (+1-1)
  • (modified) clang/lib/StaticAnalyzer/Checkers/TrustReturnsNonnullChecker.cpp (+1-1)
  • (modified) clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h (+1-1)
  • (modified) clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp (+2-2)
  • (modified) clang/lib/StaticAnalyzer/Core/CallEvent.cpp (+2-2)
  • (modified) clang/lib/StaticAnalyzer/Core/DynamicType.cpp (+3-2)
  • (modified) clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp (+1-1)
  • (modified) clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp (+1-1)
  • (modified) clang/lib/Tooling/Transformer/SourceCodeBuilders.cpp (+1-1)
  • (modified) clang/lib/Tooling/Transformer/Stencil.cpp (+2-2)
  • (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp (+1-1)
diff --git a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
index b7f0c08b2a7d4b..f4c5523184630f 100644
--- a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
@@ -93,7 +93,7 @@ static bool isVarThatIsPossiblyChanged(const Decl *Func, const Stmt *LoopStmt,
       if (T.isVolatileQualified())
         return true;
 
-      if (!T->isAnyPointerType() && !T->isReferenceType())
+      if (!T->isPointerOrObjCObjectPointerType() && !T->isReferenceType())
         break;
 
       T = T->getPointeeType();
diff --git a/clang-tools-extra/clang-tidy/bugprone/SuspiciousMemoryComparisonCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SuspiciousMemoryComparisonCheck.cpp
index 84957e0b8190c0..7779b6725673cb 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SuspiciousMemoryComparisonCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SuspiciousMemoryComparisonCheck.cpp
@@ -45,7 +45,8 @@ void SuspiciousMemoryComparisonCheck::check(
   for (unsigned int ArgIndex = 0; ArgIndex < 2; ++ArgIndex) {
     const Expr *ArgExpr = CE->getArg(ArgIndex);
     QualType ArgType = ArgExpr->IgnoreImplicit()->getType();
-    const Type *PointeeType = ArgType->getPointeeOrArrayElementType();
+    const Type *PointeeType =
+        ArgType->getPointerOrObjCPointerOrArrayElementType();
     assert(PointeeType != nullptr && "PointeeType should always be available.");
     QualType PointeeQualifiedType(PointeeType, 0);
 
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/InitVariablesCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/InitVariablesCheck.cpp
index 3eef2fd12cc8e5..be1673d5c08c98 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/InitVariablesCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/InitVariablesCheck.cpp
@@ -95,7 +95,7 @@ void InitVariablesCheck::check(const MatchFinder::MatchResult &Result) {
   else if (TypePtr->isFloatingType()) {
     InitializationString = " = NAN";
     AddMathInclude = true;
-  } else if (TypePtr->isAnyPointerType()) {
+  } else if (TypePtr->isPointerOrObjCObjectPointerType()) {
     if (getLangOpts().CPlusPlus11)
       InitializationString = " = nullptr";
     else
diff --git a/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp b/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp
index 5abe4f77d65984..36628d0fd84be5 100644
--- a/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp
+++ b/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp
@@ -229,7 +229,7 @@ static bool isTypedefTypeMatching(const TypedefType *const Typedef,
 /// \returns type of the argument
 static const Type *argumentType(const CallExpr *const CE, const size_t Idx) {
   const QualType QT = CE->getArg(Idx)->IgnoreImpCasts()->getType();
-  return QT.getTypePtr()->getPointeeOrArrayElementType();
+  return QT.getTypePtr()->getPointerOrObjCPointerOrArrayElementType();
 }
 
 void TypeMismatchCheck::registerMatchers(MatchFinder *Finder) {
diff --git a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
index 3f63eec2c51a8c..dc740377c4db14 100644
--- a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
@@ -1218,7 +1218,7 @@ StyleKind IdentifierNamingCheck::findStyleKind(
       return SK_ConstexprVariable;
 
     if (!Type.isNull() && Type.isConstQualified()) {
-      if (Type.getTypePtr()->isAnyPointerType() &&
+      if (Type.getTypePtr()->isPointerOrObjCObjectPointerType() &&
           NamingStyles[SK_ConstantPointerParameter])
         return SK_ConstantPointerParameter;
 
@@ -1232,7 +1232,8 @@ StyleKind IdentifierNamingCheck::findStyleKind(
     if (Decl->isParameterPack() && NamingStyles[SK_ParameterPack])
       return SK_ParameterPack;
 
-    if (!Type.isNull() && Type.getTypePtr()->isAnyPointerType() &&
+    if (!Type.isNull() &&
+        Type.getTypePtr()->isPointerOrObjCObjectPointerType() &&
         NamingStyles[SK_PointerParameter])
       return SK_PointerParameter;
 
@@ -1508,7 +1509,8 @@ StyleKind IdentifierNamingCheck::findStyleKindForVar(
     if (Var->isStaticDataMember() && NamingStyles[SK_ClassConstant])
       return SK_ClassConstant;
 
-    if (Var->isFileVarDecl() && Type.getTypePtr()->isAnyPointerType() &&
+    if (Var->isFileVarDecl() &&
+        Type.getTypePtr()->isPointerOrObjCObjectPointerType() &&
         NamingStyles[SK_GlobalConstantPointer])
       return SK_GlobalConstantPointer;
 
@@ -1518,7 +1520,8 @@ StyleKind IdentifierNamingCheck::findStyleKindForVar(
     if (Var->isStaticLocal() && NamingStyles[SK_StaticConstant])
       return SK_StaticConstant;
 
-    if (Var->isLocalVarDecl() && Type.getTypePtr()->isAnyPointerType() &&
+    if (Var->isLocalVarDecl() &&
+        Type.getTypePtr()->isPointerOrObjCObjectPointerType() &&
         NamingStyles[SK_LocalConstantPointer])
       return SK_LocalConstantPointer;
 
@@ -1535,7 +1538,8 @@ StyleKind IdentifierNamingCheck::findStyleKindForVar(
   if (Var->isStaticDataMember() && NamingStyles[SK_ClassMember])
     return SK_ClassMember;
 
-  if (Var->isFileVarDecl() && Type.getTypePtr()->isAnyPointerType() &&
+  if (Var->isFileVarDecl() &&
+      Type.getTypePtr()->isPointerOrObjCObjectPointerType() &&
       NamingStyles[SK_GlobalPointer])
     return SK_GlobalPointer;
 
@@ -1545,7 +1549,8 @@ StyleKind IdentifierNamingCheck::findStyleKindForVar(
   if (Var->isStaticLocal() && NamingStyles[SK_StaticVariable])
     return SK_StaticVariable;
 
-  if (Var->isLocalVarDecl() && Type.getTypePtr()->isAnyPointerType() &&
+  if (Var->isLocalVarDecl() &&
+      Type.getTypePtr()->isPointerOrObjCObjectPointerType() &&
       NamingStyles[SK_LocalPointer])
     return SK_LocalPointer;
 
diff --git a/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp b/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp
index c5eaff88e0ed3b..dc6b459e05bdfb 100644
--- a/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp
@@ -472,7 +472,8 @@ static bool areTypesCompatible(QualType ArgType, QualType ParamType,
 
   // Unless argument and param are both multilevel pointers, the types are not
   // convertible.
-  if (!(ParamType->isAnyPointerType() && ArgType->isAnyPointerType()))
+  if (!(ParamType->isPointerOrObjCObjectPointerType() &&
+        ArgType->isPointerOrObjCObjectPointerType()))
     return false;
 
   return arePointerTypesCompatible(ArgType, ParamType, IsParamContinuouslyConst,
diff --git a/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp b/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
index 0fea7946a59f95..eec39d97a94a72 100644
--- a/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
+++ b/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
@@ -84,7 +84,7 @@ inline bool isPointerOrPointerToMember(const Type *T) {
 }
 
 std::optional<QualType> getPointeeOrArrayElementQualType(QualType T) {
-  if (T->isAnyPointerType() || T->isMemberPointerType())
+  if (T->isPointerOrObjCObjectPointerType() || T->isMemberPointerType())
     return T->getPointeeType();
 
   if (T->isArrayType())
diff --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp b/clang-tools-extra/clangd/SemanticHighlighting.cpp
index e6d16af2495fec..238b28eb976960 100644
--- a/clang-tools-extra/clangd/SemanticHighlighting.cpp
+++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp
@@ -296,7 +296,7 @@ bool isDefaultLibrary(const Decl *D) {
 bool isDefaultLibrary(const Type *T) {
   if (!T)
     return false;
-  const Type *Underlying = T->getPointeeOrArrayElementType();
+  const Type *Underlying = T->getPointerOrObjCPointerOrArrayElementType();
   if (Underlying->isBuiltinType())
     return true;
   if (auto *TD = dyn_cast<TemplateTypeParmType>(Underlying))
diff --git a/clang/include/clang/AST/CanonicalType.h b/clang/include/clang/AST/CanonicalType.h
index 6699284d215bd0..8c0b9aa39df941 100644
--- a/clang/include/clang/AST/CanonicalType.h
+++ b/clang/include/clang/AST/CanonicalType.h
@@ -286,7 +286,7 @@ class CanProxyBase {
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isDerivedType)
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isScalarType)
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isAggregateType)
-  LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isAnyPointerType)
+  LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isPointerOrObjCObjectPointerType)
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVoidPointerType)
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isFunctionPointerType)
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isMemberFunctionPointerType)
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 78677df578c4bc..80602a85fbcff4 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -2536,7 +2536,8 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
   bool isPointerType() const;
   bool isPointerOrReferenceType() const;
   bool isSignableType() const;
-  bool isAnyPointerType() const;   // Any C pointer or ObjC object pointer
+  bool isPointerOrObjCObjectPointerType()
+      const; // Any C pointer or ObjC object pointer
   bool isCountAttributedType() const;
   bool isBlockPointerType() const;
   bool isVoidPointerType() const;
@@ -2862,15 +2863,29 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
   /// This should never be used when type qualifiers are meaningful.
   const Type *getArrayElementTypeNoTypeQual() const;
 
-  /// If this is a pointer type, return the pointee type.
+  /// If this is a C or ObjC pointer type, return the pointee type. Notably,
+  /// this does not handle things like member pointers or block pointers.
+  ///
   /// If this is an array type, return the array element type.
+  ///
   /// This should never be used when type qualifiers are meaningful.
-  const Type *getPointeeOrArrayElementType() const;
+  const Type *getPointerOrObjCPointerOrArrayElementType() const;
 
-  /// If this is a pointer, ObjC object pointer, or block
-  /// pointer, this returns the respective pointee.
+  /// Return the 'pointee type' for any of the following kinds of types,
+  /// and an empty QualType otherwise.
+  ///
+  ///   - PointerType
+  ///   - ObjCObjectPointerType
+  ///   - BlockPointerType
+  ///   - ReferenceType
+  ///   - MemberPointerType
+  ///   - DecayedType
   QualType getPointeeType() const;
 
+  /// Return getElementType() if this is an array type, and getPointeeType()
+  /// otherwise.
+  QualType getPointerLikeOrArrayElementType() const;
+
   /// Return the specified type with any "sugar" removed from the type,
   /// removing any typedefs, typeofs, etc., as well as any qualifiers.
   const Type *getUnqualifiedDesugaredType() const;
@@ -8196,7 +8211,7 @@ inline bool Type::isPointerOrReferenceType() const {
   return isPointerType() || isReferenceType();
 }
 
-inline bool Type::isAnyPointerType() const {
+inline bool Type::isPointerOrObjCObjectPointerType() const {
   return isPointerType() || isObjCObjectPointerType();
 }
 
@@ -8656,8 +8671,8 @@ inline bool Type::isUndeducedType() const {
 inline bool Type::isOverloadableType() const {
   if (!isDependentType())
     return isRecordType() || isEnumeralType();
-  return !isArrayType() && !isFunctionType() && !isAnyPointerType() &&
-         !isMemberPointerType();
+  return !isArrayType() && !isFunctionType() &&
+         !isPointerOrObjCObjectPointerType() && !isMemberPointerType();
 }
 
 /// Determines whether this type is written as a typedef-name.
@@ -8690,9 +8705,9 @@ inline const Type *Type::getBaseElementTypeUnsafe() const {
   return type;
 }
 
-inline const Type *Type::getPointeeOrArrayElementType() const {
+inline const Type *Type::getPointerOrObjCPointerOrArrayElementType() const {
   const Type *type = this;
-  if (type->isAnyPointerType())
+  if (type->isPointerOrObjCObjectPointerType())
     return type->getPointeeType().getTypePtr();
   else if (type->isArrayType())
     return type->getBaseElementTypeUnsafe();
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 239fcba4e5e057..d9f505c5645f06 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -4156,7 +4156,7 @@ AST_MATCHER_P(QualType, asString, std::string, Name) {
 AST_MATCHER_P(
     QualType, pointsTo, internal::Matcher<QualType>,
     InnerMatcher) {
-  return (!Node.isNull() && Node->isAnyPointerType() &&
+  return (!Node.isNull() && Node->isPointerOrObjCObjectPointerType() &&
           InnerMatcher.matches(Node->getPointeeType(), Finder, Builder));
 }
 
@@ -6605,7 +6605,7 @@ AST_MATCHER(QualType, isAnyCharacter) {
 /// varDecl(hasType(isAnyPointer()))
 ///   matches "int *i" and "Foo *f", but not "int j".
 AST_MATCHER(QualType, isAnyPointer) {
-  return Node->isAnyPointerType();
+  return Node->isPointerOrObjCObjectPointerType();
 }
 
 /// Matches QualType nodes that are const-qualified, i.e., that
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index f88bf70d72398c..15e01bdbcd6ed5 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -787,7 +787,7 @@ class SymbolicRegion : public SubRegion {
     // Because pointer arithmetic is represented by ElementRegion layers,
     // the base symbol here should not contain any arithmetic.
     assert(isa_and_nonnull<SymbolData>(s));
-    assert(s->getType()->isAnyPointerType() ||
+    assert(s->getType()->isPointerOrObjCObjectPointerType() ||
            s->getType()->isReferenceType() ||
            s->getType()->isBlockPointerType());
     assert(isa<UnknownSpaceRegion>(sreg) || isa<HeapSpaceRegion>(sreg) ||
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h
index fcc9c02999b3b0..d175b6d2886095 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h
@@ -264,7 +264,8 @@ class SMTConv {
                                           uint64_t FromBitWidth) {
     if ((FromTy->isIntegralOrEnumerationType() &&
          ToTy->isIntegralOrEnumerationType()) ||
-        (FromTy->isAnyPointerType() ^ ToTy->isAnyPointerType()) ||
+        (FromTy->isPointerOrObjCObjectPointerType() ^
+         ToTy->isPointerOrObjCObjectPointerType()) ||
         (FromTy->isBlockPointerType() ^ ToTy->isBlockPointerType()) ||
         (FromTy->isReferenceType() ^ ToTy->isReferenceType())) {
 
@@ -365,7 +366,8 @@ class SMTConv {
 
       // If the two operands are pointers and the operation is a subtraction,
       // the result is of type ptrdiff_t, which is signed
-      if (LTy->isAnyPointerType() && RTy->isAnyPointerType() && Op == BO_Sub) {
+      if (LTy->isPointerOrObjCObjectPointerType() &&
+          RTy->isPointerOrObjCObjectPointerType() && Op == BO_Sub) {
         *RetTy = Ctx.getPointerDiffType();
       }
     }
@@ -509,8 +511,9 @@ class SMTConv {
                             Solver->mkFloat(Zero));
     }
 
-    if (Ty->isIntegralOrEnumerationType() || Ty->isAnyPointerType() ||
-        Ty->isBlockPointerType() || Ty->isReferenceType()) {
+    if (Ty->isIntegralOrEnumerationType() ||
+        Ty->isPointerOrObjCObjectPointerType() || Ty->isBlockPointerType() ||
+        Ty->isReferenceType()) {
 
       // Skip explicit comparison for boolean types
       bool isSigned = Ty->isSignedIntegerOrEnumerationType();
@@ -613,7 +616,8 @@ class SMTConv {
       return;
     }
 
-    if ((LTy->isAnyPointerType() || RTy->isAnyPointerType()) ||
+    if ((LTy->isPointerOrObjCObjectPointerType() ||
+         RTy->isPointerOrObjCObjectPointerType()) ||
         (LTy->isBlockPointerType() || RTy->isBlockPointerType()) ||
         (LTy->isReferenceType() || RTy->isReferenceType())) {
       // TODO: Refactor to Sema::FindCompositePointerType(), and
@@ -624,7 +628,8 @@ class SMTConv {
 
       // Cast the non-pointer type to the pointer type.
       // TODO: Be more strict about this.
-      if ((LTy->isAnyPointerType() ^ RTy->isAnyPointerType()) ||
+      if ((LTy->isPointerOrObjCObjectPointerType() ^
+           RTy->isPointerOrObjCObjectPointerType()) ||
           (LTy->isBlockPointerType() ^ RTy->isBlockPointerType()) ||
           (LTy->isReferenceType() ^ RTy->isReferenceType())) {
         if (LTy->isNullPtrType() || LTy->isBlockPointerType() ||
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 54430d426a82a8..93e6b08644807a 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -356,8 +356,7 @@ class SValBuilder {
   /// space.
   /// \param type pointer type.
   loc::ConcreteInt makeNullWithType(QualType type) {
-    // We cannot use the `isAnyPointerType()`.
-    assert((type->isPointerType() || type->isObjCObjectPointerType() ||
+    assert((type->isPointerOrObjCObjectPointerType() ||
             type->isBlockPointerType() || type->isNullPtrType() ||
             type->isReferenceType()) &&
            "makeNullWithType must use pointer type");
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index aeb57b28077c61..c6c6951ba32198 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -260,7 +260,7 @@ class Loc : public DefinedSVal {
   void dumpToStream(raw_ostream &Out) const;
 
   static bool isLocType(QualType T) {
-    return T->isAnyPointerType() || T->isBlockPointerType() ||
+    return T->isPointerOrObjCObjectPointerType() || T->isBlockPointerType() ||
            T->isReferenceType() || T->isNullPtrType();
   }
 
diff --git a/clang/lib/ARCMigrate/ObjCMT.cpp b/clang/lib/ARCMigrate/ObjCMT.cpp
index c1bc7c762088f2..47c130379d5126 100644
--- a/clang/lib/ARCMigrate/ObjCMT.cpp
+++ b/clang/lib/ARCMigrate/ObjCMT.cpp
@@ -1042,7 +1042,7 @@ void ObjCMigrateASTConsumer::migrateMethodInstanceType(ASTContext &Ctx,
 }
 
 static bool TypeIsInnerPointer(QualType T) {
-  if (!T->isAnyPointerType())
+  if (!T->isPointerOrObjCObjectPointerType())
     return false;
   if (T->isObjCObjectPointerType() || T->isObjCBuiltinType() ||
       T->isBlockPointerType() || T->isFunctionPointerType() ||
@@ -1366,7 +1366,7 @@ static bool IsVoidStarType(QualType Ty) {
 /// CF object types or of the "void *" variety. It returns true if we don't care about the type
 /// such as a non-pointer or pointers which have no ownership issues (such as "int *").
 static bool AuditedType (QualType AT) {
-  if (!AT->isAnyPointerType() && !AT->isBlockPointerType())
+  if (!AT->isPointerOrObjCObjectPointerType() && !AT->isBlockPointerType())
     return true;
   // FIXME. There isn't much we can say about CF pointer type; or is there?
   if (ento::coreFoundation::isCFObjectRef(AT) ||
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index be1dd29d462788..9d4743bd0a0aa7 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -2980,9 +2980,9 @@ bool ASTContext::isSentinelNullExpr(const Expr *E) {
   // nullptr_t is always treated as null.
   if (E->getType()->isNullPtrType()) return true;
 
-  if (E->getType()->isAnyPointerType() &&
-      E->IgnoreParenCasts()->isNullPointerConstant(*this,
-                                                Expr::NPC_ValueDependentIsNull))
+  if (E->getType()->isPointerOrObjCObjectPointerType() &&
+      E->IgnoreParenCasts()->isNullPointerConstant(
+          *this, Expr::NPC_ValueDependentIsNull))
     return true;
 
   // Unfortunately, __null has type 'int'.
@@ -3518,7 +3518,7 @@ QualType ASTContext::getObjCGCQualType(QualType T,
 
   if (const auto *ptr = T->getAs<PointerType>()) {
     QualType Pointee = ptr->getPointeeType();
-    if (Pointee->isAnyPointerType()) {...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Jan 14, 2025

@llvm/pr-subscribers-backend-risc-v

Author: None (Sirraide)

Changes

Changes

tl;dr: The names are inaccurate and continue to cause confusion.

This pr currently makes the following changes:

  • Rename isAnyPointerType() to isPointerOrObjCObjectPointerType().
  • Rename getPointeeOrArrayElementType() to getPointerOrObjCPointerOrArrayElementType().
  • Introduce getPointerLikeOrArrayElementType() which actually is a superset of the functionality that getPointeeType() provides (I don’t think we can call this getPointeeOrArrayElementType() because that would effectively just mean that the behaviour of this function changes all of a sudden, which may cause even more confusion for people that are not aware that we’re making this change). A function like this that actually supports member pointers is needed for #121525.
  • Elaborate on what types getPointeeType() actually supports in a comment. getPointeeType() actually ends up being fine imo because it does actually handle anything that could reasonably be conceived of as having a ‘pointee’.

Open Questions

  • The names for the first two are rather verbose; I’m open to suggestions as to better names for these functions since that was the best that I managed to come up with...
  • I’ve already discussed this somewhat with @AaronBallman and @cor3ntin, and I think that we probably don’t want to introduce any new helpers like isAnyPointerType() that claim to handle ‘all pointer types’, mainly because a lot of the calls to isAnyPointerType() are currently of the form if (Ty-&gt;isAnyPointerType() || Ty-&gt;someOtherPredicate()), where someOtherPredicate() may check for ReferenceType, MemberPointerType, etc. It seems that nearly every call site is different in what ‘pointer-like types’ it cares about, so a general helper is unlikely to be of any use pretty much ever.
  • I’m planning to do a general clean-up pass and look at all call sites of what used to be isAnyPointerType() to see if there is anything weird—so far, two instances of rather obvious dead code have surfaced as a result of the renaming (see below)—but my plan is to do that as a follow-up pr.
  • Additionally, there are a few places we could probably clean up by either introducing or using newer helper functions, e.g. we now have isPointerOrReferenceType(), so it would be possible to replace every instance of Ty-&gt;isPointerType() || Ty-&gt;isReferenceType() with Ty-&gt;isPointerOrReferenceType() and additionally introduce new helpers for common combinations of these predicates. At the same time, that sounds a bit like a reformatting pass with extra steps, and we usually tend to eschew these because they interact poorly with git blame from what I recall, so I’m not sure if that’s a good idea.
  • @AaronBallman There is an AST matcher with the name isAnyPointer(), which uses isAnyPointerType(). I’m not sure what exactly we want to do with that one.

Background

In the Type class, we currently have the following function:

bool isAnyPointerType() const;

which, one might reasonably assume, ought to return true if this is ‘any pointer type’, whatever that means. It turns out that what that actually ends up meaning is:

// Any C pointer or ObjC object pointer

That is, it does not include

  • Member pointers,
  • Block pointers,
  • nullptr_t.

Of course, one might argue that e.g. member pointers aren’t actually pointers but offsets, which is true, but we still call them MemberPointerTypes, so by name alone, they are still ‘a kind of pointer’.

Searching for occurrences yields several cases where someone has fallen for this and misunderstood what ‘any pointer type’ was actually supposed to mean. I’ve renamed it to isPointerOrObjCObjectPointerType(), so these misuses end up being rather apparent. There seem to be at least two places that are currently in the code base where someone got confused about this:

  • Here, we end up checking if Pointee is a pointer or Objective-C pointer... or Objective-C pointer.

    return Pointee->isPointerOrObjCObjectPointerType() ||
    Pointee->isObjCObjectPointerType() || Pointee->isMemberPointerType();

  • Here, it would seem that both of these if statements together end up being functionally equivalent to
    if (!Ty-&gt;isObjectPointerType()) return false;

    static bool TypeIsInnerPointer(QualType T) {
    if (!T->isPointerOrObjCObjectPointerType())
    return false;
    if (T->isObjCObjectPointerType() || T->isObjCBuiltinType() ||
    T->isBlockPointerType() || T->isFunctionPointerType() ||
    ento::coreFoundation::isCFObjectRef(T))
    return false;

Additionally, I can recall several instances of me either reading or writing code that uses isAnyPointerType() and then getting confused why something wasn’t working properly, and I’ve heard similar sentiment from others.

Another possible instance of that might be getPointeeOrArrayElementType(). You’d think based on its name that it’s an extension of getPointeeType() that also handles arrays, but that’s wrong: the former calls isAnyPointerType() before delegating to getPointeeType(), which means that unlike getPointeeType(), this function does not handle block or member pointers at all. Confusion about this fact in particular just a few days ago is what prompted me to address this issue.


Patch is 96.82 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/122938.diff

69 Files Affected:

  • (modified) clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp (+1-1)
  • (modified) clang-tools-extra/clang-tidy/bugprone/SuspiciousMemoryComparisonCheck.cpp (+2-1)
  • (modified) clang-tools-extra/clang-tidy/cppcoreguidelines/InitVariablesCheck.cpp (+1-1)
  • (modified) clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp (+1-1)
  • (modified) clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp (+11-6)
  • (modified) clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp (+2-1)
  • (modified) clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp (+1-1)
  • (modified) clang-tools-extra/clangd/SemanticHighlighting.cpp (+1-1)
  • (modified) clang/include/clang/AST/CanonicalType.h (+1-1)
  • (modified) clang/include/clang/AST/Type.h (+25-10)
  • (modified) clang/include/clang/ASTMatchers/ASTMatchers.h (+2-2)
  • (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h (+1-1)
  • (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h (+11-6)
  • (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h (+1-2)
  • (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h (+1-1)
  • (modified) clang/lib/ARCMigrate/ObjCMT.cpp (+2-2)
  • (modified) clang/lib/AST/ASTContext.cpp (+5-5)
  • (modified) clang/lib/AST/ASTImporter.cpp (+1-1)
  • (modified) clang/lib/AST/Expr.cpp (+2-2)
  • (modified) clang/lib/AST/ExprCXX.cpp (+1-1)
  • (modified) clang/lib/AST/ExprConstant.cpp (+1-1)
  • (modified) clang/lib/AST/MicrosoftMangle.cpp (+3-2)
  • (modified) clang/lib/AST/Type.cpp (+6)
  • (modified) clang/lib/Analysis/ThreadSafetyCommon.cpp (+1-1)
  • (modified) clang/lib/Analysis/UninitializedValues.cpp (+2-1)
  • (modified) clang/lib/CodeGen/CGCall.cpp (+2-1)
  • (modified) clang/lib/CodeGen/CGExpr.cpp (+2-1)
  • (modified) clang/lib/CodeGen/CGHLSLRuntime.cpp (+1-1)
  • (modified) clang/lib/CodeGen/CGOpenMPRuntime.cpp (+21-16)
  • (modified) clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp (+4-2)
  • (modified) clang/lib/CodeGen/CGStmtOpenMP.cpp (+6-4)
  • (modified) clang/lib/CodeGen/CodeGenTypes.cpp (+2-1)
  • (modified) clang/lib/CodeGen/Targets/SystemZ.cpp (+1-1)
  • (modified) clang/lib/ExtractAPI/DeclarationFragments.cpp (+1-1)
  • (modified) clang/lib/Frontend/ASTUnit.cpp (+3-3)
  • (modified) clang/lib/Sema/SemaAPINotes.cpp (+2-2)
  • (modified) clang/lib/Sema/SemaARM.cpp (+12-10)
  • (modified) clang/lib/Sema/SemaCast.cpp (+22-15)
  • (modified) clang/lib/Sema/SemaChecking.cpp (+7-5)
  • (modified) clang/lib/Sema/SemaCodeComplete.cpp (+4-3)
  • (modified) clang/lib/Sema/SemaDecl.cpp (+7-6)
  • (modified) clang/lib/Sema/SemaDeclAttr.cpp (+7-6)
  • (modified) clang/lib/Sema/SemaExpr.cpp (+34-26)
  • (modified) clang/lib/Sema/SemaExprCXX.cpp (+5-5)
  • (modified) clang/lib/Sema/SemaInit.cpp (+4-2)
  • (modified) clang/lib/Sema/SemaLookup.cpp (+2-1)
  • (modified) clang/lib/Sema/SemaOpenACC.cpp (+1-1)
  • (modified) clang/lib/Sema/SemaOpenCL.cpp (+3-1)
  • (modified) clang/lib/Sema/SemaOpenMP.cpp (+19-15)
  • (modified) clang/lib/Sema/SemaOverload.cpp (+8-7)
  • (modified) clang/lib/Sema/SemaRISCV.cpp (+2-1)
  • (modified) clang/lib/Sema/SemaSYCL.cpp (+2-2)
  • (modified) clang/lib/Sema/SemaTemplateDeduction.cpp (+1-1)
  • (modified) clang/lib/Sema/SemaType.cpp (+4-4)
  • (modified) clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp (+1-1)
  • (modified) clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp (+2-1)
  • (modified) clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp (+1-1)
  • (modified) clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp (+1-1)
  • (modified) clang/lib/StaticAnalyzer/Checkers/TrustNonnullChecker.cpp (+1-1)
  • (modified) clang/lib/StaticAnalyzer/Checkers/TrustReturnsNonnullChecker.cpp (+1-1)
  • (modified) clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h (+1-1)
  • (modified) clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp (+2-2)
  • (modified) clang/lib/StaticAnalyzer/Core/CallEvent.cpp (+2-2)
  • (modified) clang/lib/StaticAnalyzer/Core/DynamicType.cpp (+3-2)
  • (modified) clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp (+1-1)
  • (modified) clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp (+1-1)
  • (modified) clang/lib/Tooling/Transformer/SourceCodeBuilders.cpp (+1-1)
  • (modified) clang/lib/Tooling/Transformer/Stencil.cpp (+2-2)
  • (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp (+1-1)
diff --git a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
index b7f0c08b2a7d4b..f4c5523184630f 100644
--- a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
@@ -93,7 +93,7 @@ static bool isVarThatIsPossiblyChanged(const Decl *Func, const Stmt *LoopStmt,
       if (T.isVolatileQualified())
         return true;
 
-      if (!T->isAnyPointerType() && !T->isReferenceType())
+      if (!T->isPointerOrObjCObjectPointerType() && !T->isReferenceType())
         break;
 
       T = T->getPointeeType();
diff --git a/clang-tools-extra/clang-tidy/bugprone/SuspiciousMemoryComparisonCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SuspiciousMemoryComparisonCheck.cpp
index 84957e0b8190c0..7779b6725673cb 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SuspiciousMemoryComparisonCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SuspiciousMemoryComparisonCheck.cpp
@@ -45,7 +45,8 @@ void SuspiciousMemoryComparisonCheck::check(
   for (unsigned int ArgIndex = 0; ArgIndex < 2; ++ArgIndex) {
     const Expr *ArgExpr = CE->getArg(ArgIndex);
     QualType ArgType = ArgExpr->IgnoreImplicit()->getType();
-    const Type *PointeeType = ArgType->getPointeeOrArrayElementType();
+    const Type *PointeeType =
+        ArgType->getPointerOrObjCPointerOrArrayElementType();
     assert(PointeeType != nullptr && "PointeeType should always be available.");
     QualType PointeeQualifiedType(PointeeType, 0);
 
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/InitVariablesCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/InitVariablesCheck.cpp
index 3eef2fd12cc8e5..be1673d5c08c98 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/InitVariablesCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/InitVariablesCheck.cpp
@@ -95,7 +95,7 @@ void InitVariablesCheck::check(const MatchFinder::MatchResult &Result) {
   else if (TypePtr->isFloatingType()) {
     InitializationString = " = NAN";
     AddMathInclude = true;
-  } else if (TypePtr->isAnyPointerType()) {
+  } else if (TypePtr->isPointerOrObjCObjectPointerType()) {
     if (getLangOpts().CPlusPlus11)
       InitializationString = " = nullptr";
     else
diff --git a/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp b/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp
index 5abe4f77d65984..36628d0fd84be5 100644
--- a/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp
+++ b/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp
@@ -229,7 +229,7 @@ static bool isTypedefTypeMatching(const TypedefType *const Typedef,
 /// \returns type of the argument
 static const Type *argumentType(const CallExpr *const CE, const size_t Idx) {
   const QualType QT = CE->getArg(Idx)->IgnoreImpCasts()->getType();
-  return QT.getTypePtr()->getPointeeOrArrayElementType();
+  return QT.getTypePtr()->getPointerOrObjCPointerOrArrayElementType();
 }
 
 void TypeMismatchCheck::registerMatchers(MatchFinder *Finder) {
diff --git a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
index 3f63eec2c51a8c..dc740377c4db14 100644
--- a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
@@ -1218,7 +1218,7 @@ StyleKind IdentifierNamingCheck::findStyleKind(
       return SK_ConstexprVariable;
 
     if (!Type.isNull() && Type.isConstQualified()) {
-      if (Type.getTypePtr()->isAnyPointerType() &&
+      if (Type.getTypePtr()->isPointerOrObjCObjectPointerType() &&
           NamingStyles[SK_ConstantPointerParameter])
         return SK_ConstantPointerParameter;
 
@@ -1232,7 +1232,8 @@ StyleKind IdentifierNamingCheck::findStyleKind(
     if (Decl->isParameterPack() && NamingStyles[SK_ParameterPack])
       return SK_ParameterPack;
 
-    if (!Type.isNull() && Type.getTypePtr()->isAnyPointerType() &&
+    if (!Type.isNull() &&
+        Type.getTypePtr()->isPointerOrObjCObjectPointerType() &&
         NamingStyles[SK_PointerParameter])
       return SK_PointerParameter;
 
@@ -1508,7 +1509,8 @@ StyleKind IdentifierNamingCheck::findStyleKindForVar(
     if (Var->isStaticDataMember() && NamingStyles[SK_ClassConstant])
       return SK_ClassConstant;
 
-    if (Var->isFileVarDecl() && Type.getTypePtr()->isAnyPointerType() &&
+    if (Var->isFileVarDecl() &&
+        Type.getTypePtr()->isPointerOrObjCObjectPointerType() &&
         NamingStyles[SK_GlobalConstantPointer])
       return SK_GlobalConstantPointer;
 
@@ -1518,7 +1520,8 @@ StyleKind IdentifierNamingCheck::findStyleKindForVar(
     if (Var->isStaticLocal() && NamingStyles[SK_StaticConstant])
       return SK_StaticConstant;
 
-    if (Var->isLocalVarDecl() && Type.getTypePtr()->isAnyPointerType() &&
+    if (Var->isLocalVarDecl() &&
+        Type.getTypePtr()->isPointerOrObjCObjectPointerType() &&
         NamingStyles[SK_LocalConstantPointer])
       return SK_LocalConstantPointer;
 
@@ -1535,7 +1538,8 @@ StyleKind IdentifierNamingCheck::findStyleKindForVar(
   if (Var->isStaticDataMember() && NamingStyles[SK_ClassMember])
     return SK_ClassMember;
 
-  if (Var->isFileVarDecl() && Type.getTypePtr()->isAnyPointerType() &&
+  if (Var->isFileVarDecl() &&
+      Type.getTypePtr()->isPointerOrObjCObjectPointerType() &&
       NamingStyles[SK_GlobalPointer])
     return SK_GlobalPointer;
 
@@ -1545,7 +1549,8 @@ StyleKind IdentifierNamingCheck::findStyleKindForVar(
   if (Var->isStaticLocal() && NamingStyles[SK_StaticVariable])
     return SK_StaticVariable;
 
-  if (Var->isLocalVarDecl() && Type.getTypePtr()->isAnyPointerType() &&
+  if (Var->isLocalVarDecl() &&
+      Type.getTypePtr()->isPointerOrObjCObjectPointerType() &&
       NamingStyles[SK_LocalPointer])
     return SK_LocalPointer;
 
diff --git a/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp b/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp
index c5eaff88e0ed3b..dc6b459e05bdfb 100644
--- a/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp
@@ -472,7 +472,8 @@ static bool areTypesCompatible(QualType ArgType, QualType ParamType,
 
   // Unless argument and param are both multilevel pointers, the types are not
   // convertible.
-  if (!(ParamType->isAnyPointerType() && ArgType->isAnyPointerType()))
+  if (!(ParamType->isPointerOrObjCObjectPointerType() &&
+        ArgType->isPointerOrObjCObjectPointerType()))
     return false;
 
   return arePointerTypesCompatible(ArgType, ParamType, IsParamContinuouslyConst,
diff --git a/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp b/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
index 0fea7946a59f95..eec39d97a94a72 100644
--- a/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
+++ b/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
@@ -84,7 +84,7 @@ inline bool isPointerOrPointerToMember(const Type *T) {
 }
 
 std::optional<QualType> getPointeeOrArrayElementQualType(QualType T) {
-  if (T->isAnyPointerType() || T->isMemberPointerType())
+  if (T->isPointerOrObjCObjectPointerType() || T->isMemberPointerType())
     return T->getPointeeType();
 
   if (T->isArrayType())
diff --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp b/clang-tools-extra/clangd/SemanticHighlighting.cpp
index e6d16af2495fec..238b28eb976960 100644
--- a/clang-tools-extra/clangd/SemanticHighlighting.cpp
+++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp
@@ -296,7 +296,7 @@ bool isDefaultLibrary(const Decl *D) {
 bool isDefaultLibrary(const Type *T) {
   if (!T)
     return false;
-  const Type *Underlying = T->getPointeeOrArrayElementType();
+  const Type *Underlying = T->getPointerOrObjCPointerOrArrayElementType();
   if (Underlying->isBuiltinType())
     return true;
   if (auto *TD = dyn_cast<TemplateTypeParmType>(Underlying))
diff --git a/clang/include/clang/AST/CanonicalType.h b/clang/include/clang/AST/CanonicalType.h
index 6699284d215bd0..8c0b9aa39df941 100644
--- a/clang/include/clang/AST/CanonicalType.h
+++ b/clang/include/clang/AST/CanonicalType.h
@@ -286,7 +286,7 @@ class CanProxyBase {
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isDerivedType)
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isScalarType)
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isAggregateType)
-  LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isAnyPointerType)
+  LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isPointerOrObjCObjectPointerType)
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVoidPointerType)
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isFunctionPointerType)
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isMemberFunctionPointerType)
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 78677df578c4bc..80602a85fbcff4 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -2536,7 +2536,8 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
   bool isPointerType() const;
   bool isPointerOrReferenceType() const;
   bool isSignableType() const;
-  bool isAnyPointerType() const;   // Any C pointer or ObjC object pointer
+  bool isPointerOrObjCObjectPointerType()
+      const; // Any C pointer or ObjC object pointer
   bool isCountAttributedType() const;
   bool isBlockPointerType() const;
   bool isVoidPointerType() const;
@@ -2862,15 +2863,29 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
   /// This should never be used when type qualifiers are meaningful.
   const Type *getArrayElementTypeNoTypeQual() const;
 
-  /// If this is a pointer type, return the pointee type.
+  /// If this is a C or ObjC pointer type, return the pointee type. Notably,
+  /// this does not handle things like member pointers or block pointers.
+  ///
   /// If this is an array type, return the array element type.
+  ///
   /// This should never be used when type qualifiers are meaningful.
-  const Type *getPointeeOrArrayElementType() const;
+  const Type *getPointerOrObjCPointerOrArrayElementType() const;
 
-  /// If this is a pointer, ObjC object pointer, or block
-  /// pointer, this returns the respective pointee.
+  /// Return the 'pointee type' for any of the following kinds of types,
+  /// and an empty QualType otherwise.
+  ///
+  ///   - PointerType
+  ///   - ObjCObjectPointerType
+  ///   - BlockPointerType
+  ///   - ReferenceType
+  ///   - MemberPointerType
+  ///   - DecayedType
   QualType getPointeeType() const;
 
+  /// Return getElementType() if this is an array type, and getPointeeType()
+  /// otherwise.
+  QualType getPointerLikeOrArrayElementType() const;
+
   /// Return the specified type with any "sugar" removed from the type,
   /// removing any typedefs, typeofs, etc., as well as any qualifiers.
   const Type *getUnqualifiedDesugaredType() const;
@@ -8196,7 +8211,7 @@ inline bool Type::isPointerOrReferenceType() const {
   return isPointerType() || isReferenceType();
 }
 
-inline bool Type::isAnyPointerType() const {
+inline bool Type::isPointerOrObjCObjectPointerType() const {
   return isPointerType() || isObjCObjectPointerType();
 }
 
@@ -8656,8 +8671,8 @@ inline bool Type::isUndeducedType() const {
 inline bool Type::isOverloadableType() const {
   if (!isDependentType())
     return isRecordType() || isEnumeralType();
-  return !isArrayType() && !isFunctionType() && !isAnyPointerType() &&
-         !isMemberPointerType();
+  return !isArrayType() && !isFunctionType() &&
+         !isPointerOrObjCObjectPointerType() && !isMemberPointerType();
 }
 
 /// Determines whether this type is written as a typedef-name.
@@ -8690,9 +8705,9 @@ inline const Type *Type::getBaseElementTypeUnsafe() const {
   return type;
 }
 
-inline const Type *Type::getPointeeOrArrayElementType() const {
+inline const Type *Type::getPointerOrObjCPointerOrArrayElementType() const {
   const Type *type = this;
-  if (type->isAnyPointerType())
+  if (type->isPointerOrObjCObjectPointerType())
     return type->getPointeeType().getTypePtr();
   else if (type->isArrayType())
     return type->getBaseElementTypeUnsafe();
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 239fcba4e5e057..d9f505c5645f06 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -4156,7 +4156,7 @@ AST_MATCHER_P(QualType, asString, std::string, Name) {
 AST_MATCHER_P(
     QualType, pointsTo, internal::Matcher<QualType>,
     InnerMatcher) {
-  return (!Node.isNull() && Node->isAnyPointerType() &&
+  return (!Node.isNull() && Node->isPointerOrObjCObjectPointerType() &&
           InnerMatcher.matches(Node->getPointeeType(), Finder, Builder));
 }
 
@@ -6605,7 +6605,7 @@ AST_MATCHER(QualType, isAnyCharacter) {
 /// varDecl(hasType(isAnyPointer()))
 ///   matches "int *i" and "Foo *f", but not "int j".
 AST_MATCHER(QualType, isAnyPointer) {
-  return Node->isAnyPointerType();
+  return Node->isPointerOrObjCObjectPointerType();
 }
 
 /// Matches QualType nodes that are const-qualified, i.e., that
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index f88bf70d72398c..15e01bdbcd6ed5 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -787,7 +787,7 @@ class SymbolicRegion : public SubRegion {
     // Because pointer arithmetic is represented by ElementRegion layers,
     // the base symbol here should not contain any arithmetic.
     assert(isa_and_nonnull<SymbolData>(s));
-    assert(s->getType()->isAnyPointerType() ||
+    assert(s->getType()->isPointerOrObjCObjectPointerType() ||
            s->getType()->isReferenceType() ||
            s->getType()->isBlockPointerType());
     assert(isa<UnknownSpaceRegion>(sreg) || isa<HeapSpaceRegion>(sreg) ||
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h
index fcc9c02999b3b0..d175b6d2886095 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h
@@ -264,7 +264,8 @@ class SMTConv {
                                           uint64_t FromBitWidth) {
     if ((FromTy->isIntegralOrEnumerationType() &&
          ToTy->isIntegralOrEnumerationType()) ||
-        (FromTy->isAnyPointerType() ^ ToTy->isAnyPointerType()) ||
+        (FromTy->isPointerOrObjCObjectPointerType() ^
+         ToTy->isPointerOrObjCObjectPointerType()) ||
         (FromTy->isBlockPointerType() ^ ToTy->isBlockPointerType()) ||
         (FromTy->isReferenceType() ^ ToTy->isReferenceType())) {
 
@@ -365,7 +366,8 @@ class SMTConv {
 
       // If the two operands are pointers and the operation is a subtraction,
       // the result is of type ptrdiff_t, which is signed
-      if (LTy->isAnyPointerType() && RTy->isAnyPointerType() && Op == BO_Sub) {
+      if (LTy->isPointerOrObjCObjectPointerType() &&
+          RTy->isPointerOrObjCObjectPointerType() && Op == BO_Sub) {
         *RetTy = Ctx.getPointerDiffType();
       }
     }
@@ -509,8 +511,9 @@ class SMTConv {
                             Solver->mkFloat(Zero));
     }
 
-    if (Ty->isIntegralOrEnumerationType() || Ty->isAnyPointerType() ||
-        Ty->isBlockPointerType() || Ty->isReferenceType()) {
+    if (Ty->isIntegralOrEnumerationType() ||
+        Ty->isPointerOrObjCObjectPointerType() || Ty->isBlockPointerType() ||
+        Ty->isReferenceType()) {
 
       // Skip explicit comparison for boolean types
       bool isSigned = Ty->isSignedIntegerOrEnumerationType();
@@ -613,7 +616,8 @@ class SMTConv {
       return;
     }
 
-    if ((LTy->isAnyPointerType() || RTy->isAnyPointerType()) ||
+    if ((LTy->isPointerOrObjCObjectPointerType() ||
+         RTy->isPointerOrObjCObjectPointerType()) ||
         (LTy->isBlockPointerType() || RTy->isBlockPointerType()) ||
         (LTy->isReferenceType() || RTy->isReferenceType())) {
       // TODO: Refactor to Sema::FindCompositePointerType(), and
@@ -624,7 +628,8 @@ class SMTConv {
 
       // Cast the non-pointer type to the pointer type.
       // TODO: Be more strict about this.
-      if ((LTy->isAnyPointerType() ^ RTy->isAnyPointerType()) ||
+      if ((LTy->isPointerOrObjCObjectPointerType() ^
+           RTy->isPointerOrObjCObjectPointerType()) ||
           (LTy->isBlockPointerType() ^ RTy->isBlockPointerType()) ||
           (LTy->isReferenceType() ^ RTy->isReferenceType())) {
         if (LTy->isNullPtrType() || LTy->isBlockPointerType() ||
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 54430d426a82a8..93e6b08644807a 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -356,8 +356,7 @@ class SValBuilder {
   /// space.
   /// \param type pointer type.
   loc::ConcreteInt makeNullWithType(QualType type) {
-    // We cannot use the `isAnyPointerType()`.
-    assert((type->isPointerType() || type->isObjCObjectPointerType() ||
+    assert((type->isPointerOrObjCObjectPointerType() ||
             type->isBlockPointerType() || type->isNullPtrType() ||
             type->isReferenceType()) &&
            "makeNullWithType must use pointer type");
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index aeb57b28077c61..c6c6951ba32198 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -260,7 +260,7 @@ class Loc : public DefinedSVal {
   void dumpToStream(raw_ostream &Out) const;
 
   static bool isLocType(QualType T) {
-    return T->isAnyPointerType() || T->isBlockPointerType() ||
+    return T->isPointerOrObjCObjectPointerType() || T->isBlockPointerType() ||
            T->isReferenceType() || T->isNullPtrType();
   }
 
diff --git a/clang/lib/ARCMigrate/ObjCMT.cpp b/clang/lib/ARCMigrate/ObjCMT.cpp
index c1bc7c762088f2..47c130379d5126 100644
--- a/clang/lib/ARCMigrate/ObjCMT.cpp
+++ b/clang/lib/ARCMigrate/ObjCMT.cpp
@@ -1042,7 +1042,7 @@ void ObjCMigrateASTConsumer::migrateMethodInstanceType(ASTContext &Ctx,
 }
 
 static bool TypeIsInnerPointer(QualType T) {
-  if (!T->isAnyPointerType())
+  if (!T->isPointerOrObjCObjectPointerType())
     return false;
   if (T->isObjCObjectPointerType() || T->isObjCBuiltinType() ||
       T->isBlockPointerType() || T->isFunctionPointerType() ||
@@ -1366,7 +1366,7 @@ static bool IsVoidStarType(QualType Ty) {
 /// CF object types or of the "void *" variety. It returns true if we don't care about the type
 /// such as a non-pointer or pointers which have no ownership issues (such as "int *").
 static bool AuditedType (QualType AT) {
-  if (!AT->isAnyPointerType() && !AT->isBlockPointerType())
+  if (!AT->isPointerOrObjCObjectPointerType() && !AT->isBlockPointerType())
     return true;
   // FIXME. There isn't much we can say about CF pointer type; or is there?
   if (ento::coreFoundation::isCFObjectRef(AT) ||
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index be1dd29d462788..9d4743bd0a0aa7 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -2980,9 +2980,9 @@ bool ASTContext::isSentinelNullExpr(const Expr *E) {
   // nullptr_t is always treated as null.
   if (E->getType()->isNullPtrType()) return true;
 
-  if (E->getType()->isAnyPointerType() &&
-      E->IgnoreParenCasts()->isNullPointerConstant(*this,
-                                                Expr::NPC_ValueDependentIsNull))
+  if (E->getType()->isPointerOrObjCObjectPointerType() &&
+      E->IgnoreParenCasts()->isNullPointerConstant(
+          *this, Expr::NPC_ValueDependentIsNull))
     return true;
 
   // Unfortunately, __null has type 'int'.
@@ -3518,7 +3518,7 @@ QualType ASTContext::getObjCGCQualType(QualType T,
 
   if (const auto *ptr = T->getAs<PointerType>()) {
     QualType Pointee = ptr->getPointeeType();
-    if (Pointee->isAnyPointerType()) {...
[truncated]

@cor3ntin
Copy link
Contributor

cor3ntin commented Jan 14, 2025

Thanks for working on this.

A few comment: getPointerLikeOrArrayElementType is not used, and I'm rather concerned by what it does.
Removing pointiness in only some cases seem dangerous, and not super useful...

Renaming getPointeeOrArrayElementType to getPointerOrArrayElementType seems wrong. However, if we put an assert in these function that the type is indeed a pointer or an array, how much code break? I suspect not much, and we could fix the caller. ie this function is too magic/does too much.

I would rather not use Like in any of the name because in C++ this is often use to mean "a type that behaves like this core construct". ie unique_ptr is pointer-like

@Sirraide
Copy link
Member Author

A few comment: getPointerLikeOrArrayElementType is not used, and I'm rather concerned by what it does.
Removing pointiness in only some cases seem dangerous, and not super useful...

That’s fair, I don’t think it’s crucial to add that or anything.

Renaming getPointeeOrArrayElementType to getPointerOrArrayElementType seems wrong. However, if we put an assert in these function that the type is indeed a pointer or an array, how much code break? I suspect not much, and we could fix the caller. ie this function is too magic/does too much.

Ah, I think you’re confusing two functions there: getPointeeOrArrayElementType() is being renamed to getPointerOrObjCPointerOrArrayElementType(), not getPointerOrArrayElementType().

@Sirraide
Copy link
Member Author

That’s fair, I don’t think it’s crucial to add that or anything.

If anything the pr in question can either add that or put that somewhere else; I’ll remove that function from this pr.

@Sirraide Sirraide force-pushed the is-any-pointer-type branch from 6117dc0 to f0350e1 Compare January 14, 2025 17:56
@Sirraide
Copy link
Member Author

(just removed the last two commits that only added that function)

@cor3ntin
Copy link
Contributor

Ah, I think you’re confusing two functions there: getPointeeOrArrayElementType() is being renamed to getPointerOrObjCPointerOrArrayElementType(), not getPointerOrArrayElementType().

Not confused. renaming getPointeeFoo to getPointerBar does not seem correct, especially as getPointeeOrArrayElementType does indeed return a pointee.

And my other point, is that there should not be a use case for "If T is a pointer give me the pointee, otherwise give me T" - which is why I'm suggesting functions returning a pointee should not accept a non-pointer type

@Sirraide
Copy link
Member Author

Not confused. renaming getPointeeFoo to getPointerBar does not seem correct, especially as getPointeeOrArrayElementType does indeed return a pointee.

Ah, I see, in that case the only other name I could think of would be something like getPointerOrObjCPointerPointeeOrArrayElementType. I personally was reading getPointerOrObjCPointerOrArrayElementType() as ‘get the element type of a pointer, objc pointer, or array’.

@Sirraide
Copy link
Member Author

ping

@AaronBallman
Copy link
Collaborator

Thank you for working on cleaning up these APIs! They are definitely a source of confusion in practice, so paying down this tech debt is great!

The names for the first two are rather verbose; I’m open to suggestions as to better names for these functions since that was the best that I managed to come up with...

Given the fact that there tend to be custom predicates anyway, what about an API where you pass in the kinds of pointers you're after:

enum PointerLikeKind {
  C = 1U << 0U,
  ObjC = 1U << 1U,
  Block = 1U << 2U,
  Member = 1U << 3U,
  Reference = 1U << 4U,
  ...
};

bool isPointerLike(unsigned PLK) const;
Type *getPointeeFromPointerLike(unsigned PLK);
const Type *getPointeeFromPointerLike(unsigned PLK) const;

and then people can migrate to that (though we probably want to use the fancy enum class bitmask functionality rather than this style above, but we need to pick something that's not onerous to use at call sites). This would replace isAnyPointerType() and friends, so those APIs would go away.

As for the array element API, that one is really odd because it does things like strip qualifiers and doesn't handle multidimensional arrays gracefully. There are 17 uses of it, so I wonder if it makes sense to remove that API entirely and just handle the array case explicitly.

Would that be something you would be willing to explore to see if it leads to a cleaner end-state?

@Sirraide
Copy link
Member Author

Sirraide commented Jan 27, 2025

Aaron and I just talked about this a bit, and I agree it would be cleaner to just make a single function that can be used everywhere and whose behaviour is customised with an enum. I’ll experiment with that approach and see how it goes. Also, my plan was to try and remove isPointerOrObjCObjectPointerType() entirely in a follow-up pr anyway, and it does make more sense to just do that right away.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:AArch64 backend:ARM backend:RISC-V backend:SystemZ clang:analysis clang:codegen clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:openmp OpenMP related changes to Clang clang:static analyzer clang Clang issues not falling into any other category clang-tidy clang-tools-extra clangd HLSL HLSL Language Support lldb
Projects
Status: No status
Development

Successfully merging this pull request may close these issues.

4 participants