]> granicus.if.org Git - clang/commitdiff
Look for and diagnose missing sentinel argument on message
authorFariborz Jahanian <fjahanian@apple.com>
Wed, 13 May 2009 23:20:50 +0000 (23:20 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Wed, 13 May 2009 23:20:50 +0000 (23:20 +0000)
dispatch arguments which have sentinel attribute.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@71737 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaDeclAttr.cpp
lib/Sema/SemaExpr.cpp
test/SemaObjC/method-sentinel-attr.m [new file with mode: 0644]

index 299299df2e44fff846b6d316160db31d2c405305..79299a4700bafc9e71c83d070ef0ccaaf1b472c4 100644 (file)
@@ -763,6 +763,12 @@ def warn_deprecated : Warning<"%0 is deprecated">,
 def warn_unavailable : Warning<"%0 is unavailable">;
 def note_unavailable_here : Note<
   "function has been explicitly marked %select{unavailable|deleted}0 here">;
+def warn_not_enough_argument : Warning<
+  "not enough variable arguments in %0 declaration to fit a sentinel">;
+def warn_missing_sentinel : Warning <
+  "missing sentinel in method dispatch">;
+def note_sentinel_here : Note<
+  "method has been explicitly marked sentinel here">;
 def warn_missing_prototype : Warning<
   "no previous prototype for function %0">,
   InGroup<DiagGroup<"missing-prototypes">>, DefaultIgnore;
index 4d054fb8e03e340aa605e5ea07fed9084b55f181..7606e84d527014bd703301d7dac6c7084b83c127 100644 (file)
@@ -725,8 +725,7 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
       << Attr.getName() << 3 /*function or method*/;
     return;
   }
-  
-  // FIXME: Actually create the attribute.
+  d->addAttr(::new (S.Context) SentinelAttr(sentinel, nullPos));
 }
 
 static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S) {
index f1da408669ca1e72196a2936cbee0f3ca224251e..a1c170cf2846c79f205dcea7451563d3455e383a 100644 (file)
@@ -95,6 +95,50 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) {
 void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
                                  Expr **Args, unsigned NumArgs)
 {
+  const SentinelAttr *attr = D->getAttr<SentinelAttr>();
+  if (!attr) 
+    return;
+  ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D);
+  // FIXME: function calls for later.
+  if (!MD)
+    return;
+  int sentinelPos = attr->getSentinel();
+  int nullPos = attr->getNullPos();
+  // skip over named parameters.
+  ObjCMethodDecl::param_iterator P, E = MD->param_end();
+  unsigned int i = 0;
+  for (P = MD->param_begin(); (P != E && i < NumArgs); ++P) {
+    if (nullPos)
+      --nullPos;
+    else
+      ++i;
+  }
+  if (P != E || i >= NumArgs) {
+    Diag(Loc, diag::warn_not_enough_argument) << D->getDeclName();
+    Diag(D->getLocation(), diag::note_sentinel_here);
+    return;
+  }
+  int sentinel = i;
+  while (sentinelPos > 0 && i < NumArgs-1) {
+    --sentinelPos;
+    ++i;
+  }
+  if (sentinelPos > 0) {
+    Diag(Loc, diag::warn_not_enough_argument) << D->getDeclName();
+    Diag(D->getLocation(), diag::note_sentinel_here);
+    return;
+  }
+  while (i < NumArgs-1) {
+    ++i;
+    ++sentinel;
+  }
+  Expr *sentinelExpr = Args[sentinel];
+  if (sentinelExpr && (!sentinelExpr->getType()->isPointerType() ||
+                       !sentinelExpr->isNullPointerConstant(Context))) {
+    Diag(Loc, diag::warn_missing_sentinel);
+    Diag(D->getLocation(), diag::note_sentinel_here);
+  }
+  return;
 }
 
 SourceRange Sema::getExprRange(ExprTy *E) const {
diff --git a/test/SemaObjC/method-sentinel-attr.m b/test/SemaObjC/method-sentinel-attr.m
new file mode 100644 (file)
index 0000000..8f31e9a
--- /dev/null
@@ -0,0 +1,37 @@
+// RUN: clang-cc  -fsyntax-only -verify %s
+
+#define NULL (void*)0
+
+#define ATTR __attribute__ ((__sentinel__)) 
+
+@interface INTF
+- (void) foo1 : (int)x, ... ATTR; // expected-note {{method has been explicitly marked sentinel here}}
+- (void) foo3 : (int)x __attribute__ ((__sentinel__)) ; // expected-warning {{'sentinel' attribute only supported for variadic functions}}
+- (void) foo5 : (int)x, ... __attribute__ ((__sentinel__(1))); // expected-note {{method has been explicitly marked sentinel here}}
+- (void) foo6 : (int)x, ... __attribute__ ((__sentinel__(5))); // expected-note {{method has been explicitly marked sentinel here}}
+- (void) foo7 : (int)x, ... __attribute__ ((__sentinel__(0))); // expected-note {{method has been explicitly marked sentinel here}}
+- (void) foo8 : (int)x, ... __attribute__ ((__sentinel__("a")));  // expected-error {{'sentinel' attribute requires parameter 1 to be an integer constant}}
+- (void) foo9 : (int)x, ... __attribute__ ((__sentinel__(-1)));  // expected-error {{'sentinel' parameter 1 less than zero}}
+- (void) foo10 : (int)x, ... __attribute__ ((__sentinel__(1,1)));
+- (void) foo11 : (int)x, ... __attribute__ ((__sentinel__(1,1,3)));  // expected-error {{attribute requires 0, 1 or 2 argument(s)}}
+- (void) foo12 : (int)x, ... ATTR; // expected-note {{method has been explicitly marked sentinel here}}
+@end
+
+int main ()
+{
+  INTF *p;
+
+  [p foo1:1, NULL]; // OK
+  [p foo1:1, 0];  // expected-warning {{missing sentinel in method dispatch}}
+  [p foo5:1, NULL, 2]; // OK
+  [p foo5:1, 2, NULL, 1]; // OK
+  [p foo5:1, NULL, 2, 1];  // expected-warning {{missing sentinel in method dispatch}}
+
+  [p foo6:1,2,3,4,5,6,7];  // expected-warning {{missing sentinel in method dispatch}}
+  [p foo6:1,NULL,3,4,5,6,7]; // OK
+  [p foo7:1];   // expected-warning {{not enough variable arguments in 'foo7:' declaration to fit a sentinel}}
+  [p foo7:1, NULL]; // ok
+
+  [p foo12:1]; // expected-warning {{not enough variable arguments in 'foo12:' declaration to fit a sentinel}}
+}