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)
366 unsigned CommandID) {
384 Argument *A =
new (Allocator) Argument(
SourceRange(ArgLocBegin,
394 llvm::makeArrayRef(A, 1));
399 StringRef CommandName) {
406 unsigned CommandID) {
409 LocBegin, LocEnd, CommandID,
417 return new (Allocator)
TextComment(LocBegin, LocEnd, Text);
421 unsigned CommandID) {
467 bool IsSelfClosing) {
472 else if (!isHTMLEndTagForbidden(Tag->
getTagName()))
473 HTMLOpenTags.push_back(Tag);
481 if (isHTMLEndTagForbidden(TagName)) {
482 Diag(HET->
getLocation(), diag::warn_doc_html_end_forbidden)
488 bool FoundOpen =
false;
490 I = HTMLOpenTags.rbegin(),
E = HTMLOpenTags.rend();
492 if ((*I)->getTagName() == TagName) {
498 Diag(HET->
getLocation(), diag::warn_doc_html_end_unbalanced)
504 while (!HTMLOpenTags.empty()) {
506 StringRef LastNotClosedTagName = HST->
getTagName();
507 if (LastNotClosedTagName == TagName) {
514 if (isHTMLEndTagOptional(LastNotClosedTagName))
517 bool OpenLineInvalid;
521 bool CloseLineInvalid;
526 if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine) {
527 Diag(HST->
getLocation(), diag::warn_doc_html_start_end_mismatch)
532 Diag(HST->
getLocation(), diag::warn_doc_html_start_end_mismatch)
535 Diag(HET->
getLocation(), diag::note_doc_html_end_tag)
550 while (!HTMLOpenTags.empty()) {
555 Diag(HST->
getLocation(), diag::warn_doc_html_missing_end_tag)
574 Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
585 assert(ThisDeclInfo &&
"should not call this check on a bare comment");
601 case Decl::CXXConstructor:
604 case Decl::CXXDestructor:
609 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();
858 if (
const auto *VD = dyn_cast<DeclaratorDecl>(ThisDeclInfo->
CurrentDecl))
860 else if (
const auto *PD =
861 dyn_cast<ObjCPropertyDecl>(ThisDeclInfo->
CurrentDecl))
904 dyn_cast_or_null<RecordDecl>(ThisDeclInfo->
CurrentDecl))
905 return RD->isUnion();
925 (isa<ClassTemplateDecl>(ThisDeclInfo->
CurrentDecl));
934 (isa<FunctionTemplateDecl>(ThisDeclInfo->
CurrentDecl));
962 ThisDeclInfo->
fill();
967 for (
unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
978 class SimpleTypoCorrector {
989 explicit SimpleTypoCorrector(StringRef
Typo)
993 void addDecl(
const NamedDecl *ND);
995 const NamedDecl *getBestDecl()
const {
1002 unsigned getBestDeclIndex()
const {
1003 assert(getBestDecl());
1008 void SimpleTypoCorrector::addDecl(
const NamedDecl *ND) {
1011 const IdentifierInfo *II = ND->getIdentifier();
1015 StringRef
Name = II->getName();
1016 unsigned MinPossibleEditDistance =
abs((
int)Name.size() - (int)
Typo.size());
1017 if (MinPossibleEditDistance > 0 &&
1018 Typo.size() / MinPossibleEditDistance < 3)
1033 SimpleTypoCorrector Corrector(Typo);
1034 for (
unsigned i = 0, e = ParamVars.size(); i != e; ++i)
1035 Corrector.addDecl(ParamVars[i]);
1036 if (Corrector.getBestDecl())
1037 return Corrector.getBestDeclIndex();
1043 bool ResolveTParamReferenceHelper(
1047 for (
unsigned i = 0, e = TemplateParameters->
size(); i != e; ++i) {
1051 Position->push_back(i);
1056 dyn_cast<TemplateTemplateParmDecl>(Param)) {
1057 Position->push_back(i);
1058 if (ResolveTParamReferenceHelper(Name, TTP->getTemplateParameters(),
1061 Position->pop_back();
1073 if (!TemplateParameters)
1076 return ResolveTParamReferenceHelper(Name, TemplateParameters, Position);
1080 void CorrectTypoInTParamReferenceHelper(
1082 SimpleTypoCorrector &Corrector) {
1083 for (
unsigned i = 0, e = TemplateParameters->
size(); i != e; ++i) {
1085 Corrector.addDecl(Param);
1088 dyn_cast<TemplateTemplateParmDecl>(Param))
1089 CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(),
1098 SimpleTypoCorrector Corrector(Typo);
1099 CorrectTypoInTParamReferenceHelper(TemplateParameters, Corrector);
1100 if (
const NamedDecl *ND = Corrector.getBestDecl()) {
1102 assert(II &&
"SimpleTypoCorrector should not return this decl");
1112 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.
SourceLocation getEnd() const
FunctionDecl - An instance of this class is created to represent a function declaration or definition...
A (possibly-)qualified type.
IdentifierInfo * getIdentifier() const
getIdentifier - Get the identifier that names this declaration, if there is one.
static LLVM_READONLY bool isWhitespace(unsigned char c)
Return true if this character is horizontal or vertical ASCII whitespace: ' ', '\t', '\f', '\v', '\n', '\r'.
Defines the SourceManager interface.
IdentifierInfo * getIdentifierInfo(StringRef Name) const
Return information about the specified preprocessor identifier token.
Decl - This represents one declaration (or definition), e.g.
__DEVICE__ long long abs(long long __n)
Defines the C++ template declaration subclasses.
unsigned getPresumedLineNumber(SourceLocation Loc, bool *Invalid=nullptr) const
NamedDecl * getParam(unsigned Idx)
bool isBlockPointerType() const
VarDecl - An instance of this class is created to represent a variable declaration or definition...
ObjCMethodDecl - Represents an instance or class method declaration.
Stores a list of template parameters for a TemplateDecl and its derived classes.
ParmVarDecl - Represents a parameter to a function.
RecordDecl - Represents a struct/union/class.
One of these records is kept for each identifier that is lexed.
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.
detail::InMemoryDirectory::const_iterator I
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.
TemplateTemplateParmDecl - Declares a template template parameter, e.g., "T" in.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
ArrayRef< FormatToken * > Tokens
SourceLocation getBegin() const
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
detail::InMemoryDirectory::const_iterator E
const T * getAs() const
Member-template getAs<specific type>'.
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.
NamedDecl - This represents a decl with a name.
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.