llvm-project

Форк
0
/
Comment.cpp 
390 строк · 12.4 Кб
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-exception
6
//
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

18
namespace clang {
19
namespace comments {
20

21
// Check that no comment class has a non-trival destructor. They are allocated
22
// 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 COMMENT
29
#undef ABSTRACT_COMMENT
30

31
// DeclInfo is also allocated with a BumpPtrAllocator.
32
static_assert(std::is_trivially_destructible_v<DeclInfo>,
33
              "DeclInfo should be trivially destructible!");
34

35
const 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 COMMENT
45
#undef ABSTRACT_COMMENT
46
  }
47
  llvm_unreachable("Unknown comment kind!");
48
}
49

50
namespace {
51
struct good {};
52
struct bad {};
53

54
template <typename T>
55
good implements_child_begin_end(Comment::child_iterator (T::*)() const) {
56
  return good();
57
}
58

59
LLVM_ATTRIBUTE_UNUSED
60
static inline bad implements_child_begin_end(
61
                      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
LLVM_ATTRIBUTE_UNUSED
69
static 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 COMMENT
76
#undef ABSTRACT_COMMENT
77
}
78

79
#undef ASSERT_IMPLEMENTS_child_begin
80

81
} // end unnamed namespace
82

83
Comment::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 COMMENT
93
#undef ABSTRACT_COMMENT
94
  }
95
  llvm_unreachable("Unknown comment kind!");
96
}
97

98
Comment::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 COMMENT
108
#undef ABSTRACT_COMMENT
109
  }
110
  llvm_unreachable("Unknown comment kind!");
111
}
112

113
bool TextComment::isWhitespaceNoCache() const {
114
  return llvm::all_of(Text, clang::isWhitespace);
115
}
116

117
bool 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
    } else
123
      return false;
124
  }
125
  return true;
126
}
127

128
static 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
  if (ElaboratedTypeLoc ETL = TL.getAs<ElaboratedTypeLoc>())
151
    return ETL.getNamedTypeLoc();
152

153
  return TL;
154
}
155

156
static bool getFunctionTypeLoc(TypeLoc TL, FunctionTypeLoc &ResFTL) {
157
  TypeLoc PrevTL;
158
  while (PrevTL != TL) {
159
    PrevTL = TL;
160
    TL = lookThroughTypedefOrTypeAliasLocs(TL);
161
  }
162

163
  if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) {
164
    ResFTL = FTL;
165
    return true;
166
  }
167

168
  if (TemplateSpecializationTypeLoc STL =
169
          TL.getAs<TemplateSpecializationTypeLoc>()) {
170
    // If we have a typedef to a template specialization with exactly one
171
    // template argument of a function type, this looks like std::function,
172
    // boost::function, or other function wrapper.  Treat these typedefs as
173
    // functions.
174
    if (STL.getNumArgs() != 1)
175
      return false;
176
    TemplateArgumentLoc MaybeFunction = STL.getArgLoc(0);
177
    if (MaybeFunction.getArgument().getKind() != TemplateArgument::Type)
178
      return false;
179
    TypeSourceInfo *MaybeFunctionTSI = MaybeFunction.getTypeSourceInfo();
180
    TypeLoc TL = MaybeFunctionTSI->getTypeLoc().getUnqualifiedLoc();
181
    if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) {
182
      ResFTL = FTL;
183
      return true;
184
    }
185
  }
186

187
  return false;
188
}
189

190
const char *
191
ParamCommandComment::getDirectionAsString(ParamCommandPassDirection D) {
192
  switch (D) {
193
  case ParamCommandPassDirection::In:
194
    return "[in]";
195
  case ParamCommandPassDirection::Out:
196
    return "[out]";
197
  case ParamCommandPassDirection::InOut:
198
    return "[in,out]";
199
  }
200
  llvm_unreachable("unknown PassDirection");
201
}
202

