brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.5 KiB · 361a8a7 Raw
397 lines · cpp
1//===--- Comment.cpp - Comment AST node implementation --------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "clang/AST/Comment.h"10#include "clang/AST/ASTContext.h"11#include "clang/AST/Decl.h"12#include "clang/AST/DeclObjC.h"13#include "clang/AST/DeclTemplate.h"14#include "clang/Basic/CharInfo.h"15#include "llvm/Support/ErrorHandling.h"16#include <type_traits>17 18namespace clang {19namespace comments {20 21// Check that no comment class has a non-trival destructor. They are allocated22// with a BumpPtrAllocator and therefore their destructor is not executed.23#define ABSTRACT_COMMENT(COMMENT)24#define COMMENT(CLASS, PARENT)                                                 \25  static_assert(std::is_trivially_destructible<CLASS>::value,                  \26                #CLASS " should be trivially destructible!");27#include "clang/AST/CommentNodes.inc"28#undef COMMENT29#undef ABSTRACT_COMMENT30 31// DeclInfo is also allocated with a BumpPtrAllocator.32static_assert(std::is_trivially_destructible_v<DeclInfo>,33              "DeclInfo should be trivially destructible!");34 35const char *Comment::getCommentKindName() const {36  switch (getCommentKind()) {37  case CommentKind::None:38    return "None";39#define ABSTRACT_COMMENT(COMMENT)40#define COMMENT(CLASS, PARENT)                                                 \41  case CommentKind::CLASS:                                                     \42    return #CLASS;43#include "clang/AST/CommentNodes.inc"44#undef COMMENT45#undef ABSTRACT_COMMENT46  }47  llvm_unreachable("Unknown comment kind!");48}49 50namespace {51struct good {};52struct bad {};53 54template <typename T>55good implements_child_begin_end(Comment::child_iterator (T::*)() const) {56  return good();57}58 59[[maybe_unused]]60static inline bad61implements_child_begin_end(Comment::child_iterator (Comment::*)() const) {62  return bad();63}64 65#define ASSERT_IMPLEMENTS_child_begin(function) \66  (void) good(implements_child_begin_end(function))67 68[[maybe_unused]]69static inline void CheckCommentASTNodes() {70#define ABSTRACT_COMMENT(COMMENT)71#define COMMENT(CLASS, PARENT) \72  ASSERT_IMPLEMENTS_child_begin(&CLASS::child_begin); \73  ASSERT_IMPLEMENTS_child_begin(&CLASS::child_end);74#include "clang/AST/CommentNodes.inc"75#undef COMMENT76#undef ABSTRACT_COMMENT77}78 79#undef ASSERT_IMPLEMENTS_child_begin80 81} // end unnamed namespace82 83Comment::child_iterator Comment::child_begin() const {84  switch (getCommentKind()) {85  case CommentKind::None:86    llvm_unreachable("comment without a kind");87#define ABSTRACT_COMMENT(COMMENT)88#define COMMENT(CLASS, PARENT)                                                 \89  case CommentKind::CLASS:                                                     \90    return static_cast<const CLASS *>(this)->child_begin();91#include "clang/AST/CommentNodes.inc"92#undef COMMENT93#undef ABSTRACT_COMMENT94  }95  llvm_unreachable("Unknown comment kind!");96}97 98Comment::child_iterator Comment::child_end() const {99  switch (getCommentKind()) {100  case CommentKind::None:101    llvm_unreachable("comment without a kind");102#define ABSTRACT_COMMENT(COMMENT)103#define COMMENT(CLASS, PARENT)                                                 \104  case CommentKind::CLASS:                                                     \105    return static_cast<const CLASS *>(this)->child_end();106#include "clang/AST/CommentNodes.inc"107#undef COMMENT108#undef ABSTRACT_COMMENT109  }110  llvm_unreachable("Unknown comment kind!");111}112 113bool TextComment::isWhitespaceNoCache() const {114  return llvm::all_of(Text, clang::isWhitespace);115}116 117bool ParagraphComment::isWhitespaceNoCache() const {118  for (child_iterator I = child_begin(), E = child_end(); I != E; ++I) {119    if (const TextComment *TC = dyn_cast<TextComment>(*I)) {120      if (!TC->isWhitespace())121        return false;122    } else123      return false;124  }125  return true;126}127 128static TypeLoc lookThroughTypedefOrTypeAliasLocs(TypeLoc &SrcTL) {129  TypeLoc TL = SrcTL.IgnoreParens();130 131  // Look through attribute types.132  if (AttributedTypeLoc AttributeTL = TL.getAs<AttributedTypeLoc>())133    return AttributeTL.getModifiedLoc();134  // Look through qualified types.135  if (QualifiedTypeLoc QualifiedTL = TL.getAs<QualifiedTypeLoc>())136    return QualifiedTL.getUnqualifiedLoc();137  // Look through pointer types.138  if (PointerTypeLoc PointerTL = TL.getAs<PointerTypeLoc>())139    return PointerTL.getPointeeLoc().getUnqualifiedLoc();140  // Look through reference types.141  if (ReferenceTypeLoc ReferenceTL = TL.getAs<ReferenceTypeLoc>())142    return ReferenceTL.getPointeeLoc().getUnqualifiedLoc();143  // Look through adjusted types.144  if (AdjustedTypeLoc ATL = TL.getAs<AdjustedTypeLoc>())145    return ATL.getOriginalLoc();146  if (BlockPointerTypeLoc BlockPointerTL = TL.getAs<BlockPointerTypeLoc>())147    return BlockPointerTL.getPointeeLoc().getUnqualifiedLoc();148  if (MemberPointerTypeLoc MemberPointerTL = TL.getAs<MemberPointerTypeLoc>())149    return MemberPointerTL.getPointeeLoc().getUnqualifiedLoc();150 151  return TL;152}153 154static bool getFunctionTypeLoc(TypeLoc TL, FunctionTypeLoc &ResFTL) {155  TypeLoc PrevTL;156  while (PrevTL != TL) {157    PrevTL = TL;158    TL = lookThroughTypedefOrTypeAliasLocs(TL);159  }160 161  if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) {162    ResFTL = FTL;163    return true;164  }165 166  if (TemplateSpecializationTypeLoc STL =167          TL.getAs<TemplateSpecializationTypeLoc>()) {168    // If we have a typedef to a template specialization with exactly one169    // template argument of a function type, this looks like std::function,170    // boost::function, or other function wrapper.  Treat these typedefs as171    // functions.172    if (STL.getNumArgs() != 1)173      return false;174    TemplateArgumentLoc MaybeFunction = STL.getArgLoc(0);175    if (MaybeFunction.getArgument().getKind() != TemplateArgument::Type)176      return false;177    TypeSourceInfo *MaybeFunctionTSI = MaybeFunction.getTypeSourceInfo();178    TypeLoc TL = MaybeFunctionTSI->getTypeLoc().getUnqualifiedLoc();179    if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) {180      ResFTL = FTL;181      return true;182    }183  }184 185  return false;186}187 188const char *189ParamCommandComment::getDirectionAsString(ParamCommandPassDirection D) {190  switch (D) {191  case ParamCommandPassDirection::In:192    return "[in]";193  case ParamCommandPassDirection::Out:194    return "[out]";195  case ParamCommandPassDirection::InOut:196    return "[in,out]";197  }198  llvm_unreachable("unknown PassDirection");199}200 201void DeclInfo::fill() {202  assert(!IsFilled);203 204  // Set defaults.205  Kind = OtherKind;206  TemplateKind = NotTemplate;207  IsObjCMethod = false;208  IsInstanceMethod = false;209  IsClassMethod = false;210  IsVariadic = false;211  ParamVars = {};212  TemplateParameters = nullptr;213 214  if (!CommentDecl) {215    // If there is no declaration, the defaults is our only guess.216    IsFilled = true;217    return;218  }219  CurrentDecl = CommentDecl;220 221  Decl::Kind K = CommentDecl->getKind();222  const TypeSourceInfo *TSI = nullptr;223  switch (K) {224  default:225    // Defaults are should be good for declarations we don't handle explicitly.226    break;227  case Decl::Function:228  case Decl::CXXMethod:229  case Decl::CXXConstructor:230  case Decl::CXXDestructor:231  case Decl::CXXConversion: {232    const FunctionDecl *FD = cast<FunctionDecl>(CommentDecl);233    Kind = FunctionKind;234    ParamVars = FD->parameters();235    ReturnType = FD->getReturnType();236    unsigned NumLists = FD->getNumTemplateParameterLists();237    if (NumLists != 0) {238      TemplateKind = TemplateSpecialization;239      TemplateParameters =240          FD->getTemplateParameterList(NumLists - 1);241    }242 243    if (K == Decl::CXXMethod || K == Decl::CXXConstructor ||244        K == Decl::CXXDestructor || K == Decl::CXXConversion) {245      const CXXMethodDecl *MD = cast<CXXMethodDecl>(CommentDecl);246      IsInstanceMethod = MD->isInstance();247      IsClassMethod = !IsInstanceMethod;248    }249    IsVariadic = FD->isVariadic();250    assert(involvesFunctionType());251    break;252  }253  case Decl::ObjCMethod: {254    const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(CommentDecl);255    Kind = FunctionKind;256    ParamVars = MD->parameters();257    ReturnType = MD->getReturnType();258    IsObjCMethod = true;259    IsInstanceMethod = MD->isInstanceMethod();260    IsClassMethod = !IsInstanceMethod;261    IsVariadic = MD->isVariadic();262    assert(involvesFunctionType());263    break;264  }265  case Decl::FunctionTemplate: {266    const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(CommentDecl);267    Kind = FunctionKind;268    TemplateKind = Template;269    const FunctionDecl *FD = FTD->getTemplatedDecl();270    ParamVars = FD->parameters();271    ReturnType = FD->getReturnType();272    TemplateParameters = FTD->getTemplateParameters();273    IsVariadic = FD->isVariadic();274    assert(involvesFunctionType());275    break;276  }277  case Decl::ClassTemplate: {278    const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(CommentDecl);279    Kind = ClassKind;280    TemplateKind = Template;281    TemplateParameters = CTD->getTemplateParameters();282    break;283  }284  case Decl::ClassTemplatePartialSpecialization: {285    const ClassTemplatePartialSpecializationDecl *CTPSD =286        cast<ClassTemplatePartialSpecializationDecl>(CommentDecl);287    Kind = ClassKind;288    TemplateKind = TemplatePartialSpecialization;289    TemplateParameters = CTPSD->getTemplateParameters();290    break;291  }292  case Decl::VarTemplatePartialSpecialization: {293    const auto *VTPSD = cast<VarTemplatePartialSpecializationDecl>(CommentDecl);294    Kind = VariableKind;295    TemplateKind = TemplatePartialSpecialization;296    TemplateParameters = VTPSD->getTemplateParameters();297    break;298  }299  case Decl::ClassTemplateSpecialization:300    Kind = ClassKind;301    TemplateKind = TemplateSpecialization;302    break;303  case Decl::Record:304  case Decl::CXXRecord:305    Kind = ClassKind;306    break;307  case Decl::Var:308    if (const VarTemplateDecl *VTD =309            cast<VarDecl>(CommentDecl)->getDescribedVarTemplate()) {310      TemplateKind = TemplateSpecialization;311      TemplateParameters = VTD->getTemplateParameters();312    }313    [[fallthrough]];314  case Decl::Field:315  case Decl::EnumConstant:316  case Decl::ObjCIvar:317  case Decl::ObjCAtDefsField:318  case Decl::ObjCProperty:319    if (const auto *VD = dyn_cast<DeclaratorDecl>(CommentDecl))320      TSI = VD->getTypeSourceInfo();321    else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(CommentDecl))322      TSI = PD->getTypeSourceInfo();323    Kind = VariableKind;324    break;325  case Decl::VarTemplate: {326    const VarTemplateDecl *VTD = cast<VarTemplateDecl>(CommentDecl);327    Kind = VariableKind;328    TemplateKind = Template;329    TemplateParameters = VTD->getTemplateParameters();330    if (const VarDecl *VD = VTD->getTemplatedDecl())331      TSI = VD->getTypeSourceInfo();332    break;333  }334  case Decl::Namespace:335    Kind = NamespaceKind;336    break;337  case Decl::TypeAlias:338  case Decl::Typedef:339    Kind = TypedefKind;340    TSI = cast<TypedefNameDecl>(CommentDecl)->getTypeSourceInfo();341    break;342  case Decl::TypeAliasTemplate: {343    const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(CommentDecl);344    Kind = TypedefKind;345    TemplateKind = Template;346    TemplateParameters = TAT->getTemplateParameters();347    if (TypeAliasDecl *TAD = TAT->getTemplatedDecl())348      TSI = TAD->getTypeSourceInfo();349    break;350  }351  case Decl::Enum:352    Kind = EnumKind;353    break;354  }355 356  // If the type is a typedef / using to something we consider a function,357  // extract arguments and return type.358  if (TSI) {359    TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc();360    FunctionTypeLoc FTL;361    if (getFunctionTypeLoc(TL, FTL)) {362      ParamVars = FTL.getParams();363      ReturnType = FTL.getReturnLoc().getType();364      if (const auto *FPT = dyn_cast<FunctionProtoType>(FTL.getTypePtr()))365        IsVariadic = FPT->isVariadic();366      assert(involvesFunctionType());367    }368  }369 370  IsFilled = true;371}372 373StringRef ParamCommandComment::getParamName(const FullComment *FC) const {374  assert(isParamIndexValid());375  if (isVarArgParam())376    return "...";377  return FC->getDeclInfo()->ParamVars[getParamIndex()]->getName();378}379 380StringRef TParamCommandComment::getParamName(const FullComment *FC) const {381  assert(isPositionValid());382  const TemplateParameterList *TPL = FC->getDeclInfo()->TemplateParameters;383  for (unsigned i = 0, e = getDepth(); i != e; ++i) {384    assert(TPL && "Unknown TemplateParameterList");385    if (i == e - 1)386      return TPL->getParam(getIndex(i))->getName();387    const NamedDecl *Param = TPL->getParam(getIndex(i));388    if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param))389      TPL = TTP->getTemplateParameters();390  }391  return "";392}393 394} // end namespace comments395} // end namespace clang396 397