[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