chrisbazley created this revision.
Herald added subscribers: kadircet, arphaman.
Herald added a project: All.
chrisbazley requested review of this revision.
Herald added projects: clang, clang-tools-extra.
Herald added a subscriber: cfe-commits.

The purpose of this change is to ensure that a
qualified declaration such as '_Optional int *' is
treated as equivalent to the annotated declaration
'int *_Nullable' in all situations where type
qualifiers are available.

The new method falls back to Type::getNullability() if
called for a QualType which is not a pointer to an
_Optional-qualified type.

Updated all of the callers which previously invoked
Type::getNullability() via QualType::operator->() so
that they call the new method directly on the QualType
instead.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D142736

Files:
  clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
  clang/include/clang/AST/ASTContext.h
  clang/include/clang/AST/Type.h
  clang/lib/AST/ASTContext.cpp
  clang/lib/AST/Type.cpp
  clang/lib/CodeGen/CGCall.cpp
  clang/lib/CodeGen/CGDecl.cpp
  clang/lib/CodeGen/CodeGenFunction.cpp
  clang/lib/Sema/Sema.cpp
  clang/lib/Sema/SemaChecking.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaDeclObjC.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaExprObjC.cpp
  clang/lib/Sema/SemaLambda.cpp
  clang/lib/Sema/SemaObjCProperty.cpp
  clang/lib/Sema/SemaType.cpp
  clang/tools/libclang/CXType.cpp

Index: clang/tools/libclang/CXType.cpp
===================================================================
--- clang/tools/libclang/CXType.cpp
+++ clang/tools/libclang/CXType.cpp
@@ -1332,7 +1332,7 @@
   if (T.isNull())
     return CXTypeNullability_Invalid;
 
