1 //===--- CommentSema.cpp - Doxygen comment semantic analysis --------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "clang/AST/CommentSema.h"
11 #include "clang/AST/Attr.h"
12 #include "clang/AST/CommentCommandTraits.h"
13 #include "clang/AST/CommentDiagnostic.h"
14 #include "clang/AST/Decl.h"
15 #include "clang/AST/DeclTemplate.h"
16 #include "clang/Basic/SourceManager.h"
17 #include "clang/Lex/Preprocessor.h"
18 #include "llvm/ADT/SmallString.h"
19 #include "llvm/ADT/StringSwitch.h"
25 #include "clang/AST/CommentHTMLTagsProperties.inc"
26 } // unnamed namespace
28 Sema::Sema(llvm::BumpPtrAllocator
&Allocator
, const SourceManager
&SourceMgr
,
29 DiagnosticsEngine
&Diags
, CommandTraits
&Traits
,
30 const Preprocessor
*PP
) :
31 Allocator(Allocator
), SourceMgr(SourceMgr
), Diags(Diags
), Traits(Traits
),
32 PP(PP
), ThisDeclInfo(nullptr), BriefCommand(nullptr),
33 HeaderfileCommand(nullptr) {
36 void Sema::setDecl(const Decl
*D
) {
40 ThisDeclInfo
= new (Allocator
) DeclInfo
;
41 ThisDeclInfo
->CommentDecl
= D
;
42 ThisDeclInfo
->IsFilled
= false;
45 ParagraphComment
*Sema::actOnParagraphComment(
46 ArrayRef
<InlineContentComment
*> Content
) {
47 return new (Allocator
) ParagraphComment(Content
);
50 BlockCommandComment
*Sema::actOnBlockCommandStart(
51 SourceLocation LocBegin
,
52 SourceLocation LocEnd
,
54 CommandMarkerKind CommandMarker
) {
55 BlockCommandComment
*BC
= new (Allocator
) BlockCommandComment(LocBegin
, LocEnd
,
58 checkContainerDecl(BC
);
62 void Sema::actOnBlockCommandArgs(BlockCommandComment
*Command
,
63 ArrayRef
<BlockCommandComment::Argument
> Args
) {
64 Command
->setArgs(Args
);
67 void Sema::actOnBlockCommandFinish(BlockCommandComment
*Command
,
68 ParagraphComment
*Paragraph
) {
69 Command
->setParagraph(Paragraph
);
70 checkBlockCommandEmptyParagraph(Command
);
71 checkBlockCommandDuplicate(Command
);
73 // These checks only make sense if the comment is attached to a
75 checkReturnsCommand(Command
);
76 checkDeprecatedCommand(Command
);
80 ParamCommandComment
*Sema::actOnParamCommandStart(
81 SourceLocation LocBegin
,
82 SourceLocation LocEnd
,
84 CommandMarkerKind CommandMarker
) {
85 ParamCommandComment
*Command
=
86 new (Allocator
) ParamCommandComment(LocBegin
, LocEnd
, CommandID
,
89 if (!isFunctionDecl())
90 Diag(Command
->getLocation(),
91 diag::warn_doc_param_not_attached_to_a_function_decl
)
93 << Command
->getCommandNameRange(Traits
);
98 void Sema::checkFunctionDeclVerbatimLine(const BlockCommandComment
*Comment
) {
99 const CommandInfo
*Info
= Traits
.getCommandInfo(Comment
->getCommandID());
100 if (!Info
->IsFunctionDeclarationCommand
)
104 switch (Comment
->getCommandID()) {
105 case CommandTraits::KCI_function
:
106 DiagSelect
= (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 1 : 0;
108 case CommandTraits::KCI_functiongroup
:
109 DiagSelect
= (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 2 : 0;
111 case CommandTraits::KCI_method
:
112 DiagSelect
= !isObjCMethodDecl() ? 3 : 0;
114 case CommandTraits::KCI_methodgroup
:
115 DiagSelect
= !isObjCMethodDecl() ? 4 : 0;
117 case CommandTraits::KCI_callback
:
118 DiagSelect
= !isFunctionPointerVarDecl() ? 5 : 0;
125 Diag(Comment
->getLocation(), diag::warn_doc_function_method_decl_mismatch
)
126 << Comment
->getCommandMarker()
127 << (DiagSelect
-1) << (DiagSelect
-1)
128 << Comment
->getSourceRange();
131 void Sema::checkContainerDeclVerbatimLine(const BlockCommandComment
*Comment
) {
132 const CommandInfo
*Info
= Traits
.getCommandInfo(Comment
->getCommandID());
133 if (!Info
->IsRecordLikeDeclarationCommand
)
136 switch (Comment
->getCommandID()) {
137 case CommandTraits::KCI_class
:
138 DiagSelect
= (!isClassOrStructDecl() && !isClassTemplateDecl()) ? 1 : 0;
139 // Allow @class command on @interface declarations.
140 // FIXME. Currently, \class and @class are indistinguishable. So,
141 // \class is also allowed on an @interface declaration
142 if (DiagSelect
&& Comment
->getCommandMarker() && isObjCInterfaceDecl())
145 case CommandTraits::KCI_interface
:
146 DiagSelect
= !isObjCInterfaceDecl() ? 2 : 0;
148 case CommandTraits::KCI_protocol
:
149 DiagSelect
= !isObjCProtocolDecl() ? 3 : 0;
151 case CommandTraits::KCI_struct
:
152 DiagSelect
= !isClassOrStructDecl() ? 4 : 0;
154 case CommandTraits::KCI_union
:
155 DiagSelect
= !isUnionDecl() ? 5 : 0;
162 Diag(Comment
->getLocation(), diag::warn_doc_api_container_decl_mismatch
)
163 << Comment
->getCommandMarker()
164 << (DiagSelect
-1) << (DiagSelect
-1)
165 << Comment
->getSourceRange();
168 void Sema::checkContainerDecl(const BlockCommandComment
*Comment
) {
169 const CommandInfo
*Info
= Traits
.getCommandInfo(Comment
->getCommandID());
170 if (!Info
->IsRecordLikeDetailCommand
|| isRecordLikeDecl())
173 switch (Comment
->getCommandID()) {
174 case CommandTraits::KCI_classdesign
:
177 case CommandTraits::KCI_coclass
:
180 case CommandTraits::KCI_dependency
:
183 case CommandTraits::KCI_helper
:
186 case CommandTraits::KCI_helperclass
:
189 case CommandTraits::KCI_helps
:
192 case CommandTraits::KCI_instancesize
:
195 case CommandTraits::KCI_ownership
:
198 case CommandTraits::KCI_performance
:
201 case CommandTraits::KCI_security
:
204 case CommandTraits::KCI_superclass
:
212 Diag(Comment
->getLocation(), diag::warn_doc_container_decl_mismatch
)
213 << Comment
->getCommandMarker()
215 << Comment
->getSourceRange();
218 /// \brief Turn a string into the corresponding PassDirection or -1 if it's not
220 static int getParamPassDirection(StringRef Arg
) {
221 return llvm::StringSwitch
<int>(Arg
)
222 .Case("[in]", ParamCommandComment::In
)
223 .Case("[out]", ParamCommandComment::Out
)
224 .Cases("[in,out]", "[out,in]", ParamCommandComment::InOut
)
228 void Sema::actOnParamCommandDirectionArg(ParamCommandComment
*Command
,
229 SourceLocation ArgLocBegin
,
230 SourceLocation ArgLocEnd
,
232 std::string ArgLower
= Arg
.lower();
233 int Direction
= getParamPassDirection(ArgLower
);
235 if (Direction
== -1) {
236 // Try again with whitespace removed.
238 std::remove_if(ArgLower
.begin(), ArgLower
.end(), clang::isWhitespace
),
240 Direction
= getParamPassDirection(ArgLower
);
242 SourceRange
ArgRange(ArgLocBegin
, ArgLocEnd
);
243 if (Direction
!= -1) {
244 const char *FixedName
= ParamCommandComment::getDirectionAsString(
245 (ParamCommandComment::PassDirection
)Direction
);
246 Diag(ArgLocBegin
, diag::warn_doc_param_spaces_in_direction
)
247 << ArgRange
<< FixItHint::CreateReplacement(ArgRange
, FixedName
);
249 Diag(ArgLocBegin
, diag::warn_doc_param_invalid_direction
) << ArgRange
;
250 Direction
= ParamCommandComment::In
; // Sane fall back.
253 Command
->setDirection((ParamCommandComment::PassDirection
)Direction
,
257 void Sema::actOnParamCommandParamNameArg(ParamCommandComment
*Command
,
258 SourceLocation ArgLocBegin
,
259 SourceLocation ArgLocEnd
,
261 // Parser will not feed us more arguments than needed.
262 assert(Command
->getNumArgs() == 0);
264 if (!Command
->isDirectionExplicit()) {
265 // User didn't provide a direction argument.
266 Command
->setDirection(ParamCommandComment::In
, /* Explicit = */ false);
268 typedef BlockCommandComment::Argument Argument
;
269 Argument
*A
= new (Allocator
) Argument(SourceRange(ArgLocBegin
,
272 Command
->setArgs(llvm::makeArrayRef(A
, 1));
275 void Sema::actOnParamCommandFinish(ParamCommandComment
*Command
,
276 ParagraphComment
*Paragraph
) {
277 Command
->setParagraph(Paragraph
);
278 checkBlockCommandEmptyParagraph(Command
);
281 TParamCommandComment
*Sema::actOnTParamCommandStart(
282 SourceLocation LocBegin
,
283 SourceLocation LocEnd
,
285 CommandMarkerKind CommandMarker
) {
286 TParamCommandComment
*Command
=
287 new (Allocator
) TParamCommandComment(LocBegin
, LocEnd
, CommandID
,
290 if (!isTemplateOrSpecialization())
291 Diag(Command
->getLocation(),
292 diag::warn_doc_tparam_not_attached_to_a_template_decl
)
294 << Command
->getCommandNameRange(Traits
);
299 void Sema::actOnTParamCommandParamNameArg(TParamCommandComment
*Command
,
300 SourceLocation ArgLocBegin
,
301 SourceLocation ArgLocEnd
,
303 // Parser will not feed us more arguments than needed.
304 assert(Command
->getNumArgs() == 0);
306 typedef BlockCommandComment::Argument Argument
;
307 Argument
*A
= new (Allocator
) Argument(SourceRange(ArgLocBegin
,
310 Command
->setArgs(llvm::makeArrayRef(A
, 1));
312 if (!isTemplateOrSpecialization()) {
313 // We already warned that this \\tparam is not attached to a template decl.
317 const TemplateParameterList
*TemplateParameters
=
318 ThisDeclInfo
->TemplateParameters
;
319 SmallVector
<unsigned, 2> Position
;
320 if (resolveTParamReference(Arg
, TemplateParameters
, &Position
)) {
321 Command
->setPosition(copyArray(llvm::makeArrayRef(Position
)));
322 TParamCommandComment
*&PrevCommand
= TemplateParameterDocs
[Arg
];
324 SourceRange
ArgRange(ArgLocBegin
, ArgLocEnd
);
325 Diag(ArgLocBegin
, diag::warn_doc_tparam_duplicate
)
327 Diag(PrevCommand
->getLocation(), diag::note_doc_tparam_previous
)
328 << PrevCommand
->getParamNameRange();
330 PrevCommand
= Command
;
334 SourceRange
ArgRange(ArgLocBegin
, ArgLocEnd
);
335 Diag(ArgLocBegin
, diag::warn_doc_tparam_not_found
)
338 if (!TemplateParameters
|| TemplateParameters
->size() == 0)
341 StringRef CorrectedName
;
342 if (TemplateParameters
->size() == 1) {
343 const NamedDecl
*Param
= TemplateParameters
->getParam(0);
344 const IdentifierInfo
*II
= Param
->getIdentifier();
346 CorrectedName
= II
->getName();
348 CorrectedName
= correctTypoInTParamReference(Arg
, TemplateParameters
);
351 if (!CorrectedName
.empty()) {
352 Diag(ArgLocBegin
, diag::note_doc_tparam_name_suggestion
)
354 << FixItHint::CreateReplacement(ArgRange
, CorrectedName
);
360 void Sema::actOnTParamCommandFinish(TParamCommandComment
*Command
,
361 ParagraphComment
*Paragraph
) {
362 Command
->setParagraph(Paragraph
);
363 checkBlockCommandEmptyParagraph(Command
);
366 InlineCommandComment
*Sema::actOnInlineCommand(SourceLocation CommandLocBegin
,
367 SourceLocation CommandLocEnd
,
368 unsigned CommandID
) {
369 ArrayRef
<InlineCommandComment::Argument
> Args
;
370 StringRef CommandName
= Traits
.getCommandInfo(CommandID
)->Name
;
371 return new (Allocator
) InlineCommandComment(
375 getInlineCommandRenderKind(CommandName
),
379 InlineCommandComment
*Sema::actOnInlineCommand(SourceLocation CommandLocBegin
,
380 SourceLocation CommandLocEnd
,
382 SourceLocation ArgLocBegin
,
383 SourceLocation ArgLocEnd
,
385 typedef InlineCommandComment::Argument Argument
;
386 Argument
*A
= new (Allocator
) Argument(SourceRange(ArgLocBegin
,
389 StringRef CommandName
= Traits
.getCommandInfo(CommandID
)->Name
;
391 return new (Allocator
) InlineCommandComment(
395 getInlineCommandRenderKind(CommandName
),
396 llvm::makeArrayRef(A
, 1));
399 InlineContentComment
*Sema::actOnUnknownCommand(SourceLocation LocBegin
,
400 SourceLocation LocEnd
,
401 StringRef CommandName
) {
402 unsigned CommandID
= Traits
.registerUnknownCommand(CommandName
)->getID();
403 return actOnUnknownCommand(LocBegin
, LocEnd
, CommandID
);
406 InlineContentComment
*Sema::actOnUnknownCommand(SourceLocation LocBegin
,
407 SourceLocation LocEnd
,
408 unsigned CommandID
) {
409 ArrayRef
<InlineCommandComment::Argument
> Args
;
410 return new (Allocator
) InlineCommandComment(
411 LocBegin
, LocEnd
, CommandID
,
412 InlineCommandComment::RenderNormal
,
416 TextComment
*Sema::actOnText(SourceLocation LocBegin
,
417 SourceLocation LocEnd
,
419 return new (Allocator
) TextComment(LocBegin
, LocEnd
, Text
);
422 VerbatimBlockComment
*Sema::actOnVerbatimBlockStart(SourceLocation Loc
,
423 unsigned CommandID
) {
424 StringRef CommandName
= Traits
.getCommandInfo(CommandID
)->Name
;
425 return new (Allocator
) VerbatimBlockComment(
427 Loc
.getLocWithOffset(1 + CommandName
.size()),
431 VerbatimBlockLineComment
*Sema::actOnVerbatimBlockLine(SourceLocation Loc
,
433 return new (Allocator
) VerbatimBlockLineComment(Loc
, Text
);
436 void Sema::actOnVerbatimBlockFinish(
437 VerbatimBlockComment
*Block
,
438 SourceLocation CloseNameLocBegin
,
440 ArrayRef
<VerbatimBlockLineComment
*> Lines
) {
441 Block
->setCloseName(CloseName
, CloseNameLocBegin
);
442 Block
->setLines(Lines
);
445 VerbatimLineComment
*Sema::actOnVerbatimLine(SourceLocation LocBegin
,
447 SourceLocation TextBegin
,
449 VerbatimLineComment
*VL
= new (Allocator
) VerbatimLineComment(
451 TextBegin
.getLocWithOffset(Text
.size()),
455 checkFunctionDeclVerbatimLine(VL
);
456 checkContainerDeclVerbatimLine(VL
);
460 HTMLStartTagComment
*Sema::actOnHTMLStartTagStart(SourceLocation LocBegin
,
462 return new (Allocator
) HTMLStartTagComment(LocBegin
, TagName
);
465 void Sema::actOnHTMLStartTagFinish(
466 HTMLStartTagComment
*Tag
,
467 ArrayRef
<HTMLStartTagComment::Attribute
> Attrs
,
468 SourceLocation GreaterLoc
,
469 bool IsSelfClosing
) {
470 Tag
->setAttrs(Attrs
);
471 Tag
->setGreaterLoc(GreaterLoc
);
473 Tag
->setSelfClosing();
474 else if (!isHTMLEndTagForbidden(Tag
->getTagName()))
475 HTMLOpenTags
.push_back(Tag
);
478 HTMLEndTagComment
*Sema::actOnHTMLEndTag(SourceLocation LocBegin
,
479 SourceLocation LocEnd
,
481 HTMLEndTagComment
*HET
=
482 new (Allocator
) HTMLEndTagComment(LocBegin
, LocEnd
, TagName
);
483 if (isHTMLEndTagForbidden(TagName
)) {
484 Diag(HET
->getLocation(), diag::warn_doc_html_end_forbidden
)
485 << TagName
<< HET
->getSourceRange();
486 HET
->setIsMalformed();
490 bool FoundOpen
= false;
491 for (SmallVectorImpl
<HTMLStartTagComment
*>::const_reverse_iterator
492 I
= HTMLOpenTags
.rbegin(), E
= HTMLOpenTags
.rend();
494 if ((*I
)->getTagName() == TagName
) {
500 Diag(HET
->getLocation(), diag::warn_doc_html_end_unbalanced
)
501 << HET
->getSourceRange();
502 HET
->setIsMalformed();
506 while (!HTMLOpenTags
.empty()) {
507 HTMLStartTagComment
*HST
= HTMLOpenTags
.pop_back_val();
508 StringRef LastNotClosedTagName
= HST
->getTagName();
509 if (LastNotClosedTagName
== TagName
) {
510 // If the start tag is malformed, end tag is malformed as well.
511 if (HST
->isMalformed())
512 HET
->setIsMalformed();
516 if (isHTMLEndTagOptional(LastNotClosedTagName
))
519 bool OpenLineInvalid
;
520 const unsigned OpenLine
= SourceMgr
.getPresumedLineNumber(
523 bool CloseLineInvalid
;
524 const unsigned CloseLine
= SourceMgr
.getPresumedLineNumber(
528 if (OpenLineInvalid
|| CloseLineInvalid
|| OpenLine
== CloseLine
) {
529 Diag(HST
->getLocation(), diag::warn_doc_html_start_end_mismatch
)
530 << HST
->getTagName() << HET
->getTagName()
531 << HST
->getSourceRange() << HET
->getSourceRange();
532 HST
->setIsMalformed();
534 Diag(HST
->getLocation(), diag::warn_doc_html_start_end_mismatch
)
535 << HST
->getTagName() << HET
->getTagName()
536 << HST
->getSourceRange();
537 Diag(HET
->getLocation(), diag::note_doc_html_end_tag
)
538 << HET
->getSourceRange();
539 HST
->setIsMalformed();
546 FullComment
*Sema::actOnFullComment(
547 ArrayRef
<BlockContentComment
*> Blocks
) {
548 FullComment
*FC
= new (Allocator
) FullComment(Blocks
, ThisDeclInfo
);
549 resolveParamCommandIndexes(FC
);
551 // Complain about HTML tags that are not closed.
552 while (!HTMLOpenTags
.empty()) {
553 HTMLStartTagComment
*HST
= HTMLOpenTags
.pop_back_val();
554 if (isHTMLEndTagOptional(HST
->getTagName()))
557 Diag(HST
->getLocation(), diag::warn_doc_html_missing_end_tag
)
558 << HST
->getTagName() << HST
->getSourceRange();
559 HST
->setIsMalformed();
565 void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment
*Command
) {
566 if (Traits
.getCommandInfo(Command
->getCommandID())->IsEmptyParagraphAllowed
)
569 ParagraphComment
*Paragraph
= Command
->getParagraph();
570 if (Paragraph
->isWhitespace()) {
571 SourceLocation DiagLoc
;
572 if (Command
->getNumArgs() > 0)
573 DiagLoc
= Command
->getArgRange(Command
->getNumArgs() - 1).getEnd();
574 if (!DiagLoc
.isValid())
575 DiagLoc
= Command
->getCommandNameRange(Traits
).getEnd();
576 Diag(DiagLoc
, diag::warn_doc_block_command_empty_paragraph
)
577 << Command
->getCommandMarker()
578 << Command
->getCommandName(Traits
)
579 << Command
->getSourceRange();
583 void Sema::checkReturnsCommand(const BlockCommandComment
*Command
) {
584 if (!Traits
.getCommandInfo(Command
->getCommandID())->IsReturnsCommand
)
587 assert(ThisDeclInfo
&& "should not call this check on a bare comment");
589 if (isFunctionDecl()) {
590 if (ThisDeclInfo
->ReturnType
->isVoidType()) {
592 switch (ThisDeclInfo
->CommentDecl
->getKind()) {
594 if (ThisDeclInfo
->IsObjCMethod
)
599 case Decl::CXXConstructor
:
602 case Decl::CXXDestructor
:
606 Diag(Command
->getLocation(),
607 diag::warn_doc_returns_attached_to_a_void_function
)
608 << Command
->getCommandMarker()
609 << Command
->getCommandName(Traits
)
611 << Command
->getSourceRange();
615 else if (isObjCPropertyDecl())
618 Diag(Command
->getLocation(),
619 diag::warn_doc_returns_not_attached_to_a_function_decl
)
620 << Command
->getCommandMarker()
621 << Command
->getCommandName(Traits
)
622 << Command
->getSourceRange();
625 void Sema::checkBlockCommandDuplicate(const BlockCommandComment
*Command
) {
626 const CommandInfo
*Info
= Traits
.getCommandInfo(Command
->getCommandID());
627 const BlockCommandComment
*PrevCommand
= nullptr;
628 if (Info
->IsBriefCommand
) {
630 BriefCommand
= Command
;
633 PrevCommand
= BriefCommand
;
634 } else if (Info
->IsHeaderfileCommand
) {
635 if (!HeaderfileCommand
) {
636 HeaderfileCommand
= Command
;
639 PrevCommand
= HeaderfileCommand
;
641 // We don't want to check this command for duplicates.
644 StringRef CommandName
= Command
->getCommandName(Traits
);
645 StringRef PrevCommandName
= PrevCommand
->getCommandName(Traits
);
646 Diag(Command
->getLocation(), diag::warn_doc_block_command_duplicate
)
647 << Command
->getCommandMarker()
649 << Command
->getSourceRange();
650 if (CommandName
== PrevCommandName
)
651 Diag(PrevCommand
->getLocation(), diag::note_doc_block_command_previous
)
652 << PrevCommand
->getCommandMarker()
654 << PrevCommand
->getSourceRange();
656 Diag(PrevCommand
->getLocation(),
657 diag::note_doc_block_command_previous_alias
)
658 << PrevCommand
->getCommandMarker()
663 void Sema::checkDeprecatedCommand(const BlockCommandComment
*Command
) {
664 if (!Traits
.getCommandInfo(Command
->getCommandID())->IsDeprecatedCommand
)
667 assert(ThisDeclInfo
&& "should not call this check on a bare comment");
669 const Decl
*D
= ThisDeclInfo
->CommentDecl
;
673 if (D
->hasAttr
<DeprecatedAttr
>() ||
674 D
->hasAttr
<AvailabilityAttr
>() ||
675 D
->hasAttr
<UnavailableAttr
>())
678 Diag(Command
->getLocation(),
679 diag::warn_doc_deprecated_not_sync
)
680 << Command
->getSourceRange();
682 // Try to emit a fixit with a deprecation attribute.
683 if (const FunctionDecl
*FD
= dyn_cast
<FunctionDecl
>(D
)) {
684 // Don't emit a Fix-It for non-member function definitions. GCC does not
685 // accept attributes on them.
686 const DeclContext
*Ctx
= FD
->getDeclContext();
687 if ((!Ctx
|| !Ctx
->isRecord()) &&
688 FD
->doesThisDeclarationHaveABody())
691 StringRef AttributeSpelling
= "__attribute__((deprecated))";
693 TokenValue Tokens
[] = {
694 tok::kw___attribute
, tok::l_paren
, tok::l_paren
,
695 PP
->getIdentifierInfo("deprecated"),
696 tok::r_paren
, tok::r_paren
698 StringRef MacroName
= PP
->getLastMacroWithSpelling(FD
->getLocation(),
700 if (!MacroName
.empty())
701 AttributeSpelling
= MacroName
;
704 SmallString
<64> TextToInsert(" ");
705 TextToInsert
+= AttributeSpelling
;
706 Diag(FD
->getLocEnd(),
707 diag::note_add_deprecation_attr
)
708 << FixItHint::CreateInsertion(FD
->getLocEnd().getLocWithOffset(1),
713 void Sema::resolveParamCommandIndexes(const FullComment
*FC
) {
714 if (!isFunctionDecl()) {
715 // We already warned that \\param commands are not attached to a function
720 SmallVector
<ParamCommandComment
*, 8> UnresolvedParamCommands
;
722 // Comment AST nodes that correspond to \c ParamVars for which we have
723 // found a \\param command or NULL if no documentation was found so far.
724 SmallVector
<ParamCommandComment
*, 8> ParamVarDocs
;
726 ArrayRef
<const ParmVarDecl
*> ParamVars
= getParamVars();
727 ParamVarDocs
.resize(ParamVars
.size(), nullptr);
729 // First pass over all \\param commands: resolve all parameter names.
730 for (Comment::child_iterator I
= FC
->child_begin(), E
= FC
->child_end();
732 ParamCommandComment
*PCC
= dyn_cast
<ParamCommandComment
>(*I
);
733 if (!PCC
|| !PCC
->hasParamName())
735 StringRef ParamName
= PCC
->getParamNameAsWritten();
737 // Check that referenced parameter name is in the function decl.
738 const unsigned ResolvedParamIndex
= resolveParmVarReference(ParamName
,
740 if (ResolvedParamIndex
== ParamCommandComment::VarArgParamIndex
) {
741 PCC
->setIsVarArgParam();
744 if (ResolvedParamIndex
== ParamCommandComment::InvalidParamIndex
) {
745 UnresolvedParamCommands
.push_back(PCC
);
748 PCC
->setParamIndex(ResolvedParamIndex
);
749 if (ParamVarDocs
[ResolvedParamIndex
]) {
750 SourceRange ArgRange
= PCC
->getParamNameRange();
751 Diag(ArgRange
.getBegin(), diag::warn_doc_param_duplicate
)
752 << ParamName
<< ArgRange
;
753 ParamCommandComment
*PrevCommand
= ParamVarDocs
[ResolvedParamIndex
];
754 Diag(PrevCommand
->getLocation(), diag::note_doc_param_previous
)
755 << PrevCommand
->getParamNameRange();
757 ParamVarDocs
[ResolvedParamIndex
] = PCC
;
760 // Find parameter declarations that have no corresponding \\param.
761 SmallVector
<const ParmVarDecl
*, 8> OrphanedParamDecls
;
762 for (unsigned i
= 0, e
= ParamVarDocs
.size(); i
!= e
; ++i
) {
763 if (!ParamVarDocs
[i
])
764 OrphanedParamDecls
.push_back(ParamVars
[i
]);
767 // Second pass over unresolved \\param commands: do typo correction.
768 // Suggest corrections from a set of parameter declarations that have no
769 // corresponding \\param.
770 for (unsigned i
= 0, e
= UnresolvedParamCommands
.size(); i
!= e
; ++i
) {
771 const ParamCommandComment
*PCC
= UnresolvedParamCommands
[i
];
773 SourceRange ArgRange
= PCC
->getParamNameRange();
774 StringRef ParamName
= PCC
->getParamNameAsWritten();
775 Diag(ArgRange
.getBegin(), diag::warn_doc_param_not_found
)
776 << ParamName
<< ArgRange
;
778 // All parameters documented -- can't suggest a correction.
779 if (OrphanedParamDecls
.size() == 0)
782 unsigned CorrectedParamIndex
= ParamCommandComment::InvalidParamIndex
;
783 if (OrphanedParamDecls
.size() == 1) {
784 // If one parameter is not documented then that parameter is the only
785 // possible suggestion.
786 CorrectedParamIndex
= 0;
788 // Do typo correction.
789 CorrectedParamIndex
= correctTypoInParmVarReference(ParamName
,
792 if (CorrectedParamIndex
!= ParamCommandComment::InvalidParamIndex
) {
793 const ParmVarDecl
*CorrectedPVD
= OrphanedParamDecls
[CorrectedParamIndex
];
794 if (const IdentifierInfo
*CorrectedII
= CorrectedPVD
->getIdentifier())
795 Diag(ArgRange
.getBegin(), diag::note_doc_param_name_suggestion
)
796 << CorrectedII
->getName()
797 << FixItHint::CreateReplacement(ArgRange
, CorrectedII
->getName());
802 bool Sema::isFunctionDecl() {
805 if (!ThisDeclInfo
->IsFilled
)
807 return ThisDeclInfo
->getKind() == DeclInfo::FunctionKind
;
810 bool Sema::isAnyFunctionDecl() {
811 return isFunctionDecl() && ThisDeclInfo
->CurrentDecl
&&
812 isa
<FunctionDecl
>(ThisDeclInfo
->CurrentDecl
);
815 bool Sema::isFunctionOrMethodVariadic() {
816 if (!isAnyFunctionDecl() && !isObjCMethodDecl() && !isFunctionTemplateDecl())
818 if (const FunctionDecl
*FD
=
819 dyn_cast
<FunctionDecl
>(ThisDeclInfo
->CurrentDecl
))
820 return FD
->isVariadic();
821 if (const FunctionTemplateDecl
*FTD
=
822 dyn_cast
<FunctionTemplateDecl
>(ThisDeclInfo
->CurrentDecl
))
823 return FTD
->getTemplatedDecl()->isVariadic();
824 if (const ObjCMethodDecl
*MD
=
825 dyn_cast
<ObjCMethodDecl
>(ThisDeclInfo
->CurrentDecl
))
826 return MD
->isVariadic();
830 bool Sema::isObjCMethodDecl() {
831 return isFunctionDecl() && ThisDeclInfo
->CurrentDecl
&&
832 isa
<ObjCMethodDecl
>(ThisDeclInfo
->CurrentDecl
);
835 bool Sema::isFunctionPointerVarDecl() {
838 if (!ThisDeclInfo
->IsFilled
)
840 if (ThisDeclInfo
->getKind() == DeclInfo::VariableKind
) {
841 if (const VarDecl
*VD
= dyn_cast_or_null
<VarDecl
>(ThisDeclInfo
->CurrentDecl
)) {
842 QualType QT
= VD
->getType();
843 return QT
->isFunctionPointerType();
849 bool Sema::isObjCPropertyDecl() {
852 if (!ThisDeclInfo
->IsFilled
)
854 return ThisDeclInfo
->CurrentDecl
->getKind() == Decl::ObjCProperty
;
857 bool Sema::isTemplateOrSpecialization() {
860 if (!ThisDeclInfo
->IsFilled
)
862 return ThisDeclInfo
->getTemplateKind() != DeclInfo::NotTemplate
;
865 bool Sema::isRecordLikeDecl() {
868 if (!ThisDeclInfo
->IsFilled
)
870 return isUnionDecl() || isClassOrStructDecl() || isObjCInterfaceDecl() ||
871 isObjCProtocolDecl();
874 bool Sema::isUnionDecl() {
877 if (!ThisDeclInfo
->IsFilled
)
879 if (const RecordDecl
*RD
=
880 dyn_cast_or_null
<RecordDecl
>(ThisDeclInfo
->CurrentDecl
))
881 return RD
->isUnion();
885 bool Sema::isClassOrStructDecl() {
888 if (!ThisDeclInfo
->IsFilled
)
890 return ThisDeclInfo
->CurrentDecl
&&
891 isa
<RecordDecl
>(ThisDeclInfo
->CurrentDecl
) &&
895 bool Sema::isClassTemplateDecl() {
898 if (!ThisDeclInfo
->IsFilled
)
900 return ThisDeclInfo
->CurrentDecl
&&
901 (isa
<ClassTemplateDecl
>(ThisDeclInfo
->CurrentDecl
));
904 bool Sema::isFunctionTemplateDecl() {
907 if (!ThisDeclInfo
->IsFilled
)
909 return ThisDeclInfo
->CurrentDecl
&&
910 (isa
<FunctionTemplateDecl
>(ThisDeclInfo
->CurrentDecl
));
913 bool Sema::isObjCInterfaceDecl() {
916 if (!ThisDeclInfo
->IsFilled
)
918 return ThisDeclInfo
->CurrentDecl
&&
919 isa
<ObjCInterfaceDecl
>(ThisDeclInfo
->CurrentDecl
);
922 bool Sema::isObjCProtocolDecl() {
925 if (!ThisDeclInfo
->IsFilled
)
927 return ThisDeclInfo
->CurrentDecl
&&
928 isa
<ObjCProtocolDecl
>(ThisDeclInfo
->CurrentDecl
);
931 ArrayRef
<const ParmVarDecl
*> Sema::getParamVars() {
932 if (!ThisDeclInfo
->IsFilled
)
934 return ThisDeclInfo
->ParamVars
;
937 void Sema::inspectThisDecl() {
938 ThisDeclInfo
->fill();
941 unsigned Sema::resolveParmVarReference(StringRef Name
,
942 ArrayRef
<const ParmVarDecl
*> ParamVars
) {
943 for (unsigned i
= 0, e
= ParamVars
.size(); i
!= e
; ++i
) {
944 const IdentifierInfo
*II
= ParamVars
[i
]->getIdentifier();
945 if (II
&& II
->getName() == Name
)
948 if (Name
== "..." && isFunctionOrMethodVariadic())
949 return ParamCommandComment::VarArgParamIndex
;
950 return ParamCommandComment::InvalidParamIndex
;
954 class SimpleTypoCorrector
{
956 const unsigned MaxEditDistance
;
958 const NamedDecl
*BestDecl
;
959 unsigned BestEditDistance
;
964 SimpleTypoCorrector(StringRef Typo
) :
965 Typo(Typo
), MaxEditDistance((Typo
.size() + 2) / 3),
966 BestDecl(nullptr), BestEditDistance(MaxEditDistance
+ 1),
967 BestIndex(0), NextIndex(0)
970 void addDecl(const NamedDecl
*ND
);
972 const NamedDecl
*getBestDecl() const {
973 if (BestEditDistance
> MaxEditDistance
)
979 unsigned getBestDeclIndex() const {
980 assert(getBestDecl());
985 void SimpleTypoCorrector::addDecl(const NamedDecl
*ND
) {
986 unsigned CurrIndex
= NextIndex
++;
988 const IdentifierInfo
*II
= ND
->getIdentifier();
992 StringRef Name
= II
->getName();
993 unsigned MinPossibleEditDistance
= abs((int)Name
.size() - (int)Typo
.size());
994 if (MinPossibleEditDistance
> 0 &&
995 Typo
.size() / MinPossibleEditDistance
< 3)
998 unsigned EditDistance
= Typo
.edit_distance(Name
, true, MaxEditDistance
);
999 if (EditDistance
< BestEditDistance
) {
1000 BestEditDistance
= EditDistance
;
1002 BestIndex
= CurrIndex
;
1005 } // unnamed namespace
1007 unsigned Sema::correctTypoInParmVarReference(
1009 ArrayRef
<const ParmVarDecl
*> ParamVars
) {
1010 SimpleTypoCorrector
Corrector(Typo
);
1011 for (unsigned i
= 0, e
= ParamVars
.size(); i
!= e
; ++i
)
1012 Corrector
.addDecl(ParamVars
[i
]);
1013 if (Corrector
.getBestDecl())
1014 return Corrector
.getBestDeclIndex();
1016 return ParamCommandComment::InvalidParamIndex
;
1020 bool ResolveTParamReferenceHelper(
1022 const TemplateParameterList
*TemplateParameters
,
1023 SmallVectorImpl
<unsigned> *Position
) {
1024 for (unsigned i
= 0, e
= TemplateParameters
->size(); i
!= e
; ++i
) {
1025 const NamedDecl
*Param
= TemplateParameters
->getParam(i
);
1026 const IdentifierInfo
*II
= Param
->getIdentifier();
1027 if (II
&& II
->getName() == Name
) {
1028 Position
->push_back(i
);
1032 if (const TemplateTemplateParmDecl
*TTP
=
1033 dyn_cast
<TemplateTemplateParmDecl
>(Param
)) {
1034 Position
->push_back(i
);
1035 if (ResolveTParamReferenceHelper(Name
, TTP
->getTemplateParameters(),
1038 Position
->pop_back();
1043 } // unnamed namespace
1045 bool Sema::resolveTParamReference(
1047 const TemplateParameterList
*TemplateParameters
,
1048 SmallVectorImpl
<unsigned> *Position
) {
1050 if (!TemplateParameters
)
1053 return ResolveTParamReferenceHelper(Name
, TemplateParameters
, Position
);
1057 void CorrectTypoInTParamReferenceHelper(
1058 const TemplateParameterList
*TemplateParameters
,
1059 SimpleTypoCorrector
&Corrector
) {
1060 for (unsigned i
= 0, e
= TemplateParameters
->size(); i
!= e
; ++i
) {
1061 const NamedDecl
*Param
= TemplateParameters
->getParam(i
);
1062 Corrector
.addDecl(Param
);
1064 if (const TemplateTemplateParmDecl
*TTP
=
1065 dyn_cast
<TemplateTemplateParmDecl
>(Param
))
1066 CorrectTypoInTParamReferenceHelper(TTP
->getTemplateParameters(),
1070 } // unnamed namespace
1072 StringRef
Sema::correctTypoInTParamReference(
1074 const TemplateParameterList
*TemplateParameters
) {
1075 SimpleTypoCorrector
Corrector(Typo
);
1076 CorrectTypoInTParamReferenceHelper(TemplateParameters
, Corrector
);
1077 if (const NamedDecl
*ND
= Corrector
.getBestDecl()) {
1078 const IdentifierInfo
*II
= ND
->getIdentifier();
1079 assert(II
&& "SimpleTypoCorrector should not return this decl");
1080 return II
->getName();
1085 InlineCommandComment::RenderKind
1086 Sema::getInlineCommandRenderKind(StringRef Name
) const {
1087 assert(Traits
.getCommandInfo(Name
)->IsInlineCommand
);
1089 return llvm::StringSwitch
<InlineCommandComment::RenderKind
>(Name
)
1090 .Case("b", InlineCommandComment::RenderBold
)
1091 .Cases("c", "p", InlineCommandComment::RenderMonospaced
)
1092 .Cases("a", "e", "em", InlineCommandComment::RenderEmphasized
)
1093 .Default(InlineCommandComment::RenderNormal
);
1096 } // end namespace comments
1097 } // end namespace clang