]> granicus.if.org Git - clang/commitdiff
[PR32667] -Wdocumentation should allow @param/@returns for fields/variables
authorAlex Lorenz <arphaman@gmail.com>
Fri, 21 Apr 2017 14:17:49 +0000 (14:17 +0000)
committerAlex Lorenz <arphaman@gmail.com>
Fri, 21 Apr 2017 14:17:49 +0000 (14:17 +0000)
that have a function/block pointer type

This commit improves the -Wdocumentation warning by making sure that @param and
@returns commands won't trigger warnings when used for fields, variables,
or properties whose type is a function/block pointer type. The
function/block pointer type must be specified directly with the declaration,
and when a typedef is used the warning is still emitted.

In the future we might also want to handle the std::function type as well.

rdar://24978538

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

include/clang/AST/CommentSema.h
lib/AST/Comment.cpp
lib/AST/CommentSema.cpp
test/Sema/warn-documentation.cpp
test/Sema/warn-documentation.m

index 6a803836e8482f1012635da3f739250f7ade5e05..230e52739f24cad9f6be8130c428bac73ccdeada 100644 (file)
@@ -208,6 +208,10 @@ public:
   /// \returns \c true if declaration that this comment is attached to declares
   /// a function pointer.
   bool isFunctionPointerVarDecl();
+  /// \returns \c true if the declaration that this comment is attached to
+  /// declares a variable or a field whose type is a function or a block
+  /// pointer.
+  bool isFunctionOrBlockPointerVarLikeDecl();
   bool isFunctionOrMethodVariadic();
   bool isObjCMethodDecl();
   bool isObjCPropertyDecl();
index 7a7d3dd8304e60c53a126ba2439a3f00be3cd5ff..20ff2430df2e826252e91011f130f35579645271 100644 (file)
@@ -280,8 +280,25 @@ void DeclInfo::fill() {
   case Decl::EnumConstant:
   case Decl::ObjCIvar:
   case Decl::ObjCAtDefsField:
+  case Decl::ObjCProperty: {
+    const TypeSourceInfo *TSI;
+    if (const auto *VD = dyn_cast<DeclaratorDecl>(CommentDecl))
+      TSI = VD->getTypeSourceInfo();
+    else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(CommentDecl))
+      TSI = PD->getTypeSourceInfo();
+    else
+      TSI = nullptr;
+    if (TSI) {
+      TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc();
+      FunctionTypeLoc FTL;
+      if (getFunctionTypeLoc(TL, FTL)) {
+        ParamVars = FTL.getParams();
+        ReturnType = FTL.getReturnLoc().getType();
+      }
+    }
     Kind = VariableKind;
     break;
+  }
   case Decl::Namespace:
     Kind = NamespaceKind;
     break;
index d39a9b26b2a8db1246d553b80176b3b08ca183ac..b96ef6cc94b7a02487389c6fcdc059e936019505 100644 (file)
@@ -86,7 +86,7 @@ ParamCommandComment *Sema::actOnParamCommandStart(
       new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID,
                                           CommandMarker);
 
-  if (!isFunctionDecl())
+  if (!isFunctionDecl() && !isFunctionOrBlockPointerVarLikeDecl())
     Diag(Command->getLocation(),
          diag::warn_doc_param_not_attached_to_a_function_decl)
       << CommandMarker
@@ -584,7 +584,7 @@ void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
 
   assert(ThisDeclInfo && "should not call this check on a bare comment");
 