-  if (auto nullability = T->getNullability()) {
+  if (auto nullability = T.getNullability()) {
     switch (*nullability) {
       case NullabilityKind::NonNull:
         return CXTypeNullability_NonNull;
Index: clang/lib/Sema/SemaType.cpp
===================================================================
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -4713,7 +4713,7 @@
     complainAboutMissingNullability = CAMN_InnerPointers;
 
     if (T->canHaveNullability(/*ResultIfUnknown*/ false) &&
-        !T->getNullability()) {
+        !T.getNullability()) {
       // Note that we allow but don't require nullability on dependent types.
       ++NumPointersRemaining;
     }
@@ -4935,7 +4935,7 @@
   // nullability and perform consistency checking.
   if (S.CodeSynthesisContexts.empty()) {
     if (T->canHaveNullability(/*ResultIfUnknown*/ false) &&
-        !T->getNullability()) {
+        !T.getNullability()) {
       if (isVaList(T)) {
         // Record that we've seen a pointer, but do nothing else.
         if (NumPointersRemaining > 0)
@@ -4959,7 +4959,7 @@
     }
 
     if (complainAboutMissingNullability == CAMN_Yes && T->isArrayType() &&
-        !T->getNullability() && !isVaList(T) && D.isPrototypeContext() &&
+        !T.getNullability() && !isVaList(T) && D.isPrototypeContext() &&
         !hasOuterPointerLikeChunk(D, D.getNumTypeObjects())) {
       checkNullabilityConsistency(S, SimplePointerKind::Array,
                                   D.getDeclSpec().getTypeSpecTypeLoc());
@@ -7415,7 +7415,7 @@
   // This (unlike the code above) looks through typedefs that might
   // have nullability specifiers on them, which means we cannot
   // provide a useful Fix-It.
-  if (auto existingNullability = desugared->getNullability()) {
+  if (auto existingNullability = desugared.getNullability()) {
     if (nullability != *existingNullability) {
       S.Diag(nullabilityLoc, diag::err_nullability_conflicting)
         << DiagNullabilityKind(nullability, isContextSensitive)
@@ -7514,7 +7514,7 @@
   // If we started with an object pointer type, rebuild it.
   if (ptrType) {
     equivType = S.Context.getObjCObjectPointerType(equivType);
-    if (auto nullability = type->getNullability()) {
+    if (auto nullability = type.getNullability()) {
       // We create a nullability attribute from the __kindof attribute.
       // Make sure that will make sense.
       assert(attr.getAttributeSpellingListIndex() == 0 &&
Index: clang/lib/Sema/SemaObjCProperty.cpp
===================================================================
--- clang/lib/Sema/SemaObjCProperty.cpp
+++ clang/lib/Sema/SemaObjCProperty.cpp
@@ -2754,7 +2754,7 @@
 
   if (Attributes & ObjCPropertyAttribute::kind_weak) {
     // 'weak' and 'nonnull' are mutually exclusive.
-    if (auto nullability = PropertyTy->getNullability()) {
+    if (auto nullability = PropertyTy.getNullability()) {
       if (*nullability == NullabilityKind::NonNull)
         Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
           << "nonnull" << "weak";
Index: clang/lib/Sema/SemaLambda.cpp
===================================================================
--- clang/lib/Sema/SemaLambda.cpp
+++ clang/lib/Sema/SemaLambda.cpp
@@ -777,8 +777,8 @@
     if (Context.getCanonicalFunctionResultType(ReturnType) ==
           Context.getCanonicalFunctionResultType(CSI.ReturnType)) {
       // Use the return type with the strictest possible nullability annotation.
-      auto RetTyNullability = ReturnType->getNullability();
-      auto BlockNullability = CSI.ReturnType->getNullability();
+      auto RetTyNullability = ReturnType.getNullability();
+      auto BlockNullability = CSI.ReturnType.getNullability();
       if (BlockNullability &&
           (!RetTyNullability ||
            hasWeakerNullability(*RetTyNullability, *BlockNullability)))
Index: clang/lib/Sema/SemaExprObjC.cpp
===================================================================
--- clang/lib/Sema/SemaExprObjC.cpp
+++ clang/lib/Sema/SemaExprObjC.cpp
@@ -593,7 +593,7 @@
       BoxedType = NSStringPointer;
       // Transfer the nullability from method's return type.
       std::optional<NullabilityKind> Nullability =
-          BoxingMethod->getReturnType()->getNullability();
+          BoxingMethod->getReturnType().getNullability();
       if (Nullability)
         BoxedType = Context.getAttributedType(
             AttributedType::getNullabilityAttrKind(*Nullability), BoxedType,
@@ -1465,7 +1465,7 @@
   auto transferNullability = [&](QualType type) -> QualType {
     // If the method's result type has nullability, extract it.
     if (auto nullability =
-            Method->getSendResultType(ReceiverType)->getNullability()) {
+            Method->getSendResultType(ReceiverType).getNullability()) {
       // Strip off any outer nullability sugar from the provided type.
       (void)AttributedType::stripOuterNullability(type);
 
@@ -1544,7 +1544,7 @@
         assert(MD->isClassMethod() && "expected a class method");
         QualType NewResultType = Context.getObjCObjectPointerType(
             Context.getObjCInterfaceType(MD->getClassInterface()));
-        if (auto Nullability = resultType->getNullability())
+        if (auto Nullability = resultType.getNullability())
           NewResultType = Context.getAttributedType(
               AttributedType::getNullabilityAttrKind(*Nullability),
               NewResultType, NewResultType);
@@ -1562,7 +1562,7 @@
   // Map the nullability of the result into a table index.
   unsigned receiverNullabilityIdx = 0;
   if (std::optional<NullabilityKind> nullability =
-          ReceiverType->getNullability()) {
+          ReceiverType.getNullability()) {
     if (*nullability == NullabilityKind::NullableResult)
       nullability = NullabilityKind::Nullable;
     receiverNullabilityIdx = 1 + static_cast<unsigned>(*nullability);
@@ -1570,7 +1570,7 @@
 
   unsigned resultNullabilityIdx = 0;
   if (std::optional<NullabilityKind> nullability =
-          resultType->getNullability()) {
+          resultType.getNullability()) {
     if (*nullability == NullabilityKind::NullableResult)
       nullability = NullabilityKind::Nullable;
     resultNullabilityIdx = 1 + static_cast<unsigned>(*nullability);
@@ -1603,7 +1603,7 @@
     } else {
       resultType = resultType.getDesugaredType(Context);
     }
-  } while (resultType->getNullability());
+  } while (resultType.getNullability());
 
   // Add nullability back if needed.
   if (newResultNullabilityIdx > 0) {
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -9308,7 +9308,7 @@
     return ResTy;
 
   auto GetNullability = [](QualType Ty) {
-    std::optional<NullabilityKind> Kind = Ty->getNullability();
+    std::optional<NullabilityKind> Kind = Ty.getNullability();
     if (Kind) {
       // For our purposes, treat _Nullable_result as _Nullable.
       if (*Kind == NullabilityKind::NullableResult)
@@ -9345,7 +9345,7 @@
     return ResTy;
 
   // Strip all nullability from ResTy.
-  while (ResTy->getNullability())
+  while (ResTy.getNullability())
     ResTy = ResTy.getSingleStepDesugaredType(Ctx);
 
   // Create a new AttributedType with the new nullability kind.
Index: clang/lib/Sema/SemaDeclObjC.cpp
===================================================================
--- clang/lib/Sema/SemaDeclObjC.cpp
+++ clang/lib/Sema/SemaDeclObjC.cpp
@@ -2370,8 +2370,8 @@
       !S.Context.hasSameNullabilityTypeQualifier(MethodImpl->getReturnType(),
                                                  MethodDecl->getReturnType(),
                                                  false)) {
-    auto nullabilityMethodImpl = *MethodImpl->getReturnType()->getNullability();
-    auto nullabilityMethodDecl = *MethodDecl->getReturnType()->getNullability();
+    auto nullabilityMethodImpl = *MethodImpl->getReturnType().getNullability();
+    auto nullabilityMethodDecl = *MethodDecl->getReturnType().getNullability();
     S.Diag(MethodImpl->getLocation(),
            diag::warn_conflicting_nullability_attr_overriding_ret_types)
         << DiagNullabilityKind(nullabilityMethodImpl,
@@ -2458,10 +2458,10 @@
       !S.Context.hasSameNullabilityTypeQualifier(ImplTy, IfaceTy, true)) {
     S.Diag(ImplVar->getLocation(),
            diag::warn_conflicting_nullability_attr_overriding_param_types)
-        << DiagNullabilityKind(*ImplTy->getNullability(),
+        << DiagNullabilityKind(*ImplTy.getNullability(),
                                ((ImplVar->getObjCDeclQualifier() &
                                  Decl::OBJC_TQ_CSNullability) != 0))
-        << DiagNullabilityKind(*IfaceTy->getNullability(),
+        << DiagNullabilityKind(*IfaceTy.getNullability(),
                                ((IfaceVar->getObjCDeclQualifier() &
                                  Decl::OBJC_TQ_CSNullability) != 0));
     S.Diag(IfaceVar->getLocation(), diag::note_previous_declaration);
@@ -4546,8 +4546,8 @@
                                               QualType prevType,
                                               bool prevUsesCSKeyword) {
   // Determine the nullability of both types.
-  auto nullability = type->getNullability();
-  auto prevNullability = prevType->getNullability();
+  auto nullability = type.getNullability();
+  auto prevNullability = prevType.getNullability();
 
   // Easy case: both have nullability.
   if (nullability.has_value() == prevNullability.has_value()) {
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -3399,8 +3399,8 @@
 static void mergeParamDeclTypes(ParmVarDecl *NewParam,
                                 const ParmVarDecl *OldParam,
                                 Sema &S) {
-  if (auto Oldnullability = OldParam->getType()->getNullability()) {
-    if (auto Newnullability = NewParam->getType()->getNullability()) {
+  if (auto Oldnullability = OldParam->getType().getNullability()) {
+    if (auto Newnullability = NewParam->getType().getNullability()) {
       if (*Oldnullability != *Newnullability) {
         S.Diag(NewParam->getLocation(), diag::warn_mismatched_nullability_attr)
           << DiagNullabilityKind(
Index: clang/lib/Sema/SemaChecking.cpp
===================================================================
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -5636,7 +5636,7 @@
 /// Returns true if the value evaluates to null.
 static bool CheckNonNullExpr(Sema &S, const Expr *Expr) {
   // If the expression has non-null type, it doesn't evaluate to null.
-  if (auto nullability = Expr->IgnoreImplicit()->getType()->getNullability()) {
+  if (auto nullability = Expr->IgnoreImplicit()->getType().getNullability()) {
     if (*nullability == NullabilityKind::NonNull)
       return false;
   }
@@ -5721,7 +5721,7 @@
 
 /// Determine whether the given type has a non-null nullability annotation.
 static bool isNonNullType(QualType type) {
-  if (auto nullability = type->getNullability())
+  if (auto nullability = type.getNullability())
     return *nullability == NullabilityKind::NonNull;
 
   return false;
Index: clang/lib/Sema/Sema.cpp
===================================================================
--- clang/lib/Sema/Sema.cpp
+++ clang/lib/Sema/Sema.cpp
@@ -565,12 +565,12 @@
 void Sema::diagnoseNullableToNonnullConversion(QualType DstType,
                                                QualType SrcType,
                                                SourceLocation Loc) {
-  std::optional<NullabilityKind> ExprNullability = SrcType->getNullability();
+  std::optional<NullabilityKind> ExprNullability = SrcType.getNullability();
   if (!ExprNullability || (*ExprNullability != NullabilityKind::Nullable &&
                            *ExprNullability != NullabilityKind::NullableResult))
     return;
 
-  std::optional<NullabilityKind> TypeNullability = DstType->getNullability();
+  std::optional<NullabilityKind> TypeNullability = DstType.getNullability();
   if (!TypeNullability || *TypeNullability != NullabilityKind::NonNull)
     return;
 
Index: clang/lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.cpp
+++ clang/lib/CodeGen/CodeGenFunction.cpp
@@ -960,7 +960,7 @@
   // If we're checking nullability, we need to know whether we can check the
   // return value. Initialize the flag to 'true' and refine it in EmitParmDecl.
   if (SanOpts.has(SanitizerKind::NullabilityReturn)) {
-    auto Nullability = FnRetTy->getNullability();
+    auto Nullability = FnRetTy.getNullability();
     if (Nullability && *Nullability == NullabilityKind::NonNull) {
       if (!(SanOpts.has(SanitizerKind::ReturnsNonnullAttribute) &&
             CurCodeDecl && CurCodeDecl->getAttr<ReturnsNonNullAttr>()))
Index: clang/lib/CodeGen/CGDecl.cpp
===================================================================
--- clang/lib/CodeGen/CGDecl.cpp
+++ clang/lib/CodeGen/CGDecl.cpp
@@ -759,7 +759,7 @@
   if (!SanOpts.has(SanitizerKind::NullabilityAssign))
     return;
 
-  auto Nullability = LHS.getType()->getNullability();
+  auto Nullability = LHS.getType().getNullability();
   if (!Nullability || *Nullability != NullabilityKind::NonNull)
     return;
 
@@ -2616,7 +2616,7 @@
   // function satisfy their nullability preconditions. This makes it necessary
   // to emit null checks for args in the function body itself.
   if (requiresReturnValueNullabilityCheck()) {
-    auto Nullability = Ty->getNullability();
+    auto Nullability = Ty.getNullability();
     if (Nullability && *Nullability == NullabilityKind::NonNull) {
       SanitizerScope SanScope(this);
       RetValNullabilityPrecondition =
Index: clang/lib/CodeGen/CGCall.cpp
===================================================================
--- clang/lib/CodeGen/CGCall.cpp
+++ clang/lib/CodeGen/CGCall.cpp
@@ -4123,7 +4123,7 @@
 
   bool CanCheckNullability = false;
   if (SanOpts.has(SanitizerKind::NullabilityArg) && !NNAttr && PVD) {
-    auto Nullability = PVD->getType()->getNullability();
+    auto Nullability = PVD->getType().getNullability();
     CanCheckNullability = Nullability &&
                           *Nullability == NullabilityKind::NonNull &&
                           PVD->getTypeSourceInfo();
Index: clang/lib/AST/Type.cpp
===================================================================
--- clang/lib/AST/Type.cpp
+++ clang/lib/AST/Type.cpp
@@ -1534,6 +1534,16 @@
   return getUnqualifiedType();
 }
 
+std::optional<NullabilityKind> QualType::getNullability() const {
+  if (const PointerType *PT = getTypePtr()->getAs<PointerType>()) {
+    auto PointeeType = PT->getPointeeType();
+    if (PointeeType.isOptionalQualified()) {
+      return NullabilityKind::Nullable;
+    }
+  }
+  return getTypePtr()->getNullability();
+}
+
 std::optional<ArrayRef<QualType>>
 Type::getObjCSubstitutions(const DeclContext *dc) const {
   // Look through method scopes.
Index: clang/lib/AST/ASTContext.cpp
===================================================================
--- clang/lib/AST/ASTContext.cpp
+++ clang/lib/AST/ASTContext.cpp
@@ -6939,7 +6939,7 @@
                                      PrettyArrayType->getIndexTypeQualifiers());
 
   // int x[_Nullable] -> int * _Nullable
-  if (auto Nullability = Ty->getNullability()) {
+  if (auto Nullability = Ty.getNullability()) {
     Result = const_cast<ASTContext *>(this)->getAttributedType(
         AttributedType::getNullabilityAttrKind(*Nullability), Result, Result);
   }
Index: clang/include/clang/AST/Type.h
===================================================================
--- clang/include/clang/AST/Type.h
+++ clang/include/clang/AST/Type.h
@@ -1400,6 +1400,12 @@
   /// Remove all qualifiers including _Atomic.
   QualType getAtomicUnqualifiedType() const;
 
+  /// Determine the nullability of the given type.
+  ///
+  /// Accounts for nullability that is only captured as sugar within the type
+  /// system, as well as when it is part of the canonical type.
+  std::optional<NullabilityKind> getNullability() const;
+
 private:
   // These methods are implemented in a separate translation unit;
   // "static"-ize them to avoid creating temporary QualTypes in the
Index: clang/include/clang/AST/ASTContext.h
===================================================================
--- clang/include/clang/AST/ASTContext.h
+++ clang/include/clang/AST/ASTContext.h
@@ -2558,8 +2558,8 @@
 
   bool hasSameNullabilityTypeQualifier(QualType SubT, QualType SuperT,
                                        bool IsParam) const {
-    auto SubTnullability = SubT->getNullability();
-    auto SuperTnullability = SuperT->getNullability();
+    auto SubTnullability = SubT.getNullability();
+    auto SuperTnullability = SuperT.getNullability();
     if (SubTnullability.has_value() == SuperTnullability.has_value()) {
       // Neither has nullability; return true
       if (!SubTnullability)
Index: clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
+++ clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
@@ -918,7 +918,7 @@
   auto AST = TU.build();
   EXPECT_THAT(*AST.getDiagnostics(), IsEmpty());
   const auto *X = cast<FunctionDecl>(findDecl(AST, "foo")).getParamDecl(0);
-  ASSERT_TRUE(X->getOriginalType()->getNullability() ==
+  ASSERT_TRUE(X->getOriginalType().getNullability() ==
               NullabilityKind::NonNull);
 }
 
@@ -936,10 +936,10 @@
   EXPECT_THAT(*AST.getDiagnostics(),
               ElementsAre(diagName("pp_eof_in_assume_nonnull")));
   const auto *X = cast<FunctionDecl>(findDecl(AST, "foo")).getParamDecl(0);
-  ASSERT_TRUE(X->getOriginalType()->getNullability() ==
+  ASSERT_TRUE(X->getOriginalType().getNullability() ==
               NullabilityKind::NonNull);
   const auto *Y = cast<FunctionDecl>(findDecl(AST, "bar")).getParamDecl(0);
-  ASSERT_FALSE(Y->getOriginalType()->getNullability());
+  ASSERT_FALSE(Y->getOriginalType().getNullability());
 }
 
 TEST(DiagnosticsTest, InsideMacros) {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D142736: Add Qu... Christopher Bazley via Phabricator via cfe-commits

Reply via email to