xref: /openbsd-src/gnu/llvm/clang/lib/AST/CommentSema.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1e5dd7070Spatrick //===--- CommentSema.cpp - Doxygen comment semantic analysis --------------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick 
9e5dd7070Spatrick #include "clang/AST/CommentSema.h"
10e5dd7070Spatrick #include "clang/AST/Attr.h"
11e5dd7070Spatrick #include "clang/AST/CommentCommandTraits.h"
12e5dd7070Spatrick #include "clang/AST/CommentDiagnostic.h"
13e5dd7070Spatrick #include "clang/AST/Decl.h"
14e5dd7070Spatrick #include "clang/AST/DeclTemplate.h"
15ec727ea7Spatrick #include "clang/Basic/LLVM.h"
16e5dd7070Spatrick #include "clang/Basic/SourceManager.h"
17e5dd7070Spatrick #include "clang/Lex/Preprocessor.h"
18e5dd7070Spatrick #include "llvm/ADT/SmallString.h"
19e5dd7070Spatrick #include "llvm/ADT/StringSwitch.h"
20e5dd7070Spatrick 
21e5dd7070Spatrick namespace clang {
22e5dd7070Spatrick namespace comments {
23e5dd7070Spatrick 
24e5dd7070Spatrick namespace {
25e5dd7070Spatrick #include "clang/AST/CommentHTMLTagsProperties.inc"
26e5dd7070Spatrick } // end anonymous namespace
27e5dd7070Spatrick 
Sema(llvm::BumpPtrAllocator & Allocator,const SourceManager & SourceMgr,DiagnosticsEngine & Diags,CommandTraits & Traits,const Preprocessor * PP)28e5dd7070Spatrick Sema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr,
29e5dd7070Spatrick            DiagnosticsEngine &Diags, CommandTraits &Traits,
30e5dd7070Spatrick            const Preprocessor *PP) :
31e5dd7070Spatrick     Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits),
32e5dd7070Spatrick     PP(PP), ThisDeclInfo(nullptr), BriefCommand(nullptr),
33e5dd7070Spatrick     HeaderfileCommand(nullptr) {
34e5dd7070Spatrick }
35e5dd7070Spatrick 
setDecl(const Decl * D)36e5dd7070Spatrick void Sema::setDecl(const Decl *D) {
37e5dd7070Spatrick   if (!D)
38e5dd7070Spatrick     return;
39e5dd7070Spatrick 
40e5dd7070Spatrick   ThisDeclInfo = new (Allocator) DeclInfo;
41e5dd7070Spatrick   ThisDeclInfo->CommentDecl = D;
42e5dd7070Spatrick   ThisDeclInfo->IsFilled = false;
43e5dd7070Spatrick }
44e5dd7070Spatrick 
actOnParagraphComment(ArrayRef<InlineContentComment * > Content)45e5dd7070Spatrick ParagraphComment *Sema::actOnParagraphComment(
46e5dd7070Spatrick                               ArrayRef<InlineContentComment *> Content) {
47e5dd7070Spatrick   return new (Allocator) ParagraphComment(Content);
48e5dd7070Spatrick }
49e5dd7070Spatrick 
actOnBlockCommandStart(SourceLocation LocBegin,SourceLocation LocEnd,unsigned CommandID,CommandMarkerKind CommandMarker)50e5dd7070Spatrick BlockCommandComment *Sema::actOnBlockCommandStart(
51e5dd7070Spatrick                                       SourceLocation LocBegin,
52e5dd7070Spatrick                                       SourceLocation LocEnd,
53e5dd7070Spatrick                                       unsigned CommandID,
54e5dd7070Spatrick                                       CommandMarkerKind CommandMarker) {
55e5dd7070Spatrick   BlockCommandComment *BC = new (Allocator) BlockCommandComment(LocBegin, LocEnd,
56e5dd7070Spatrick                                                                 CommandID,
57e5dd7070Spatrick                                                                 CommandMarker);
58e5dd7070Spatrick   checkContainerDecl(BC);
59e5dd7070Spatrick   return BC;
60e5dd7070Spatrick }
61e5dd7070Spatrick 
actOnBlockCommandArgs(BlockCommandComment * Command,ArrayRef<BlockCommandComment::Argument> Args)62e5dd7070Spatrick void Sema::actOnBlockCommandArgs(BlockCommandComment *Command,
63e5dd7070Spatrick                                  ArrayRef<BlockCommandComment::Argument> Args) {
64e5dd7070Spatrick   Command->setArgs(Args);
65e5dd7070Spatrick }
66e5dd7070Spatrick 
actOnBlockCommandFinish(BlockCommandComment * Command,ParagraphComment * Paragraph)67e5dd7070Spatrick void Sema::actOnBlockCommandFinish(BlockCommandComment *Command,
68e5dd7070Spatrick                                    ParagraphComment *Paragraph) {
69e5dd7070Spatrick   Command->setParagraph(Paragraph);
70e5dd7070Spatrick   checkBlockCommandEmptyParagraph(Command);
71e5dd7070Spatrick   checkBlockCommandDuplicate(Command);
72e5dd7070Spatrick   if (ThisDeclInfo) {
73e5dd7070Spatrick     // These checks only make sense if the comment is attached to a
74e5dd7070Spatrick     // declaration.
75e5dd7070Spatrick     checkReturnsCommand(Command);
76e5dd7070Spatrick     checkDeprecatedCommand(Command);
77e5dd7070Spatrick   }
78e5dd7070Spatrick }
79e5dd7070Spatrick 
actOnParamCommandStart(SourceLocation LocBegin,SourceLocation LocEnd,unsigned CommandID,CommandMarkerKind CommandMarker)80e5dd7070Spatrick ParamCommandComment *Sema::actOnParamCommandStart(
81e5dd7070Spatrick                                       SourceLocation LocBegin,
82e5dd7070Spatrick                                       SourceLocation LocEnd,
83e5dd7070Spatrick                                       unsigned CommandID,
84e5dd7070Spatrick                                       CommandMarkerKind CommandMarker) {
85e5dd7070Spatrick   ParamCommandComment *Command =
86e5dd7070Spatrick       new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID,
87e5dd7070Spatrick                                           CommandMarker);
88e5dd7070Spatrick 
89*12c85518Srobert   if (!involvesFunctionType())
90e5dd7070Spatrick     Diag(Command->getLocation(),
91e5dd7070Spatrick          diag::warn_doc_param_not_attached_to_a_function_decl)
92e5dd7070Spatrick       << CommandMarker
93e5dd7070Spatrick       << Command->getCommandNameRange(Traits);
94e5dd7070Spatrick 
95e5dd7070Spatrick   return Command;
96e5dd7070Spatrick }
97e5dd7070Spatrick 
checkFunctionDeclVerbatimLine(const BlockCommandComment * Comment)98e5dd7070Spatrick void Sema::checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment) {
99e5dd7070Spatrick   const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
100e5dd7070Spatrick   if (!Info->IsFunctionDeclarationCommand)
101e5dd7070Spatrick     return;
102e5dd7070Spatrick 
103e5dd7070Spatrick   unsigned DiagSelect;
104e5dd7070Spatrick   switch (Comment->getCommandID()) {
105e5dd7070Spatrick     case CommandTraits::KCI_function:
106e5dd7070Spatrick       DiagSelect = (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 1 : 0;
107e5dd7070Spatrick       break;
108e5dd7070Spatrick     case CommandTraits::KCI_functiongroup:
109e5dd7070Spatrick       DiagSelect = (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 2 : 0;
110e5dd7070Spatrick       break;
111e5dd7070Spatrick     case CommandTraits::KCI_method:
112e5dd7070Spatrick       DiagSelect = !isObjCMethodDecl() ? 3 : 0;
113e5dd7070Spatrick       break;
114e5dd7070Spatrick     case CommandTraits::KCI_methodgroup:
115e5dd7070Spatrick       DiagSelect = !isObjCMethodDecl() ? 4 : 0;
116e5dd7070Spatrick       break;
117e5dd7070Spatrick     case CommandTraits::KCI_callback:
118e5dd7070Spatrick       DiagSelect = !isFunctionPointerVarDecl() ? 5 : 0;
119e5dd7070Spatrick       break;
120e5dd7070Spatrick     default:
121e5dd7070Spatrick       DiagSelect = 0;
122e5dd7070Spatrick       break;
123e5dd7070Spatrick   }
124e5dd7070Spatrick   if (DiagSelect)
125e5dd7070Spatrick     Diag(Comment->getLocation(), diag::warn_doc_function_method_decl_mismatch)
126e5dd7070Spatrick     << Comment->getCommandMarker()
127e5dd7070Spatrick     << (DiagSelect-1) << (DiagSelect-1)
128e5dd7070Spatrick     << Comment->getSourceRange();
129e5dd7070Spatrick }
130e5dd7070Spatrick 
checkContainerDeclVerbatimLine(const BlockCommandComment * Comment)131e5dd7070Spatrick void Sema::checkContainerDeclVerbatimLine(const BlockCommandComment *Comment) {
132e5dd7070Spatrick   const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
133e5dd7070Spatrick   if (!Info->IsRecordLikeDeclarationCommand)
134e5dd7070Spatrick     return;
135e5dd7070Spatrick   unsigned DiagSelect;
136e5dd7070Spatrick   switch (Comment->getCommandID()) {
137e5dd7070Spatrick     case CommandTraits::KCI_class:
138ec727ea7Spatrick       DiagSelect =
139ec727ea7Spatrick           (!isClassOrStructOrTagTypedefDecl() && !isClassTemplateDecl()) ? 1
140ec727ea7Spatrick                                                                          : 0;
141e5dd7070Spatrick       // Allow @class command on @interface declarations.
142e5dd7070Spatrick       // FIXME. Currently, \class and @class are indistinguishable. So,
143e5dd7070Spatrick       // \class is also allowed on an @interface declaration
144e5dd7070Spatrick       if (DiagSelect && Comment->getCommandMarker() && isObjCInterfaceDecl())
145e5dd7070Spatrick         DiagSelect = 0;
146e5dd7070Spatrick       break;
147e5dd7070Spatrick     case CommandTraits::KCI_interface:
148e5dd7070Spatrick       DiagSelect = !isObjCInterfaceDecl() ? 2 : 0;
149e5dd7070Spatrick       break;
150e5dd7070Spatrick     case CommandTraits::KCI_protocol:
151e5dd7070Spatrick       DiagSelect = !isObjCProtocolDecl() ? 3 : 0;
152e5dd7070Spatrick       break;
153e5dd7070Spatrick     case CommandTraits::KCI_struct:
154ec727ea7Spatrick       DiagSelect = !isClassOrStructOrTagTypedefDecl() ? 4 : 0;
155e5dd7070Spatrick       break;
156e5dd7070Spatrick     case CommandTraits::KCI_union:
157e5dd7070Spatrick       DiagSelect = !isUnionDecl() ? 5 : 0;
158e5dd7070Spatrick       break;
159e5dd7070Spatrick     default:
160e5dd7070Spatrick       DiagSelect = 0;
161e5dd7070Spatrick       break;
162e5dd7070Spatrick   }
163e5dd7070Spatrick   if (DiagSelect)
164e5dd7070Spatrick     Diag(Comment->getLocation(), diag::warn_doc_api_container_decl_mismatch)
165e5dd7070Spatrick     << Comment->getCommandMarker()
166e5dd7070Spatrick     << (DiagSelect-1) << (DiagSelect-1)
167e5dd7070Spatrick     << Comment->getSourceRange();
168e5dd7070Spatrick }
169e5dd7070Spatrick 
checkContainerDecl(const BlockCommandComment * Comment)170e5dd7070Spatrick void Sema::checkContainerDecl(const BlockCommandComment *Comment) {
171e5dd7070Spatrick   const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
172e5dd7070Spatrick   if (!Info->IsRecordLikeDetailCommand || isRecordLikeDecl())
173e5dd7070Spatrick     return;
174e5dd7070Spatrick   unsigned DiagSelect;
175e5dd7070Spatrick   switch (Comment->getCommandID()) {
176e5dd7070Spatrick     case CommandTraits::KCI_classdesign:
177e5dd7070Spatrick       DiagSelect = 1;
178e5dd7070Spatrick       break;
179e5dd7070Spatrick     case CommandTraits::KCI_coclass:
180e5dd7070Spatrick       DiagSelect = 2;
181e5dd7070Spatrick       break;
182e5dd7070Spatrick     case CommandTraits::KCI_dependency:
183e5dd7070Spatrick       DiagSelect = 3;
184e5dd7070Spatrick       break;
185e5dd7070Spatrick     case CommandTraits::KCI_helper:
186e5dd7070Spatrick       DiagSelect = 4;
187e5dd7070Spatrick       break;
188e5dd7070Spatrick     case CommandTraits::KCI_helperclass:
189e5dd7070Spatrick       DiagSelect = 5;
190e5dd7070Spatrick       break;
191e5dd7070Spatrick     case CommandTraits::KCI_helps:
192e5dd7070Spatrick       DiagSelect = 6;
193e5dd7070Spatrick       break;
194e5dd7070Spatrick     case CommandTraits::KCI_instancesize:
195e5dd7070Spatrick       DiagSelect = 7;
196e5dd7070Spatrick       break;
197e5dd7070Spatrick     case CommandTraits::KCI_ownership:
198e5dd7070Spatrick       DiagSelect = 8;
199e5dd7070Spatrick       break;
200e5dd7070Spatrick     case CommandTraits::KCI_performance:
201e5dd7070Spatrick       DiagSelect = 9;
202e5dd7070Spatrick       break;
203e5dd7070Spatrick     case CommandTraits::KCI_security:
204e5dd7070Spatrick       DiagSelect = 10;
205e5dd7070Spatrick       break;
206e5dd7070Spatrick     case CommandTraits::KCI_superclass:
207e5dd7070Spatrick       DiagSelect = 11;
208e5dd7070Spatrick       break;
209e5dd7070Spatrick     default:
210e5dd7070Spatrick       DiagSelect = 0;
211e5dd7070Spatrick       break;
212e5dd7070Spatrick   }
213e5dd7070Spatrick   if (DiagSelect)
214e5dd7070Spatrick     Diag(Comment->getLocation(), diag::warn_doc_container_decl_mismatch)
215e5dd7070Spatrick     << Comment->getCommandMarker()
216e5dd7070Spatrick     << (DiagSelect-1)
217e5dd7070Spatrick     << Comment->getSourceRange();
218e5dd7070Spatrick }
219e5dd7070Spatrick 
220e5dd7070Spatrick /// Turn a string into the corresponding PassDirection or -1 if it's not
221e5dd7070Spatrick /// valid.
getParamPassDirection(StringRef Arg)222e5dd7070Spatrick static int getParamPassDirection(StringRef Arg) {
223e5dd7070Spatrick   return llvm::StringSwitch<int>(Arg)
224e5dd7070Spatrick       .Case("[in]", ParamCommandComment::In)
225e5dd7070Spatrick       .Case("[out]", ParamCommandComment::Out)
226e5dd7070Spatrick       .Cases("[in,out]", "[out,in]", ParamCommandComment::InOut)
227e5dd7070Spatrick       .Default(-1);
228e5dd7070Spatrick }
229e5dd7070Spatrick 
actOnParamCommandDirectionArg(ParamCommandComment * Command,SourceLocation ArgLocBegin,SourceLocation ArgLocEnd,StringRef Arg)230e5dd7070Spatrick void Sema::actOnParamCommandDirectionArg(ParamCommandComment *Command,
231e5dd7070Spatrick                                          SourceLocation ArgLocBegin,
232e5dd7070Spatrick                                          SourceLocation ArgLocEnd,
233e5dd7070Spatrick                                          StringRef Arg) {
234e5dd7070Spatrick   std::string ArgLower = Arg.lower();
235e5dd7070Spatrick   int Direction = getParamPassDirection(ArgLower);
236e5dd7070Spatrick 
237e5dd7070Spatrick   if (Direction == -1) {
238e5dd7070Spatrick     // Try again with whitespace removed.
239*12c85518Srobert     llvm::erase_if(ArgLower, clang::isWhitespace);
240e5dd7070Spatrick     Direction = getParamPassDirection(ArgLower);
241e5dd7070Spatrick 
242e5dd7070Spatrick     SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
243e5dd7070Spatrick     if (Direction != -1) {
244e5dd7070Spatrick       const char *FixedName = ParamCommandComment::getDirectionAsString(
245e5dd7070Spatrick           (ParamCommandComment::PassDirection)Direction);
246e5dd7070Spatrick       Diag(ArgLocBegin, diag::warn_doc_param_spaces_in_direction)
247e5dd7070Spatrick           << ArgRange << FixItHint::CreateReplacement(ArgRange, FixedName);
248e5dd7070Spatrick     } else {
249e5dd7070Spatrick       Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction) << ArgRange;
250e5dd7070Spatrick       Direction = ParamCommandComment::In; // Sane fall back.
251e5dd7070Spatrick     }
252e5dd7070Spatrick   }
253e5dd7070Spatrick   Command->setDirection((ParamCommandComment::PassDirection)Direction,
254e5dd7070Spatrick                         /*Explicit=*/true);
255e5dd7070Spatrick }
256e5dd7070Spatrick 
actOnParamCommandParamNameArg(ParamCommandComment * Command,SourceLocation ArgLocBegin,SourceLocation ArgLocEnd,StringRef Arg)257e5dd7070Spatrick void Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command,
258e5dd7070Spatrick                                          SourceLocation ArgLocBegin,
259e5dd7070Spatrick                                          SourceLocation ArgLocEnd,
260e5dd7070Spatrick                                          StringRef Arg) {
261e5dd7070Spatrick   // Parser will not feed us more arguments than needed.
262e5dd7070Spatrick   assert(Command->getNumArgs() == 0);
263e5dd7070Spatrick 
264e5dd7070Spatrick   if (!Command->isDirectionExplicit()) {
265e5dd7070Spatrick     // User didn't provide a direction argument.
266e5dd7070Spatrick     Command->setDirection(ParamCommandComment::In, /* Explicit = */ false);
267e5dd7070Spatrick   }
268*12c85518Srobert   auto *A = new (Allocator)
269*12c85518Srobert       Comment::Argument{SourceRange(ArgLocBegin, ArgLocEnd), Arg};
270*12c85518Srobert   Command->setArgs(llvm::ArrayRef(A, 1));
271e5dd7070Spatrick }
272e5dd7070Spatrick 
actOnParamCommandFinish(ParamCommandComment * Command,ParagraphComment * Paragraph)273e5dd7070Spatrick void Sema::actOnParamCommandFinish(ParamCommandComment *Command,
274e5dd7070Spatrick                                    ParagraphComment *Paragraph) {
275e5dd7070Spatrick   Command->setParagraph(Paragraph);
276e5dd7070Spatrick   checkBlockCommandEmptyParagraph(Command);
277e5dd7070Spatrick }
278e5dd7070Spatrick 
actOnTParamCommandStart(SourceLocation LocBegin,SourceLocation LocEnd,unsigned CommandID,CommandMarkerKind CommandMarker)279e5dd7070Spatrick TParamCommandComment *Sema::actOnTParamCommandStart(
280e5dd7070Spatrick                                       SourceLocation LocBegin,
281e5dd7070Spatrick                                       SourceLocation LocEnd,
282e5dd7070Spatrick                                       unsigned CommandID,
283e5dd7070Spatrick                                       CommandMarkerKind CommandMarker) {
284e5dd7070Spatrick   TParamCommandComment *Command =
285e5dd7070Spatrick       new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID,
286e5dd7070Spatrick                                            CommandMarker);
287e5dd7070Spatrick 
288e5dd7070Spatrick   if (!isTemplateOrSpecialization())
289e5dd7070Spatrick     Diag(Command->getLocation(),
290e5dd7070Spatrick          diag::warn_doc_tparam_not_attached_to_a_template_decl)
291e5dd7070Spatrick       << CommandMarker
292e5dd7070Spatrick       << Command->getCommandNameRange(Traits);
293e5dd7070Spatrick 
294e5dd7070Spatrick   return Command;
295e5dd7070Spatrick }
296e5dd7070Spatrick 
actOnTParamCommandParamNameArg(TParamCommandComment * Command,SourceLocation ArgLocBegin,SourceLocation ArgLocEnd,StringRef Arg)297e5dd7070Spatrick void Sema::actOnTParamCommandParamNameArg(TParamCommandComment *Command,
298e5dd7070Spatrick                                           SourceLocation ArgLocBegin,
299e5dd7070Spatrick                                           SourceLocation ArgLocEnd,
300e5dd7070Spatrick                                           StringRef Arg) {
301e5dd7070Spatrick   // Parser will not feed us more arguments than needed.
302e5dd7070Spatrick   assert(Command->getNumArgs() == 0);
303e5dd7070Spatrick 
304*12c85518Srobert   auto *A = new (Allocator)
305*12c85518Srobert       Comment::Argument{SourceRange(ArgLocBegin, ArgLocEnd), Arg};
306*12c85518Srobert   Command->setArgs(llvm::ArrayRef(A, 1));
307e5dd7070Spatrick 
308e5dd7070Spatrick   if (!isTemplateOrSpecialization()) {
309e5dd7070Spatrick     // We already warned that this \\tparam is not attached to a template decl.
310e5dd7070Spatrick     return;
311e5dd7070Spatrick   }
312e5dd7070Spatrick 
313e5dd7070Spatrick   const TemplateParameterList *TemplateParameters =
314e5dd7070Spatrick       ThisDeclInfo->TemplateParameters;
315e5dd7070Spatrick   SmallVector<unsigned, 2> Position;
316e5dd7070Spatrick   if (resolveTParamReference(Arg, TemplateParameters, &Position)) {
317*12c85518Srobert     Command->setPosition(copyArray(llvm::ArrayRef(Position)));
318e5dd7070Spatrick     TParamCommandComment *&PrevCommand = TemplateParameterDocs[Arg];
319e5dd7070Spatrick     if (PrevCommand) {
320e5dd7070Spatrick       SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
321e5dd7070Spatrick       Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate)
322e5dd7070Spatrick         << Arg << ArgRange;
323e5dd7070Spatrick       Diag(PrevCommand->getLocation(), diag::note_doc_tparam_previous)
324e5dd7070Spatrick         << PrevCommand->getParamNameRange();
325e5dd7070Spatrick     }
326e5dd7070Spatrick     PrevCommand = Command;
327e5dd7070Spatrick     return;
328e5dd7070Spatrick   }
329e5dd7070Spatrick 
330e5dd7070Spatrick   SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
331e5dd7070Spatrick   Diag(ArgLocBegin, diag::warn_doc_tparam_not_found)
332e5dd7070Spatrick     << Arg << ArgRange;
333e5dd7070Spatrick 
334e5dd7070Spatrick   if (!TemplateParameters || TemplateParameters->size() == 0)
335e5dd7070Spatrick     return;
336e5dd7070Spatrick 
337e5dd7070Spatrick   StringRef CorrectedName;
338e5dd7070Spatrick   if (TemplateParameters->size() == 1) {
339e5dd7070Spatrick     const NamedDecl *Param = TemplateParameters->getParam(0);
340e5dd7070Spatrick     const IdentifierInfo *II = Param->getIdentifier();
341e5dd7070Spatrick     if (II)
342e5dd7070Spatrick       CorrectedName = II->getName();
343e5dd7070Spatrick   } else {
344e5dd7070Spatrick     CorrectedName = correctTypoInTParamReference(Arg, TemplateParameters);
345e5dd7070Spatrick   }
346e5dd7070Spatrick 
347e5dd7070Spatrick   if (!CorrectedName.empty()) {
348e5dd7070Spatrick     Diag(ArgLocBegin, diag::note_doc_tparam_name_suggestion)
349e5dd7070Spatrick       << CorrectedName
350e5dd7070Spatrick       << FixItHint::CreateReplacement(ArgRange, CorrectedName);
351e5dd7070Spatrick   }
352e5dd7070Spatrick }
353e5dd7070Spatrick 
actOnTParamCommandFinish(TParamCommandComment * Command,ParagraphComment * Paragraph)354e5dd7070Spatrick void Sema::actOnTParamCommandFinish(TParamCommandComment *Command,
355e5dd7070Spatrick                                     ParagraphComment *Paragraph) {
356e5dd7070Spatrick   Command->setParagraph(Paragraph);
357e5dd7070Spatrick   checkBlockCommandEmptyParagraph(Command);
358e5dd7070Spatrick }
359e5dd7070Spatrick 
360*12c85518Srobert InlineCommandComment *
actOnInlineCommand(SourceLocation CommandLocBegin,SourceLocation CommandLocEnd,unsigned CommandID,ArrayRef<Comment::Argument> Args)361*12c85518Srobert Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
362*12c85518Srobert                          SourceLocation CommandLocEnd, unsigned CommandID,
363*12c85518Srobert                          ArrayRef<Comment::Argument> Args) {
364e5dd7070Spatrick   StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
365e5dd7070Spatrick 
366*12c85518Srobert   return new (Allocator)
367*12c85518Srobert       InlineCommandComment(CommandLocBegin, CommandLocEnd, CommandID,
368*12c85518Srobert                            getInlineCommandRenderKind(CommandName), Args);
369e5dd7070Spatrick }
370e5dd7070Spatrick 
actOnUnknownCommand(SourceLocation LocBegin,SourceLocation LocEnd,StringRef CommandName)371e5dd7070Spatrick InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
372e5dd7070Spatrick                                                 SourceLocation LocEnd,
373e5dd7070Spatrick                                                 StringRef CommandName) {
374e5dd7070Spatrick   unsigned CommandID = Traits.registerUnknownCommand(CommandName)->getID();
375e5dd7070Spatrick   return actOnUnknownCommand(LocBegin, LocEnd, CommandID);
376e5dd7070Spatrick }
377e5dd7070Spatrick 
actOnUnknownCommand(SourceLocation LocBegin,SourceLocation LocEnd,unsigned CommandID)378e5dd7070Spatrick InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
379e5dd7070Spatrick                                                 SourceLocation LocEnd,
380e5dd7070Spatrick                                                 unsigned CommandID) {
381e5dd7070Spatrick   ArrayRef<InlineCommandComment::Argument> Args;
382e5dd7070Spatrick   return new (Allocator) InlineCommandComment(
383e5dd7070Spatrick                                   LocBegin, LocEnd, CommandID,
384e5dd7070Spatrick                                   InlineCommandComment::RenderNormal,
385e5dd7070Spatrick                                   Args);
386e5dd7070Spatrick }
387e5dd7070Spatrick 
actOnText(SourceLocation LocBegin,SourceLocation LocEnd,StringRef Text)388e5dd7070Spatrick TextComment *Sema::actOnText(SourceLocation LocBegin,
389e5dd7070Spatrick                              SourceLocation LocEnd,
390e5dd7070Spatrick                              StringRef Text) {
391e5dd7070Spatrick   return new (Allocator) TextComment(LocBegin, LocEnd, Text);
392e5dd7070Spatrick }
393e5dd7070Spatrick 
actOnVerbatimBlockStart(SourceLocation Loc,unsigned CommandID)394e5dd7070Spatrick VerbatimBlockComment *Sema::actOnVerbatimBlockStart(SourceLocation Loc,
395e5dd7070Spatrick                                                     unsigned CommandID) {
396e5dd7070Spatrick   StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
397e5dd7070Spatrick   return new (Allocator) VerbatimBlockComment(
398e5dd7070Spatrick                                   Loc,
399e5dd7070Spatrick                                   Loc.getLocWithOffset(1 + CommandName.size()),
400e5dd7070Spatrick                                   CommandID);
401e5dd7070Spatrick }
402e5dd7070Spatrick 
actOnVerbatimBlockLine(SourceLocation Loc,StringRef Text)403e5dd7070Spatrick VerbatimBlockLineComment *Sema::actOnVerbatimBlockLine(SourceLocation Loc,
404e5dd7070Spatrick                                                        StringRef Text) {
405e5dd7070Spatrick   return new (Allocator) VerbatimBlockLineComment(Loc, Text);
406e5dd7070Spatrick }
407e5dd7070Spatrick 
actOnVerbatimBlockFinish(VerbatimBlockComment * Block,SourceLocation CloseNameLocBegin,StringRef CloseName,ArrayRef<VerbatimBlockLineComment * > Lines)408e5dd7070Spatrick void Sema::actOnVerbatimBlockFinish(
409e5dd7070Spatrick                             VerbatimBlockComment *Block,
410e5dd7070Spatrick                             SourceLocation CloseNameLocBegin,
411e5dd7070Spatrick                             StringRef CloseName,
412e5dd7070Spatrick                             ArrayRef<VerbatimBlockLineComment *> Lines) {
413e5dd7070Spatrick   Block->setCloseName(CloseName, CloseNameLocBegin);
414e5dd7070Spatrick   Block->setLines(Lines);
415e5dd7070Spatrick }
416e5dd7070Spatrick 
actOnVerbatimLine(SourceLocation LocBegin,unsigned CommandID,SourceLocation TextBegin,StringRef Text)417e5dd7070Spatrick VerbatimLineComment *Sema::actOnVerbatimLine(SourceLocation LocBegin,
418e5dd7070Spatrick                                              unsigned CommandID,
419e5dd7070Spatrick                                              SourceLocation TextBegin,
420e5dd7070Spatrick                                              StringRef Text) {
421e5dd7070Spatrick   VerbatimLineComment *VL = new (Allocator) VerbatimLineComment(
422e5dd7070Spatrick                               LocBegin,
423e5dd7070Spatrick                               TextBegin.getLocWithOffset(Text.size()),
424e5dd7070Spatrick                               CommandID,
425e5dd7070Spatrick                               TextBegin,
426e5dd7070Spatrick                               Text);
427e5dd7070Spatrick   checkFunctionDeclVerbatimLine(VL);
428e5dd7070Spatrick   checkContainerDeclVerbatimLine(VL);
429e5dd7070Spatrick   return VL;
430e5dd7070Spatrick }
431e5dd7070Spatrick 
actOnHTMLStartTagStart(SourceLocation LocBegin,StringRef TagName)432e5dd7070Spatrick HTMLStartTagComment *Sema::actOnHTMLStartTagStart(SourceLocation LocBegin,
433e5dd7070Spatrick                                                   StringRef TagName) {
434e5dd7070Spatrick   return new (Allocator) HTMLStartTagComment(LocBegin, TagName);
435e5dd7070Spatrick }
436e5dd7070Spatrick 
actOnHTMLStartTagFinish(HTMLStartTagComment * Tag,ArrayRef<HTMLStartTagComment::Attribute> Attrs,SourceLocation GreaterLoc,bool IsSelfClosing)437e5dd7070Spatrick void Sema::actOnHTMLStartTagFinish(
438e5dd7070Spatrick                               HTMLStartTagComment *Tag,
439e5dd7070Spatrick                               ArrayRef<HTMLStartTagComment::Attribute> Attrs,
440e5dd7070Spatrick                               SourceLocation GreaterLoc,
441e5dd7070Spatrick                               bool IsSelfClosing) {
442e5dd7070Spatrick   Tag->setAttrs(Attrs);
443e5dd7070Spatrick   Tag->setGreaterLoc(GreaterLoc);
444e5dd7070Spatrick   if (IsSelfClosing)
445e5dd7070Spatrick     Tag->setSelfClosing();
446e5dd7070Spatrick   else if (!isHTMLEndTagForbidden(Tag->getTagName()))
447e5dd7070Spatrick     HTMLOpenTags.push_back(Tag);
448e5dd7070Spatrick }
449e5dd7070Spatrick 
actOnHTMLEndTag(SourceLocation LocBegin,SourceLocation LocEnd,StringRef TagName)450e5dd7070Spatrick HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin,
451e5dd7070Spatrick                                          SourceLocation LocEnd,
452e5dd7070Spatrick                                          StringRef TagName) {
453e5dd7070Spatrick   HTMLEndTagComment *HET =
454e5dd7070Spatrick       new (Allocator) HTMLEndTagComment(LocBegin, LocEnd, TagName);
455e5dd7070Spatrick   if (isHTMLEndTagForbidden(TagName)) {
456e5dd7070Spatrick     Diag(HET->getLocation(), diag::warn_doc_html_end_forbidden)
457e5dd7070Spatrick       << TagName << HET->getSourceRange();
458e5dd7070Spatrick     HET->setIsMalformed();
459e5dd7070Spatrick     return HET;
460e5dd7070Spatrick   }
461e5dd7070Spatrick 
462e5dd7070Spatrick   bool FoundOpen = false;
463e5dd7070Spatrick   for (SmallVectorImpl<HTMLStartTagComment *>::const_reverse_iterator
464e5dd7070Spatrick        I = HTMLOpenTags.rbegin(), E = HTMLOpenTags.rend();
465e5dd7070Spatrick        I != E; ++I) {
466e5dd7070Spatrick     if ((*I)->getTagName() == TagName) {
467e5dd7070Spatrick       FoundOpen = true;
468e5dd7070Spatrick       break;
469e5dd7070Spatrick     }
470e5dd7070Spatrick   }
471e5dd7070Spatrick   if (!FoundOpen) {
472e5dd7070Spatrick     Diag(HET->getLocation(), diag::warn_doc_html_end_unbalanced)
473e5dd7070Spatrick       << HET->getSourceRange();
474e5dd7070Spatrick     HET->setIsMalformed();
475e5dd7070Spatrick     return HET;
476e5dd7070Spatrick   }
477e5dd7070Spatrick 
478e5dd7070Spatrick   while (!HTMLOpenTags.empty()) {
479e5dd7070Spatrick     HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
480e5dd7070Spatrick     StringRef LastNotClosedTagName = HST->getTagName();
481e5dd7070Spatrick     if (LastNotClosedTagName == TagName) {
482e5dd7070Spatrick       // If the start tag is malformed, end tag is malformed as well.
483e5dd7070Spatrick       if (HST->isMalformed())
484e5dd7070Spatrick         HET->setIsMalformed();
485e5dd7070Spatrick       break;
486e5dd7070Spatrick     }
487e5dd7070Spatrick 
488e5dd7070Spatrick     if (isHTMLEndTagOptional(LastNotClosedTagName))
489e5dd7070Spatrick       continue;
490e5dd7070Spatrick 
491e5dd7070Spatrick     bool OpenLineInvalid;
492e5dd7070Spatrick     const unsigned OpenLine = SourceMgr.getPresumedLineNumber(
493e5dd7070Spatrick                                                 HST->getLocation(),
494e5dd7070Spatrick                                                 &OpenLineInvalid);
495e5dd7070Spatrick     bool CloseLineInvalid;
496e5dd7070Spatrick     const unsigned CloseLine = SourceMgr.getPresumedLineNumber(
497e5dd7070Spatrick                                                 HET->getLocation(),
498e5dd7070Spatrick                                                 &CloseLineInvalid);
499e5dd7070Spatrick 
500e5dd7070Spatrick     if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine) {
501e5dd7070Spatrick       Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
502e5dd7070Spatrick         << HST->getTagName() << HET->getTagName()
503e5dd7070Spatrick         << HST->getSourceRange() << HET->getSourceRange();
504e5dd7070Spatrick       HST->setIsMalformed();
505e5dd7070Spatrick     } else {
506e5dd7070Spatrick       Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
507e5dd7070Spatrick         << HST->getTagName() << HET->getTagName()
508e5dd7070Spatrick         << HST->getSourceRange();
509e5dd7070Spatrick       Diag(HET->getLocation(), diag::note_doc_html_end_tag)
510e5dd7070Spatrick         << HET->getSourceRange();
511e5dd7070Spatrick       HST->setIsMalformed();
512e5dd7070Spatrick     }
513e5dd7070Spatrick   }
514e5dd7070Spatrick 
515e5dd7070Spatrick   return HET;
516e5dd7070Spatrick }
517e5dd7070Spatrick 
actOnFullComment(ArrayRef<BlockContentComment * > Blocks)518e5dd7070Spatrick FullComment *Sema::actOnFullComment(
519e5dd7070Spatrick                               ArrayRef<BlockContentComment *> Blocks) {
520e5dd7070Spatrick   FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo);
521e5dd7070Spatrick   resolveParamCommandIndexes(FC);
522e5dd7070Spatrick 
523e5dd7070Spatrick   // Complain about HTML tags that are not closed.
524e5dd7070Spatrick   while (!HTMLOpenTags.empty()) {
525e5dd7070Spatrick     HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
526e5dd7070Spatrick     if (isHTMLEndTagOptional(HST->getTagName()))
527e5dd7070Spatrick       continue;
528e5dd7070Spatrick 
529e5dd7070Spatrick     Diag(HST->getLocation(), diag::warn_doc_html_missing_end_tag)
530e5dd7070Spatrick       << HST->getTagName() << HST->getSourceRange();
531e5dd7070Spatrick     HST->setIsMalformed();
532e5dd7070Spatrick   }
533e5dd7070Spatrick 
534e5dd7070Spatrick   return FC;
535e5dd7070Spatrick }
536e5dd7070Spatrick 
checkBlockCommandEmptyParagraph(BlockCommandComment * Command)537e5dd7070Spatrick void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) {
538e5dd7070Spatrick   if (Traits.getCommandInfo(Command->getCommandID())->IsEmptyParagraphAllowed)
539e5dd7070Spatrick     return;
540e5dd7070Spatrick 
541e5dd7070Spatrick   ParagraphComment *Paragraph = Command->getParagraph();
542e5dd7070Spatrick   if (Paragraph->isWhitespace()) {
543e5dd7070Spatrick     SourceLocation DiagLoc;
544e5dd7070Spatrick     if (Command->getNumArgs() > 0)
545e5dd7070Spatrick       DiagLoc = Command->getArgRange(Command->getNumArgs() - 1).getEnd();
546e5dd7070Spatrick     if (!DiagLoc.isValid())
547e5dd7070Spatrick       DiagLoc = Command->getCommandNameRange(Traits).getEnd();
548e5dd7070Spatrick     Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
549e5dd7070Spatrick       << Command->getCommandMarker()
550e5dd7070Spatrick       << Command->getCommandName(Traits)
551e5dd7070Spatrick       << Command->getSourceRange();
552e5dd7070Spatrick   }
553e5dd7070Spatrick }
554e5dd7070Spatrick 
checkReturnsCommand(const BlockCommandComment * Command)555e5dd7070Spatrick void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
556e5dd7070Spatrick   if (!Traits.getCommandInfo(Command->getCommandID())->IsReturnsCommand)
557e5dd7070Spatrick     return;
558e5dd7070Spatrick 
559e5dd7070Spatrick   assert(ThisDeclInfo && "should not call this check on a bare comment");
560e5dd7070Spatrick 
561e5dd7070Spatrick   // We allow the return command for all @properties because it can be used
562e5dd7070Spatrick   // to document the value that the property getter returns.
563e5dd7070Spatrick   if (isObjCPropertyDecl())
564e5dd7070Spatrick     return;
565*12c85518Srobert   if (involvesFunctionType()) {
566e5dd7070Spatrick     assert(!ThisDeclInfo->ReturnType.isNull() &&
567e5dd7070Spatrick            "should have a valid return type");
568e5dd7070Spatrick     if (ThisDeclInfo->ReturnType->isVoidType()) {
569e5dd7070Spatrick       unsigned DiagKind;
570e5dd7070Spatrick       switch (ThisDeclInfo->CommentDecl->getKind()) {
571e5dd7070Spatrick       default:
572e5dd7070Spatrick         if (ThisDeclInfo->IsObjCMethod)
573e5dd7070Spatrick           DiagKind = 3;
574e5dd7070Spatrick         else
575e5dd7070Spatrick           DiagKind = 0;
576e5dd7070Spatrick         break;
577e5dd7070Spatrick       case Decl::CXXConstructor:
578e5dd7070Spatrick         DiagKind = 1;
579e5dd7070Spatrick         break;
580e5dd7070Spatrick       case Decl::CXXDestructor:
581e5dd7070Spatrick         DiagKind = 2;
582e5dd7070Spatrick         break;
583e5dd7070Spatrick       }
584e5dd7070Spatrick       Diag(Command->getLocation(),
585e5dd7070Spatrick            diag::warn_doc_returns_attached_to_a_void_function)
586e5dd7070Spatrick         << Command->getCommandMarker()
587e5dd7070Spatrick         << Command->getCommandName(Traits)
588e5dd7070Spatrick         << DiagKind
589e5dd7070Spatrick         << Command->getSourceRange();
590e5dd7070Spatrick     }
591e5dd7070Spatrick     return;
592e5dd7070Spatrick   }
593e5dd7070Spatrick 
594e5dd7070Spatrick   Diag(Command->getLocation(),
595e5dd7070Spatrick        diag::warn_doc_returns_not_attached_to_a_function_decl)
596e5dd7070Spatrick     << Command->getCommandMarker()
597e5dd7070Spatrick     << Command->getCommandName(Traits)
598e5dd7070Spatrick     << Command->getSourceRange();
599e5dd7070Spatrick }
600e5dd7070Spatrick 
checkBlockCommandDuplicate(const BlockCommandComment * Command)601e5dd7070Spatrick void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) {
602e5dd7070Spatrick   const CommandInfo *Info = Traits.getCommandInfo(Command->getCommandID());
603e5dd7070Spatrick   const BlockCommandComment *PrevCommand = nullptr;
604e5dd7070Spatrick   if (Info->IsBriefCommand) {
605e5dd7070Spatrick     if (!BriefCommand) {
606e5dd7070Spatrick       BriefCommand = Command;
607e5dd7070Spatrick       return;
608e5dd7070Spatrick     }
609e5dd7070Spatrick     PrevCommand = BriefCommand;
610e5dd7070Spatrick   } else if (Info->IsHeaderfileCommand) {
611e5dd7070Spatrick     if (!HeaderfileCommand) {
612e5dd7070Spatrick       HeaderfileCommand = Command;
613e5dd7070Spatrick       return;
614e5dd7070Spatrick     }
615e5dd7070Spatrick     PrevCommand = HeaderfileCommand;
616e5dd7070Spatrick   } else {
617e5dd7070Spatrick     // We don't want to check this command for duplicates.
618e5dd7070Spatrick     return;
619e5dd7070Spatrick   }
620e5dd7070Spatrick   StringRef CommandName = Command->getCommandName(Traits);
621e5dd7070Spatrick   StringRef PrevCommandName = PrevCommand->getCommandName(Traits);
622e5dd7070Spatrick   Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate)
623e5dd7070Spatrick       << Command->getCommandMarker()
624e5dd7070Spatrick       << CommandName
625e5dd7070Spatrick       << Command->getSourceRange();
626e5dd7070Spatrick   if (CommandName == PrevCommandName)
627e5dd7070Spatrick     Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous)
628e5dd7070Spatrick         << PrevCommand->getCommandMarker()
629e5dd7070Spatrick         << PrevCommandName
630e5dd7070Spatrick         << PrevCommand->getSourceRange();
631e5dd7070Spatrick   else
632e5dd7070Spatrick     Diag(PrevCommand->getLocation(),
633e5dd7070Spatrick          diag::note_doc_block_command_previous_alias)
634e5dd7070Spatrick         << PrevCommand->getCommandMarker()
635e5dd7070Spatrick         << PrevCommandName
636e5dd7070Spatrick         << CommandName;
637e5dd7070Spatrick }
638e5dd7070Spatrick 
checkDeprecatedCommand(const BlockCommandComment * Command)639e5dd7070Spatrick void Sema::checkDeprecatedCommand(const BlockCommandComment *Command) {
640e5dd7070Spatrick   if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand)
641e5dd7070Spatrick     return;
642e5dd7070Spatrick 
643e5dd7070Spatrick   assert(ThisDeclInfo && "should not call this check on a bare comment");
644e5dd7070Spatrick 
645e5dd7070Spatrick   const Decl *D = ThisDeclInfo->CommentDecl;
646e5dd7070Spatrick   if (!D)
647e5dd7070Spatrick     return;
648e5dd7070Spatrick 
649e5dd7070Spatrick   if (D->hasAttr<DeprecatedAttr>() ||
650e5dd7070Spatrick       D->hasAttr<AvailabilityAttr>() ||
651e5dd7070Spatrick       D->hasAttr<UnavailableAttr>())
652e5dd7070Spatrick     return;
653e5dd7070Spatrick 
654e5dd7070Spatrick   Diag(Command->getLocation(), diag::warn_doc_deprecated_not_sync)
655e5dd7070Spatrick       << Command->getSourceRange() << Command->getCommandMarker();
656e5dd7070Spatrick 
657e5dd7070Spatrick   // Try to emit a fixit with a deprecation attribute.
658e5dd7070Spatrick   if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
659e5dd7070Spatrick     // Don't emit a Fix-It for non-member function definitions.  GCC does not
660e5dd7070Spatrick     // accept attributes on them.
661e5dd7070Spatrick     const DeclContext *Ctx = FD->getDeclContext();
662e5dd7070Spatrick     if ((!Ctx || !Ctx->isRecord()) &&
663e5dd7070Spatrick         FD->doesThisDeclarationHaveABody())
664e5dd7070Spatrick       return;
665e5dd7070Spatrick 
666ec727ea7Spatrick     const LangOptions &LO = FD->getLangOpts();
667e5dd7070Spatrick     const bool DoubleSquareBracket = LO.CPlusPlus14 || LO.C2x;
668e5dd7070Spatrick     StringRef AttributeSpelling =
669e5dd7070Spatrick         DoubleSquareBracket ? "[[deprecated]]" : "__attribute__((deprecated))";
670e5dd7070Spatrick     if (PP) {
671e5dd7070Spatrick       // Try to find a replacement macro:
672e5dd7070Spatrick       // - In C2x/C++14 we prefer [[deprecated]].
673e5dd7070Spatrick       // - If not found or an older C/C++ look for __attribute__((deprecated)).
674e5dd7070Spatrick       StringRef MacroName;
675e5dd7070Spatrick       if (DoubleSquareBracket) {
676e5dd7070Spatrick         TokenValue Tokens[] = {tok::l_square, tok::l_square,
677e5dd7070Spatrick                                PP->getIdentifierInfo("deprecated"),
678e5dd7070Spatrick                                tok::r_square, tok::r_square};
679e5dd7070Spatrick         MacroName = PP->getLastMacroWithSpelling(FD->getLocation(), Tokens);
680e5dd7070Spatrick         if (!MacroName.empty())
681e5dd7070Spatrick           AttributeSpelling = MacroName;
682e5dd7070Spatrick       }
683e5dd7070Spatrick 
684e5dd7070Spatrick       if (MacroName.empty()) {
685e5dd7070Spatrick         TokenValue Tokens[] = {
686e5dd7070Spatrick             tok::kw___attribute, tok::l_paren,
687e5dd7070Spatrick             tok::l_paren,        PP->getIdentifierInfo("deprecated"),
688e5dd7070Spatrick             tok::r_paren,        tok::r_paren};
689e5dd7070Spatrick         StringRef MacroName =
690e5dd7070Spatrick             PP->getLastMacroWithSpelling(FD->getLocation(), Tokens);
691e5dd7070Spatrick         if (!MacroName.empty())
692e5dd7070Spatrick           AttributeSpelling = MacroName;
693e5dd7070Spatrick       }
694e5dd7070Spatrick     }
695e5dd7070Spatrick 
696e5dd7070Spatrick     SmallString<64> TextToInsert = AttributeSpelling;
697e5dd7070Spatrick     TextToInsert += " ";
698e5dd7070Spatrick     SourceLocation Loc = FD->getSourceRange().getBegin();
699e5dd7070Spatrick     Diag(Loc, diag::note_add_deprecation_attr)
700e5dd7070Spatrick         << FixItHint::CreateInsertion(Loc, TextToInsert);
701e5dd7070Spatrick   }
702e5dd7070Spatrick }
703e5dd7070Spatrick 
resolveParamCommandIndexes(const FullComment * FC)704e5dd7070Spatrick void Sema::resolveParamCommandIndexes(const FullComment *FC) {
705*12c85518Srobert   if (!involvesFunctionType()) {
706e5dd7070Spatrick     // We already warned that \\param commands are not attached to a function
707e5dd7070Spatrick     // decl.
708e5dd7070Spatrick     return;
709e5dd7070Spatrick   }
710e5dd7070Spatrick 
711e5dd7070Spatrick   SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands;
712e5dd7070Spatrick 
713e5dd7070Spatrick   // Comment AST nodes that correspond to \c ParamVars for which we have
714e5dd7070Spatrick   // found a \\param command or NULL if no documentation was found so far.
715e5dd7070Spatrick   SmallVector<ParamCommandComment *, 8> ParamVarDocs;
716e5dd7070Spatrick 
717e5dd7070Spatrick   ArrayRef<const ParmVarDecl *> ParamVars = getParamVars();
718e5dd7070Spatrick   ParamVarDocs.resize(ParamVars.size(), nullptr);
719e5dd7070Spatrick 
720e5dd7070Spatrick   // First pass over all \\param commands: resolve all parameter names.
721e5dd7070Spatrick   for (Comment::child_iterator I = FC->child_begin(), E = FC->child_end();
722e5dd7070Spatrick        I != E; ++I) {
723e5dd7070Spatrick     ParamCommandComment *PCC = dyn_cast<ParamCommandComment>(*I);
724e5dd7070Spatrick     if (!PCC || !PCC->hasParamName())
725e5dd7070Spatrick       continue;
726e5dd7070Spatrick     StringRef ParamName = PCC->getParamNameAsWritten();
727e5dd7070Spatrick 
728e5dd7070Spatrick     // Check that referenced parameter name is in the function decl.
729e5dd7070Spatrick     const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName,
730e5dd7070Spatrick                                                                 ParamVars);
731e5dd7070Spatrick     if (ResolvedParamIndex == ParamCommandComment::VarArgParamIndex) {
732e5dd7070Spatrick       PCC->setIsVarArgParam();
733e5dd7070Spatrick       continue;
734e5dd7070Spatrick     }
735e5dd7070Spatrick     if (ResolvedParamIndex == ParamCommandComment::InvalidParamIndex) {
736e5dd7070Spatrick       UnresolvedParamCommands.push_back(PCC);
737e5dd7070Spatrick       continue;
738e5dd7070Spatrick     }
739e5dd7070Spatrick     PCC->setParamIndex(ResolvedParamIndex);
740e5dd7070Spatrick     if (ParamVarDocs[ResolvedParamIndex]) {
741e5dd7070Spatrick       SourceRange ArgRange = PCC->getParamNameRange();
742e5dd7070Spatrick       Diag(ArgRange.getBegin(), diag::warn_doc_param_duplicate)
743e5dd7070Spatrick         << ParamName << ArgRange;
744e5dd7070Spatrick       ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex];
745e5dd7070Spatrick       Diag(PrevCommand->getLocation(), diag::note_doc_param_previous)
746e5dd7070Spatrick         << PrevCommand->getParamNameRange();
747e5dd7070Spatrick     }
748e5dd7070Spatrick     ParamVarDocs[ResolvedParamIndex] = PCC;
749e5dd7070Spatrick   }
750e5dd7070Spatrick 
751e5dd7070Spatrick   // Find parameter declarations that have no corresponding \\param.
752e5dd7070Spatrick   SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls;
753e5dd7070Spatrick   for (unsigned i = 0, e = ParamVarDocs.size(); i != e; ++i) {
754e5dd7070Spatrick     if (!ParamVarDocs[i])
755e5dd7070Spatrick       OrphanedParamDecls.push_back(ParamVars[i]);
756e5dd7070Spatrick   }
757e5dd7070Spatrick 
758e5dd7070Spatrick   // Second pass over unresolved \\param commands: do typo correction.
759e5dd7070Spatrick   // Suggest corrections from a set of parameter declarations that have no
760e5dd7070Spatrick   // corresponding \\param.
761e5dd7070Spatrick   for (unsigned i = 0, e = UnresolvedParamCommands.size(); i != e; ++i) {
762e5dd7070Spatrick     const ParamCommandComment *PCC = UnresolvedParamCommands[i];
763e5dd7070Spatrick 
764e5dd7070Spatrick     SourceRange ArgRange = PCC->getParamNameRange();
765e5dd7070Spatrick     StringRef ParamName = PCC->getParamNameAsWritten();
766e5dd7070Spatrick     Diag(ArgRange.getBegin(), diag::warn_doc_param_not_found)
767e5dd7070Spatrick       << ParamName << ArgRange;
768e5dd7070Spatrick 
769e5dd7070Spatrick     // All parameters documented -- can't suggest a correction.
770e5dd7070Spatrick     if (OrphanedParamDecls.size() == 0)
771e5dd7070Spatrick       continue;
772e5dd7070Spatrick 
773e5dd7070Spatrick     unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex;
774e5dd7070Spatrick     if (OrphanedParamDecls.size() == 1) {
775e5dd7070Spatrick       // If one parameter is not documented then that parameter is the only
776e5dd7070Spatrick       // possible suggestion.
777e5dd7070Spatrick       CorrectedParamIndex = 0;
778e5dd7070Spatrick     } else {
779e5dd7070Spatrick       // Do typo correction.
780e5dd7070Spatrick       CorrectedParamIndex = correctTypoInParmVarReference(ParamName,
781e5dd7070Spatrick                                                           OrphanedParamDecls);
782e5dd7070Spatrick     }
783e5dd7070Spatrick     if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) {
784e5dd7070Spatrick       const ParmVarDecl *CorrectedPVD = OrphanedParamDecls[CorrectedParamIndex];
785e5dd7070Spatrick       if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier())
786e5dd7070Spatrick         Diag(ArgRange.getBegin(), diag::note_doc_param_name_suggestion)
787e5dd7070Spatrick           << CorrectedII->getName()
788e5dd7070Spatrick           << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName());
789e5dd7070Spatrick     }
790e5dd7070Spatrick   }
791e5dd7070Spatrick }
792e5dd7070Spatrick 
involvesFunctionType()793*12c85518Srobert bool Sema::involvesFunctionType() {
794*12c85518Srobert   if (!ThisDeclInfo)
795*12c85518Srobert     return false;
796*12c85518Srobert   if (!ThisDeclInfo->IsFilled)
797*12c85518Srobert     inspectThisDecl();
798*12c85518Srobert   return ThisDeclInfo->involvesFunctionType();
799*12c85518Srobert }
800*12c85518Srobert 
isFunctionDecl()801e5dd7070Spatrick bool Sema::isFunctionDecl() {
802e5dd7070Spatrick   if (!ThisDeclInfo)
803e5dd7070Spatrick     return false;
804e5dd7070Spatrick   if (!ThisDeclInfo->IsFilled)
805e5dd7070Spatrick     inspectThisDecl();
806e5dd7070Spatrick   return ThisDeclInfo->getKind() == DeclInfo::FunctionKind;
807e5dd7070Spatrick }
808e5dd7070Spatrick 
isAnyFunctionDecl()809e5dd7070Spatrick bool Sema::isAnyFunctionDecl() {
810e5dd7070Spatrick   return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
811e5dd7070Spatrick          isa<FunctionDecl>(ThisDeclInfo->CurrentDecl);
812e5dd7070Spatrick }
813e5dd7070Spatrick 
isFunctionOrMethodVariadic()814e5dd7070Spatrick bool Sema::isFunctionOrMethodVariadic() {
815*12c85518Srobert   if (!ThisDeclInfo)
816e5dd7070Spatrick     return false;
817*12c85518Srobert   if (!ThisDeclInfo->IsFilled)
818*12c85518Srobert     inspectThisDecl();
819*12c85518Srobert   return ThisDeclInfo->IsVariadic;
820e5dd7070Spatrick }
821e5dd7070Spatrick 
isObjCMethodDecl()822e5dd7070Spatrick bool Sema::isObjCMethodDecl() {
823e5dd7070Spatrick   return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
824e5dd7070Spatrick          isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl);
825e5dd7070Spatrick }
826e5dd7070Spatrick 
isFunctionPointerVarDecl()827e5dd7070Spatrick bool Sema::isFunctionPointerVarDecl() {
828e5dd7070Spatrick   if (!ThisDeclInfo)
829e5dd7070Spatrick     return false;
830e5dd7070Spatrick   if (!ThisDeclInfo->IsFilled)
831e5dd7070Spatrick     inspectThisDecl();
832e5dd7070Spatrick   if (ThisDeclInfo->getKind() == DeclInfo::VariableKind) {
833e5dd7070Spatrick     if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(ThisDeclInfo->CurrentDecl)) {
834e5dd7070Spatrick       QualType QT = VD->getType();
835e5dd7070Spatrick       return QT->isFunctionPointerType();
836e5dd7070Spatrick     }
837e5dd7070Spatrick   }
838e5dd7070Spatrick   return false;
839e5dd7070Spatrick }
840e5dd7070Spatrick 
isObjCPropertyDecl()841e5dd7070Spatrick bool Sema::isObjCPropertyDecl() {
842e5dd7070Spatrick   if (!ThisDeclInfo)
843e5dd7070Spatrick     return false;
844e5dd7070Spatrick   if (!ThisDeclInfo->IsFilled)
845e5dd7070Spatrick     inspectThisDecl();
846e5dd7070Spatrick   return ThisDeclInfo->CurrentDecl->getKind() == Decl::ObjCProperty;
847e5dd7070Spatrick }
848e5dd7070Spatrick 
isTemplateOrSpecialization()849e5dd7070Spatrick bool Sema::isTemplateOrSpecialization() {
850e5dd7070Spatrick   if (!ThisDeclInfo)
851e5dd7070Spatrick     return false;
852e5dd7070Spatrick   if (!ThisDeclInfo->IsFilled)
853e5dd7070Spatrick     inspectThisDecl();
854e5dd7070Spatrick   return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate;
855e5dd7070Spatrick }
856e5dd7070Spatrick 
isRecordLikeDecl()857e5dd7070Spatrick bool Sema::isRecordLikeDecl() {
858e5dd7070Spatrick   if (!ThisDeclInfo)
859e5dd7070Spatrick     return false;
860e5dd7070Spatrick   if (!ThisDeclInfo->IsFilled)
861e5dd7070Spatrick     inspectThisDecl();
862e5dd7070Spatrick   return isUnionDecl() || isClassOrStructDecl() || isObjCInterfaceDecl() ||
863e5dd7070Spatrick          isObjCProtocolDecl();
864e5dd7070Spatrick }
865e5dd7070Spatrick 
isUnionDecl()866e5dd7070Spatrick bool Sema::isUnionDecl() {
867e5dd7070Spatrick   if (!ThisDeclInfo)
868e5dd7070Spatrick     return false;
869e5dd7070Spatrick   if (!ThisDeclInfo->IsFilled)
870e5dd7070Spatrick     inspectThisDecl();
871e5dd7070Spatrick   if (const RecordDecl *RD =
872e5dd7070Spatrick         dyn_cast_or_null<RecordDecl>(ThisDeclInfo->CurrentDecl))
873e5dd7070Spatrick     return RD->isUnion();
874e5dd7070Spatrick   return false;
875e5dd7070Spatrick }
isClassOrStructDeclImpl(const Decl * D)876ec727ea7Spatrick static bool isClassOrStructDeclImpl(const Decl *D) {
877ec727ea7Spatrick   if (auto *record = dyn_cast_or_null<RecordDecl>(D))
878ec727ea7Spatrick     return !record->isUnion();
879ec727ea7Spatrick 
880ec727ea7Spatrick   return false;
881ec727ea7Spatrick }
882e5dd7070Spatrick 
isClassOrStructDecl()883e5dd7070Spatrick bool Sema::isClassOrStructDecl() {
884e5dd7070Spatrick   if (!ThisDeclInfo)
885e5dd7070Spatrick     return false;
886e5dd7070Spatrick   if (!ThisDeclInfo->IsFilled)
887e5dd7070Spatrick     inspectThisDecl();
888ec727ea7Spatrick 
889ec727ea7Spatrick   if (!ThisDeclInfo->CurrentDecl)
890ec727ea7Spatrick     return false;
891ec727ea7Spatrick 
892ec727ea7Spatrick   return isClassOrStructDeclImpl(ThisDeclInfo->CurrentDecl);
893ec727ea7Spatrick }
894ec727ea7Spatrick 
isClassOrStructOrTagTypedefDecl()895ec727ea7Spatrick bool Sema::isClassOrStructOrTagTypedefDecl() {
896ec727ea7Spatrick   if (!ThisDeclInfo)
897ec727ea7Spatrick     return false;
898ec727ea7Spatrick   if (!ThisDeclInfo->IsFilled)
899ec727ea7Spatrick     inspectThisDecl();
900ec727ea7Spatrick 
901ec727ea7Spatrick   if (!ThisDeclInfo->CurrentDecl)
902ec727ea7Spatrick     return false;
903ec727ea7Spatrick 
904ec727ea7Spatrick   if (isClassOrStructDeclImpl(ThisDeclInfo->CurrentDecl))
905ec727ea7Spatrick     return true;
906ec727ea7Spatrick 
907ec727ea7Spatrick   if (auto *ThisTypedefDecl = dyn_cast<TypedefDecl>(ThisDeclInfo->CurrentDecl)) {
908ec727ea7Spatrick     auto UnderlyingType = ThisTypedefDecl->getUnderlyingType();
909ec727ea7Spatrick     if (auto ThisElaboratedType = dyn_cast<ElaboratedType>(UnderlyingType)) {
910ec727ea7Spatrick       auto DesugaredType = ThisElaboratedType->desugar();
911ec727ea7Spatrick       if (auto *DesugaredTypePtr = DesugaredType.getTypePtrOrNull()) {
912ec727ea7Spatrick         if (auto *ThisRecordType = dyn_cast<RecordType>(DesugaredTypePtr)) {
913ec727ea7Spatrick           return isClassOrStructDeclImpl(ThisRecordType->getAsRecordDecl());
914ec727ea7Spatrick         }
915ec727ea7Spatrick       }
916ec727ea7Spatrick     }
917ec727ea7Spatrick   }
918ec727ea7Spatrick 
919ec727ea7Spatrick   return false;
920e5dd7070Spatrick }
921e5dd7070Spatrick 
isClassTemplateDecl()922e5dd7070Spatrick bool Sema::isClassTemplateDecl() {
923e5dd7070Spatrick   if (!ThisDeclInfo)
924e5dd7070Spatrick     return false;
925e5dd7070Spatrick   if (!ThisDeclInfo->IsFilled)
926e5dd7070Spatrick     inspectThisDecl();
927e5dd7070Spatrick   return ThisDeclInfo->CurrentDecl &&
928e5dd7070Spatrick           (isa<ClassTemplateDecl>(ThisDeclInfo->CurrentDecl));
929e5dd7070Spatrick }
930e5dd7070Spatrick 
isFunctionTemplateDecl()931e5dd7070Spatrick bool Sema::isFunctionTemplateDecl() {
932e5dd7070Spatrick   if (!ThisDeclInfo)
933e5dd7070Spatrick     return false;
934e5dd7070Spatrick   if (!ThisDeclInfo->IsFilled)
935e5dd7070Spatrick     inspectThisDecl();
936e5dd7070Spatrick   return ThisDeclInfo->CurrentDecl &&
937e5dd7070Spatrick          (isa<FunctionTemplateDecl>(ThisDeclInfo->CurrentDecl));
938e5dd7070Spatrick }
939e5dd7070Spatrick 
isObjCInterfaceDecl()940e5dd7070Spatrick bool Sema::isObjCInterfaceDecl() {
941e5dd7070Spatrick   if (!ThisDeclInfo)
942e5dd7070Spatrick     return false;
943e5dd7070Spatrick   if (!ThisDeclInfo->IsFilled)
944e5dd7070Spatrick     inspectThisDecl();
945e5dd7070Spatrick   return ThisDeclInfo->CurrentDecl &&
946e5dd7070Spatrick          isa<ObjCInterfaceDecl>(ThisDeclInfo->CurrentDecl);
947e5dd7070Spatrick }
948e5dd7070Spatrick 
isObjCProtocolDecl()949e5dd7070Spatrick bool Sema::isObjCProtocolDecl() {
950e5dd7070Spatrick   if (!ThisDeclInfo)
951e5dd7070Spatrick     return false;
952e5dd7070Spatrick   if (!ThisDeclInfo->IsFilled)
953e5dd7070Spatrick     inspectThisDecl();
954e5dd7070Spatrick   return ThisDeclInfo->CurrentDecl &&
955e5dd7070Spatrick          isa<ObjCProtocolDecl>(ThisDeclInfo->CurrentDecl);
956e5dd7070Spatrick }
957e5dd7070Spatrick 
getParamVars()958e5dd7070Spatrick ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
959e5dd7070Spatrick   if (!ThisDeclInfo->IsFilled)
960e5dd7070Spatrick     inspectThisDecl();
961e5dd7070Spatrick   return ThisDeclInfo->ParamVars;
962e5dd7070Spatrick }
963e5dd7070Spatrick 
inspectThisDecl()964e5dd7070Spatrick void Sema::inspectThisDecl() {
965e5dd7070Spatrick   ThisDeclInfo->fill();
966e5dd7070Spatrick }
967e5dd7070Spatrick 
resolveParmVarReference(StringRef Name,ArrayRef<const ParmVarDecl * > ParamVars)968e5dd7070Spatrick unsigned Sema::resolveParmVarReference(StringRef Name,
969e5dd7070Spatrick                                        ArrayRef<const ParmVarDecl *> ParamVars) {
970e5dd7070Spatrick   for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
971e5dd7070Spatrick     const IdentifierInfo *II = ParamVars[i]->getIdentifier();
972e5dd7070Spatrick     if (II && II->getName() == Name)
973e5dd7070Spatrick       return i;
974e5dd7070Spatrick   }
975e5dd7070Spatrick   if (Name == "..." && isFunctionOrMethodVariadic())
976e5dd7070Spatrick     return ParamCommandComment::VarArgParamIndex;
977e5dd7070Spatrick   return ParamCommandComment::InvalidParamIndex;
978e5dd7070Spatrick }
979e5dd7070Spatrick 
980e5dd7070Spatrick namespace {
981e5dd7070Spatrick class SimpleTypoCorrector {
982e5dd7070Spatrick   const NamedDecl *BestDecl;
983e5dd7070Spatrick 
984e5dd7070Spatrick   StringRef Typo;
985e5dd7070Spatrick   const unsigned MaxEditDistance;
986e5dd7070Spatrick 
987e5dd7070Spatrick   unsigned BestEditDistance;
988e5dd7070Spatrick   unsigned BestIndex;
989e5dd7070Spatrick   unsigned NextIndex;
990e5dd7070Spatrick 
991e5dd7070Spatrick public:
SimpleTypoCorrector(StringRef Typo)992e5dd7070Spatrick   explicit SimpleTypoCorrector(StringRef Typo)
993e5dd7070Spatrick       : BestDecl(nullptr), Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3),
994e5dd7070Spatrick         BestEditDistance(MaxEditDistance + 1), BestIndex(0), NextIndex(0) {}
995e5dd7070Spatrick 
996e5dd7070Spatrick   void addDecl(const NamedDecl *ND);
997e5dd7070Spatrick 
getBestDecl() const998e5dd7070Spatrick   const NamedDecl *getBestDecl() const {
999e5dd7070Spatrick     if (BestEditDistance > MaxEditDistance)
1000e5dd7070Spatrick       return nullptr;
1001e5dd7070Spatrick 
1002e5dd7070Spatrick     return BestDecl;
1003e5dd7070Spatrick   }
1004e5dd7070Spatrick 
getBestDeclIndex() const1005e5dd7070Spatrick   unsigned getBestDeclIndex() const {
1006e5dd7070Spatrick     assert(getBestDecl());
1007e5dd7070Spatrick     return BestIndex;
1008e5dd7070Spatrick   }
1009e5dd7070Spatrick };
1010e5dd7070Spatrick 
addDecl(const NamedDecl * ND)1011e5dd7070Spatrick void SimpleTypoCorrector::addDecl(const NamedDecl *ND) {
1012e5dd7070Spatrick   unsigned CurrIndex = NextIndex++;
1013e5dd7070Spatrick 
1014e5dd7070Spatrick   const IdentifierInfo *II = ND->getIdentifier();
1015e5dd7070Spatrick   if (!II)
1016e5dd7070Spatrick     return;
1017e5dd7070Spatrick 
1018e5dd7070Spatrick   StringRef Name = II->getName();
1019e5dd7070Spatrick   unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());
1020e5dd7070Spatrick   if (MinPossibleEditDistance > 0 &&
1021e5dd7070Spatrick       Typo.size() / MinPossibleEditDistance < 3)
1022e5dd7070Spatrick     return;
1023e5dd7070Spatrick 
1024e5dd7070Spatrick   unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
1025e5dd7070Spatrick   if (EditDistance < BestEditDistance) {
1026e5dd7070Spatrick     BestEditDistance = EditDistance;
1027e5dd7070Spatrick     BestDecl = ND;
1028e5dd7070Spatrick     BestIndex = CurrIndex;
1029e5dd7070Spatrick   }
1030e5dd7070Spatrick }
1031e5dd7070Spatrick } // end anonymous namespace
1032e5dd7070Spatrick 
correctTypoInParmVarReference(StringRef Typo,ArrayRef<const ParmVarDecl * > ParamVars)1033e5dd7070Spatrick unsigned Sema::correctTypoInParmVarReference(
1034e5dd7070Spatrick                                     StringRef Typo,
1035e5dd7070Spatrick                                     ArrayRef<const ParmVarDecl *> ParamVars) {
1036e5dd7070Spatrick   SimpleTypoCorrector Corrector(Typo);
1037e5dd7070Spatrick   for (unsigned i = 0, e = ParamVars.size(); i != e; ++i)
1038e5dd7070Spatrick     Corrector.addDecl(ParamVars[i]);
1039e5dd7070Spatrick   if (Corrector.getBestDecl())
1040e5dd7070Spatrick     return Corrector.getBestDeclIndex();
1041e5dd7070Spatrick   else
1042e5dd7070Spatrick     return ParamCommandComment::InvalidParamIndex;
1043e5dd7070Spatrick }
1044e5dd7070Spatrick 
1045e5dd7070Spatrick namespace {
ResolveTParamReferenceHelper(StringRef Name,const TemplateParameterList * TemplateParameters,SmallVectorImpl<unsigned> * Position)1046e5dd7070Spatrick bool ResolveTParamReferenceHelper(
1047e5dd7070Spatrick                             StringRef Name,
1048e5dd7070Spatrick                             const TemplateParameterList *TemplateParameters,
1049e5dd7070Spatrick                             SmallVectorImpl<unsigned> *Position) {
1050e5dd7070Spatrick   for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
1051e5dd7070Spatrick     const NamedDecl *Param = TemplateParameters->getParam(i);
1052e5dd7070Spatrick     const IdentifierInfo *II = Param->getIdentifier();
1053e5dd7070Spatrick     if (II && II->getName() == Name) {
1054e5dd7070Spatrick       Position->push_back(i);
1055e5dd7070Spatrick       return true;
1056e5dd7070Spatrick     }
1057e5dd7070Spatrick 
1058e5dd7070Spatrick     if (const TemplateTemplateParmDecl *TTP =
1059e5dd7070Spatrick             dyn_cast<TemplateTemplateParmDecl>(Param)) {
1060e5dd7070Spatrick       Position->push_back(i);
1061e5dd7070Spatrick       if (ResolveTParamReferenceHelper(Name, TTP->getTemplateParameters(),
1062e5dd7070Spatrick                                        Position))
1063e5dd7070Spatrick         return true;
1064e5dd7070Spatrick       Position->pop_back();
1065e5dd7070Spatrick     }
1066e5dd7070Spatrick   }
1067e5dd7070Spatrick   return false;
1068e5dd7070Spatrick }
1069e5dd7070Spatrick } // end anonymous namespace
1070e5dd7070Spatrick 
resolveTParamReference(StringRef Name,const TemplateParameterList * TemplateParameters,SmallVectorImpl<unsigned> * Position)1071e5dd7070Spatrick bool Sema::resolveTParamReference(
1072e5dd7070Spatrick                             StringRef Name,
1073e5dd7070Spatrick                             const TemplateParameterList *TemplateParameters,
1074e5dd7070Spatrick                             SmallVectorImpl<unsigned> *Position) {
1075e5dd7070Spatrick   Position->clear();
1076e5dd7070Spatrick   if (!TemplateParameters)
1077e5dd7070Spatrick     return false;
1078e5dd7070Spatrick 
1079e5dd7070Spatrick   return ResolveTParamReferenceHelper(Name, TemplateParameters, Position);
1080e5dd7070Spatrick }
1081e5dd7070Spatrick 
1082e5dd7070Spatrick namespace {
CorrectTypoInTParamReferenceHelper(const TemplateParameterList * TemplateParameters,SimpleTypoCorrector & Corrector)1083e5dd7070Spatrick void CorrectTypoInTParamReferenceHelper(
1084e5dd7070Spatrick                             const TemplateParameterList *TemplateParameters,
1085e5dd7070Spatrick                             SimpleTypoCorrector &Corrector) {
1086e5dd7070Spatrick   for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
1087e5dd7070Spatrick     const NamedDecl *Param = TemplateParameters->getParam(i);
1088e5dd7070Spatrick     Corrector.addDecl(Param);
1089e5dd7070Spatrick 
1090e5dd7070Spatrick     if (const TemplateTemplateParmDecl *TTP =
1091e5dd7070Spatrick             dyn_cast<TemplateTemplateParmDecl>(Param))
1092e5dd7070Spatrick       CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(),
1093e5dd7070Spatrick                                          Corrector);
1094e5dd7070Spatrick   }
1095e5dd7070Spatrick }
1096e5dd7070Spatrick } // end anonymous namespace
1097e5dd7070Spatrick 
correctTypoInTParamReference(StringRef Typo,const TemplateParameterList * TemplateParameters)1098e5dd7070Spatrick StringRef Sema::correctTypoInTParamReference(
1099e5dd7070Spatrick                             StringRef Typo,
1100e5dd7070Spatrick                             const TemplateParameterList *TemplateParameters) {
1101e5dd7070Spatrick   SimpleTypoCorrector Corrector(Typo);
1102e5dd7070Spatrick   CorrectTypoInTParamReferenceHelper(TemplateParameters, Corrector);
1103e5dd7070Spatrick   if (const NamedDecl *ND = Corrector.getBestDecl()) {
1104e5dd7070Spatrick     const IdentifierInfo *II = ND->getIdentifier();
1105e5dd7070Spatrick     assert(II && "SimpleTypoCorrector should not return this decl");
1106e5dd7070Spatrick     return II->getName();
1107e5dd7070Spatrick   }
1108e5dd7070Spatrick   return StringRef();
1109e5dd7070Spatrick }
1110e5dd7070Spatrick 
1111e5dd7070Spatrick InlineCommandComment::RenderKind
getInlineCommandRenderKind(StringRef Name) const1112e5dd7070Spatrick Sema::getInlineCommandRenderKind(StringRef Name) const {
1113e5dd7070Spatrick   assert(Traits.getCommandInfo(Name)->IsInlineCommand);
1114e5dd7070Spatrick 
1115e5dd7070Spatrick   return llvm::StringSwitch<InlineCommandComment::RenderKind>(Name)
1116e5dd7070Spatrick       .Case("b", InlineCommandComment::RenderBold)
1117e5dd7070Spatrick       .Cases("c", "p", InlineCommandComment::RenderMonospaced)
1118e5dd7070Spatrick       .Cases("a", "e", "em", InlineCommandComment::RenderEmphasized)
1119e5dd7070Spatrick       .Case("anchor", InlineCommandComment::RenderAnchor)
1120e5dd7070Spatrick       .Default(InlineCommandComment::RenderNormal);
1121e5dd7070Spatrick }
1122e5dd7070Spatrick 
1123e5dd7070Spatrick } // end namespace comments
1124e5dd7070Spatrick } // end namespace clang
1125