summaryrefslogtreecommitdiff
path: root/clang/lib/AST/CommentSema.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/AST/CommentSema.cpp')
-rw-r--r--clang/lib/AST/CommentSema.cpp50
1 files changed, 44 insertions, 6 deletions
diff --git a/clang/lib/AST/CommentSema.cpp b/clang/lib/AST/CommentSema.cpp
index 53c1832d1dd2..7642e73fa171 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;
@@ -688,7 +691,7 @@ void Sema::checkDeprecatedCommand(const BlockCommandComment *Command) {
FD->doesThisDeclarationHaveABody())
return;
- const LangOptions &LO = FD->getASTContext().getLangOpts();
+ const LangOptions &LO = FD->getLangOpts();
const bool DoubleSquareBracket = LO.CPlusPlus14 || LO.C2x;
StringRef AttributeSpelling =
DoubleSquareBracket ? "[[deprecated]]" : "__attribute__((deprecated))";
@@ -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() {