blob: bb0d03ebd27a949b4f7669ce2a36ed2bd653c929 [file] [log] [blame]
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +00001//===--- CommentSema.cpp - Doxygen comment semantic analysis --------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "clang/AST/CommentSema.h"
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +000011#include "clang/AST/CommentDiagnostic.h"
12#include "clang/AST/Decl.h"
13#include "clang/AST/DeclObjC.h"
14#include "clang/Basic/SourceManager.h"
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +000015#include "llvm/ADT/StringSwitch.h"
16
17namespace clang {
18namespace comments {
19
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +000020Sema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr,
21 DiagnosticsEngine &Diags) :
Dmitri Gribenko8487c522012-07-23 17:40:30 +000022 Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), ThisDecl(NULL),
23 IsThisDeclInspected(false) {
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +000024}
25
26void Sema::setDecl(const Decl *D) {
27 ThisDecl = D;
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +000028}
29
30ParagraphComment *Sema::actOnParagraphComment(
31 ArrayRef<InlineContentComment *> Content) {
32 return new (Allocator) ParagraphComment(Content);
33}
34
35BlockCommandComment *Sema::actOnBlockCommandStart(SourceLocation LocBegin,
36 SourceLocation LocEnd,
37 StringRef Name) {
38 return new (Allocator) BlockCommandComment(LocBegin, LocEnd, Name);
39}
40
41BlockCommandComment *Sema::actOnBlockCommandArgs(
42 BlockCommandComment *Command,
43 ArrayRef<BlockCommandComment::Argument> Args) {
44 Command->setArgs(Args);
45 return Command;
46}
47
48BlockCommandComment *Sema::actOnBlockCommandFinish(
49 BlockCommandComment *Command,
50 ParagraphComment *Paragraph) {
51 Command->setParagraph(Paragraph);
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +000052 checkBlockCommandEmptyParagraph(Command);
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +000053 return Command;
54}
55
56ParamCommandComment *Sema::actOnParamCommandStart(SourceLocation LocBegin,
57 SourceLocation LocEnd,
58 StringRef Name) {
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +000059 ParamCommandComment *Command =
60 new (Allocator) ParamCommandComment(LocBegin, LocEnd, Name);
61
Dmitri Gribenko8487c522012-07-23 17:40:30 +000062 if (!isFunctionDecl())
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +000063 Diag(Command->getLocation(),
64 diag::warn_doc_param_not_attached_to_a_function_decl)
65 << Command->getCommandNameRange();
66
67 return Command;
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +000068}
69
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +000070ParamCommandComment *Sema::actOnParamCommandDirectionArg(
71 ParamCommandComment *Command,
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +000072 SourceLocation ArgLocBegin,
73 SourceLocation ArgLocEnd,
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +000074 StringRef Arg) {
75 ParamCommandComment::PassDirection Direction;
76 std::string ArgLower = Arg.lower();
77 // TODO: optimize: lower Name first (need an API in SmallString for that),
78 // after that StringSwitch.
79 if (ArgLower == "[in]")
80 Direction = ParamCommandComment::In;
81 else if (ArgLower == "[out]")
82 Direction = ParamCommandComment::Out;
83 else if (ArgLower == "[in,out]" || ArgLower == "[out,in]")
84 Direction = ParamCommandComment::InOut;
85 else {
86 // Remove spaces.
87 std::string::iterator O = ArgLower.begin();
88 for (std::string::iterator I = ArgLower.begin(), E = ArgLower.end();
89 I != E; ++I) {
90 const char C = *I;
91 if (C != ' ' && C != '\n' && C != '\r' &&
92 C != '\t' && C != '\v' && C != '\f')
93 *O++ = C;
94 }
95 ArgLower.resize(O - ArgLower.begin());
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +000096
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +000097 bool RemovingWhitespaceHelped = false;
98 if (ArgLower == "[in]") {
99 Direction = ParamCommandComment::In;
100 RemovingWhitespaceHelped = true;
101 } else if (ArgLower == "[out]") {
102 Direction = ParamCommandComment::Out;
103 RemovingWhitespaceHelped = true;
104 } else if (ArgLower == "[in,out]" || ArgLower == "[out,in]") {
105 Direction = ParamCommandComment::InOut;
106 RemovingWhitespaceHelped = true;
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000107 } else {
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000108 Direction = ParamCommandComment::In;
109 RemovingWhitespaceHelped = false;
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000110 }
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000111
112 SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
113 if (RemovingWhitespaceHelped)
114 Diag(ArgLocBegin, diag::warn_doc_param_spaces_in_direction)
115 << ArgRange
116 << FixItHint::CreateReplacement(
117 ArgRange,
118 ParamCommandComment::getDirectionAsString(Direction));
119 else
120 Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction)
121 << ArgRange;
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000122 }
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000123 Command->setDirection(Direction, /* Explicit = */ true);
124 return Command;
125}
126
127ParamCommandComment *Sema::actOnParamCommandParamNameArg(
128 ParamCommandComment *Command,
129 SourceLocation ArgLocBegin,
130 SourceLocation ArgLocEnd,
131 StringRef Arg) {
132 // Parser will not feed us more arguments than needed.
Dmitri Gribenko0eaf69d2012-07-13 19:02:42 +0000133 assert(Command->getNumArgs() == 0);
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000134
135 if (!Command->isDirectionExplicit()) {
136 // User didn't provide a direction argument.
137 Command->setDirection(ParamCommandComment::In, /* Explicit = */ false);
138 }
139 typedef BlockCommandComment::Argument Argument;
140 Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
141 ArgLocEnd),
142 Arg);
143 Command->setArgs(llvm::makeArrayRef(A, 1));
144
Dmitri Gribenko8487c522012-07-23 17:40:30 +0000145 if (!isFunctionDecl()) {
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000146 // We already warned that this \\param is not attached to a function decl.
147 return Command;
148 }
149
Dmitri Gribenko8487c522012-07-23 17:40:30 +0000150 ArrayRef<const ParmVarDecl *> ParamVars = getParamVars();
151
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000152 // Check that referenced parameter name is in the function decl.
Dmitri Gribenko8487c522012-07-23 17:40:30 +0000153 const unsigned ResolvedParamIndex = resolveParmVarReference(Arg, ParamVars);
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000154 if (ResolvedParamIndex != ParamCommandComment::InvalidParamIndex) {
155 Command->setParamIndex(ResolvedParamIndex);
Dmitri Gribenko65822772012-07-24 21:44:16 +0000156 if (ParamVarDocs[ResolvedParamIndex]) {
157 SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
158 Diag(ArgLocBegin, diag::warn_doc_param_duplicate)
159 << Arg << ArgRange;
160 ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex];
161 Diag(PrevCommand->getLocation(), diag::note_doc_param_previous)
162 << PrevCommand->getParamNameRange();
163 }
164 ParamVarDocs[ResolvedParamIndex] = Command;
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000165 return Command;
166 }
167
168 SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
169 Diag(ArgLocBegin, diag::warn_doc_param_not_found)
170 << Arg << ArgRange;
171
Dmitri Gribenkobbb7af32012-07-27 21:34:43 +0000172 // No parameters -- can't suggest a correction.
173 if (ParamVars.size() == 0)
174 return Command;
175
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000176 unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex;
Dmitri Gribenko8487c522012-07-23 17:40:30 +0000177 if (ParamVars.size() == 1) {
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000178 // If function has only one parameter then only that parameter
179 // can be documented.
180 CorrectedParamIndex = 0;
181 } else {
182 // Do typo correction.
Dmitri Gribenko8487c522012-07-23 17:40:30 +0000183 CorrectedParamIndex = correctTypoInParmVarReference(Arg, ParamVars);
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000184 }
185 if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) {
186 const ParmVarDecl *CorrectedPVD = ParamVars[CorrectedParamIndex];
187 if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier())
188 Diag(ArgLocBegin, diag::note_doc_param_name_suggestion)
189 << CorrectedII->getName()
190 << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName());
191 }
192
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000193 return Command;
194}
195
196ParamCommandComment *Sema::actOnParamCommandFinish(ParamCommandComment *Command,
197 ParagraphComment *Paragraph) {
198 Command->setParagraph(Paragraph);
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000199 checkBlockCommandEmptyParagraph(Command);
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000200 return Command;
201}
202
203InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
204 SourceLocation CommandLocEnd,
205 StringRef CommandName) {
206 ArrayRef<InlineCommandComment::Argument> Args;
Dmitri Gribenko2d66a502012-07-23 16:43:01 +0000207 return new (Allocator) InlineCommandComment(
208 CommandLocBegin,
209 CommandLocEnd,
210 CommandName,
211 getInlineCommandRenderKind(CommandName),
212 Args);
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000213}
214
215InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
216 SourceLocation CommandLocEnd,
217 StringRef CommandName,
218 SourceLocation ArgLocBegin,
219 SourceLocation ArgLocEnd,
220 StringRef Arg) {
221 typedef InlineCommandComment::Argument Argument;
222 Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
223 ArgLocEnd),
224 Arg);
225
Dmitri Gribenko2d66a502012-07-23 16:43:01 +0000226 return new (Allocator) InlineCommandComment(
227 CommandLocBegin,
228 CommandLocEnd,
229 CommandName,
230 getInlineCommandRenderKind(CommandName),
231 llvm::makeArrayRef(A, 1));
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000232}
233
234InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
235 SourceLocation LocEnd,
236 StringRef Name) {
237 ArrayRef<InlineCommandComment::Argument> Args;
Dmitri Gribenko2d66a502012-07-23 16:43:01 +0000238 return new (Allocator) InlineCommandComment(
239 LocBegin, LocEnd, Name,
240 InlineCommandComment::RenderNormal,
241 Args);
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000242}
243
244TextComment *Sema::actOnText(SourceLocation LocBegin,
245 SourceLocation LocEnd,
246 StringRef Text) {
247 return new (Allocator) TextComment(LocBegin, LocEnd, Text);
248}
249
250VerbatimBlockComment *Sema::actOnVerbatimBlockStart(SourceLocation Loc,
251 StringRef Name) {
252 return new (Allocator) VerbatimBlockComment(
253 Loc,
254 Loc.getLocWithOffset(1 + Name.size()),
255 Name);
256}
257
258VerbatimBlockLineComment *Sema::actOnVerbatimBlockLine(SourceLocation Loc,
259 StringRef Text) {
260 return new (Allocator) VerbatimBlockLineComment(Loc, Text);
261}
262
263VerbatimBlockComment *Sema::actOnVerbatimBlockFinish(
264 VerbatimBlockComment *Block,
265 SourceLocation CloseNameLocBegin,
266 StringRef CloseName,
267 ArrayRef<VerbatimBlockLineComment *> Lines) {
268 Block->setCloseName(CloseName, CloseNameLocBegin);
269 Block->setLines(Lines);
270 return Block;
271}
272
273VerbatimLineComment *Sema::actOnVerbatimLine(SourceLocation LocBegin,
274 StringRef Name,
275 SourceLocation TextBegin,
276 StringRef Text) {
277 return new (Allocator) VerbatimLineComment(
278 LocBegin,
279 TextBegin.getLocWithOffset(Text.size()),
280 Name,
281 TextBegin,
282 Text);
283}
284
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000285HTMLStartTagComment *Sema::actOnHTMLStartTagStart(SourceLocation LocBegin,
286 StringRef TagName) {
287 return new (Allocator) HTMLStartTagComment(LocBegin, TagName);
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000288}
289
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000290HTMLStartTagComment *Sema::actOnHTMLStartTagFinish(
291 HTMLStartTagComment *Tag,
292 ArrayRef<HTMLStartTagComment::Attribute> Attrs,
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000293 SourceLocation GreaterLoc,
294 bool IsSelfClosing) {
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000295 Tag->setAttrs(Attrs);
296 Tag->setGreaterLoc(GreaterLoc);
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000297 if (IsSelfClosing)
298 Tag->setSelfClosing();
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000299 else if (!isHTMLEndTagForbidden(Tag->getTagName()))
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000300 HTMLOpenTags.push_back(Tag);
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000301 return Tag;
302}
303
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000304HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin,
305 SourceLocation LocEnd,
306 StringRef TagName) {
307 HTMLEndTagComment *HET =
308 new (Allocator) HTMLEndTagComment(LocBegin, LocEnd, TagName);
309 if (isHTMLEndTagForbidden(TagName)) {
310 Diag(HET->getLocation(), diag::warn_doc_html_end_forbidden)
311 << TagName << HET->getSourceRange();
312 return HET;
Dmitri Gribenko3d986982012-07-12 23:37:09 +0000313 }
314
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000315 bool FoundOpen = false;
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000316 for (SmallVectorImpl<HTMLStartTagComment *>::const_reverse_iterator
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000317 I = HTMLOpenTags.rbegin(), E = HTMLOpenTags.rend();
318 I != E; ++I) {
319 if ((*I)->getTagName() == TagName) {
320 FoundOpen = true;
321 break;
322 }
323 }
324 if (!FoundOpen) {
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000325 Diag(HET->getLocation(), diag::warn_doc_html_end_unbalanced)
326 << HET->getSourceRange();
327 return HET;
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000328 }
329
330 while (!HTMLOpenTags.empty()) {
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000331 const HTMLStartTagComment *HST = HTMLOpenTags.back();
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000332 HTMLOpenTags.pop_back();
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000333 StringRef LastNotClosedTagName = HST->getTagName();
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000334 if (LastNotClosedTagName == TagName)
335 break;
336
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000337 if (isHTMLEndTagOptional(LastNotClosedTagName))
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000338 continue;
339
340 bool OpenLineInvalid;
341 const unsigned OpenLine = SourceMgr.getPresumedLineNumber(
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000342 HST->getLocation(),
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000343 &OpenLineInvalid);
344 bool CloseLineInvalid;
345 const unsigned CloseLine = SourceMgr.getPresumedLineNumber(
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000346 HET->getLocation(),
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000347 &CloseLineInvalid);
348
349 if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine)
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000350 Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
351 << HST->getTagName() << HET->getTagName()
352 << HST->getSourceRange() << HET->getSourceRange();
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000353 else {
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000354 Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
355 << HST->getTagName() << HET->getTagName()
356 << HST->getSourceRange();
357 Diag(HET->getLocation(), diag::note_doc_html_end_tag)
358 << HET->getSourceRange();
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000359 }
360 }
361
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000362 return HET;
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000363}
364
365FullComment *Sema::actOnFullComment(
366 ArrayRef<BlockContentComment *> Blocks) {
367 return new (Allocator) FullComment(Blocks);
368}
369
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000370void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) {
371 ParagraphComment *Paragraph = Command->getParagraph();
372 if (Paragraph->isWhitespace()) {
373 SourceLocation DiagLoc;
Dmitri Gribenko0eaf69d2012-07-13 19:02:42 +0000374 if (Command->getNumArgs() > 0)
375 DiagLoc = Command->getArgRange(Command->getNumArgs() - 1).getEnd();
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000376 if (!DiagLoc.isValid())
377 DiagLoc = Command->getCommandNameRange().getEnd();
378 Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
379 << Command->getCommandName()
380 << Command->getSourceRange();
381 }
382}
383
Dmitri Gribenko8487c522012-07-23 17:40:30 +0000384bool Sema::isFunctionDecl() {
Dmitri Gribenko00c59f72012-07-24 20:58:46 +0000385 if (!IsThisDeclInspected)
386 inspectThisDecl();
Dmitri Gribenko8487c522012-07-23 17:40:30 +0000387 return IsFunctionDecl;
388}
389
390ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
Dmitri Gribenko00c59f72012-07-24 20:58:46 +0000391 if (!IsThisDeclInspected)
392 inspectThisDecl();
Dmitri Gribenko8487c522012-07-23 17:40:30 +0000393 return ParamVars;
394}
395
396void Sema::inspectThisDecl() {
Dmitri Gribenko65822772012-07-24 21:44:16 +0000397 assert(!IsThisDeclInspected);
Dmitri Gribenko8487c522012-07-23 17:40:30 +0000398 if (!ThisDecl) {
399 IsFunctionDecl = false;
400 ParamVars = ArrayRef<const ParmVarDecl *>();
401 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ThisDecl)) {
402 IsFunctionDecl = true;
403 ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
404 FD->getNumParams());
405 } else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(ThisDecl)) {
406 IsFunctionDecl = true;
407 ParamVars = ArrayRef<const ParmVarDecl *>(MD->param_begin(),
408 MD->param_size());
409 } else {
410 IsFunctionDecl = false;
411 ParamVars = ArrayRef<const ParmVarDecl *>();
412 }
Dmitri Gribenko65822772012-07-24 21:44:16 +0000413 ParamVarDocs.resize(ParamVars.size(), NULL);
Dmitri Gribenko8487c522012-07-23 17:40:30 +0000414 IsThisDeclInspected = true;
415}
416
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000417unsigned Sema::resolveParmVarReference(StringRef Name,
Dmitri Gribenko8487c522012-07-23 17:40:30 +0000418 ArrayRef<const ParmVarDecl *> ParamVars) {
419 for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000420 const IdentifierInfo *II = ParamVars[i]->getIdentifier();
421 if (II && II->getName() == Name)
422 return i;
423 }
424 return ParamCommandComment::InvalidParamIndex;
425}
426
427unsigned Sema::correctTypoInParmVarReference(
428 StringRef Typo,
Dmitri Gribenko8487c522012-07-23 17:40:30 +0000429 ArrayRef<const ParmVarDecl *> ParamVars) {
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000430 const unsigned MaxEditDistance = (Typo.size() + 2) / 3;
Richard Smith18b7f952012-07-11 22:33:59 +0000431 unsigned BestPVDIndex = 0;
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000432 unsigned BestEditDistance = MaxEditDistance + 1;
Dmitri Gribenko8487c522012-07-23 17:40:30 +0000433 for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000434 const IdentifierInfo *II = ParamVars[i]->getIdentifier();
435 if (II) {
436 StringRef Name = II->getName();
NAKAMURA Takumidc5796c2012-07-12 00:45:08 +0000437 unsigned MinPossibleEditDistance =
438 abs((int)Name.size() - (int)Typo.size());
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000439 if (MinPossibleEditDistance > 0 &&
440 Typo.size() / MinPossibleEditDistance < 3)
441 continue;
442
443 unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
444 if (EditDistance < BestEditDistance) {
445 BestEditDistance = EditDistance;
446 BestPVDIndex = i;
447 }
448 }
449 }
450
451 if (BestEditDistance <= MaxEditDistance)
452 return BestPVDIndex;
453 else
Dmitri Gribenko0ba58802012-07-27 23:26:26 +0000454 return ParamCommandComment::InvalidParamIndex;
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000455}
456
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000457// TODO: tablegen
458bool Sema::isBlockCommand(StringRef Name) {
459 return llvm::StringSwitch<bool>(Name)
Dmitri Gribenko3d3d22c2012-07-18 00:44:55 +0000460 .Cases("brief", "short", true)
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000461 .Case("result", true)
462 .Case("return", true)
463 .Case("returns", true)
464 .Case("author", true)
465 .Case("authors", true)
466 .Case("pre", true)
467 .Case("post", true)
468 .Default(false) || isParamCommand(Name);
469}
470
471bool Sema::isParamCommand(StringRef Name) {
472 return llvm::StringSwitch<bool>(Name)
473 .Case("param", true)
474 .Case("arg", true)
475 .Default(false);
476}
477
478unsigned Sema::getBlockCommandNumArgs(StringRef Name) {
479 return llvm::StringSwitch<unsigned>(Name)
Dmitri Gribenko3d3d22c2012-07-18 00:44:55 +0000480 .Cases("brief", "short", 0)
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000481 .Case("pre", 0)
482 .Case("post", 0)
483 .Case("author", 0)
484 .Case("authors", 0)
485 .Default(0);
486}
487
Dmitri Gribenko2d66a502012-07-23 16:43:01 +0000488bool Sema::isInlineCommand(StringRef Name) const {
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000489 return llvm::StringSwitch<bool>(Name)
Dmitri Gribenkoc48dd8e2012-07-19 00:21:03 +0000490 .Case("b", true)
491 .Cases("c", "p", true)
492 .Cases("a", "e", "em", true)
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000493 .Default(false);
494}
495
Dmitri Gribenko2d66a502012-07-23 16:43:01 +0000496InlineCommandComment::RenderKind
497Sema::getInlineCommandRenderKind(StringRef Name) const {
498 assert(isInlineCommand(Name));
499
500 return llvm::StringSwitch<InlineCommandComment::RenderKind>(Name)
501 .Case("b", InlineCommandComment::RenderBold)
502 .Cases("c", "p", InlineCommandComment::RenderMonospaced)
503 .Cases("a", "e", "em", InlineCommandComment::RenderEmphasized)
504 .Default(InlineCommandComment::RenderNormal);
505}
506
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000507bool Sema::isHTMLEndTagOptional(StringRef Name) {
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000508 return llvm::StringSwitch<bool>(Name)
Dmitri Gribenko3d986982012-07-12 23:37:09 +0000509 .Case("p", true)
510 .Case("li", true)
511 .Case("dt", true)
512 .Case("dd", true)
513 .Case("tr", true)
514 .Case("th", true)
515 .Case("td", true)
516 .Case("thead", true)
517 .Case("tfoot", true)
518 .Case("tbody", true)
519 .Case("colgroup", true)
520 .Default(false);
521}
522
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000523bool Sema::isHTMLEndTagForbidden(StringRef Name) {
Dmitri Gribenko3d986982012-07-12 23:37:09 +0000524 return llvm::StringSwitch<bool>(Name)
525 .Case("br", true)
526 .Case("hr", true)
527 .Case("img", true)
528 .Case("col", true)
529 .Default(false);
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000530}
531
532} // end namespace comments
533} // end namespace clang
534