-  if (isFunctionDecl()) {
+  if (isFunctionDecl() || isFunctionOrBlockPointerVarLikeDecl()) {
     if (ThisDeclInfo->ReturnType->isVoidType()) {
       unsigned DiagKind;
       switch (ThisDeclInfo->CommentDecl->getKind()) {
@@ -844,6 +844,30 @@ bool Sema::isFunctionPointerVarDecl() {
   return false;
 }
 
+bool Sema::isFunctionOrBlockPointerVarLikeDecl() {
+  if (!ThisDeclInfo)
+    return false;
+  if (!ThisDeclInfo->IsFilled)
+    inspectThisDecl();
+  if (ThisDeclInfo->getKind() != DeclInfo::VariableKind ||
+      !ThisDeclInfo->CurrentDecl)
+    return false;
+  QualType QT;
+  if (const auto *VD = dyn_cast<DeclaratorDecl>(ThisDeclInfo->CurrentDecl))
+    QT = VD->getType();
+  else if (const auto *PD =
+               dyn_cast<ObjCPropertyDecl>(ThisDeclInfo->CurrentDecl))
+    QT = PD->getType();
+  else
+    return false;
+  // We would like to warn about the 'returns'/'param' commands for
+  // variables that don't directly specify the function type, so type aliases
+  // can be ignored.
+  if (QT->getAs<TypedefType>())
+    return false;
+  return QT->isFunctionPointerType() || QT->isBlockPointerType();
+}
+
 bool Sema::isObjCPropertyDecl() {
   if (!ThisDeclInfo)
     return false;
index 34d8f5fd2da2802d4b2f34b68270f9276266b603..0c92b2aa029fe6764ba8eda03d8fe87a99be1e08 100644 (file)
@@ -1210,3 +1210,75 @@ template <class T> T test_function (T arg);
 /*!     @function test_function<int>
 */
 template <> int test_function<int> (int arg);
+
+namespace AllowParamAndReturnsOnFunctionPointerVars {
+
+/**
+ * functionPointerVariable
+ *
+ * @param i is integer.
+ * @returns integer.
+ */
+int (*functionPointerVariable)(int i);
+
+struct HasFields {
+  /**
+   * functionPointerField
+   *
+   * @param i is integer.
+   * @returns integer.
+   */
+  int (*functionPointerField)(int i);
+};
+
+// expected-warning@+5 {{'\returns' command used in a comment that is attached to a function returning void}}
+/**
+ * functionPointerVariable
+ *
+ * \param p not here.
+ * \returns integer.
+ */
+void (*functionPointerVariableThatLeadsNowhere)();
+
+// Still warn about param/returns commands for variables that don't specify
+// the type directly:
+
+/**
+ * FunctionPointerTypedef
+ *
+ * \param i is integer.
+ * \returns integer.
+ */
+typedef int (*FunctionPointerTypedef)(int i);
+
+/**
+ * FunctionPointerTypealias
+ *
+ * \param i is integer.
+ * \returns integer.
+ */
+using FunctionPointerTypealias = int (*)(int i);
+
+// expected-warning@+5 {{'@param' command used in a comment that is not attached to a function declaration}}
+// expected-warning@+5 {{'@returns' command used in a comment that is not attached to a function or method declaration}}
+/**
+ * functionPointerVariable
+ *
+ * @param i is integer.
+ * @returns integer.
+ */
+FunctionPointerTypedef functionPointerTypedefVariable;
+
+struct HasMoreFields {
+  // expected-warning@+5 {{'\param' command used in a comment that is not attached to a function declaration}}
+  // expected-warning@+5 {{'\returns' command used in a comment that is not attached to a function or method declaration}}
+  /**
+   * functionPointerTypealiasField
+   *
+   * \param i is integer.
+   * \returns integer.
+   */
+  FunctionPointerTypealias functionPointerTypealiasField;
+};
+
+}
index 5e95e2a1e8a2f359d826321a3c269b772a3c34f4..a8538f02be1bd6f749e77772d761b427d7a5c283 100644 (file)
@@ -229,3 +229,65 @@ int FooBar();
 - (void) VarArgMeth : (id)arg, ... {}
 @end
 
+/**
+ * blockPointerVariable
+ *
+ * @param i is integer.
+ * @returns integer.
+ */
+int (^blockPointerVariable)(int i);
+
+struct HasFields {
+  /**
+   * blockPointerField
+   *
+   * \param i is integer.
+   * \returns integer.
+   */
+  int (^blockPointerFields)(int i);
+};
+
+// expected-warning@+5 {{'\returns' command used in a comment that is attached to a function returning void}}
+/**
+ * functionPointerVariable
+ *
+ * \param p not here.
+ * \returns integer.
+ */
+void (^blockPointerVariableThatLeadsNowhere)();
+
+@interface CheckFunctionBlockPointerVars {
+  /**
+   * functionPointerIVar
+   *
+   * @param i is integer.
+   * @returns integer.
+   */
+  int (*functionPointerIVar)(int i);
+
+  /**
+   * blockPointerIVar
+   *
+   * \param i is integer.
+   * \returns integer.
+   */
+  int (^blockPointerIVar)(int i);
+}
+
+/**
+ * functionPointerProperty
+ *
+ * @param i is integer.
+ * @returns integer.
+ */
+@property int (*functionPointerProperty)(int i);
+
+/**
+ * blockPointerProperty
+ *
+ * \param i is integer.
+ * \returns integer.
+ */
+@property int (^blockPointerProperty)(int i);
+
+@end