r240158 - Check for consistent use of nullability type specifiers in a header.

Douglas Gregor dgregor at apple.com
Fri Jun 19 11:27:46 PDT 2015


Author: dgregor
Date: Fri Jun 19 13:27:45 2015
New Revision: 240158

URL: http://llvm.org/viewvc/llvm-project?rev=240158&view=rev
Log:
Check for consistent use of nullability type specifiers in a header.

Adds a new warning (under -Wnullability-completeness) that complains
about pointer, block pointer, or member pointer declarations that have
not been annotated with nullability information (directly or inferred)
within a header that contains some nullability annotations. This is
intended to be used to help maintain the completeness of nullability
information within a header that has already been audited.

Note that, for performance reasons, this warning will underrepresent
the number of non-annotated pointers in the case where more than one
pointer is seen before the first nullability type specifier, because
we're only tracking one piece of information per header. Part of
rdar://problem/18868820.

Added:
    cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-1.h   (with props)
    cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-2.h   (with props)
    cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-3.h   (with props)
    cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-4.h   (with props)
    cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-5.h   (with props)
    cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-6.h   (with props)
    cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-7.h   (with props)
    cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-8.h   (with props)
    cfe/trunk/test/SemaObjCXX/nullability-consistency.mm
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticGroups.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/AttributeList.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Parse/ParseObjc.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-1.h
    cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=240158&r1=240157&r2=240158&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Fri Jun 19 13:27:45 2015
@@ -251,6 +251,7 @@ def NewlineEOF : DiagGroup<"newline-eof"
 def Nullability : DiagGroup<"nullability">;
 def NullabilityDeclSpec : DiagGroup<"nullability-declspec">;
 def NullableToNonNullConversion : DiagGroup<"nullable-to-nonnull-conversion">;
+def NullabilityCompleteness : DiagGroup<"nullability-completeness">;
 def NullArithmetic : DiagGroup<"null-arithmetic">;
 def NullCharacter : DiagGroup<"null-character">;
 def NullDereference : DiagGroup<"null-dereference">;

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=240158&r1=240157&r2=240158&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Jun 19 13:27:45 2015
@@ -7718,6 +7718,11 @@ def warn_null_resettable_setter : Warnin
   "synthesized setter %0 for null_resettable property %1 does not handle nil">,
   InGroup<Nullability>;
 
+def warn_nullability_missing : Warning<
+  "%select{pointer|block pointer|member pointer}0 is missing a nullability "
+  "type specifier (__nonnull, __nullable, or __null_unspecified)">,
+  InGroup<NullabilityCompleteness>;
+
 }
 
 } // end of sema component.

Modified: cfe/trunk/include/clang/Sema/AttributeList.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/AttributeList.h?rev=240158&r1=240157&r2=240158&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/AttributeList.h (original)
+++ cfe/trunk/include/clang/Sema/AttributeList.h Fri Jun 19 13:27:45 2015
@@ -81,6 +81,8 @@ public:
     AS_Declspec,
     /// __ptr16, alignas(...), etc.
     AS_Keyword,
+    /// Context-sensitive version of a keyword attribute.
+    AS_ContextSensitiveKeyword,
     /// #pragma ...
     AS_Pragma
   };
@@ -120,9 +122,6 @@ private:
   /// True if this has a ParsedType
   unsigned HasParsedType : 1;
 
-  /// True when this keyword attribute is a context-sensitive keyword.
-  unsigned IsContextSensitiveKeyword : 1;
-
   unsigned AttrKind : 8;
 
   /// \brief The location of the 'unavailable' keyword in an
@@ -223,8 +222,7 @@ private:
       ScopeLoc(scopeLoc), EllipsisLoc(ellipsisLoc), NumArgs(numArgs),
       SyntaxUsed(syntaxUsed), Invalid(false), UsedAsTypeAttr(false),
       IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(false),
