Add the ns_consumes_self, ns_consumed, cf_consumed, and ns_returns_autoreleased
attributes for the benefit of the static analyzer.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124174 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index 49d3ab6..9b0982a 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -146,10 +146,17 @@
def CFReturnsRetained : InheritableAttr {
let Spellings = ["cf_returns_retained"];
+ let Subjects = [ObjCMethod, Function];
}
def CFReturnsNotRetained : InheritableAttr {
let Spellings = ["cf_returns_not_retained"];
+ let Subjects = [ObjCMethod, Function];
+}
+
+def CFConsumed : InheritableAttr {
+ let Spellings = ["cf_consumed"];
+ let Subjects = [ParmVar];
}
def Cleanup : InheritableAttr {
@@ -326,10 +333,27 @@
def NSReturnsRetained : InheritableAttr {
let Spellings = ["ns_returns_retained"];
+ let Subjects = [ObjCMethod, Function];
}
def NSReturnsNotRetained : InheritableAttr {
let Spellings = ["ns_returns_not_retained"];
+ let Subjects = [ObjCMethod, Function];
+}
+
+def NSReturnsAutoreleased : InheritableAttr {
+ let Spellings = ["ns_returns_autoreleased"];
+ let Subjects = [ObjCMethod, Function];
+}
+
+def NSConsumesSelf : InheritableAttr {
+ let Spellings = ["ns_consumes_self"];
+ let Subjects = [ObjCMethod];
+}
+
+def NSConsumed : InheritableAttr {
+ let Spellings = ["ns_consumed"];
+ let Subjects = [ParmVar];
}
def ObjCException : InheritableAttr {
@@ -337,7 +361,7 @@
}
def ObjCNSObject : InheritableAttr {
- let Spellings = ["NSOjbect"];
+ let Spellings = ["NSObject"];
}
def Overloadable : Attr {
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 0d26ac1..e29d098 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1040,15 +1040,15 @@
def warn_attribute_wrong_decl_type : Warning<
"%0 attribute only applies to %select{function|union|"
"variable and function|function or method|parameter|"
- "parameter or Objective-C method |function, method or block|"
+ "parameter or Objective-C method|function, method or block|"
"virtual method or class|function, method, or parameter|class|virtual method"
- "|member|variable}1 types">;
+ "|member|variable|method}1 types">;
def err_attribute_wrong_decl_type : Error<
"%0 attribute only applies to %select{function|union|"
"variable and function|function or method|parameter|"
- "parameter or Objective-C method |function, method or block|"
+ "parameter or Objective-C method|function, method or block|"
"virtual method or class|function, method, or parameter|class|virtual method"
- "|member|variable}1 types">;
+ "|member|variable|method}1 types">;
def warn_function_attribute_wrong_type : Warning<
"%0 only applies to function types; type here is %1">;
def warn_gnu_inline_attribute_requires_inline : Warning<
@@ -1179,8 +1179,11 @@
def err_attribute_overloadable_no_prototype : Error<
"'overloadable' function %0 must have a prototype">;
def warn_ns_attribute_wrong_return_type : Warning<
- "%0 attribute only applies to functions or methods that "
- "return a pointer or Objective-C object">;
+ "%0 attribute only applies to %select{functions|methods}1 that "
+ "return %select{an Objective-C object|a pointer}2">;
+def warn_ns_attribute_wrong_parameter_type : Warning<
+ "%0 attribute only applies to %select{Objective-C object|pointer}1 "
+ "parameters">;
// Function Parameter Semantic Analysis.
def err_param_with_void_type : Error<"argument may not have 'void' type">;
diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h
index 4326118..91389a4 100644
--- a/include/clang/Sema/AttributeList.h
+++ b/include/clang/Sema/AttributeList.h
@@ -129,6 +129,10 @@
AT_cf_returns_retained, // Clang-specific.
AT_ns_returns_not_retained, // Clang-specific.
AT_ns_returns_retained, // Clang-specific.
+ AT_ns_returns_autoreleased, // Clang-specific.
+ AT_cf_consumed, // Clang-specific.
+ AT_ns_consumed, // Clang-specific.
+ AT_ns_consumes_self, // Clang-specific.
AT_objc_gc,
AT_overloadable, // Clang-specific.
AT_ownership_holds, // Clang-specific.
diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp
index f5149a3..77d9625 100644
--- a/lib/Sema/AttributeList.cpp
+++ b/lib/Sema/AttributeList.cpp
@@ -105,8 +105,12 @@
.Case("analyzer_noreturn", AT_analyzer_noreturn)
.Case("warn_unused_result", AT_warn_unused_result)
.Case("carries_dependency", AT_carries_dependency)
+ .Case("ns_consumed", AT_ns_consumed)
+ .Case("ns_consumes_self", AT_ns_consumes_self)
+ .Case("ns_returns_autoreleased", AT_ns_returns_autoreleased)
.Case("ns_returns_not_retained", AT_ns_returns_not_retained)
.Case("ns_returns_retained", AT_ns_returns_retained)
+ .Case("cf_consumed", AT_cf_consumed)
.Case("cf_returns_not_retained", AT_cf_returns_not_retained)
.Case("cf_returns_retained", AT_cf_returns_retained)
.Case("ownership_returns", AT_ownership_returns)
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index dce229b..474c7cb 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -2441,48 +2441,116 @@
// Checker-specific attribute handlers.
//===----------------------------------------------------------------------===//
-static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr,
+static bool isValidSubjectOfNSAttribute(Sema &S, QualType type) {
+ return type->isObjCObjectPointerType() || S.Context.isObjCNSObjectType(type);
+}
+static bool isValidSubjectOfCFAttribute(Sema &S, QualType type) {
+ return type->isPointerType() || isValidSubjectOfNSAttribute(S, type);
+}
+
+static void HandleNSConsumedAttr(Decl *d, const AttributeList &attr, Sema &S) {
+ ParmVarDecl *param = dyn_cast<ParmVarDecl>(d);
+ if (!param) {
+ S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type)
+ << SourceRange(attr.getLoc()) << attr.getName() << 4 /*parameter*/;
+ return;
+ }
+
+ bool typeOK, cf;
+ if (attr.getKind() == AttributeList::AT_ns_consumed) {
+ typeOK = isValidSubjectOfNSAttribute(S, param->getType());
+ cf = false;
+ } else {
+ typeOK = isValidSubjectOfCFAttribute(S, param->getType());
+ cf = true;
+ }
+
+ if (!typeOK) {
+ S.Diag(d->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type)
+ << SourceRange(attr.getLoc()) << attr.getName() << cf;
+ return;
+ }
+
+ if (cf)
+ param->addAttr(::new (S.Context) CFConsumedAttr(attr.getLoc(), S.Context));
+ else
+ param->addAttr(::new (S.Context) NSConsumedAttr(attr.getLoc(), S.Context));
+}
+
+static void HandleNSConsumesSelfAttr(Decl *d, const AttributeList &attr,
+ Sema &S) {
+ if (!isa<ObjCMethodDecl>(d)) {
+ S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type)
+ << SourceRange(attr.getLoc()) << attr.getName() << 13 /*method*/;
+ return;
+ }
+
+ d->addAttr(::new (S.Context) NSConsumesSelfAttr(attr.getLoc(), S.Context));
+}
+
+static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &attr,
Sema &S) {
- QualType RetTy;
+ QualType returnType;
if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d))
- RetTy = MD->getResultType();
+ returnType = MD->getResultType();
else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(d))
- RetTy = FD->getResultType();
+ returnType = FD->getResultType();
else {
- SourceLocation L = Attr.getLoc();
S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type)
- << SourceRange(L, L) << Attr.getName() << 3 /* function or method */;
+ << SourceRange(attr.getLoc()) << attr.getName()
+ << 3 /* function or method */;
return;
}
- if (!(S.Context.isObjCNSObjectType(RetTy) || RetTy->getAs<PointerType>()
- || RetTy->getAs<ObjCObjectPointerType>())) {
- SourceLocation L = Attr.getLoc();
+ bool typeOK;
+ bool cf;
+ switch (attr.getKind()) {
+ default: llvm_unreachable("invalid ownership attribute"); return;
+ case AttributeList::AT_ns_returns_autoreleased:
+ case AttributeList::AT_ns_returns_retained:
+ case AttributeList::AT_ns_returns_not_retained:
+ typeOK = isValidSubjectOfNSAttribute(S, returnType);
+ cf = false;
+ break;
+
+ case AttributeList::AT_cf_returns_retained:
+ case AttributeList::AT_cf_returns_not_retained:
+ typeOK = isValidSubjectOfCFAttribute(S, returnType);
+ cf = true;
+ break;
+ }
+
+ if (!typeOK) {
S.Diag(d->getLocStart(), diag::warn_ns_attribute_wrong_return_type)
- << SourceRange(L, L) << Attr.getName();
+ << SourceRange(attr.getLoc())
+ << attr.getName() << isa<ObjCMethodDecl>(d) << cf;
return;
}
- switch (Attr.getKind()) {
+ switch (attr.getKind()) {
default:
assert(0 && "invalid ownership attribute");
return;
+ case AttributeList::AT_ns_returns_autoreleased:
+ d->addAttr(::new (S.Context) NSReturnsAutoreleasedAttr(attr.getLoc(),
+ S.Context));
+ return;
case AttributeList::AT_cf_returns_not_retained:
- d->addAttr(::new (S.Context) CFReturnsNotRetainedAttr(Attr.getLoc(),
+ d->addAttr(::new (S.Context) CFReturnsNotRetainedAttr(attr.getLoc(),
S.Context));
return;
case AttributeList::AT_ns_returns_not_retained:
- d->addAttr(::new (S.Context) NSReturnsNotRetainedAttr(Attr.getLoc(),
+ d->addAttr(::new (S.Context) NSReturnsNotRetainedAttr(attr.getLoc(),
S.Context));
return;
case AttributeList::AT_cf_returns_retained:
- d->addAttr(::new (S.Context) CFReturnsRetainedAttr(Attr.getLoc(),
+ d->addAttr(::new (S.Context) CFReturnsRetainedAttr(attr.getLoc(),
S.Context));
return;
case AttributeList::AT_ns_returns_retained:
- d->addAttr(::new (S.Context) NSReturnsRetainedAttr(Attr.getLoc(),
+ d->addAttr(::new (S.Context) NSReturnsRetainedAttr(attr.getLoc(),
S.Context));
return;
};
@@ -2629,6 +2697,12 @@
case AttributeList::AT_vecreturn: HandleVecReturnAttr (D, Attr, S); break;
// Checker-specific.
+ case AttributeList::AT_cf_consumed:
+ case AttributeList::AT_ns_consumed: HandleNSConsumedAttr (D, Attr, S); break;
+ case AttributeList::AT_ns_consumes_self:
+ HandleNSConsumesSelfAttr(D, Attr, S); break;
+
+ case AttributeList::AT_ns_returns_autoreleased:
case AttributeList::AT_ns_returns_not_retained:
case AttributeList::AT_cf_returns_not_retained:
case AttributeList::AT_ns_returns_retained:
diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m
index 3bf350f..ac136cb 100644
--- a/test/Analysis/retain-release.m
+++ b/test/Analysis/retain-release.m
@@ -1210,7 +1210,7 @@
- (MyStringTy) returnsAnOwnedTypedString NS_RETURNS_RETAINED; // no-warning
- (NSString*) newString NS_RETURNS_NOT_RETAINED; // no-warning
- (NSString*) newStringNoAttr;
-- (int) returnsAnOwnedInt NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to functions or methods that return a pointer or Objective-C object}}
+- (int) returnsAnOwnedInt NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to methods that return an Objective-C object}}
@end
static int ownership_attribute_doesnt_go_here NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to function or method types}}