CommentSema.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846
  1. //===--- 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. #include "clang/AST/CommentSema.h"
  10. #include "clang/AST/Attr.h"
  11. #include "clang/AST/CommentCommandTraits.h"
  12. #include "clang/AST/CommentDiagnostic.h"
  13. #include "clang/AST/Decl.h"
  14. #include "clang/AST/DeclTemplate.h"
  15. #include "clang/Basic/SourceManager.h"
  16. #include "clang/Lex/Preprocessor.h"
  17. #include "llvm/ADT/SmallString.h"
  18. #include "llvm/ADT/StringSwitch.h"
  19. namespace clang {
  20. namespace comments {
  21. namespace {
  22. #include "clang/AST/CommentHTMLTagsProperties.inc"
  23. } // unnamed namespace
  24. Sema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr,
  25. DiagnosticsEngine &Diags, CommandTraits &Traits,
  26. const Preprocessor *PP) :
  27. Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits),
  28. PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), ReturnsCommand(NULL),
  29. HeaderfileCommand(NULL) {
  30. }
  31. void Sema::setDecl(const Decl *D) {
  32. if (!D)
  33. return;
  34. ThisDeclInfo = new (Allocator) DeclInfo;
  35. ThisDeclInfo->CommentDecl = D;
  36. ThisDeclInfo->IsFilled = false;
  37. }
  38. ParagraphComment *Sema::actOnParagraphComment(
  39. ArrayRef<InlineContentComment *> Content) {
  40. return new (Allocator) ParagraphComment(Content);
  41. }
  42. BlockCommandComment *Sema::actOnBlockCommandStart(SourceLocation LocBegin,
  43. SourceLocation LocEnd,
  44. unsigned CommandID) {
  45. return new (Allocator) BlockCommandComment(LocBegin, LocEnd, CommandID);
  46. }
  47. void Sema::actOnBlockCommandArgs(BlockCommandComment *Command,
  48. ArrayRef<BlockCommandComment::Argument> Args) {
  49. Command->setArgs(Args);
  50. }
  51. void Sema::actOnBlockCommandFinish(BlockCommandComment *Command,
  52. ParagraphComment *Paragraph) {
  53. Command->setParagraph(Paragraph);
  54. checkBlockCommandEmptyParagraph(Command);
  55. checkBlockCommandDuplicate(Command);
  56. checkReturnsCommand(Command);
  57. checkDeprecatedCommand(Command);
  58. }
  59. ParamCommandComment *Sema::actOnParamCommandStart(SourceLocation LocBegin,
  60. SourceLocation LocEnd,
  61. unsigned CommandID) {
  62. ParamCommandComment *Command =
  63. new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID);
  64. if (!isFunctionDecl())
  65. Diag(Command->getLocation(),
  66. diag::warn_doc_param_not_attached_to_a_function_decl)
  67. << Command->getCommandNameRange(Traits);
  68. return Command;
  69. }
  70. void Sema::actOnParamCommandDirectionArg(ParamCommandComment *Command,
  71. SourceLocation ArgLocBegin,
  72. SourceLocation ArgLocEnd,
  73. StringRef Arg) {
  74. ParamCommandComment::PassDirection Direction;
  75. std::string ArgLower = Arg.lower();
  76. // TODO: optimize: lower Name first (need an API in SmallString for that),
  77. // after that StringSwitch.
  78. if (ArgLower == "[in]")
  79. Direction = ParamCommandComment::In;
  80. else if (ArgLower == "[out]")
  81. Direction = ParamCommandComment::Out;
  82. else if (ArgLower == "[in,out]" || ArgLower == "[out,in]")
  83. Direction = ParamCommandComment::InOut;
  84. else {
  85. // Remove spaces.
  86. std::string::iterator O = ArgLower.begin();
  87. for (std::string::iterator I = ArgLower.begin(), E = ArgLower.end();
  88. I != E; ++I) {
  89. const char C = *I;
  90. if (C != ' ' && C != '\n' && C != '\r' &&
  91. C != '\t' && C != '\v' && C != '\f')
  92. *O++ = C;
  93. }
  94. ArgLower.resize(O - ArgLower.begin());
  95. bool RemovingWhitespaceHelped = false;
  96. if (ArgLower == "[in]") {
  97. Direction = ParamCommandComment::In;
  98. RemovingWhitespaceHelped = true;
  99. } else if (ArgLower == "[out]") {
  100. Direction = ParamCommandComment::Out;
  101. RemovingWhitespaceHelped = true;
  102. } else if (ArgLower == "[in,out]" || ArgLower == "[out,in]") {
  103. Direction = ParamCommandComment::InOut;
  104. RemovingWhitespaceHelped = true;
  105. } else {
  106. Direction = ParamCommandComment::In;
  107. RemovingWhitespaceHelped = false;
  108. }
  109. SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
  110. if (RemovingWhitespaceHelped)
  111. Diag(ArgLocBegin, diag::warn_doc_param_spaces_in_direction)
  112. << ArgRange
  113. << FixItHint::CreateReplacement(
  114. ArgRange,
  115. ParamCommandComment::getDirectionAsString(Direction));
  116. else
  117. Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction)
  118. << ArgRange;
  119. }
  120. Command->setDirection(Direction, /* Explicit = */ true);
  121. }
  122. void Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command,
  123. SourceLocation ArgLocBegin,
  124. SourceLocation ArgLocEnd,
  125. StringRef Arg) {
  126. // Parser will not feed us more arguments than needed.
  127. assert(Command->getNumArgs() == 0);
  128. if (!Command->isDirectionExplicit()) {
  129. // User didn't provide a direction argument.
  130. Command->setDirection(ParamCommandComment::In, /* Explicit = */ false);
  131. }
  132. typedef BlockCommandComment::Argument Argument;
  133. Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
  134. ArgLocEnd),
  135. Arg);
  136. Command->setArgs(llvm::makeArrayRef(A, 1));
  137. }
  138. void Sema::actOnParamCommandFinish(ParamCommandComment *Command,
  139. ParagraphComment *Paragraph) {
  140. Command->setParagraph(Paragraph);
  141. checkBlockCommandEmptyParagraph(Command);
  142. }
  143. TParamCommandComment *Sema::actOnTParamCommandStart(SourceLocation LocBegin,
  144. SourceLocation LocEnd,
  145. unsigned CommandID) {
  146. TParamCommandComment *Command =
  147. new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID);
  148. if (!isTemplateOrSpecialization())
  149. Diag(Command->getLocation(),
  150. diag::warn_doc_tparam_not_attached_to_a_template_decl)
  151. << Command->getCommandNameRange(Traits);
  152. return Command;
  153. }
  154. void Sema::actOnTParamCommandParamNameArg(TParamCommandComment *Command,
  155. SourceLocation ArgLocBegin,
  156. SourceLocation ArgLocEnd,
  157. StringRef Arg) {
  158. // Parser will not feed us more arguments than needed.
  159. assert(Command->getNumArgs() == 0);
  160. typedef BlockCommandComment::Argument Argument;
  161. Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
  162. ArgLocEnd),
  163. Arg);
  164. Command->setArgs(llvm::makeArrayRef(A, 1));
  165. if (!isTemplateOrSpecialization()) {
  166. // We already warned that this \\tparam is not attached to a template decl.
  167. return;
  168. }
  169. const TemplateParameterList *TemplateParameters =
  170. ThisDeclInfo->TemplateParameters;
  171. SmallVector<unsigned, 2> Position;
  172. if (resolveTParamReference(Arg, TemplateParameters, &Position)) {
  173. Command->setPosition(copyArray(llvm::makeArrayRef(Position)));
  174. llvm::StringMap<TParamCommandComment *>::iterator PrevCommandIt =
  175. TemplateParameterDocs.find(Arg);
  176. if (PrevCommandIt != TemplateParameterDocs.end()) {
  177. SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
  178. Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate)
  179. << Arg << ArgRange;
  180. TParamCommandComment *PrevCommand = PrevCommandIt->second;
  181. Diag(PrevCommand->getLocation(), diag::note_doc_tparam_previous)
  182. << PrevCommand->getParamNameRange();
  183. }
  184. TemplateParameterDocs[Arg] = Command;
  185. return;
  186. }
  187. SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
  188. Diag(ArgLocBegin, diag::warn_doc_tparam_not_found)
  189. << Arg << ArgRange;
  190. if (!TemplateParameters || TemplateParameters->size() == 0)
  191. return;
  192. StringRef CorrectedName;
  193. if (TemplateParameters->size() == 1) {
  194. const NamedDecl *Param = TemplateParameters->getParam(0);
  195. const IdentifierInfo *II = Param->getIdentifier();
  196. if (II)
  197. CorrectedName = II->getName();
  198. } else {
  199. CorrectedName = correctTypoInTParamReference(Arg, TemplateParameters);
  200. }
  201. if (!CorrectedName.empty()) {
  202. Diag(ArgLocBegin, diag::note_doc_tparam_name_suggestion)
  203. << CorrectedName
  204. << FixItHint::CreateReplacement(ArgRange, CorrectedName);
  205. }
  206. return;
  207. }
  208. void Sema::actOnTParamCommandFinish(TParamCommandComment *Command,
  209. ParagraphComment *Paragraph) {
  210. Command->setParagraph(Paragraph);
  211. checkBlockCommandEmptyParagraph(Command);
  212. }
  213. InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
  214. SourceLocation CommandLocEnd,
  215. unsigned CommandID) {
  216. ArrayRef<InlineCommandComment::Argument> Args;
  217. StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
  218. return new (Allocator) InlineCommandComment(
  219. CommandLocBegin,
  220. CommandLocEnd,
  221. CommandID,
  222. getInlineCommandRenderKind(CommandName),
  223. Args);
  224. }
  225. InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
  226. SourceLocation CommandLocEnd,
  227. unsigned CommandID,
  228. SourceLocation ArgLocBegin,
  229. SourceLocation ArgLocEnd,
  230. StringRef Arg) {
  231. typedef InlineCommandComment::Argument Argument;
  232. Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
  233. ArgLocEnd),
  234. Arg);
  235. StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
  236. return new (Allocator) InlineCommandComment(
  237. CommandLocBegin,
  238. CommandLocEnd,
  239. CommandID,
  240. getInlineCommandRenderKind(CommandName),
  241. llvm::makeArrayRef(A, 1));
  242. }
  243. InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
  244. SourceLocation LocEnd,
  245. StringRef CommandName) {
  246. unsigned CommandID = Traits.registerUnknownCommand(CommandName)->getID();
  247. return actOnUnknownCommand(LocBegin, LocEnd, CommandID);
  248. }
  249. InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
  250. SourceLocation LocEnd,
  251. unsigned CommandID) {
  252. ArrayRef<InlineCommandComment::Argument> Args;
  253. return new (Allocator) InlineCommandComment(
  254. LocBegin, LocEnd, CommandID,
  255. InlineCommandComment::RenderNormal,
  256. Args);
  257. }
  258. TextComment *Sema::actOnText(SourceLocation LocBegin,
  259. SourceLocation LocEnd,
  260. StringRef Text) {
  261. return new (Allocator) TextComment(LocBegin, LocEnd, Text);
  262. }
  263. VerbatimBlockComment *Sema::actOnVerbatimBlockStart(SourceLocation Loc,
  264. unsigned CommandID) {
  265. StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
  266. return new (Allocator) VerbatimBlockComment(
  267. Loc,
  268. Loc.getLocWithOffset(1 + CommandName.size()),
  269. CommandID);
  270. }
  271. VerbatimBlockLineComment *Sema::actOnVerbatimBlockLine(SourceLocation Loc,
  272. StringRef Text) {
  273. return new (Allocator) VerbatimBlockLineComment(Loc, Text);
  274. }
  275. void Sema::actOnVerbatimBlockFinish(
  276. VerbatimBlockComment *Block,
  277. SourceLocation CloseNameLocBegin,
  278. StringRef CloseName,
  279. ArrayRef<VerbatimBlockLineComment *> Lines) {
  280. Block->setCloseName(CloseName, CloseNameLocBegin);
  281. Block->setLines(Lines);
  282. }
  283. VerbatimLineComment *Sema::actOnVerbatimLine(SourceLocation LocBegin,
  284. unsigned CommandID,
  285. SourceLocation TextBegin,
  286. StringRef Text) {
  287. return new (Allocator) VerbatimLineComment(
  288. LocBegin,
  289. TextBegin.getLocWithOffset(Text.size()),
  290. CommandID,
  291. TextBegin,
  292. Text);
  293. }
  294. HTMLStartTagComment *Sema::actOnHTMLStartTagStart(SourceLocation LocBegin,
  295. StringRef TagName) {
  296. return new (Allocator) HTMLStartTagComment(LocBegin, TagName);
  297. }
  298. void Sema::actOnHTMLStartTagFinish(
  299. HTMLStartTagComment *Tag,
  300. ArrayRef<HTMLStartTagComment::Attribute> Attrs,
  301. SourceLocation GreaterLoc,
  302. bool IsSelfClosing) {
  303. Tag->setAttrs(Attrs);
  304. Tag->setGreaterLoc(GreaterLoc);
  305. if (IsSelfClosing)
  306. Tag->setSelfClosing();
  307. else if (!isHTMLEndTagForbidden(Tag->getTagName()))
  308. HTMLOpenTags.push_back(Tag);
  309. }
  310. HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin,
  311. SourceLocation LocEnd,
  312. StringRef TagName) {
  313. HTMLEndTagComment *HET =
  314. new (Allocator) HTMLEndTagComment(LocBegin, LocEnd, TagName);
  315. if (isHTMLEndTagForbidden(TagName)) {
  316. Diag(HET->getLocation(), diag::warn_doc_html_end_forbidden)
  317. << TagName << HET->getSourceRange();
  318. return HET;
  319. }
  320. bool FoundOpen = false;
  321. for (SmallVectorImpl<HTMLStartTagComment *>::const_reverse_iterator
  322. I = HTMLOpenTags.rbegin(), E = HTMLOpenTags.rend();
  323. I != E; ++I) {
  324. if ((*I)->getTagName() == TagName) {
  325. FoundOpen = true;
  326. break;
  327. }
  328. }
  329. if (!FoundOpen) {
  330. Diag(HET->getLocation(), diag::warn_doc_html_end_unbalanced)
  331. << HET->getSourceRange();
  332. return HET;
  333. }
  334. while (!HTMLOpenTags.empty()) {
  335. const HTMLStartTagComment *HST = HTMLOpenTags.back();
  336. HTMLOpenTags.pop_back();
  337. StringRef LastNotClosedTagName = HST->getTagName();
  338. if (LastNotClosedTagName == TagName)
  339. break;
  340. if (isHTMLEndTagOptional(LastNotClosedTagName))
  341. continue;
  342. bool OpenLineInvalid;
  343. const unsigned OpenLine = SourceMgr.getPresumedLineNumber(
  344. HST->getLocation(),
  345. &OpenLineInvalid);
  346. bool CloseLineInvalid;
  347. const unsigned CloseLine = SourceMgr.getPresumedLineNumber(
  348. HET->getLocation(),
  349. &CloseLineInvalid);
  350. if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine)
  351. Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
  352. << HST->getTagName() << HET->getTagName()
  353. << HST->getSourceRange() << HET->getSourceRange();
  354. else {
  355. Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
  356. << HST->getTagName() << HET->getTagName()
  357. << HST->getSourceRange();
  358. Diag(HET->getLocation(), diag::note_doc_html_end_tag)
  359. << HET->getSourceRange();
  360. }
  361. }
  362. return HET;
  363. }
  364. FullComment *Sema::actOnFullComment(
  365. ArrayRef<BlockContentComment *> Blocks) {
  366. FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo);
  367. resolveParamCommandIndexes(FC);
  368. return FC;
  369. }
  370. void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) {
  371. if (Traits.getCommandInfo(Command->getCommandID())->IsEmptyParagraphAllowed)
  372. return;
  373. ParagraphComment *Paragraph = Command->getParagraph();
  374. if (Paragraph->isWhitespace()) {
  375. SourceLocation DiagLoc;
  376. if (Command->getNumArgs() > 0)
  377. DiagLoc = Command->getArgRange(Command->getNumArgs() - 1).getEnd();
  378. if (!DiagLoc.isValid())
  379. DiagLoc = Command->getCommandNameRange(Traits).getEnd();
  380. Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
  381. << Command->getHDCommand()
  382. << Command->getCommandName(Traits)
  383. << Command->getSourceRange();
  384. }
  385. }
  386. void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
  387. if (!Traits.getCommandInfo(Command->getCommandID())->IsReturnsCommand)
  388. return;
  389. if (isFunctionDecl()) {
  390. if (ThisDeclInfo->ResultType->isVoidType()) {
  391. unsigned DiagKind;
  392. switch (ThisDeclInfo->CommentDecl->getKind()) {
  393. default:
  394. if (ThisDeclInfo->IsObjCMethod)
  395. DiagKind = 3;
  396. else
  397. DiagKind = 0;
  398. break;
  399. case Decl::CXXConstructor:
  400. DiagKind = 1;
  401. break;
  402. case Decl::CXXDestructor:
  403. DiagKind = 2;
  404. break;
  405. }
  406. Diag(Command->getLocation(),
  407. diag::warn_doc_returns_attached_to_a_void_function)
  408. << Command->getHDCommand()
  409. << Command->getCommandName(Traits)
  410. << DiagKind
  411. << Command->getSourceRange();
  412. }
  413. return;
  414. }
  415. else if (isObjCPropertyDecl())
  416. return;
  417. Diag(Command->getLocation(),
  418. diag::warn_doc_returns_not_attached_to_a_function_decl)
  419. << Command->getHDCommand()
  420. << Command->getCommandName(Traits)
  421. << Command->getSourceRange();
  422. }
  423. void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) {
  424. const CommandInfo *Info = Traits.getCommandInfo(Command->getCommandID());
  425. const BlockCommandComment *PrevCommand = NULL;
  426. if (Info->IsBriefCommand) {
  427. if (!BriefCommand) {
  428. BriefCommand = Command;
  429. return;
  430. }
  431. PrevCommand = BriefCommand;
  432. } else if (Info->IsReturnsCommand) {
  433. if (!ReturnsCommand) {
  434. ReturnsCommand = Command;
  435. return;
  436. }
  437. PrevCommand = ReturnsCommand;
  438. } else if (Info->IsHeaderfileCommand) {
  439. if (!HeaderfileCommand) {
  440. HeaderfileCommand = Command;
  441. return;
  442. }
  443. PrevCommand = HeaderfileCommand;
  444. } else {
  445. // We don't want to check this command for duplicates.
  446. return;
  447. }
  448. StringRef CommandName = Command->getCommandName(Traits);
  449. StringRef PrevCommandName = PrevCommand->getCommandName(Traits);
  450. Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate)
  451. << Command->getHDCommand()
  452. << CommandName
  453. << Command->getSourceRange();
  454. if (CommandName == PrevCommandName)
  455. Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous)
  456. << PrevCommand->getHDCommand()
  457. << PrevCommandName
  458. << PrevCommand->getSourceRange();
  459. else
  460. Diag(PrevCommand->getLocation(),
  461. diag::note_doc_block_command_previous_alias)
  462. << PrevCommand->getHDCommand()
  463. << PrevCommandName
  464. << CommandName;
  465. }
  466. void Sema::checkDeprecatedCommand(const BlockCommandComment *Command) {
  467. if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand)
  468. return;
  469. const Decl *D = ThisDeclInfo->CommentDecl;
  470. if (!D)
  471. return;
  472. if (D->hasAttr<DeprecatedAttr>() ||
  473. D->hasAttr<AvailabilityAttr>() ||
  474. D->hasAttr<UnavailableAttr>())
  475. return;
  476. Diag(Command->getLocation(),
  477. diag::warn_doc_deprecated_not_sync)
  478. << Command->getSourceRange();
  479. // Try to emit a fixit with a deprecation attribute.
  480. if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
  481. // Don't emit a Fix-It for non-member function definitions. GCC does not
  482. // accept attributes on them.
  483. const DeclContext *Ctx = FD->getDeclContext();
  484. if ((!Ctx || !Ctx->isRecord()) &&
  485. FD->doesThisDeclarationHaveABody())
  486. return;
  487. StringRef AttributeSpelling = "__attribute__((deprecated))";
  488. if (PP) {
  489. TokenValue Tokens[] = {
  490. tok::kw___attribute, tok::l_paren, tok::l_paren,
  491. PP->getIdentifierInfo("deprecated"),
  492. tok::r_paren, tok::r_paren
  493. };
  494. StringRef MacroName = PP->getLastMacroWithSpelling(FD->getLocation(),
  495. Tokens);
  496. if (!MacroName.empty())
  497. AttributeSpelling = MacroName;
  498. }
  499. SmallString<64> TextToInsert(" ");
  500. TextToInsert += AttributeSpelling;
  501. Diag(FD->getLocEnd(),
  502. diag::note_add_deprecation_attr)
  503. << FixItHint::CreateInsertion(FD->getLocEnd().getLocWithOffset(1),
  504. TextToInsert);
  505. }
  506. }
  507. void Sema::resolveParamCommandIndexes(const FullComment *FC) {
  508. if (!isFunctionDecl()) {
  509. // We already warned that \\param commands are not attached to a function
  510. // decl.
  511. return;
  512. }
  513. SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands;
  514. // Comment AST nodes that correspond to \c ParamVars for which we have
  515. // found a \\param command or NULL if no documentation was found so far.
  516. SmallVector<ParamCommandComment *, 8> ParamVarDocs;
  517. ArrayRef<const ParmVarDecl *> ParamVars = getParamVars();
  518. ParamVarDocs.resize(ParamVars.size(), NULL);
  519. // First pass over all \\param commands: resolve all parameter names.
  520. for (Comment::child_iterator I = FC->child_begin(), E = FC->child_end();
  521. I != E; ++I) {
  522. ParamCommandComment *PCC = dyn_cast<ParamCommandComment>(*I);
  523. if (!PCC || !PCC->hasParamName())
  524. continue;
  525. StringRef ParamName = PCC->getParamNameAsWritten();
  526. // Check that referenced parameter name is in the function decl.
  527. const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName,
  528. ParamVars);
  529. if (ResolvedParamIndex == ParamCommandComment::InvalidParamIndex) {
  530. UnresolvedParamCommands.push_back(PCC);
  531. continue;
  532. }
  533. PCC->setParamIndex(ResolvedParamIndex);
  534. if (ParamVarDocs[ResolvedParamIndex]) {
  535. SourceRange ArgRange = PCC->getParamNameRange();
  536. Diag(ArgRange.getBegin(), diag::warn_doc_param_duplicate)
  537. << ParamName << ArgRange;
  538. ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex];
  539. Diag(PrevCommand->getLocation(), diag::note_doc_param_previous)
  540. << PrevCommand->getParamNameRange();
  541. }
  542. ParamVarDocs[ResolvedParamIndex] = PCC;
  543. }
  544. // Find parameter declarations that have no corresponding \\param.
  545. SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls;
  546. for (unsigned i = 0, e = ParamVarDocs.size(); i != e; ++i) {
  547. if (!ParamVarDocs[i])
  548. OrphanedParamDecls.push_back(ParamVars[i]);
  549. }
  550. // Second pass over unresolved \\param commands: do typo correction.
  551. // Suggest corrections from a set of parameter declarations that have no
  552. // corresponding \\param.
  553. for (unsigned i = 0, e = UnresolvedParamCommands.size(); i != e; ++i) {
  554. const ParamCommandComment *PCC = UnresolvedParamCommands[i];
  555. SourceRange ArgRange = PCC->getParamNameRange();
  556. StringRef ParamName = PCC->getParamNameAsWritten();
  557. Diag(ArgRange.getBegin(), diag::warn_doc_param_not_found)
  558. << ParamName << ArgRange;
  559. // All parameters documented -- can't suggest a correction.
  560. if (OrphanedParamDecls.size() == 0)
  561. continue;
  562. unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex;
  563. if (OrphanedParamDecls.size() == 1) {
  564. // If one parameter is not documented then that parameter is the only
  565. // possible suggestion.
  566. CorrectedParamIndex = 0;
  567. } else {
  568. // Do typo correction.
  569. CorrectedParamIndex = correctTypoInParmVarReference(ParamName,
  570. OrphanedParamDecls);
  571. }
  572. if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) {
  573. const ParmVarDecl *CorrectedPVD = OrphanedParamDecls[CorrectedParamIndex];
  574. if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier())
  575. Diag(ArgRange.getBegin(), diag::note_doc_param_name_suggestion)
  576. << CorrectedII->getName()
  577. << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName());
  578. }
  579. }
  580. }
  581. bool Sema::isFunctionDecl() {
  582. if (!ThisDeclInfo)
  583. return false;
  584. if (!ThisDeclInfo->IsFilled)
  585. inspectThisDecl();
  586. return ThisDeclInfo->getKind() == DeclInfo::FunctionKind;
  587. }
  588. bool Sema::isObjCPropertyDecl() {
  589. if (!ThisDeclInfo)
  590. return false;
  591. if (!ThisDeclInfo->IsFilled)
  592. inspectThisDecl();
  593. return ThisDeclInfo->CurrentDecl->getKind() == Decl::ObjCProperty;
  594. }
  595. bool Sema::isTemplateOrSpecialization() {
  596. if (!ThisDeclInfo)
  597. return false;
  598. if (!ThisDeclInfo->IsFilled)
  599. inspectThisDecl();
  600. return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate;
  601. }
  602. ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
  603. if (!ThisDeclInfo->IsFilled)
  604. inspectThisDecl();
  605. return ThisDeclInfo->ParamVars;
  606. }
  607. void Sema::inspectThisDecl() {
  608. ThisDeclInfo->fill();
  609. }
  610. unsigned Sema::resolveParmVarReference(StringRef Name,
  611. ArrayRef<const ParmVarDecl *> ParamVars) {
  612. for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
  613. const IdentifierInfo *II = ParamVars[i]->getIdentifier();
  614. if (II && II->getName() == Name)
  615. return i;
  616. }
  617. return ParamCommandComment::InvalidParamIndex;
  618. }
  619. namespace {
  620. class SimpleTypoCorrector {
  621. StringRef Typo;
  622. const unsigned MaxEditDistance;
  623. const NamedDecl *BestDecl;
  624. unsigned BestEditDistance;
  625. unsigned BestIndex;
  626. unsigned NextIndex;
  627. public:
  628. SimpleTypoCorrector(StringRef Typo) :
  629. Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3),
  630. BestDecl(NULL), BestEditDistance(MaxEditDistance + 1),
  631. BestIndex(0), NextIndex(0)
  632. { }
  633. void addDecl(const NamedDecl *ND);
  634. const NamedDecl *getBestDecl() const {
  635. if (BestEditDistance > MaxEditDistance)
  636. return NULL;
  637. return BestDecl;
  638. }
  639. unsigned getBestDeclIndex() const {
  640. assert(getBestDecl());
  641. return BestIndex;
  642. }
  643. };
  644. void SimpleTypoCorrector::addDecl(const NamedDecl *ND) {
  645. unsigned CurrIndex = NextIndex++;
  646. const IdentifierInfo *II = ND->getIdentifier();
  647. if (!II)
  648. return;
  649. StringRef Name = II->getName();
  650. unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());
  651. if (MinPossibleEditDistance > 0 &&
  652. Typo.size() / MinPossibleEditDistance < 3)
  653. return;
  654. unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
  655. if (EditDistance < BestEditDistance) {
  656. BestEditDistance = EditDistance;
  657. BestDecl = ND;
  658. BestIndex = CurrIndex;
  659. }
  660. }
  661. } // unnamed namespace
  662. unsigned Sema::correctTypoInParmVarReference(
  663. StringRef Typo,
  664. ArrayRef<const ParmVarDecl *> ParamVars) {
  665. SimpleTypoCorrector Corrector(Typo);
  666. for (unsigned i = 0, e = ParamVars.size(); i != e; ++i)
  667. Corrector.addDecl(ParamVars[i]);
  668. if (Corrector.getBestDecl())
  669. return Corrector.getBestDeclIndex();
  670. else
  671. return ParamCommandComment::InvalidParamIndex;
  672. }
  673. namespace {
  674. bool ResolveTParamReferenceHelper(
  675. StringRef Name,
  676. const TemplateParameterList *TemplateParameters,
  677. SmallVectorImpl<unsigned> *Position) {
  678. for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
  679. const NamedDecl *Param = TemplateParameters->getParam(i);
  680. const IdentifierInfo *II = Param->getIdentifier();
  681. if (II && II->getName() == Name) {
  682. Position->push_back(i);
  683. return true;
  684. }
  685. if (const TemplateTemplateParmDecl *TTP =
  686. dyn_cast<TemplateTemplateParmDecl>(Param)) {
  687. Position->push_back(i);
  688. if (ResolveTParamReferenceHelper(Name, TTP->getTemplateParameters(),
  689. Position))
  690. return true;
  691. Position->pop_back();
  692. }
  693. }
  694. return false;
  695. }
  696. } // unnamed namespace
  697. bool Sema::resolveTParamReference(
  698. StringRef Name,
  699. const TemplateParameterList *TemplateParameters,
  700. SmallVectorImpl<unsigned> *Position) {
  701. Position->clear();
  702. if (!TemplateParameters)
  703. return false;
  704. return ResolveTParamReferenceHelper(Name, TemplateParameters, Position);
  705. }
  706. namespace {
  707. void CorrectTypoInTParamReferenceHelper(
  708. const TemplateParameterList *TemplateParameters,
  709. SimpleTypoCorrector &Corrector) {
  710. for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
  711. const NamedDecl *Param = TemplateParameters->getParam(i);
  712. Corrector.addDecl(Param);
  713. if (const TemplateTemplateParmDecl *TTP =
  714. dyn_cast<TemplateTemplateParmDecl>(Param))
  715. CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(),
  716. Corrector);
  717. }
  718. }
  719. } // unnamed namespace
  720. StringRef Sema::correctTypoInTParamReference(
  721. StringRef Typo,
  722. const TemplateParameterList *TemplateParameters) {
  723. SimpleTypoCorrector Corrector(Typo);
  724. CorrectTypoInTParamReferenceHelper(TemplateParameters, Corrector);
  725. if (const NamedDecl *ND = Corrector.getBestDecl()) {
  726. const IdentifierInfo *II = ND->getIdentifier();
  727. assert(II && "SimpleTypoCorrector should not return this decl");
  728. return II->getName();
  729. }
  730. return StringRef();
  731. }
  732. InlineCommandComment::RenderKind
  733. Sema::getInlineCommandRenderKind(StringRef Name) const {
  734. assert(Traits.getCommandInfo(Name)->IsInlineCommand);
  735. return llvm::StringSwitch<InlineCommandComment::RenderKind>(Name)
  736. .Case("b", InlineCommandComment::RenderBold)
  737. .Cases("c", "p", InlineCommandComment::RenderMonospaced)
  738. .Cases("a", "e", "em", InlineCommandComment::RenderEmphasized)
  739. .Default(InlineCommandComment::RenderNormal);
  740. }
  741. } // end namespace comments
  742. } // end namespace clang