18 #include "llvm/ADT/SmallString.h"
19 #include "llvm/ADT/StringSwitch.h"
25 #include "clang/AST/CommentHTMLTagsProperties.inc"
31 Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits),
32 PP(PP), ThisDeclInfo(nullptr), BriefCommand(nullptr),
33 HeaderfileCommand(nullptr) {
40 ThisDeclInfo =
new (Allocator)
DeclInfo;
91 diag::warn_doc_param_not_attached_to_a_function_decl)
105 case CommandTraits::KCI_function:
108 case CommandTraits::KCI_functiongroup:
111 case CommandTraits::KCI_method:
114 case CommandTraits::KCI_methodgroup:
117 case CommandTraits::KCI_callback:
125 Diag(Comment->
getLocation(), diag::warn_doc_function_method_decl_mismatch)
127 << (DiagSelect-1) << (DiagSelect-1)
137 case CommandTraits::KCI_class:
145 case CommandTraits::KCI_interface:
148 case CommandTraits::KCI_protocol:
151 case CommandTraits::KCI_struct:
154 case CommandTraits::KCI_union:
162 Diag(Comment->
getLocation(), diag::warn_doc_api_container_decl_mismatch)
164 << (DiagSelect-1) << (DiagSelect-1)
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)
221 return llvm::StringSwitch<int>(Arg)
232 std::string ArgLower = Arg.lower();
235 if (Direction == -1) {
243 if (Direction != -1) {
246 Diag(ArgLocBegin, diag::warn_doc_param_spaces_in_direction)
249 Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction) << ArgRange;
269 Argument *A =
new (Allocator) Argument(
SourceRange(ArgLocBegin,
272 Command->
setArgs(llvm::makeArrayRef(A, 1));
292 diag::warn_doc_tparam_not_attached_to_a_template_decl)
307 Argument *A =
new (Allocator) Argument(
SourceRange(ArgLocBegin,
310 Command->
setArgs(llvm::makeArrayRef(A, 1));
325 Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate)
327 Diag(PrevCommand->
getLocation(), diag::note_doc_tparam_previous)
330 PrevCommand = Command;
335 Diag(ArgLocBegin, diag::warn_doc_tparam_not_found)
338 if (!TemplateParameters || TemplateParameters->
size() == 0)
341 StringRef CorrectedName;
342 if (TemplateParameters->
size() == 1) {
351 if (!CorrectedName.empty()) {
352 Diag(ArgLocBegin, diag::note_doc_tparam_name_suggestion)
368 unsigned CommandID) {
386 Argument *A =
new (Allocator) Argument(
SourceRange(ArgLocBegin,
396 llvm::makeArrayRef(A, 1));
401 StringRef CommandName) {
408 unsigned CommandID) {
411 LocBegin, LocEnd, CommandID,
419 return new (Allocator)
TextComment(LocBegin, LocEnd, Text);
423 unsigned CommandID) {
469 bool IsSelfClosing) {
474 else if (!isHTMLEndTagForbidden(Tag->
getTagName()))
475 HTMLOpenTags.push_back(Tag);
483 if (isHTMLEndTagForbidden(TagName)) {
484 Diag(HET->
getLocation(), diag::warn_doc_html_end_forbidden)
490 bool FoundOpen =
false;
492 I = HTMLOpenTags.rbegin(), E = HTMLOpenTags.rend();
494 if ((*I)->getTagName() == TagName) {
500 Diag(HET->
getLocation(), diag::warn_doc_html_end_unbalanced)
506 while (!HTMLOpenTags.empty()) {
508 StringRef LastNotClosedTagName = HST->
getTagName();
509 if (LastNotClosedTagName == TagName) {
516 if (isHTMLEndTagOptional(LastNotClosedTagName))
519 bool OpenLineInvalid;
523 bool CloseLineInvalid;
528 if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine) {
529 Diag(HST->
getLocation(), diag::warn_doc_html_start_end_mismatch)
534 Diag(HST->
getLocation(), diag::warn_doc_html_start_end_mismatch)
537 Diag(HET->
getLocation(), diag::note_doc_html_end_tag)
552 while (!HTMLOpenTags.empty()) {
557 Diag(HST->
getLocation(), diag::warn_doc_html_missing_end_tag)
576 Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
587 assert(ThisDeclInfo &&
"should not call this check on a bare comment");
599 case Decl::CXXConstructor:
602 case Decl::CXXDestructor:
607 diag::warn_doc_returns_attached_to_a_void_function)
619 diag::warn_doc_returns_not_attached_to_a_function_decl)
630 BriefCommand = Command;
633 PrevCommand = BriefCommand;
635 if (!HeaderfileCommand) {
636 HeaderfileCommand = Command;
639 PrevCommand = HeaderfileCommand;
646 Diag(Command->
getLocation(), diag::warn_doc_block_command_duplicate)
650 if (CommandName == PrevCommandName)
651 Diag(PrevCommand->
getLocation(), diag::note_doc_block_command_previous)
657 diag::note_doc_block_command_previous_alias)
667 assert(ThisDeclInfo &&
"should not call this check on a bare comment");
673 if (D->
hasAttr<DeprecatedAttr>() ||
674 D->
hasAttr<AvailabilityAttr>() ||
679 diag::warn_doc_deprecated_not_sync)
683 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
688 FD->doesThisDeclarationHaveABody())
691 StringRef AttributeSpelling =
"__attribute__((deprecated))";
694 tok::kw___attribute, tok::l_paren, tok::l_paren,
696 tok::r_paren, tok::r_paren
700 if (!MacroName.empty())
701 AttributeSpelling = MacroName;
705 TextToInsert += AttributeSpelling;
706 Diag(FD->getLocEnd(),
707 diag::note_add_deprecation_attr)
727 ParamVarDocs.resize(ParamVars.size(),
nullptr);
745 UnresolvedParamCommands.push_back(PCC);
749 if (ParamVarDocs[ResolvedParamIndex]) {
751 Diag(ArgRange.
getBegin(), diag::warn_doc_param_duplicate)
752 << ParamName << ArgRange;
754 Diag(PrevCommand->getLocation(), diag::note_doc_param_previous)
755 << PrevCommand->getParamNameRange();
757 ParamVarDocs[ResolvedParamIndex] = PCC;
762 for (
unsigned i = 0, e = ParamVarDocs.size(); i != e; ++i) {
763 if (!ParamVarDocs[i])
764 OrphanedParamDecls.push_back(ParamVars[i]);
770 for (
unsigned i = 0, e = UnresolvedParamCommands.size(); i != e; ++i) {
775 Diag(ArgRange.
getBegin(), diag::warn_doc_param_not_found)
776 << ParamName << ArgRange;
779 if (OrphanedParamDecls.size() == 0)
783 if (OrphanedParamDecls.size() == 1) {
786 CorrectedParamIndex = 0;
793 const ParmVarDecl *CorrectedPVD = OrphanedParamDecls[CorrectedParamIndex];
795 Diag(ArgRange.
getBegin(), diag::note_doc_param_name_suggestion)
796 << CorrectedII->getName()
820 return FD->isVariadic();
822 dyn_cast<FunctionTemplateDecl>(ThisDeclInfo->
CurrentDecl))
823 return FTD->getTemplatedDecl()->isVariadic();
825 dyn_cast<ObjCMethodDecl>(ThisDeclInfo->
CurrentDecl))
826 return MD->isVariadic();
880 dyn_cast_or_null<RecordDecl>(ThisDeclInfo->
CurrentDecl))
881 return RD->isUnion();
901 (isa<ClassTemplateDecl>(ThisDeclInfo->
CurrentDecl));
910 (isa<FunctionTemplateDecl>(ThisDeclInfo->
CurrentDecl));
938 ThisDeclInfo->
fill();
943 for (
unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
945 if (II && II->
getName() == Name)
954 class SimpleTypoCorrector {
964 SimpleTypoCorrector(StringRef
Typo) :
970 void addDecl(
const NamedDecl *ND);
972 const NamedDecl *getBestDecl()
const {
979 unsigned getBestDeclIndex()
const {
980 assert(getBestDecl());
985 void SimpleTypoCorrector::addDecl(
const NamedDecl *ND) {
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)
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();
1020 bool ResolveTParamReferenceHelper(
1024 for (
unsigned i = 0, e = TemplateParameters->
size(); i != e; ++i) {
1027 if (II && II->
getName() == Name) {
1028 Position->push_back(i);
1033 dyn_cast<TemplateTemplateParmDecl>(Param)) {
1034 Position->push_back(i);
1035 if (ResolveTParamReferenceHelper(Name, TTP->getTemplateParameters(),
1038 Position->pop_back();
1050 if (!TemplateParameters)
1053 return ResolveTParamReferenceHelper(Name, TemplateParameters, Position);
1057 void CorrectTypoInTParamReferenceHelper(
1059 SimpleTypoCorrector &Corrector) {
1060 for (
unsigned i = 0, e = TemplateParameters->
size(); i != e; ++i) {
1062 Corrector.addDecl(Param);
1065 dyn_cast<TemplateTemplateParmDecl>(Param))
1066 CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(),
1075 SimpleTypoCorrector Corrector(Typo);
1076 CorrectTypoInTParamReferenceHelper(TemplateParameters, Corrector);
1077 if (
const NamedDecl *ND = Corrector.getBestDecl()) {
1079 assert(II &&
"SimpleTypoCorrector should not return this decl");
1089 return llvm::StringSwitch<InlineCommandComment::RenderKind>(Name)
StringRef getLastMacroWithSpelling(SourceLocation Loc, ArrayRef< TokenValue > Tokens) const
Return the name of the macro defined before Loc that has spelling Tokens. If there are multiple macro...
SourceLocation getEnd() const
IdentifierInfo * getIdentifier() const
static LLVM_READONLY bool isWhitespace(unsigned char c)
Defines the SourceManager interface.
IdentifierInfo * getIdentifierInfo(StringRef Name) const
Defines the C++ template declaration subclasses.
unsigned getPresumedLineNumber(SourceLocation Loc, bool *Invalid=nullptr) const
NamedDecl * getParam(unsigned Idx)
Stores a list of template parameters for a TemplateDecl and its derived classes.
ParmVarDecl - Represents a parameter to a function.
SourceLocation getLocWithOffset(int Offset) const
Return a source location with the specified offset from this SourceLocation.
Concrete class used by the front-end to report problems and issues.
bool isFunctionPointerType() const
StringRef getName() const
Return the actual identifier string.
Defines the clang::Preprocessor interface.
Stores token information for comparing actual tokens with predefined values. Only handles simple toke...
Encodes a location in the source. The SourceManager can decode this to get at the full include stack...
bool isValid() const
Return true if this is a valid SourceLocation object.
SourceLocation getBegin() const
static FixItHint CreateInsertion(SourceLocation InsertionLoc, StringRef Code, bool BeforePreviousInsertions=false)
Create a code modification hint that inserts the given code string at a specific location.
static FixItHint CreateReplacement(CharSourceRange RemoveRange, StringRef Code)
Create a code modification hint that replaces the given source range with the given code string...
A trivial tuple used to represent a source range.
This class handles loading and caching of source files into memory.
Declaration of a template function.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.