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