[clang] 2f56789 - [clang][doxygen] Fix false -Wdocumentation warning for tag typedefs

Jan Korous via cfe-commits cfe-commits at lists.llvm.org
Thu Feb 20 11:33:29 PST 2020


Author: Jan Korous
Date: 2020-02-20T11:32:30-08:00
New Revision: 2f56789c8fe8edb57bc7a193592ecd35a393fe4a

URL: https://github.com/llvm/llvm-project/commit/2f56789c8fe8edb57bc7a193592ecd35a393fe4a
DIFF: https://github.com/llvm/llvm-project/commit/2f56789c8fe8edb57bc7a193592ecd35a393fe4a.diff

LOG: [clang][doxygen] Fix false -Wdocumentation warning for tag typedefs

For tag typedefs like this one:

/*!
@class Foo
*/
typedef class { } Foo;

clang -Wdocumentation gives:

warning: '@class' command should not be used in a comment attached to a
non-struct declaration [-Wdocumentation]

... while doxygen seems fine with it.

Differential Revision: https://reviews.llvm.org/D74746

Added: 
    clang/test/Sema/warn-documentation-tag-typedef.cpp

Modified: 
    clang/include/clang/AST/CommentSema.h
    clang/lib/AST/CommentSema.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/CommentSema.h b/clang/include/clang/AST/CommentSema.h
index 307618fa5363..6dfe0f4920d0 100644
--- a/clang/include/clang/AST/CommentSema.h
+++ b/clang/include/clang/AST/CommentSema.h
@@ -217,6 +217,9 @@ class Sema {
   bool isTemplateOrSpecialization();
   bool isRecordLikeDecl();
   bool isClassOrStructDecl();
+  /// \return \c true if the declaration that this comment is attached to
+  /// declares either struct, class or tag typedef.
+  bool isClassOrStructOrTagTypedefDecl();
   bool isUnionDecl();
   bool isObjCInterfaceDecl();
   bool isObjCProtocolDecl();

diff  --git a/clang/lib/AST/CommentSema.cpp b/clang/lib/AST/CommentSema.cpp
index 53c1832d1dd2..8102f0115cc7 100644
--- a/clang/lib/AST/CommentSema.cpp
+++ b/clang/lib/AST/CommentSema.cpp
@@ -12,6 +12,7 @@
 #include "clang/AST/CommentDiagnostic.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclTemplate.h"
+#include "clang/Basic/LLVM.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Lex/Preprocessor.h"
 #include "llvm/ADT/SmallString.h"
@@ -134,7 +135,9 @@ void Sema::checkContainerDeclVerbatimLine(const BlockCommandComment *Comment) {
   unsigned DiagSelect;
   switch (Comment->getCommandID()) {
     case CommandTraits::KCI_class:
-      DiagSelect = (!isClassOrStructDecl() && !isClassTemplateDecl()) ? 1 : 0;
+      DiagSelect =
+          (!isClassOrStructOrTagTypedefDecl() && !isClassTemplateDecl()) ? 1
+                                                                         : 0;
       // Allow @class command on @interface declarations.
       // FIXME. Currently, \class and @class are indistinguishable. So,
       // \class is also allowed on an @interface declaration
@@ -148,7 +151,7 @@ void Sema::checkContainerDeclVerbatimLine(const BlockCommandComment *Comment) {
       DiagSelect = !isObjCProtocolDecl() ? 3 : 0;
       break;
     case CommandTraits::KCI_struct:
-      DiagSelect = !isClassOrStructDecl() ? 4 : 0;
+      DiagSelect = !isClassOrStructOrTagTypedefDecl() ? 4 : 0;
       break;
     case CommandTraits::KCI_union:
       DiagSelect = !isUnionDecl() ? 5 : 0;
@@ -935,15 +938,50 @@ bool Sema::isUnionDecl() {
     return RD->isUnion();
   return false;
 }
+static bool isClassOrStructDeclImpl(const Decl *D) {
+  if (auto *record = dyn_cast_or_null<RecordDecl>(D))
+    return !record->isUnion();
+
+  return false;
+}
 
 bool Sema::isClassOrStructDecl() {
   if (!ThisDeclInfo)
     return false;
   if (!ThisDeclInfo->IsFilled)
     inspectThisDecl();
-  return ThisDeclInfo->CurrentDecl &&
-         isa<RecordDecl>(ThisDeclInfo->CurrentDecl) &&
-         !isUnionDecl();
+
+  if (!ThisDeclInfo->CurrentDecl)
+    return false;
+
+  return isClassOrStructDeclImpl(ThisDeclInfo->CurrentDecl);
+}
+
+bool Sema::isClassOrStructOrTagTypedefDecl() {
+  if (!ThisDeclInfo)
+    return false;
+  if (!ThisDeclInfo->IsFilled)
+    inspectThisDecl();
+
+  if (!ThisDeclInfo->CurrentDecl)
+    return false;
+
+  if (isClassOrStructDeclImpl(ThisDeclInfo->CurrentDecl))
+    return true;
+
+  if (auto *ThisTypedefDecl = dyn_cast<TypedefDecl>(ThisDeclInfo->CurrentDecl)) {
+    auto UnderlyingType = ThisTypedefDecl->getUnderlyingType();
+    if (auto ThisElaboratedType = dyn_cast<ElaboratedType>(UnderlyingType)) {
+      auto DesugaredType = ThisElaboratedType->desugar();
+      if (auto *DesugaredTypePtr = DesugaredType.getTypePtrOrNull()) {
+        if (auto *ThisRecordType = dyn_cast<RecordType>(DesugaredTypePtr)) {
+          return isClassOrStructDeclImpl(ThisRecordType->getAsRecordDecl());
+        }
+      }
+    }
+  }
+
+  return false;
 }
 
 bool Sema::isClassTemplateDecl() {

diff  --git a/clang/test/Sema/warn-documentation-tag-typedef.cpp b/clang/test/Sema/warn-documentation-tag-typedef.cpp
new file mode 100644
index 000000000000..0954d6a9f48d
--- /dev/null
+++ b/clang/test/Sema/warn-documentation-tag-typedef.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -Wdocumentation -fsyntax-only %s 2>&1 | FileCheck -allow-empty %s
+
+/*!
+ at class Foo
+*/
+typedef class { } Foo;
+// CHECK-NOT: warning:
+
+/*! 
+ at struct Bar
+*/
+typedef struct { } Bar;
+// CHECK-NOT: warning:


        


More information about the cfe-commits mailing list