diff --git a/clang/include/clang/AST/CommentSema.h b/clang/include/clang/AST/CommentSema.h --- a/clang/include/clang/AST/CommentSema.h +++ b/clang/include/clang/AST/CommentSema.h @@ -204,30 +204,7 @@ /// Emit diagnostics about unknown parametrs. void resolveParamCommandIndexes(const FullComment *FC); - /// \returns \c true if the declaration that this comment is attached to - /// is a pointer to function/method/block type or has such a type. - bool involvesFunctionType(); - - bool isFunctionDecl(); - bool isAnyFunctionDecl(); - - /// \returns \c true if declaration that this comment is attached to declares - /// a function pointer. - bool isFunctionPointerVarDecl(); - bool isFunctionOrMethodVariadic(); - bool isObjCMethodDecl(); - bool isObjCPropertyDecl(); - 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(); - bool isClassTemplateDecl(); - bool isFunctionTemplateDecl(); + bool hasDeclThat(bool (*check)(const DeclInfo &)); ArrayRef getParamVars(); diff --git a/clang/lib/AST/CommentSema.cpp b/clang/lib/AST/CommentSema.cpp --- a/clang/lib/AST/CommentSema.cpp +++ b/clang/lib/AST/CommentSema.cpp @@ -86,6 +86,12 @@ } } +/// \returns \c true if the declaration that this comment is attached to +/// is a pointer to function/method/block type or has such a type. +static bool involvesFunctionType(const DeclInfo &Info) { + return Info.involvesFunctionType(); +} + ParamCommandComment *Sema::actOnParamCommandStart( SourceLocation LocBegin, SourceLocation LocEnd, @@ -95,7 +101,7 @@ new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID, CommandMarker); - if (!involvesFunctionType()) + if (!hasDeclThat(involvesFunctionType)) Diag(Command->getLocation(), diag::warn_doc_param_not_attached_to_a_function_decl) << CommandMarker @@ -105,23 +111,30 @@ } void Sema::checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment) { + if (ThisDeclInfo) + inspectThisDecl(); unsigned DiagSelect; switch (Comment->getCommandID()) { case CommandTraits::KCI_function: case CommandTraits::KCI_functiongroup: - if (isAnyFunctionDecl() || isFunctionTemplateDecl()) + if (ThisDeclInfo && ThisDeclInfo->getKind() == DeclInfo::FunctionKind && + (isa(ThisDeclInfo->CurrentDecl) || + isa(ThisDeclInfo->CurrentDecl))) return; DiagSelect = 0; break; case CommandTraits::KCI_method: case CommandTraits::KCI_methodgroup: - if (isObjCMethodDecl()) + if (ThisDeclInfo && ThisDeclInfo->getKind() == DeclInfo::FunctionKind && + isa(ThisDeclInfo->CurrentDecl)) return; DiagSelect = 1; break; case CommandTraits::KCI_callback: - if (isFunctionPointerVarDecl()) - return; + if (ThisDeclInfo && ThisDeclInfo->getKind() == DeclInfo::VariableKind) + if (const auto *VD = dyn_cast(ThisDeclInfo->CurrentDecl)) + if (VD->getType()->isFunctionPointerType()) + return; DiagSelect = 2; break; default: @@ -133,35 +146,80 @@ << Comment->getSourceRange(); } +static bool isClassOrStructDeclImpl(const Decl *D) { + if (auto *record = dyn_cast_or_null(D)) + return !record->isUnion(); + + return false; +} + +/// \return \c true if the declaration that this comment is attached to +/// declares either struct, class or tag typedef. +static bool isClassOrStructOrTagTypedefDecl(const DeclInfo &Info) { + if (!Info.CurrentDecl) + return false; + + if (isClassOrStructDeclImpl(Info.CurrentDecl)) + return true; + + if (auto *ThisTypedefDecl = dyn_cast(Info.CurrentDecl)) { + auto UnderlyingType = ThisTypedefDecl->getUnderlyingType(); + if (auto ThisElaboratedType = dyn_cast(UnderlyingType)) { + auto DesugaredType = ThisElaboratedType->desugar(); + if (auto *DesugaredTypePtr = DesugaredType.getTypePtrOrNull()) { + if (auto *ThisRecordType = dyn_cast(DesugaredTypePtr)) { + return isClassOrStructDeclImpl(ThisRecordType->getAsRecordDecl()); + } + } + } + } + + return false; +} + +static bool isObjCInterfaceDecl(const DeclInfo &Info) { + return isa_and_nonnull(Info.CurrentDecl); +} + +static bool isObjCProtocolDecl(const DeclInfo &Info) { + return isa_and_nonnull(Info.CurrentDecl); +} + void Sema::checkContainerDeclVerbatimLine(const BlockCommandComment *Comment) { - switch (Comment->getCommandID()) { + if (ThisDeclInfo) { + inspectThisDecl(); + switch (Comment->getCommandID()) { case CommandTraits::KCI_class: - if (isClassOrStructOrTagTypedefDecl() || isClassTemplateDecl()) + if (isClassOrStructOrTagTypedefDecl(*ThisDeclInfo) || + isa_and_nonnull(ThisDeclInfo->CurrentDecl)) return; // Allow @class command on @interface declarations. // FIXME. Currently, \class and @class are indistinguishable. So, // \class is also allowed on an @interface declaration - if (Comment->getCommandMarker() && isObjCInterfaceDecl()) + if (Comment->getCommandMarker() && isObjCInterfaceDecl(*ThisDeclInfo)) return; break; case CommandTraits::KCI_interface: - if (isObjCInterfaceDecl()) + if (isObjCInterfaceDecl(*ThisDeclInfo)) return; break; case CommandTraits::KCI_protocol: - if (isObjCProtocolDecl()) + if (isObjCProtocolDecl(*ThisDeclInfo)) return; break; case CommandTraits::KCI_struct: - if (isClassOrStructOrTagTypedefDecl()) + if (isClassOrStructOrTagTypedefDecl(*ThisDeclInfo)) return; break; case CommandTraits::KCI_union: - if (isUnionDecl()) - return; + if (const RecordDecl *RD = + dyn_cast_or_null(ThisDeclInfo->CurrentDecl)) + if (RD->isUnion()) + return; break; default: llvm_unreachable("Unhandled command with IsRecordLikeDeclarationCommand"); + } } Diag(Comment->getLocation(), diag::warn_doc_api_container_decl_mismatch) << Comment->getCommandMarker() @@ -169,8 +227,13 @@ << Comment->getSourceRange(); } +static bool isRecordLikeDecl(const DeclInfo &Info) { + return isa_and_nonnull(Info.CurrentDecl) || + isObjCInterfaceDecl(Info) || isObjCProtocolDecl(Info); +} + void Sema::checkContainerDecl(const BlockCommandComment *Comment) { - if (isRecordLikeDecl()) + if (hasDeclThat(isRecordLikeDecl)) return; Diag(Comment->getLocation(), diag::warn_doc_container_decl_mismatch) << Comment->getCommandMarker() @@ -241,6 +304,10 @@ checkBlockCommandEmptyParagraph(Command); } +static bool isTemplateOrSpecialization(const DeclInfo &Info) { + return Info.getTemplateKind() != DeclInfo::NotTemplate; +} + TParamCommandComment *Sema::actOnTParamCommandStart( SourceLocation LocBegin, SourceLocation LocEnd, @@ -250,7 +317,7 @@ new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID, CommandMarker); - if (!isTemplateOrSpecialization()) + if (!hasDeclThat(isTemplateOrSpecialization)) Diag(Command->getLocation(), diag::warn_doc_tparam_not_attached_to_a_template_decl) << CommandMarker @@ -272,7 +339,7 @@ Arg); Command->setArgs(llvm::makeArrayRef(A, 1)); - if (!isTemplateOrSpecialization()) { + if (!hasDeclThat(isTemplateOrSpecialization)) { // We already warned that this \\tparam is not attached to a template decl. return; } @@ -546,12 +613,13 @@ void Sema::checkReturnsCommand(const BlockCommandComment *Command) { assert(ThisDeclInfo && "should not call this check on a bare comment"); + inspectThisDecl(); // We allow the return command for all @properties because it can be used // to document the value that the property getter returns. - if (isObjCPropertyDecl()) + if (ThisDeclInfo->CurrentDecl->getKind() == Decl::ObjCProperty) return; - if (involvesFunctionType()) { + if (involvesFunctionType(*ThisDeclInfo)) { assert(!ThisDeclInfo->ReturnType.isNull() && "should have a valid return type"); if (ThisDeclInfo->ReturnType->isVoidType()) { @@ -679,7 +747,7 @@ } void Sema::resolveParamCommandIndexes(const FullComment *FC) { - if (!involvesFunctionType()) { + if (!hasDeclThat(involvesFunctionType)) { // We already warned that \\param commands are not attached to a function // decl. return; @@ -767,179 +835,21 @@ } } -bool Sema::involvesFunctionType() { - if (!ThisDeclInfo) - return false; - if (!ThisDeclInfo->IsFilled) - inspectThisDecl(); - return ThisDeclInfo->involvesFunctionType(); -} - -bool Sema::isFunctionDecl() { - if (!ThisDeclInfo) - return false; - if (!ThisDeclInfo->IsFilled) - inspectThisDecl(); - return ThisDeclInfo->getKind() == DeclInfo::FunctionKind; -} - -bool Sema::isAnyFunctionDecl() { - return isFunctionDecl() && ThisDeclInfo->CurrentDecl && - isa(ThisDeclInfo->CurrentDecl); -} - -bool Sema::isFunctionOrMethodVariadic() { - if (!ThisDeclInfo) - return false; - if (!ThisDeclInfo->IsFilled) - inspectThisDecl(); - return ThisDeclInfo->IsVariadic; -} - -bool Sema::isObjCMethodDecl() { - return isFunctionDecl() && ThisDeclInfo->CurrentDecl && - isa(ThisDeclInfo->CurrentDecl); -} - -bool Sema::isFunctionPointerVarDecl() { - if (!ThisDeclInfo) - return false; - if (!ThisDeclInfo->IsFilled) - inspectThisDecl(); - if (ThisDeclInfo->getKind() == DeclInfo::VariableKind) { - if (const VarDecl *VD = dyn_cast_or_null(ThisDeclInfo->CurrentDecl)) { - QualType QT = VD->getType(); - return QT->isFunctionPointerType(); - } - } - return false; -} - -bool Sema::isObjCPropertyDecl() { +bool Sema::hasDeclThat(bool (*check)(const DeclInfo &)) { if (!ThisDeclInfo) return false; - if (!ThisDeclInfo->IsFilled) - inspectThisDecl(); - return ThisDeclInfo->CurrentDecl->getKind() == Decl::ObjCProperty; -} - -bool Sema::isTemplateOrSpecialization() { - if (!ThisDeclInfo) - return false; - if (!ThisDeclInfo->IsFilled) - inspectThisDecl(); - return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate; -} - -bool Sema::isRecordLikeDecl() { - if (!ThisDeclInfo) - return false; - if (!ThisDeclInfo->IsFilled) - inspectThisDecl(); - return isUnionDecl() || isClassOrStructDecl() || isObjCInterfaceDecl() || - isObjCProtocolDecl(); -} - -bool Sema::isUnionDecl() { - if (!ThisDeclInfo) - return false; - if (!ThisDeclInfo->IsFilled) - inspectThisDecl(); - if (const RecordDecl *RD = - dyn_cast_or_null(ThisDeclInfo->CurrentDecl)) - return RD->isUnion(); - return false; -} -static bool isClassOrStructDeclImpl(const Decl *D) { - if (auto *record = dyn_cast_or_null(D)) - return !record->isUnion(); - - return false; -} - -bool Sema::isClassOrStructDecl() { - if (!ThisDeclInfo) - return false; - if (!ThisDeclInfo->IsFilled) - inspectThisDecl(); - - 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(ThisDeclInfo->CurrentDecl)) { - auto UnderlyingType = ThisTypedefDecl->getUnderlyingType(); - if (auto ThisElaboratedType = dyn_cast(UnderlyingType)) { - auto DesugaredType = ThisElaboratedType->desugar(); - if (auto *DesugaredTypePtr = DesugaredType.getTypePtrOrNull()) { - if (auto *ThisRecordType = dyn_cast(DesugaredTypePtr)) { - return isClassOrStructDeclImpl(ThisRecordType->getAsRecordDecl()); - } - } - } - } - - return false; -} - -bool Sema::isClassTemplateDecl() { - if (!ThisDeclInfo) - return false; - if (!ThisDeclInfo->IsFilled) - inspectThisDecl(); - return ThisDeclInfo->CurrentDecl && - (isa(ThisDeclInfo->CurrentDecl)); -} - -bool Sema::isFunctionTemplateDecl() { - if (!ThisDeclInfo) - return false; - if (!ThisDeclInfo->IsFilled) - inspectThisDecl(); - return ThisDeclInfo->CurrentDecl && - (isa(ThisDeclInfo->CurrentDecl)); -} - -bool Sema::isObjCInterfaceDecl() { - if (!ThisDeclInfo) - return false; - if (!ThisDeclInfo->IsFilled) - inspectThisDecl(); - return ThisDeclInfo->CurrentDecl && - isa(ThisDeclInfo->CurrentDecl); -} - -bool Sema::isObjCProtocolDecl() { - if (!ThisDeclInfo) - return false; - if (!ThisDeclInfo->IsFilled) - inspectThisDecl(); - return ThisDeclInfo->CurrentDecl && - isa(ThisDeclInfo->CurrentDecl); + inspectThisDecl(); + return check(*ThisDeclInfo); } ArrayRef Sema::getParamVars() { - if (!ThisDeclInfo->IsFilled) - inspectThisDecl(); + inspectThisDecl(); return ThisDeclInfo->ParamVars; } void Sema::inspectThisDecl() { - ThisDeclInfo->fill(); + if (!ThisDeclInfo->IsFilled) + ThisDeclInfo->fill(); } unsigned Sema::resolveParmVarReference(StringRef Name, @@ -949,7 +859,7 @@ if (II && II->getName() == Name) return i; } - if (Name == "..." && isFunctionOrMethodVariadic()) + if (Name == "..." && ThisDeclInfo->IsVariadic) return ParamCommandComment::VarArgParamIndex; return ParamCommandComment::InvalidParamIndex; }