1239313Sdim//===--- Comment.cpp - Comment AST node implementation --------------------===//
2239313Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6239313Sdim//
7239313Sdim//===----------------------------------------------------------------------===//
8239313Sdim
9314564Sdim#include "clang/AST/Comment.h"
10243830Sdim#include "clang/AST/ASTContext.h"
11239313Sdim#include "clang/AST/Decl.h"
12239313Sdim#include "clang/AST/DeclObjC.h"
13239313Sdim#include "clang/AST/DeclTemplate.h"
14261991Sdim#include "clang/Basic/CharInfo.h"
15239313Sdim#include "llvm/Support/ErrorHandling.h"
16360784Sdim#include <type_traits>
17239313Sdim
18239313Sdimnamespace clang {
19239313Sdimnamespace comments {
20239313Sdim
21360784Sdim// Check that no comment class has a non-trival destructor. They are allocated
22360784Sdim// with a BumpPtrAllocator and therefore their destructor is not executed.
23360784Sdim#define ABSTRACT_COMMENT(COMMENT)
24360784Sdim#define COMMENT(CLASS, PARENT)                                                 \
25360784Sdim  static_assert(std::is_trivially_destructible<CLASS>::value,                  \
26360784Sdim                #CLASS " should be trivially destructible!");
27360784Sdim#include "clang/AST/CommentNodes.inc"
28360784Sdim#undef COMMENT
29360784Sdim#undef ABSTRACT_COMMENT
30360784Sdim
31360784Sdim// DeclInfo is also allocated with a BumpPtrAllocator.
32360784Sdimstatic_assert(std::is_trivially_destructible<DeclInfo>::value,
33360784Sdim              "DeclInfo should be trivially destructible!");
34360784Sdim
35239313Sdimconst char *Comment::getCommentKindName() const {
36239313Sdim  switch (getCommentKind()) {
37239313Sdim  case NoCommentKind: return "NoCommentKind";
38239313Sdim#define ABSTRACT_COMMENT(COMMENT)
39239313Sdim#define COMMENT(CLASS, PARENT) \
40239313Sdim  case CLASS##Kind: \
41239313Sdim    return #CLASS;
42239313Sdim#include "clang/AST/CommentNodes.inc"
43239313Sdim#undef COMMENT
44239313Sdim#undef ABSTRACT_COMMENT
45239313Sdim  }
46239313Sdim  llvm_unreachable("Unknown comment kind!");
47239313Sdim}
48239313Sdim
49239313Sdimnamespace {
50239313Sdimstruct good {};
51239313Sdimstruct bad {};
52239313Sdim
53239313Sdimtemplate <typename T>
54239313Sdimgood implements_child_begin_end(Comment::child_iterator (T::*)() const) {
55239313Sdim  return good();
56239313Sdim}
57239313Sdim
58261991SdimLLVM_ATTRIBUTE_UNUSED
59239313Sdimstatic inline bad implements_child_begin_end(
60239313Sdim                      Comment::child_iterator (Comment::*)() const) {
61239313Sdim  return bad();
62239313Sdim}
63239313Sdim
64239313Sdim#define ASSERT_IMPLEMENTS_child_begin(function) \
65261991Sdim  (void) good(implements_child_begin_end(function))
66239313Sdim
67261991SdimLLVM_ATTRIBUTE_UNUSED
68239313Sdimstatic inline void CheckCommentASTNodes() {
69239313Sdim#define ABSTRACT_COMMENT(COMMENT)
70239313Sdim#define COMMENT(CLASS, PARENT) \
71239313Sdim  ASSERT_IMPLEMENTS_child_begin(&CLASS::child_begin); \
72239313Sdim  ASSERT_IMPLEMENTS_child_begin(&CLASS::child_end);
73239313Sdim#include "clang/AST/CommentNodes.inc"
74239313Sdim#undef COMMENT
75239313Sdim#undef ABSTRACT_COMMENT
76239313Sdim}
77239313Sdim
78239313Sdim#undef ASSERT_IMPLEMENTS_child_begin
79239313Sdim
80239313Sdim} // end unnamed namespace
81239313Sdim
82239313SdimComment::child_iterator Comment::child_begin() const {
83239313Sdim  switch (getCommentKind()) {
84239313Sdim  case NoCommentKind: llvm_unreachable("comment without a kind");
85239313Sdim#define ABSTRACT_COMMENT(COMMENT)
86239313Sdim#define COMMENT(CLASS, PARENT) \
87239313Sdim  case CLASS##Kind: \
88239313Sdim    return static_cast<const CLASS *>(this)->child_begin();
89239313Sdim#include "clang/AST/CommentNodes.inc"
90239313Sdim#undef COMMENT
91239313Sdim#undef ABSTRACT_COMMENT
92239313Sdim  }
93239313Sdim  llvm_unreachable("Unknown comment kind!");
94239313Sdim}
95239313Sdim
96239313SdimComment::child_iterator Comment::child_end() const {
97239313Sdim  switch (getCommentKind()) {
98239313Sdim  case NoCommentKind: llvm_unreachable("comment without a kind");
99239313Sdim#define ABSTRACT_COMMENT(COMMENT)
100239313Sdim#define COMMENT(CLASS, PARENT) \
101239313Sdim  case CLASS##Kind: \
102239313Sdim    return static_cast<const CLASS *>(this)->child_end();
103239313Sdim#include "clang/AST/CommentNodes.inc"
104239313Sdim#undef COMMENT
105239313Sdim#undef ABSTRACT_COMMENT
106239313Sdim  }
107239313Sdim  llvm_unreachable("Unknown comment kind!");
108239313Sdim}
109239313Sdim
110239313Sdimbool TextComment::isWhitespaceNoCache() const {
111239313Sdim  for (StringRef::const_iterator I = Text.begin(), E = Text.end();
112239313Sdim       I != E; ++I) {
113261991Sdim    if (!clang::isWhitespace(*I))
114239313Sdim      return false;
115239313Sdim  }
116239313Sdim  return true;
117239313Sdim}
118239313Sdim
119239313Sdimbool ParagraphComment::isWhitespaceNoCache() const {
120239313Sdim  for (child_iterator I = child_begin(), E = child_end(); I != E; ++I) {
121239313Sdim    if (const TextComment *TC = dyn_cast<TextComment>(*I)) {
122239313Sdim      if (!TC->isWhitespace())
123239313Sdim        return false;
124239313Sdim    } else
125239313Sdim      return false;
126239313Sdim  }
127239313Sdim  return true;
128239313Sdim}
129239313Sdim
130314564Sdimstatic TypeLoc lookThroughTypedefOrTypeAliasLocs(TypeLoc &SrcTL) {
131314564Sdim  TypeLoc TL = SrcTL.IgnoreParens();
132314564Sdim
133321369Sdim  // Look through attribute types.
134321369Sdim  if (AttributedTypeLoc AttributeTL = TL.getAs<AttributedTypeLoc>())
135321369Sdim    return AttributeTL.getModifiedLoc();
136314564Sdim  // Look through qualified types.
137314564Sdim  if (QualifiedTypeLoc QualifiedTL = TL.getAs<QualifiedTypeLoc>())
138314564Sdim    return QualifiedTL.getUnqualifiedLoc();
139314564Sdim  // Look through pointer types.
140314564Sdim  if (PointerTypeLoc PointerTL = TL.getAs<PointerTypeLoc>())
141314564Sdim    return PointerTL.getPointeeLoc().getUnqualifiedLoc();
142314564Sdim  // Look through reference types.
143314564Sdim  if (ReferenceTypeLoc ReferenceTL = TL.getAs<ReferenceTypeLoc>())
144314564Sdim    return ReferenceTL.getPointeeLoc().getUnqualifiedLoc();
145314564Sdim  // Look through adjusted types.
146314564Sdim  if (AdjustedTypeLoc ATL = TL.getAs<AdjustedTypeLoc>())
147314564Sdim    return ATL.getOriginalLoc();
148314564Sdim  if (BlockPointerTypeLoc BlockPointerTL = TL.getAs<BlockPointerTypeLoc>())
149314564Sdim    return BlockPointerTL.getPointeeLoc().getUnqualifiedLoc();
150314564Sdim  if (MemberPointerTypeLoc MemberPointerTL = TL.getAs<MemberPointerTypeLoc>())
151314564Sdim    return MemberPointerTL.getPointeeLoc().getUnqualifiedLoc();
152314564Sdim  if (ElaboratedTypeLoc ETL = TL.getAs<ElaboratedTypeLoc>())
153314564Sdim    return ETL.getNamedTypeLoc();
154314564Sdim
155314564Sdim  return TL;
156314564Sdim}
157314564Sdim
158314564Sdimstatic bool getFunctionTypeLoc(TypeLoc TL, FunctionTypeLoc &ResFTL) {
159314564Sdim  TypeLoc PrevTL;
160314564Sdim  while (PrevTL != TL) {
161314564Sdim    PrevTL = TL;
162314564Sdim    TL = lookThroughTypedefOrTypeAliasLocs(TL);
163314564Sdim  }
164314564Sdim
165314564Sdim  if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) {
166314564Sdim    ResFTL = FTL;
167314564Sdim    return true;
168314564Sdim  }
169314564Sdim
170314564Sdim  if (TemplateSpecializationTypeLoc STL =
171314564Sdim          TL.getAs<TemplateSpecializationTypeLoc>()) {
172314564Sdim    // If we have a typedef to a template specialization with exactly one
173314564Sdim    // template argument of a function type, this looks like std::function,
174314564Sdim    // boost::function, or other function wrapper.  Treat these typedefs as
175314564Sdim    // functions.
176314564Sdim    if (STL.getNumArgs() != 1)
177314564Sdim      return false;
178314564Sdim    TemplateArgumentLoc MaybeFunction = STL.getArgLoc(0);
179314564Sdim    if (MaybeFunction.getArgument().getKind() != TemplateArgument::Type)
180314564Sdim      return false;
181314564Sdim    TypeSourceInfo *MaybeFunctionTSI = MaybeFunction.getTypeSourceInfo();
182314564Sdim    TypeLoc TL = MaybeFunctionTSI->getTypeLoc().getUnqualifiedLoc();
183314564Sdim    if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) {
184314564Sdim      ResFTL = FTL;
185314564Sdim      return true;
186314564Sdim    }
187314564Sdim  }
188314564Sdim
189314564Sdim  return false;
190314564Sdim}
191314564Sdim
192239313Sdimconst char *ParamCommandComment::getDirectionAsString(PassDirection D) {
193239313Sdim  switch (D) {
194239313Sdim  case ParamCommandComment::In:
195239313Sdim    return "[in]";
196239313Sdim  case ParamCommandComment::Out:
197239313Sdim    return "[out]";
198239313Sdim  case ParamCommandComment::InOut:
199239313Sdim    return "[in,out]";
200239313Sdim  }
201239313Sdim  llvm_unreachable("unknown PassDirection");
202239313Sdim}
203239313Sdim
204239313Sdimvoid DeclInfo::fill() {
205239313Sdim  assert(!IsFilled);
206239313Sdim
207239313Sdim  // Set defaults.
208239313Sdim  Kind = OtherKind;
209239313Sdim  TemplateKind = NotTemplate;
210239313Sdim  IsObjCMethod = false;
211239313Sdim  IsInstanceMethod = false;
212239313Sdim  IsClassMethod = false;
213251662Sdim  ParamVars = None;
214276479Sdim  TemplateParameters = nullptr;
215239313Sdim
216243830Sdim  if (!CommentDecl) {
217239313Sdim    // If there is no declaration, the defaults is our only guess.
218239313Sdim    IsFilled = true;
219239313Sdim    return;
220239313Sdim  }
221243830Sdim  CurrentDecl = CommentDecl;
222341825Sdim
223243830Sdim  Decl::Kind K = CommentDecl->getKind();
224239313Sdim  switch (K) {
225239313Sdim  default:
226239313Sdim    // Defaults are should be good for declarations we don't handle explicitly.
227239313Sdim    break;
228239313Sdim  case Decl::Function:
229239313Sdim  case Decl::CXXMethod:
230239313Sdim  case Decl::CXXConstructor:
231239313Sdim  case Decl::CXXDestructor:
232239313Sdim  case Decl::CXXConversion: {
233243830Sdim    const FunctionDecl *FD = cast<FunctionDecl>(CommentDecl);
234239313Sdim    Kind = FunctionKind;
235309124Sdim    ParamVars = FD->parameters();
236276479Sdim    ReturnType = FD->getReturnType();
237239313Sdim    unsigned NumLists = FD->getNumTemplateParameterLists();
238239313Sdim    if (NumLists != 0) {
239239313Sdim      TemplateKind = TemplateSpecialization;
240239313Sdim      TemplateParameters =
241239313Sdim          FD->getTemplateParameterList(NumLists - 1);
242239313Sdim    }
243239313Sdim
244239313Sdim    if (K == Decl::CXXMethod || K == Decl::CXXConstructor ||
245239313Sdim        K == Decl::CXXDestructor || K == Decl::CXXConversion) {
246243830Sdim      const CXXMethodDecl *MD = cast<CXXMethodDecl>(CommentDecl);
247239313Sdim      IsInstanceMethod = MD->isInstance();
248239313Sdim      IsClassMethod = !IsInstanceMethod;
249239313Sdim    }
250239313Sdim    break;
251239313Sdim  }
252239313Sdim  case Decl::ObjCMethod: {
253243830Sdim    const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(CommentDecl);
254239313Sdim    Kind = FunctionKind;
255309124Sdim    ParamVars = MD->parameters();
256276479Sdim    ReturnType = MD->getReturnType();
257239313Sdim    IsObjCMethod = true;
258239313Sdim    IsInstanceMethod = MD->isInstanceMethod();
259239313Sdim    IsClassMethod = !IsInstanceMethod;
260239313Sdim    break;
261239313Sdim  }
262239313Sdim  case Decl::FunctionTemplate: {
263243830Sdim    const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(CommentDecl);
264239313Sdim    Kind = FunctionKind;
265239313Sdim    TemplateKind = Template;
266239313Sdim    const FunctionDecl *FD = FTD->getTemplatedDecl();
267309124Sdim    ParamVars = FD->parameters();
268276479Sdim    ReturnType = FD->getReturnType();
269239313Sdim    TemplateParameters = FTD->getTemplateParameters();
270239313Sdim    break;
271239313Sdim  }
272239313Sdim  case Decl::ClassTemplate: {
273243830Sdim    const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(CommentDecl);
274239313Sdim    Kind = ClassKind;
275239313Sdim    TemplateKind = Template;
276239313Sdim    TemplateParameters = CTD->getTemplateParameters();
277239313Sdim    break;
278239313Sdim  }
279239313Sdim  case Decl::ClassTemplatePartialSpecialization: {
280239313Sdim    const ClassTemplatePartialSpecializationDecl *CTPSD =
281243830Sdim        cast<ClassTemplatePartialSpecializationDecl>(CommentDecl);
282239313Sdim    Kind = ClassKind;
283239313Sdim    TemplateKind = TemplatePartialSpecialization;
284239313Sdim    TemplateParameters = CTPSD->getTemplateParameters();
285239313Sdim    break;
286239313Sdim  }
287239313Sdim  case Decl::ClassTemplateSpecialization:
288239313Sdim    Kind = ClassKind;
289239313Sdim    TemplateKind = TemplateSpecialization;
290239313Sdim    break;
291239313Sdim  case Decl::Record:
292239313Sdim  case Decl::CXXRecord:
293239313Sdim    Kind = ClassKind;
294239313Sdim    break;
295239313Sdim  case Decl::Var:
296239313Sdim  case Decl::Field:
297239313Sdim  case Decl::EnumConstant:
298239313Sdim  case Decl::ObjCIvar:
299239313Sdim  case Decl::ObjCAtDefsField:
300321369Sdim  case Decl::ObjCProperty: {
301321369Sdim    const TypeSourceInfo *TSI;
302321369Sdim    if (const auto *VD = dyn_cast<DeclaratorDecl>(CommentDecl))
303321369Sdim      TSI = VD->getTypeSourceInfo();
304321369Sdim    else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(CommentDecl))
305321369Sdim      TSI = PD->getTypeSourceInfo();
306321369Sdim    else
307321369Sdim      TSI = nullptr;
308321369Sdim    if (TSI) {
309321369Sdim      TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc();
310321369Sdim      FunctionTypeLoc FTL;
311321369Sdim      if (getFunctionTypeLoc(TL, FTL)) {
312321369Sdim        ParamVars = FTL.getParams();
313321369Sdim        ReturnType = FTL.getReturnLoc().getType();
314321369Sdim      }
315321369Sdim    }
316239313Sdim    Kind = VariableKind;
317239313Sdim    break;
318321369Sdim  }
319239313Sdim  case Decl::Namespace:
320239313Sdim    Kind = NamespaceKind;
321239313Sdim    break;
322314564Sdim  case Decl::TypeAlias:
323243830Sdim  case Decl::Typedef: {
324243830Sdim    Kind = TypedefKind;
325314564Sdim    // If this is a typedef / using to something we consider a function, extract
326243830Sdim    // arguments and return type.
327314564Sdim    const TypeSourceInfo *TSI =
328314564Sdim        K == Decl::Typedef
329314564Sdim            ? cast<TypedefDecl>(CommentDecl)->getTypeSourceInfo()
330314564Sdim            : cast<TypeAliasDecl>(CommentDecl)->getTypeSourceInfo();
331243830Sdim    if (!TSI)
332243830Sdim      break;
333243830Sdim    TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc();
334314564Sdim    FunctionTypeLoc FTL;
335314564Sdim    if (getFunctionTypeLoc(TL, FTL)) {
336314564Sdim      Kind = FunctionKind;
337314564Sdim      ParamVars = FTL.getParams();
338314564Sdim      ReturnType = FTL.getReturnLoc().getType();
339243830Sdim    }
340243830Sdim    break;
341243830Sdim  }
342239313Sdim  case Decl::TypeAliasTemplate: {
343243830Sdim    const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(CommentDecl);
344239313Sdim    Kind = TypedefKind;
345239313Sdim    TemplateKind = Template;
346239313Sdim    TemplateParameters = TAT->getTemplateParameters();
347314564Sdim    TypeAliasDecl *TAD = TAT->getTemplatedDecl();
348314564Sdim    if (!TAD)
349314564Sdim      break;
350314564Sdim
351314564Sdim    const TypeSourceInfo *TSI = TAD->getTypeSourceInfo();
352314564Sdim    if (!TSI)
353314564Sdim      break;
354314564Sdim    TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc();
355314564Sdim    FunctionTypeLoc FTL;
356314564Sdim    if (getFunctionTypeLoc(TL, FTL)) {
357314564Sdim      Kind = FunctionKind;
358314564Sdim      ParamVars = FTL.getParams();
359314564Sdim      ReturnType = FTL.getReturnLoc().getType();
360314564Sdim    }
361239313Sdim    break;
362239313Sdim  }
363239313Sdim  case Decl::Enum:
364239313Sdim    Kind = EnumKind;
365239313Sdim    break;
366239313Sdim  }
367239313Sdim
368239313Sdim  IsFilled = true;
369239313Sdim}
370239313Sdim
371243830SdimStringRef ParamCommandComment::getParamName(const FullComment *FC) const {
372243830Sdim  assert(isParamIndexValid());
373261991Sdim  if (isVarArgParam())
374261991Sdim    return "...";
375261991Sdim  return FC->getDeclInfo()->ParamVars[getParamIndex()]->getName();
376243830Sdim}
377243830Sdim
378243830SdimStringRef TParamCommandComment::getParamName(const FullComment *FC) const {
379243830Sdim  assert(isPositionValid());
380261991Sdim  const TemplateParameterList *TPL = FC->getDeclInfo()->TemplateParameters;
381243830Sdim  for (unsigned i = 0, e = getDepth(); i != e; ++i) {
382360784Sdim    assert(TPL && "Unknown TemplateParameterList");
383360784Sdim    if (i == e - 1)
384243830Sdim      return TPL->getParam(getIndex(i))->getName();
385243830Sdim    const NamedDecl *Param = TPL->getParam(getIndex(i));
386360784Sdim    if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param))
387243830Sdim      TPL = TTP->getTemplateParameters();
388243830Sdim  }
389243830Sdim  return "";
390243830Sdim}
391243830Sdim
392239313Sdim} // end namespace comments
393239313Sdim} // end namespace clang
394239313Sdim
395