Path: blob/main/contrib/llvm-project/clang/lib/AST/Comment.cpp
35260 views
//===--- Comment.cpp - Comment AST node implementation --------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "clang/AST/Comment.h"9#include "clang/AST/ASTContext.h"10#include "clang/AST/Decl.h"11#include "clang/AST/DeclObjC.h"12#include "clang/AST/DeclTemplate.h"13#include "clang/Basic/CharInfo.h"14#include "llvm/Support/ErrorHandling.h"15#include <type_traits>1617namespace clang {18namespace comments {1920// Check that no comment class has a non-trival destructor. They are allocated21// with a BumpPtrAllocator and therefore their destructor is not executed.22#define ABSTRACT_COMMENT(COMMENT)23#define COMMENT(CLASS, PARENT) \24static_assert(std::is_trivially_destructible<CLASS>::value, \25#CLASS " should be trivially destructible!");26#include "clang/AST/CommentNodes.inc"27#undef COMMENT28#undef ABSTRACT_COMMENT2930// DeclInfo is also allocated with a BumpPtrAllocator.31static_assert(std::is_trivially_destructible_v<DeclInfo>,32"DeclInfo should be trivially destructible!");3334const char *Comment::getCommentKindName() const {35switch (getCommentKind()) {36case CommentKind::None:37return "None";38#define ABSTRACT_COMMENT(COMMENT)39#define COMMENT(CLASS, PARENT) \40case CommentKind::CLASS: \41return #CLASS;42#include "clang/AST/CommentNodes.inc"43#undef COMMENT44#undef ABSTRACT_COMMENT45}46llvm_unreachable("Unknown comment kind!");47}4849namespace {50struct good {};51struct bad {};5253template <typename T>54good implements_child_begin_end(Comment::child_iterator (T::*)() const) {55return good();56}5758LLVM_ATTRIBUTE_UNUSED59static inline bad implements_child_begin_end(60Comment::child_iterator (Comment::*)() const) {61return bad();62}6364#define ASSERT_IMPLEMENTS_child_begin(function) \65(void) good(implements_child_begin_end(function))6667LLVM_ATTRIBUTE_UNUSED68static inline void CheckCommentASTNodes() {69#define ABSTRACT_COMMENT(COMMENT)70#define COMMENT(CLASS, PARENT) \71ASSERT_IMPLEMENTS_child_begin(&CLASS::child_begin); \72ASSERT_IMPLEMENTS_child_begin(&CLASS::child_end);73#include "clang/AST/CommentNodes.inc"74#undef COMMENT75#undef ABSTRACT_COMMENT76}7778#undef ASSERT_IMPLEMENTS_child_begin7980} // end unnamed namespace8182Comment::child_iterator Comment::child_begin() const {83switch (getCommentKind()) {84case CommentKind::None:85llvm_unreachable("comment without a kind");86#define ABSTRACT_COMMENT(COMMENT)87#define COMMENT(CLASS, PARENT) \88case CommentKind::CLASS: \89return static_cast<const CLASS *>(this)->child_begin();90#include "clang/AST/CommentNodes.inc"91#undef COMMENT92#undef ABSTRACT_COMMENT93}94llvm_unreachable("Unknown comment kind!");95}9697Comment::child_iterator Comment::child_end() const {98switch (getCommentKind()) {99case CommentKind::None:100llvm_unreachable("comment without a kind");101#define ABSTRACT_COMMENT(COMMENT)102#define COMMENT(CLASS, PARENT) \103case CommentKind::CLASS: \104return static_cast<const CLASS *>(this)->child_end();105#include "clang/AST/CommentNodes.inc"106#undef COMMENT107#undef ABSTRACT_COMMENT108}109llvm_unreachable("Unknown comment kind!");110}111112bool TextComment::isWhitespaceNoCache() const {113return llvm::all_of(Text, clang::isWhitespace);114}115116bool ParagraphComment::isWhitespaceNoCache() const {117for (child_iterator I = child_begin(), E = child_end(); I != E; ++I) {118if (const TextComment *TC = dyn_cast<TextComment>(*I)) {119if (!TC->isWhitespace())120return false;121} else122return false;123}124return true;125}126127static TypeLoc lookThroughTypedefOrTypeAliasLocs(TypeLoc &SrcTL) {128TypeLoc TL = SrcTL.IgnoreParens();129130// Look through attribute types.131if (AttributedTypeLoc AttributeTL = TL.getAs<AttributedTypeLoc>())132return AttributeTL.getModifiedLoc();133// Look through qualified types.134if (QualifiedTypeLoc QualifiedTL = TL.getAs<QualifiedTypeLoc>())135return QualifiedTL.getUnqualifiedLoc();136// Look through pointer types.137if (PointerTypeLoc PointerTL = TL.getAs<PointerTypeLoc>())138return PointerTL.getPointeeLoc().getUnqualifiedLoc();139// Look through reference types.140if (ReferenceTypeLoc ReferenceTL = TL.getAs<ReferenceTypeLoc>())141return ReferenceTL.getPointeeLoc().getUnqualifiedLoc();142// Look through adjusted types.143if (AdjustedTypeLoc ATL = TL.getAs<AdjustedTypeLoc>())144return ATL.getOriginalLoc();145if (BlockPointerTypeLoc BlockPointerTL = TL.getAs<BlockPointerTypeLoc>())146return BlockPointerTL.getPointeeLoc().getUnqualifiedLoc();147if (MemberPointerTypeLoc MemberPointerTL = TL.getAs<MemberPointerTypeLoc>())148return MemberPointerTL.getPointeeLoc().getUnqualifiedLoc();149if (ElaboratedTypeLoc ETL = TL.getAs<ElaboratedTypeLoc>())150return ETL.getNamedTypeLoc();151152return TL;153}154155static bool getFunctionTypeLoc(TypeLoc TL, FunctionTypeLoc &ResFTL) {156TypeLoc PrevTL;157while (PrevTL != TL) {158PrevTL = TL;159TL = lookThroughTypedefOrTypeAliasLocs(TL);160}161162if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) {163ResFTL = FTL;164return true;165}166167if (TemplateSpecializationTypeLoc STL =168TL.getAs<TemplateSpecializationTypeLoc>()) {169// If we have a typedef to a template specialization with exactly one170// template argument of a function type, this looks like std::function,171// boost::function, or other function wrapper. Treat these typedefs as172// functions.173if (STL.getNumArgs() != 1)174return false;175TemplateArgumentLoc MaybeFunction = STL.getArgLoc(0);176if (MaybeFunction.getArgument().getKind() != TemplateArgument::Type)177return false;178TypeSourceInfo *MaybeFunctionTSI = MaybeFunction.getTypeSourceInfo();179TypeLoc TL = MaybeFunctionTSI->getTypeLoc().getUnqualifiedLoc();180if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) {181ResFTL = FTL;182return true;183}184}185186return false;187}188189const char *190ParamCommandComment::getDirectionAsString(ParamCommandPassDirection D) {191switch (D) {192case ParamCommandPassDirection::In:193return "[in]";194case ParamCommandPassDirection::Out:195return "[out]";196case ParamCommandPassDirection::InOut:197return "[in,out]";198}199llvm_unreachable("unknown PassDirection");200}201202void DeclInfo::fill() {203assert(!IsFilled);204205// Set defaults.206Kind = OtherKind;207TemplateKind = NotTemplate;208IsObjCMethod = false;209IsInstanceMethod = false;210IsClassMethod = false;211IsVariadic = false;212ParamVars = std::nullopt;213TemplateParameters = nullptr;214215if (!CommentDecl) {216// If there is no declaration, the defaults is our only guess.217IsFilled = true;218return;219}220CurrentDecl = CommentDecl;221222Decl::Kind K = CommentDecl->getKind();223const TypeSourceInfo *TSI = nullptr;224switch (K) {225default:226// Defaults are should be good for declarations we don't handle explicitly.227break;228case Decl::Function:229case Decl::CXXMethod:230case Decl::CXXConstructor:231case Decl::CXXDestructor:232case Decl::CXXConversion: {233const FunctionDecl *FD = cast<FunctionDecl>(CommentDecl);234Kind = FunctionKind;235ParamVars = FD->parameters();236ReturnType = FD->getReturnType();237unsigned NumLists = FD->getNumTemplateParameterLists();238if (NumLists != 0) {239TemplateKind = TemplateSpecialization;240TemplateParameters =241FD->getTemplateParameterList(NumLists - 1);242}243244if (K == Decl::CXXMethod || K == Decl::CXXConstructor ||245K == Decl::CXXDestructor || K == Decl::CXXConversion) {246const CXXMethodDecl *MD = cast<CXXMethodDecl>(CommentDecl);247IsInstanceMethod = MD->isInstance();248IsClassMethod = !IsInstanceMethod;249}250IsVariadic = FD->isVariadic();251assert(involvesFunctionType());252break;253}254case Decl::ObjCMethod: {255const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(CommentDecl);256Kind = FunctionKind;257ParamVars = MD->parameters();258ReturnType = MD->getReturnType();259IsObjCMethod = true;260IsInstanceMethod = MD->isInstanceMethod();261IsClassMethod = !IsInstanceMethod;262IsVariadic = MD->isVariadic();263assert(involvesFunctionType());264break;265}266case Decl::FunctionTemplate: {267const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(CommentDecl);268Kind = FunctionKind;269TemplateKind = Template;270const FunctionDecl *FD = FTD->getTemplatedDecl();271ParamVars = FD->parameters();272ReturnType = FD->getReturnType();273TemplateParameters = FTD->getTemplateParameters();274IsVariadic = FD->isVariadic();275assert(involvesFunctionType());276break;277}278case Decl::ClassTemplate: {279const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(CommentDecl);280Kind = ClassKind;281TemplateKind = Template;282TemplateParameters = CTD->getTemplateParameters();283break;284}285case Decl::ClassTemplatePartialSpecialization: {286const ClassTemplatePartialSpecializationDecl *CTPSD =287cast<ClassTemplatePartialSpecializationDecl>(CommentDecl);288Kind = ClassKind;289TemplateKind = TemplatePartialSpecialization;290TemplateParameters = CTPSD->getTemplateParameters();291break;292}293case Decl::ClassTemplateSpecialization:294Kind = ClassKind;295TemplateKind = TemplateSpecialization;296break;297case Decl::Record:298case Decl::CXXRecord:299Kind = ClassKind;300break;301case Decl::Var:302if (const VarTemplateDecl *VTD =303cast<VarDecl>(CommentDecl)->getDescribedVarTemplate()) {304TemplateKind = TemplateSpecialization;305TemplateParameters = VTD->getTemplateParameters();306}307[[fallthrough]];308case Decl::Field:309case Decl::EnumConstant:310case Decl::ObjCIvar:311case Decl::ObjCAtDefsField:312case Decl::ObjCProperty:313if (const auto *VD = dyn_cast<DeclaratorDecl>(CommentDecl))314TSI = VD->getTypeSourceInfo();315else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(CommentDecl))316TSI = PD->getTypeSourceInfo();317Kind = VariableKind;318break;319case Decl::VarTemplate: {320const VarTemplateDecl *VTD = cast<VarTemplateDecl>(CommentDecl);321Kind = VariableKind;322TemplateKind = Template;323TemplateParameters = VTD->getTemplateParameters();324if (const VarDecl *VD = VTD->getTemplatedDecl())325TSI = VD->getTypeSourceInfo();326break;327}328case Decl::Namespace:329Kind = NamespaceKind;330break;331case Decl::TypeAlias:332case Decl::Typedef:333Kind = TypedefKind;334TSI = cast<TypedefNameDecl>(CommentDecl)->getTypeSourceInfo();335break;336case Decl::TypeAliasTemplate: {337const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(CommentDecl);338Kind = TypedefKind;339TemplateKind = Template;340TemplateParameters = TAT->getTemplateParameters();341if (TypeAliasDecl *TAD = TAT->getTemplatedDecl())342TSI = TAD->getTypeSourceInfo();343break;344}345case Decl::Enum:346Kind = EnumKind;347break;348}349350// If the type is a typedef / using to something we consider a function,351// extract arguments and return type.352if (TSI) {353TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc();354FunctionTypeLoc FTL;355if (getFunctionTypeLoc(TL, FTL)) {356ParamVars = FTL.getParams();357ReturnType = FTL.getReturnLoc().getType();358if (const auto *FPT = dyn_cast<FunctionProtoType>(FTL.getTypePtr()))359IsVariadic = FPT->isVariadic();360assert(involvesFunctionType());361}362}363364IsFilled = true;365}366367StringRef ParamCommandComment::getParamName(const FullComment *FC) const {368assert(isParamIndexValid());369if (isVarArgParam())370return "...";371return FC->getDeclInfo()->ParamVars[getParamIndex()]->getName();372}373374StringRef TParamCommandComment::getParamName(const FullComment *FC) const {375assert(isPositionValid());376const TemplateParameterList *TPL = FC->getDeclInfo()->TemplateParameters;377for (unsigned i = 0, e = getDepth(); i != e; ++i) {378assert(TPL && "Unknown TemplateParameterList");379if (i == e - 1)380return TPL->getParam(getIndex(i))->getName();381const NamedDecl *Param = TPL->getParam(getIndex(i));382if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param))383TPL = TTP->getTemplateParameters();384}385return "";386}387388} // end namespace comments389} // end namespace clang390391392393