203
void DeclInfo::fill() {
204
  assert(!IsFilled);
205

206
  // Set defaults.
207
  Kind = OtherKind;
208
  TemplateKind = NotTemplate;
209
  IsObjCMethod = false;
210
  IsInstanceMethod = false;
211
  IsClassMethod = false;
212
  IsVariadic = false;
213
  ParamVars = std::nullopt;
214
  TemplateParameters = nullptr;
215

216
  if (!CommentDecl) {
217
    // If there is no declaration, the defaults is our only guess.
218
    IsFilled = true;
219
    return;
220
  }
221
  CurrentDecl = CommentDecl;
222

223
  Decl::Kind K = CommentDecl->getKind();
224
  const TypeSourceInfo *TSI = nullptr;
225
  switch (K) {
226
  default:
227
    // Defaults are should be good for declarations we don't handle explicitly.
228
    break;
229
  case Decl::Function:
230
  case Decl::CXXMethod:
231
  case Decl::CXXConstructor:
232
  case Decl::CXXDestructor:
233
  case Decl::CXXConversion: {
234
    const FunctionDecl *FD = cast<FunctionDecl>(CommentDecl);
235
    Kind = FunctionKind;
236
    ParamVars = FD->parameters();
237
    ReturnType = FD->getReturnType();
238
    unsigned NumLists = FD->getNumTemplateParameterLists();
239
    if (NumLists != 0) {
240
      TemplateKind = TemplateSpecialization;
241
      TemplateParameters =
242
          FD->getTemplateParameterList(NumLists - 1);
243
    }
244

245
    if (K == Decl::CXXMethod || K == Decl::CXXConstructor ||
246
        K == Decl::CXXDestructor || K == Decl::CXXConversion) {
247
      const CXXMethodDecl *MD = cast<CXXMethodDecl>(CommentDecl);
248
      IsInstanceMethod = MD->isInstance();
249
      IsClassMethod = !IsInstanceMethod;
250
    }
251
    IsVariadic = FD->isVariadic();
252
    assert(involvesFunctionType());
253
    break;
254
  }
255
  case Decl::ObjCMethod: {
256
    const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(CommentDecl);
257
    Kind = FunctionKind;
258
    ParamVars = MD->parameters();
259
    ReturnType = MD->getReturnType();
260
    IsObjCMethod = true;
261
    IsInstanceMethod = MD->isInstanceMethod();
262
    IsClassMethod = !IsInstanceMethod;
263
    IsVariadic = MD->isVariadic();
264
    assert(involvesFunctionType());
265
    break;
266
  }
267
  case Decl::FunctionTemplate: {
268
    const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(CommentDecl);
269
    Kind = FunctionKind;
270
    TemplateKind = Template;
271
    const FunctionDecl *FD = FTD->getTemplatedDecl();
272
    ParamVars = FD->parameters();
273
    ReturnType = FD->getReturnType();
274
    TemplateParameters = FTD->getTemplateParameters();
275
    IsVariadic = FD->isVariadic();
276
    assert(involvesFunctionType());
277
    break;
278
  }
279
  case Decl::ClassTemplate: {
280
    const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(CommentDecl);
281
    Kind = ClassKind;
282
    TemplateKind = Template;
283
    TemplateParameters = CTD->getTemplateParameters();
284
    break;
285
  }
286
  case Decl::ClassTemplatePartialSpecialization: {
287
    const ClassTemplatePartialSpecializationDecl *CTPSD =
288
        cast<ClassTemplatePartialSpecializationDecl>(CommentDecl);
289
    Kind = ClassKind;
290
    TemplateKind = TemplatePartialSpecialization;
291
    TemplateParameters = CTPSD->getTemplateParameters();
292
    break;
293
  }
294
  case Decl::ClassTemplateSpecialization:
295
    Kind = ClassKind;
296
    TemplateKind = TemplateSpecialization;
297
    break;
298
  case Decl::Record:
299
  case Decl::CXXRecord:
300
    Kind = ClassKind;
301
    break;
302
  case Decl::Var:
303
    if (const VarTemplateDecl *VTD =
304
            cast<VarDecl>(CommentDecl)->getDescribedVarTemplate()) {
305
      TemplateKind = TemplateSpecialization;
306
      TemplateParameters = VTD->getTemplateParameters();
307
    }
308
    [[fallthrough]];
309
  case Decl::Field:
310
  case Decl::EnumConstant:
311
  case Decl::ObjCIvar:
312
  case Decl::ObjCAtDefsField:
313
  case Decl::ObjCProperty:
314
    if (const auto *VD = dyn_cast<DeclaratorDecl>(CommentDecl))
315
      TSI = VD->getTypeSourceInfo();
316
    else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(CommentDecl))
317
      TSI = PD->getTypeSourceInfo();
318
    Kind = VariableKind;
319
    break;
320
  case Decl::VarTemplate: {
321
    const VarTemplateDecl *VTD = cast<VarTemplateDecl>(CommentDecl);
322
    Kind = VariableKind;
323
    TemplateKind = Template;
324
    TemplateParameters = VTD->getTemplateParameters();
325
    if (const VarDecl *VD = VTD->getTemplatedDecl())
326
      TSI = VD->getTypeSourceInfo();
327
    break;
328
  }
329
  case Decl::Namespace:
330
    Kind = NamespaceKind;
331
    break;
332
  case Decl::TypeAlias:
333
  case Decl::Typedef:
334
    Kind = TypedefKind;
335
    TSI = cast<TypedefNameDecl>(CommentDecl)->getTypeSourceInfo();
336
    break;
337
  case Decl::TypeAliasTemplate: {
338
    const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(CommentDecl);
339
    Kind = TypedefKind;
340
    TemplateKind = Template;
341
    TemplateParameters = TAT->getTemplateParameters();
342
    if (TypeAliasDecl *TAD = TAT->getTemplatedDecl())
343
      TSI = TAD->getTypeSourceInfo();
344
    break;
345
  }
346
  case Decl::Enum:
347
    Kind = EnumKind;
348
    break;
349
  }
350

351
  // If the type is a typedef / using to something we consider a function,
352
  // extract arguments and return type.
353
  if (TSI) {
354
    TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc();
355
    FunctionTypeLoc FTL;
356
    if (getFunctionTypeLoc(TL, FTL)) {
357
      ParamVars = FTL.getParams();
358
      ReturnType = FTL.getReturnLoc().getType();
359
      if (const auto *FPT = dyn_cast<FunctionProtoType>(FTL.getTypePtr()))
360
        IsVariadic = FPT->isVariadic();
361
      assert(involvesFunctionType());
362
    }
363
  }
364

365
  IsFilled = true;
366
}
367

368
StringRef ParamCommandComment::getParamName(const FullComment *FC) const {
369
  assert(isParamIndexValid());
370
  if (isVarArgParam())
371
    return "...";
372
  return FC->getDeclInfo()->ParamVars[getParamIndex()]->getName();
373
}
374

375
StringRef TParamCommandComment::getParamName(const FullComment *FC) const {
376
  assert(isPositionValid());
377
  const TemplateParameterList *TPL = FC->getDeclInfo()->TemplateParameters;
378
  for (unsigned i = 0, e = getDepth(); i != e; ++i) {
379
    assert(TPL && "Unknown TemplateParameterList");
380
    if (i == e - 1)
381
      return TPL->getParam(getIndex(i))->getName();
382
    const NamedDecl *Param = TPL->getParam(getIndex(i));
383
    if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param))
384
      TPL = TTP->getTemplateParameters();
385
  }
386
  return "";
387
}
388

389
} // end namespace comments
390
} // end namespace clang
391

392

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.