-      HasParsedType(false), IsContextSensitiveKeyword(false),
-      NextInPosition(nullptr), NextInPool(nullptr) {
+      HasParsedType(false), NextInPosition(nullptr), NextInPool(nullptr) {
     if (numArgs) memcpy(getArgsBuffer(), args, numArgs * sizeof(ArgsUnion));
     AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
   }
@@ -242,8 +240,8 @@ private:
       ScopeLoc(scopeLoc), EllipsisLoc(), NumArgs(1), SyntaxUsed(syntaxUsed),
       Invalid(false), UsedAsTypeAttr(false), IsAvailability(true),
       IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(false),
-      IsContextSensitiveKeyword(false), UnavailableLoc(unavailable),
-      MessageExpr(messageExpr), NextInPosition(nullptr), NextInPool(nullptr) {
+      UnavailableLoc(unavailable), MessageExpr(messageExpr),
+      NextInPosition(nullptr), NextInPool(nullptr) {
     ArgsUnion PVal(Parm);
     memcpy(getArgsBuffer(), &PVal, sizeof(ArgsUnion));
     new (&getAvailabilitySlot(IntroducedSlot)) AvailabilityChange(introduced);
@@ -263,8 +261,7 @@ private:
     ScopeLoc(scopeLoc), EllipsisLoc(), NumArgs(3), SyntaxUsed(syntaxUsed),
     Invalid(false), UsedAsTypeAttr(false), IsAvailability(false),
     IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(false),
-    IsContextSensitiveKeyword(false), NextInPosition(nullptr),
-    NextInPool(nullptr) {
+    NextInPosition(nullptr), NextInPool(nullptr) {
     ArgsVector Args;
     Args.push_back(Parm1);
     Args.push_back(Parm2);
@@ -282,8 +279,7 @@ private:
       ScopeLoc(scopeLoc), EllipsisLoc(), NumArgs(1), SyntaxUsed(syntaxUsed),
       Invalid(false), UsedAsTypeAttr(false), IsAvailability(false),
       IsTypeTagForDatatype(true), IsProperty(false), HasParsedType(false),
-      IsContextSensitiveKeyword(false), NextInPosition(nullptr),
-      NextInPool(nullptr) {
+      NextInPosition(nullptr), NextInPool(nullptr) {
     ArgsUnion PVal(ArgKind);
     memcpy(getArgsBuffer(), &PVal, sizeof(ArgsUnion));
     TypeTagForDatatypeData &ExtraData = getTypeTagForDatatypeDataSlot();
@@ -301,8 +297,7 @@ private:
         ScopeLoc(scopeLoc), EllipsisLoc(), NumArgs(0), SyntaxUsed(syntaxUsed),
         Invalid(false), UsedAsTypeAttr(false), IsAvailability(false),
         IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(true),
-        IsContextSensitiveKeyword(false), NextInPosition(nullptr),
-        NextInPool(nullptr) {
+        NextInPosition(nullptr), NextInPool(nullptr) {
     new (&getTypeBuffer()) ParsedType(typeArg);
     AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
   }
@@ -316,8 +311,7 @@ private:
       ScopeLoc(scopeLoc), EllipsisLoc(), NumArgs(0), SyntaxUsed(syntaxUsed),
       Invalid(false), UsedAsTypeAttr(false), IsAvailability(false),
       IsTypeTagForDatatype(false), IsProperty(true), HasParsedType(false),
-      IsContextSensitiveKeyword(false), NextInPosition(nullptr),
-      NextInPool(nullptr) {
+      NextInPosition(nullptr), NextInPool(nullptr) {
     new (&getPropertyDataBuffer()) PropertyData(getterId, setterId);
     AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
   }
@@ -351,22 +345,19 @@ public:
 
   bool isAlignasAttribute() const {
     // FIXME: Use a better mechanism to determine this.
-    return getKind() == AT_Aligned && SyntaxUsed == AS_Keyword;
+    return getKind() == AT_Aligned && isKeywordAttribute();
   }
 
   bool isDeclspecAttribute() const { return SyntaxUsed == AS_Declspec; }
   bool isCXX11Attribute() const {
     return SyntaxUsed == AS_CXX11 || isAlignasAttribute();
   }
-  bool isKeywordAttribute() const { return SyntaxUsed == AS_Keyword; }
-
-  bool isContextSensitiveKeywordAttribute() const {
-    return IsContextSensitiveKeyword;
+  bool isKeywordAttribute() const {
+    return SyntaxUsed == AS_Keyword || SyntaxUsed == AS_ContextSensitiveKeyword;
   }
 
-  void setContextSensitiveKeywordAttribute() {
-    assert(SyntaxUsed == AS_Keyword);
-    IsContextSensitiveKeyword = true;
+  bool isContextSensitiveKeywordAttribute() const {
+    return SyntaxUsed == AS_ContextSensitiveKeyword;
   }
 
   bool isInvalid() const { return Invalid; }

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=240158&r1=240157&r2=240158&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Jun 19 13:27:45 2015
@@ -210,6 +210,50 @@ namespace threadSafety {
 typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType*, NamedDecl*>,
                   SourceLocation> UnexpandedParameterPack;
 
+/// Describes whether we've seen any nullability information for the given
+/// file.
+struct FileNullability {
+  /// The first pointer declarator (of any pointer kind) in the file that does
+  /// not have a corresponding nullability annotation.
+  SourceLocation PointerLoc;
+
+  /// Which kind of pointer declarator we saw.
+  uint8_t PointerKind;
+
+  /// Whether we saw any type nullability annotations in the given file.
+  bool SawTypeNullability = false;
+};
+
+/// A mapping from file IDs to a record of whether we've seen nullability
+/// information in that file.
+class FileNullabilityMap {
+  /// A mapping from file IDs to the nullability information for each file ID.
+  llvm::DenseMap<FileID, FileNullability> Map;
+
+  /// A single-element cache based on the file ID.
+  struct {
+    FileID File;
+    FileNullability Nullability;
+  } Cache;
+
+public:
+  FileNullability &operator[](FileID file) {
+    // Check the single-element cache.
+    if (file == Cache.File)
+      return Cache.Nullability;
+
+    // It's not in the single-element cache; flush the cache if we have one.
+    if (!Cache.File.isInvalid()) {
+      Map[Cache.File] = Cache.Nullability;
+    }
+
+    // Pull this entry into the cache.
+    Cache.File = file;
+    Cache.Nullability = Map[file];
+    return Cache.Nullability;
+  }
+};
+
 /// Sema - This implements semantic analysis and AST building for C.
 class Sema {
   Sema(const Sema &) = delete;
@@ -341,6 +385,9 @@ public:
   PragmaStack<StringLiteral *> ConstSegStack;
   PragmaStack<StringLiteral *> CodeSegStack;
 
+  /// A mapping that describes the nullability we've seen in each header file.
+  FileNullabilityMap NullabilityMap;
+
   /// Last section used with #pragma init_seg.
   StringLiteral *CurInitSeg;
   SourceLocation CurInitSegLoc;

Modified: cfe/trunk/lib/Parse/ParseObjc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=240158&r1=240157&r2=240158&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseObjc.cpp (original)
+++ cfe/trunk/lib/Parse/ParseObjc.cpp Fri Jun 19 13:27:45 2015
@@ -317,14 +317,12 @@ static void addContextSensitiveTypeNulla
                                                bool &addedToDeclSpec) {
   // Create the attribute.
   auto getNullabilityAttr = [&]() -> AttributeList * {
-    auto attr = D.getAttributePool().create(
-                  P.getNullabilityKeyword(nullability),
-                  SourceRange(nullabilityLoc),
-                  nullptr, SourceLocation(),
-                  nullptr, 0,
-                  AttributeList::AS_Keyword);
-    attr->setContextSensitiveKeywordAttribute();
-    return attr;
+    return D.getAttributePool().create(
+             P.getNullabilityKeyword(nullability),
+             SourceRange(nullabilityLoc),
+             nullptr, SourceLocation(),
+             nullptr, 0,
+             AttributeList::AS_ContextSensitiveKeyword);
   };
 
   if (D.getNumTypeObjects() > 0) {

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=240158&r1=240157&r2=240158&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Fri Jun 19 13:27:45 2015
@@ -2759,6 +2759,71 @@ static PointerDeclaratorKind classifyPoi
   }
 }
 
+static FileID getNullabilityCompletenessCheckFileID(Sema &S,
+                                                    SourceLocation loc) {
+  // If we're anywhere in a function, method, or closure context, don't perform
+  // completeness checks.
+  for (DeclContext *ctx = S.CurContext; ctx; ctx = ctx->getParent()) {
+    if (ctx->isFunctionOrMethod())
+      return FileID();
+
+    if (ctx->isFileContext())
+      break;
+  }
+
+  // We only care about the expansion location.
+  loc = S.SourceMgr.getExpansionLoc(loc);
+  FileID file = S.SourceMgr.getFileID(loc);
+  if (file.isInvalid())
+    return FileID();
+
+  // Retrieve file information.
+  bool invalid = false;
+  const SrcMgr::SLocEntry &sloc = S.SourceMgr.getSLocEntry(file, &invalid);
+  if (invalid || !sloc.isFile())
+    return FileID();
+
+  // We don't want to perform completeness checks on the main file or in
+  // system headers.
+  const SrcMgr::FileInfo &fileInfo = sloc.getFile();
+  if (fileInfo.getIncludeLoc().isInvalid() ||
+      fileInfo.getFileCharacteristic() != SrcMgr::C_User)
+    return FileID();
+
+  return file;
+}
+
+/// Check for consistent use of nullability.
+static void checkNullabilityConsistency(TypeProcessingState &state,
+                                        SimplePointerKind pointerKind,
+                                        SourceLocation pointerLoc) {
+  Sema &S = state.getSema();
+
+  // Determine which file we're performing consistency checking for.
+  FileID file = getNullabilityCompletenessCheckFileID(S, pointerLoc);
+  if (file.isInvalid())
+    return;
+
+  // If we haven't seen any type nullability in this file, we won't warn now
+  // about anything.
+  FileNullability &fileNullability = S.NullabilityMap[file];
+  if (!fileNullability.SawTypeNullability) {
+    // If this is the first pointer declarator in the file, record it.
+    if (fileNullability.PointerLoc.isInvalid() &&
+        !S.Context.getDiagnostics().isIgnored(diag::warn_nullability_missing,
+                                              pointerLoc)) {
+      fileNullability.PointerLoc = pointerLoc;
+      fileNullability.PointerKind = static_cast<unsigned>(pointerKind);
+    }
+
+    return;
+  }
+
+  // Complain about missing nullability.
+  S.Diag(pointerLoc, diag::warn_nullability_missing)
+    << static_cast<unsigned>(pointerKind);
+}
+
 static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
                                                 QualType declSpecType,
                                                 TypeSourceInfo *TInfo) {
@@ -2836,6 +2901,22 @@ static TypeSourceInfo *GetFullTypeForDec
       !state.getDeclarator().isObjCWeakProperty() &&
       !S.deduceWeakPropertyFromType(T)) {
     inAssumeNonNullRegion = true;
+    // Determine which file we saw the assume-nonnull region in.
+    FileID file = getNullabilityCompletenessCheckFileID(
+                    S, S.PP.getPragmaAssumeNonNullLoc());
+    if (!file.isInvalid()) {
+      FileNullability &fileNullability = S.NullabilityMap[file];
+
+      // If we haven't seen any type nullability before, now we have.
+      if (!fileNullability.SawTypeNullability) {
+        if (fileNullability.PointerLoc.isValid()) {
+          S.Diag(fileNullability.PointerLoc, diag::warn_nullability_missing)
+              << fileNullability.PointerKind;
+        }
+
+        fileNullability.SawTypeNullability = true;
+      }
+    }
   }
 
   // Whether to complain about missing nullability specifiers or not.
@@ -2857,7 +2938,7 @@ static TypeSourceInfo *GetFullTypeForDec
     // inner pointers.
     complainAboutMissingNullability = CAMN_InnerPointers;
 
-    if (T->canHaveNullability()) {
+    if (T->canHaveNullability() && !T->getNullability(S.Context)) {
       ++NumPointersRemaining;
     }
 
@@ -2967,27 +3048,42 @@ static TypeSourceInfo *GetFullTypeForDec
 
     // If we're supposed to infer nullability, do so now.
     if (inferNullability) {
+      auto syntax = inferNullabilityCS ? AttributeList::AS_ContextSensitiveKeyword
+                                       : AttributeList::AS_Keyword;
       AttributeList *nullabilityAttr = state.getDeclarator().getAttributePool()
                                          .create(
                                            S.getNullabilityKeyword(
                                              *inferNullability),
                                            SourceRange(pointerLoc),
                                            nullptr, SourceLocation(),
-                                           nullptr, 0,
-                                           AttributeList::AS_Keyword);
-      if (inferNullabilityCS)
-        nullabilityAttr->setContextSensitiveKeywordAttribute();
+                                           nullptr, 0, syntax);
 
       spliceAttrIntoList(*nullabilityAttr, attrs);
       return nullabilityAttr;
     }
 
+    // If we're supposed to complain about missing nullability, do so
+    // now if it's truly missing.
+    switch (complainAboutMissingNullability) {
+    case CAMN_No:
+      break;
+
+    case CAMN_InnerPointers:
+      if (NumPointersRemaining == 0)
+        break;
+      // Fallthrough.
+
+    case CAMN_Yes:
+      checkNullabilityConsistency(state, pointerKind, pointerLoc);
+    }
+
     return nullptr;
   };
 
   // If the type itself could have nullability but does not, infer pointer
-  // nullability.
-  if (T->canHaveNullability() && S.ActiveTemplateInstantiations.empty()) {
+  // nullability and perform consistency checking.
+  if (T->canHaveNullability() && S.ActiveTemplateInstantiations.empty() &&
+      !T->getNullability(S.Context)) {
     SimplePointerKind pointerKind = SimplePointerKind::Pointer;
     if (T->isBlockPointerType())
       pointerKind = SimplePointerKind::BlockPointer;
@@ -4919,10 +5015,27 @@ static bool handleMSPointerTypeQualifier
   return false;
 }
 
-bool Sema::checkNullabilityTypeSpecifier(QualType &type, 
+bool Sema::checkNullabilityTypeSpecifier(QualType &type,
                                          NullabilityKind nullability,
                                          SourceLocation nullabilityLoc,
                                          bool isContextSensitive) {
+  // We saw a nullability type specifier. If this is the first one for
+  // this file, note that.
+  FileID file = getNullabilityCompletenessCheckFileID(*this, nullabilityLoc);
+  if (!file.isInvalid()) {
+    FileNullability &fileNullability = NullabilityMap[file];
+    if (!fileNullability.SawTypeNullability) {
+      // If we have already seen a pointer declarator without a nullability
+      // annotation, complain about it.
+      if (fileNullability.PointerLoc.isValid()) {
+        Diag(fileNullability.PointerLoc, diag::warn_nullability_missing)
+          << fileNullability.PointerKind;
+      }
+
+      fileNullability.SawTypeNullability = true;
+    }
+  }
+
   // Check for existing nullability attributes on the type.
   QualType desugared = type;
   while (auto attributed = dyn_cast<AttributedType>(desugared.getTypePtr())) {

Added: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-1.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-1.h?rev=240158&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-1.h (added)
+++ cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-1.h Fri Jun 19 13:27:45 2015
@@ -0,0 +1,17 @@
+void f1(int *ptr); // expected-warning{{pointer is missing a nullability type specifier}}
+
+void f2(int * __nonnull);
+
+#include "nullability-consistency-2.h"
+
+void f3(int *ptr) { // expected-warning{{pointer is missing a nullability type specifier}}
+  int *other = ptr; // shouldn't warn
+}
+
+class X {
+  void mf(int *ptr); // expected-warning{{pointer is missing a nullability type specifier}}
+  int X:: *memptr; // expected-warning{{member pointer is missing a nullability type specifier}}
+};
+
+
+

Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-1.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-1.h
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-1.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-2.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-2.h?rev=240158&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-2.h (added)
+++ cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-2.h Fri Jun 19 13:27:45 2015
@@ -0,0 +1,16 @@
+void g1(int * __nonnull);
+
+void g2(int (^block)(int, int)); // expected-warning{{block pointer is missing a nullability type specifier}}
+
+void g3(const
+        id // expected-warning{{missing a nullability type specifier}}
+        volatile
+        * // expected-warning{{missing a nullability type specifier}}
+        ); 
+
+ at interface SomeClass
+ at property (retain,nonnull) id property1;
+ at property (retain,nullable) SomeClass *property2;
+- (nullable SomeClass *)method1;
+- (void)method2:(nonnull SomeClass *)param;
+ at end

Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-2.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-2.h
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-2.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-3.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-3.h?rev=240158&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-3.h (added)
+++ cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-3.h Fri Jun 19 13:27:45 2015
@@ -0,0 +1 @@
+void double_declarator1(int *__nonnull *); // expected-warning{{pointer is missing a nullability type specifier (__nonnull, __nullable, or __null_unspecified)}}

Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-3.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-3.h
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-3.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-4.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-4.h?rev=240158&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-4.h (added)
+++ cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-4.h Fri Jun 19 13:27:45 2015
@@ -0,0 +1 @@
+void double_declarator1(int * * __nonnull); // expected-warning{{pointer is missing a nullability type specifier (__nonnull, __nullable, or __null_unspecified)}}

Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-4.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-4.h
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-4.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-5.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-5.h?rev=240158&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-5.h (added)
+++ cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-5.h Fri Jun 19 13:27:45 2015
@@ -0,0 +1,14 @@
+#define SUPPRESS_NULLABILITY_WARNING(Type)                              \
+  _Pragma("clang diagnostic push")                                      \
+  _Pragma("clang diagnostic ignored \"-Wnullability-completeness\"")    \
+  Type                                                                  \
+  _Pragma("clang diagnostic pop")
+
+void suppress1(SUPPRESS_NULLABILITY_WARNING(int *) ptr); // no warning
+
+void shouldwarn5(int *ptr); //expected-warning{{missing a nullability type specifier}}
+
+void trigger5(int * __nonnull);
+
+void suppress2(SUPPRESS_NULLABILITY_WARNING(int *) ptr); // no warning
+

Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-5.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-5.h
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-5.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-6.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-6.h?rev=240158&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-6.h (added)
+++ cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-6.h Fri Jun 19 13:27:45 2015
@@ -0,0 +1,8 @@
+int *ptr; // expected-warning {{missing a nullability type specifier}}
+
+#pragma clang assume_nonnull begin
+
+extern void **blah; // expected-warning 2{{missing a nullability type specifier}}
+
+#pragma clang assume_nonnull end
+

Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-6.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-6.h
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-6.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-7.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-7.h?rev=240158&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-7.h (added)
+++ cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-7.h Fri Jun 19 13:27:45 2015
@@ -0,0 +1,40 @@
+#ifndef SOMEKIT_H
+#define SOMEKIT_H
+
+__attribute__((objc_root_class))
+#ifndef NS_ASSUME_NONNULL_BEGIN
+#if __has_feature(assume_nonnull)
+#define NS_ASSUME_NONNULL_BEGIN _Pragma("clang assume_nonnull begin")
+#define NS_ASSUME_NONNULL_END _Pragma("clang assume_nonnull end")
+#else
+#define NS_ASSUME_NONNULL_BEGIN
+#define NS_ASSUME_NONNULL_END
+#endif
+#endif
+
+NS_ASSUME_NONNULL_BEGIN
+
+ at interface A
+-(null_unspecified A*)transform:(null_unspecified A*)input __attribute__((unavailable("anything but this")));
+-(A*)transform:(A*)input integer:(int)integer;
+
+ at property (null_unspecified, nonatomic, readonly, retain) A* someA;
+ at property (null_unspecified, nonatomic, retain) A* someOtherA;
+
+ at property (nonatomic) int intValue __attribute__((unavailable("wouldn't work anyway")));
+ at end
+
+NS_ASSUME_NONNULL_END
+
+
+__attribute__((unavailable("just don't")))
+ at interface B : A
+ at end
+
+ at interface C : A
+- (instancetype)init; // expected-warning{{pointer is missing a nullability type specifier}}
+- (instancetype)initWithA:( A*)a __attribute__((objc_designated_initializer)); // expected-warning 2{{pointer is missing a nullability type specifier}}
+ at end
+
+#endif
+

Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-7.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-7.h
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-7.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-8.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-8.h?rev=240158&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-8.h (added)
+++ cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-8.h Fri Jun 19 13:27:45 2015
@@ -0,0 +1,11 @@
+typedef int* __nonnull mynonnull;
+
+__attribute__((objc_root_class))
+ at interface typedefClass
+- (void) func1:(mynonnull)i;
+ at end
+
+void func2(mynonnull i);
+
+void func3(int *); // expected-warning{{pointer is missing a nullability type specifier}}
+

Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-8.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-8.h
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-consistency-8.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-1.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-1.h?rev=240158&r1=240157&r2=240158&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-1.h (original)
+++ cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-1.h Fri Jun 19 13:27:45 2015
@@ -8,7 +8,7 @@ __attribute__((objc_root_class))
 
 struct X { };
 
-void f1(int *x);
+void f1(int *x); // expected-warning{{pointer is missing a nullability type specifier}}
 
 typedef struct __attribute__((objc_bridge(NSError))) __CFError *CFErrorRef;
 typedef NSError *NSErrorPtr;
@@ -38,14 +38,16 @@ A *f14(void);
 int * __null_unspecified f15(void);
 A * __null_unspecified f16(void);
 void f17(CFErrorRef *error); // expected-note{{no known conversion from 'A * __nonnull' to 'CFErrorRef  __nullable * __nullable' (aka '__CFError **') for 1st argument}}
-void f18(A **);
-void f19(CFErrorRefPtr error);
+void f18(A **); // expected-warning 2{{pointer is missing a nullability type specifier}}
+void f19(CFErrorRefPtr error); // expected-warning{{pointer is missing a nullability type specifier}}
 
 void g1(int (^)(int, int));
-void g2(int (^ *bp)(int, int));
-void g3(block_ptr *bp);
+void g2(int (^ *bp)(int, int)); // expected-warning{{block pointer is missing a nullability type specifier}}
+// expected-warning at -1{{pointer is missing a nullability type specifier}}
+void g3(block_ptr *bp); // expected-warning{{block pointer is missing a nullability type specifier}}
+// expected-warning at -1{{pointer is missing a nullability type specifier}}
 void g4(int (*fp)(int, int));
-void g5(int (**fp)(int, int));
+void g5(int (**fp)(int, int)); // expected-warning 2{{pointer is missing a nullability type specifier}}
 
 @interface A(Pragmas1)
 + (instancetype)aWithA:(A *)a;
@@ -54,9 +56,10 @@ void g5(int (**fp)(int, int));
 - (void)method3:(NSError **)error; // expected-note{{passing argument to parameter 'error' here}}
 - (void)method4:(NSErrorPtr *)error; // expected-note{{passing argument to parameter 'error' here}}
 - (void)method5:(NSErrorPtrPtr)error;
+// expected-warning at -1{{pointer is missing a nullability type specifier}}
 
 @property A *aProp;
- at property NSError **anError;
+ at property NSError **anError; // expected-warning 2{{pointer is missing a nullability type specifier}}
 @end
 
 int *global_int_ptr;
@@ -64,7 +67,7 @@ int *global_int_ptr;
 // typedefs not inferred __nonnull
 typedef int *int_ptr_2;
 
-typedef int *
+typedef int * // expected-warning{{pointer is missing a nullability type specifier}}
             *int_ptr_ptr;
 
 static inline void f30(void) {
@@ -86,13 +89,13 @@ static inline void f30(void) {
 
 #pragma clang assume_nonnull end
 
-void f20(A *a);
-void f21(int_ptr x);
-void f22(A_ptr y);
+void f20(A *a); // expected-warning{{pointer is missing a nullability type specifier}}
+void f21(int_ptr x); // expected-warning{{pointer is missing a nullability type specifier}}
+void f22(A_ptr y); // expected-warning{{pointer is missing a nullability type specifier}}
 void f23(int_ptr __nullable x);
 void f24(A_ptr __nullable y);
-void f25(int_ptr_2 x);
+void f25(int_ptr_2 x); // expected-warning{{pointer is missing a nullability type specifier}}
 
 @interface A(OutsidePragmas1)
-+ (instancetype)aWithInt:(int)value;
++ (instancetype)aWithInt:(int)value; // expected-warning{{pointer is missing a nullability type specifier}}
 @end

Added: cfe/trunk/test/SemaObjCXX/nullability-consistency.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/nullability-consistency.mm?rev=240158&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/nullability-consistency.mm (added)
+++ cfe/trunk/test/SemaObjCXX/nullability-consistency.mm Fri Jun 19 13:27:45 2015
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -fsyntax-only -fblocks -I %S/Inputs %s -verify
+
+#include "nullability-consistency-1.h"
+#include "nullability-consistency-3.h"
+#include "nullability-consistency-4.h"
+#include "nullability-consistency-5.h"
+#include "nullability-consistency-5.h"
+#include "nullability-consistency-6.h"
+#include "nullability-consistency-7.h"
+#include "nullability-consistency-8.h"
+
+void h1(int *ptr) { } // don't warn
+
+void h2(int * __nonnull) { }

Modified: cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp?rev=240158&r1=240157&r2=240158&view=diff
==============================================================================
--- cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp (original)
+++ cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp Fri Jun 19 13:27:45 2015
@@ -2721,7 +2721,8 @@ void EmitClangAttrParsedAttrKinds(Record
   StringMatcher("Name", Declspec, OS).Emit();
   OS << "  } else if (AttributeList::AS_CXX11 == Syntax) {\n";
   StringMatcher("Name", CXX11, OS).Emit();
-  OS << "  } else if (AttributeList::AS_Keyword == Syntax) {\n";
+  OS << "  } else if (AttributeList::AS_Keyword == Syntax || ";
+  OS << "AttributeList::AS_ContextSensitiveKeyword == Syntax) {\n";
   StringMatcher("Name", Keywords, OS).Emit();
   OS << "  } else if (AttributeList::AS_Pragma == Syntax) {\n";
   StringMatcher("Name", Pragma, OS).Emit();





More information about the cfe-commits mailing list