18#include "llvm/ADT/SmallString.h"
19#include "llvm/ADT/StringSwitch.h"
25#include "clang/AST/CommentHTMLTagsProperties.inc"
28Sema::Sema(llvm::BumpPtrAllocator &Allocator,
const SourceManager &SourceMgr,
31 Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits),
32 PP(PP), ThisDeclInfo(nullptr), BriefCommand(nullptr),
33 HeaderfileCommand(nullptr) {
40 ThisDeclInfo =
new (Allocator)
DeclInfo;
58 checkContainerDecl(BC);
70 checkBlockCommandEmptyParagraph(Command);
71 checkBlockCommandDuplicate(Command);
75 checkReturnsCommand(Command);
76 checkDeprecatedCommand(Command);
89 if (!involvesFunctionType())
91 diag::warn_doc_param_not_attached_to_a_function_decl)
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)
127 << (DiagSelect-1) << (DiagSelect-1)
131void 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:
139 (!isClassOrStructOrTagTypedefDecl() && !isClassTemplateDecl()) ? 1
144 if (DiagSelect && Comment->getCommandMarker() && isObjCInterfaceDecl())
147 case CommandTraits::KCI_interface:
148 DiagSelect = !isObjCInterfaceDecl() ? 2 : 0;
150 case CommandTraits::KCI_protocol:
151 DiagSelect = !isObjCProtocolDecl() ? 3 : 0;
153 case CommandTraits::KCI_struct:
154 DiagSelect = !isClassOrStructOrTagTypedefDecl() ? 4 : 0;
156 case CommandTraits::KCI_union:
157 DiagSelect = !isUnionDecl() ? 5 : 0;
164 Diag(Comment->getLocation(), diag::warn_doc_api_container_decl_mismatch)
165 << Comment->getCommandMarker()
166 << (DiagSelect-1) << (DiagSelect-1)
167 << Comment->getSourceRange();
170void Sema::checkContainerDecl(
const BlockCommandComment *Comment) {
171 const CommandInfo *Info = Traits.
getCommandInfo(Comment->getCommandID());
172 if (!Info->IsRecordLikeDetailCommand || isRecordLikeDecl())
175 switch (Comment->getCommandID()) {
176 case CommandTraits::KCI_classdesign:
179 case CommandTraits::KCI_coclass:
182 case CommandTraits::KCI_dependency:
185 case CommandTraits::KCI_helper:
188 case CommandTraits::KCI_helperclass:
191 case CommandTraits::KCI_helps:
194 case CommandTraits::KCI_instancesize:
197 case CommandTraits::KCI_ownership:
200 case CommandTraits::KCI_performance:
203 case CommandTraits::KCI_security:
206 case CommandTraits::KCI_superclass:
214 Diag(Comment->getLocation(), diag::warn_doc_container_decl_mismatch)
215 << Comment->getCommandMarker()
217 << Comment->getSourceRange();
223 return llvm::StringSwitch<ParamCommandPassDirection>(Arg)
234 std::string ArgLower = Arg.lower();
244 const char *FixedName =
246 Diag(ArgLocBegin, diag::warn_doc_param_spaces_in_direction)
249 Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction) << ArgRange;
269 auto *A =
new (Allocator)
277 checkBlockCommandEmptyParagraph(Command);
289 if (!isTemplateOrSpecialization())
291 diag::warn_doc_tparam_not_attached_to_a_template_decl)
305 auto *A =
new (Allocator)
309 if (!isTemplateOrSpecialization()) {
317 if (resolveTParamReference(Arg, TemplateParameters, &Position)) {
322 Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate)
324 Diag(PrevCommand->
getLocation(), diag::note_doc_tparam_previous)
327 PrevCommand = Command;
332 Diag(ArgLocBegin, diag::warn_doc_tparam_not_found)
335 if (!TemplateParameters || TemplateParameters->
size() == 0)
338 StringRef CorrectedName;
339 if (TemplateParameters->
size() == 1) {
345 CorrectedName = correctTypoInTParamReference(Arg, TemplateParameters);
348 if (!CorrectedName.empty()) {
349 Diag(ArgLocBegin, diag::note_doc_tparam_name_suggestion)
358 checkBlockCommandEmptyParagraph(Command);
367 return new (Allocator)
369 getInlineCommandRenderKind(CommandName), Args);
374 StringRef CommandName) {
381 unsigned CommandID) {
394 unsigned CommandID) {
398 Loc.getLocWithOffset(1 + CommandName.size()),
412 Block->setCloseName(CloseName, CloseNameLocBegin);
413 Block->setLines(Lines);
426 checkFunctionDeclVerbatimLine(VL);
427 checkContainerDeclVerbatimLine(VL);
440 bool IsSelfClosing) {
441 Tag->setAttrs(Attrs);
442 Tag->setGreaterLoc(GreaterLoc);
444 Tag->setSelfClosing();
445 else if (!isHTMLEndTagForbidden(Tag->getTagName()))
446 HTMLOpenTags.push_back(Tag);
454 if (isHTMLEndTagForbidden(TagName)) {
455 Diag(HET->
getLocation(), diag::warn_doc_html_end_forbidden)
461 bool FoundOpen =
false;
463 I = HTMLOpenTags.rbegin(),
E = HTMLOpenTags.rend();
465 if ((*I)->getTagName() == TagName) {
471 Diag(HET->
getLocation(), diag::warn_doc_html_end_unbalanced)
477 while (!HTMLOpenTags.empty()) {
479 StringRef LastNotClosedTagName = HST->
getTagName();
480 if (LastNotClosedTagName == TagName) {
487 if (isHTMLEndTagOptional(LastNotClosedTagName))
490 bool OpenLineInvalid;
494 bool CloseLineInvalid;
499 if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine) {
500 Diag(HST->
getLocation(), diag::warn_doc_html_start_end_mismatch)
505 Diag(HST->
getLocation(), diag::warn_doc_html_start_end_mismatch)
508 Diag(HET->
getLocation(), diag::note_doc_html_end_tag)
520 resolveParamCommandIndexes(FC);
523 while (!HTMLOpenTags.empty()) {
528 Diag(HST->
getLocation(), diag::warn_doc_html_missing_end_tag)
547 Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
554void Sema::checkReturnsCommand(
const BlockCommandComment *Command) {
558 assert(ThisDeclInfo &&
"should not call this check on a bare comment");
562 if (isObjCPropertyDecl())
564 if (involvesFunctionType()) {
566 "should have a valid return type");
576 case Decl::CXXConstructor:
579 case Decl::CXXDestructor:
583 Diag(Command->getLocation(),
584 diag::warn_doc_returns_attached_to_a_void_function)
585 << Command->getCommandMarker()
586 << Command->getCommandName(Traits)
588 << Command->getSourceRange();
593 Diag(Command->getLocation(),
594 diag::warn_doc_returns_not_attached_to_a_function_decl)
595 << Command->getCommandMarker()
596 << Command->getCommandName(Traits)
597 << Command->getSourceRange();
600void Sema::checkBlockCommandDuplicate(
const BlockCommandComment *Command) {
601 const CommandInfo *Info = Traits.
getCommandInfo(Command->getCommandID());
602 const BlockCommandComment *PrevCommand =
nullptr;
603 if (Info->IsBriefCommand) {
605 BriefCommand = Command;
608 PrevCommand = BriefCommand;
609 }
else if (Info->IsHeaderfileCommand) {
610 if (!HeaderfileCommand) {
611 HeaderfileCommand = Command;
614 PrevCommand = HeaderfileCommand;
620 StringRef PrevCommandName = PrevCommand->getCommandName(Traits);
621 Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate)
622 << Command->getCommandMarker()
624 << Command->getSourceRange();
625 if (CommandName == PrevCommandName)
626 Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous)
627 << PrevCommand->getCommandMarker()
629 << PrevCommand->getSourceRange();
631 Diag(PrevCommand->getLocation(),
632 diag::note_doc_block_command_previous_alias)
633 << PrevCommand->getCommandMarker()
638void Sema::checkDeprecatedCommand(
const BlockCommandComment *Command) {
642 assert(ThisDeclInfo &&
"should not call this check on a bare comment");
648 if (
D->hasAttr<DeprecatedAttr>() ||
649 D->hasAttr<AvailabilityAttr>() ||
650 D->hasAttr<UnavailableAttr>())
653 Diag(Command->getLocation(), diag::warn_doc_deprecated_not_sync)
654 << Command->getSourceRange() << Command->getCommandMarker();
657 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(
D)) {
660 const DeclContext *Ctx = FD->getDeclContext();
661 if ((!Ctx || !Ctx->isRecord()) &&
662 FD->doesThisDeclarationHaveABody())
665 const LangOptions &LO = FD->getLangOpts();
666 const bool DoubleSquareBracket = LO.CPlusPlus14 || LO.C23;
667 StringRef AttributeSpelling =
668 DoubleSquareBracket ?
"[[deprecated]]" :
"__attribute__((deprecated))";
674 if (DoubleSquareBracket) {
675 TokenValue Tokens[] = {tok::l_square, tok::l_square,
677 tok::r_square, tok::r_square};
679 if (!MacroName.empty())
680 AttributeSpelling = MacroName;
683 if (MacroName.empty()) {
684 TokenValue Tokens[] = {
685 tok::kw___attribute, tok::l_paren,
687 tok::r_paren, tok::r_paren};
688 StringRef MacroName =
690 if (!MacroName.empty())
691 AttributeSpelling = MacroName;
695 SmallString<64> TextToInsert = AttributeSpelling;
697 SourceLocation
Loc = FD->getSourceRange().getBegin();
698 Diag(
Loc, diag::note_add_deprecation_attr)
703void Sema::resolveParamCommandIndexes(
const FullComment *FC) {
704 if (!involvesFunctionType()) {
710 SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands;
714 SmallVector<ParamCommandComment *, 8> ParamVarDocs;
716 ArrayRef<const ParmVarDecl *> ParamVars = getParamVars();
717 ParamVarDocs.resize(ParamVars.size(),
nullptr);
722 ParamCommandComment *PCC = dyn_cast<ParamCommandComment>(*I);
723 if (!PCC || !PCC->hasParamName())
725 StringRef ParamName = PCC->getParamNameAsWritten();
728 const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName,
731 PCC->setIsVarArgParam();
735 UnresolvedParamCommands.push_back(PCC);
738 PCC->setParamIndex(ResolvedParamIndex);
739 if (ParamVarDocs[ResolvedParamIndex]) {
740 SourceRange ArgRange = PCC->getParamNameRange();
741 Diag(ArgRange.getBegin(), diag::warn_doc_param_duplicate)
742 << ParamName << ArgRange;
743 ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex];
744 Diag(PrevCommand->getLocation(), diag::note_doc_param_previous)
745 << PrevCommand->getParamNameRange();
747 ParamVarDocs[ResolvedParamIndex] = PCC;
751 SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls;
752 for (
unsigned i = 0, e = ParamVarDocs.size(); i != e; ++i) {
753 if (!ParamVarDocs[i])
754 OrphanedParamDecls.push_back(ParamVars[i]);
760 for (
unsigned i = 0, e = UnresolvedParamCommands.size(); i != e; ++i) {
761 const ParamCommandComment *PCC = UnresolvedParamCommands[i];
763 SourceRange ArgRange = PCC->getParamNameRange();
764 StringRef ParamName = PCC->getParamNameAsWritten();
765 Diag(ArgRange.getBegin(), diag::warn_doc_param_not_found)
766 << ParamName << ArgRange;
769 if (OrphanedParamDecls.size() == 0)
773 if (OrphanedParamDecls.size() == 1) {
776 CorrectedParamIndex = 0;
779 CorrectedParamIndex = correctTypoInParmVarReference(ParamName,
783 const ParmVarDecl *CorrectedPVD = OrphanedParamDecls[CorrectedParamIndex];
784 if (
const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier())
785 Diag(ArgRange.getBegin(), diag::note_doc_param_name_suggestion)
786 << CorrectedII->getName()
792bool Sema::involvesFunctionType() {
800bool Sema::isFunctionDecl() {
808bool Sema::isAnyFunctionDecl() {
809 return isFunctionDecl() && ThisDeclInfo->
CurrentDecl &&
813bool Sema::isFunctionOrMethodVariadic() {
821bool Sema::isObjCMethodDecl() {
822 return isFunctionDecl() && ThisDeclInfo->
CurrentDecl &&
826bool Sema::isFunctionPointerVarDecl() {
832 if (
const VarDecl *VD = dyn_cast_or_null<VarDecl>(ThisDeclInfo->
CurrentDecl)) {
833 QualType QT = VD->getType();
834 return QT->isFunctionPointerType();
840bool Sema::isObjCPropertyDecl() {
848bool Sema::isTemplateOrSpecialization() {
856bool Sema::isRecordLikeDecl() {
861 return isUnionDecl() || isClassOrStructDecl() || isObjCInterfaceDecl() ||
862 isObjCProtocolDecl();
865bool Sema::isUnionDecl() {
870 if (
const RecordDecl *RD =
871 dyn_cast_or_null<RecordDecl>(ThisDeclInfo->
CurrentDecl))
872 return RD->isUnion();
876 if (
auto *record = dyn_cast_or_null<RecordDecl>(
D))
877 return !record->isUnion();
882bool Sema::isClassOrStructDecl() {
894bool Sema::isClassOrStructOrTagTypedefDecl() {
906 if (
auto *ThisTypedefDecl = dyn_cast<TypedefDecl>(ThisDeclInfo->
CurrentDecl)) {
907 auto UnderlyingType = ThisTypedefDecl->getUnderlyingType();
908 if (
auto ThisElaboratedType = dyn_cast<ElaboratedType>(UnderlyingType)) {
909 auto DesugaredType = ThisElaboratedType->desugar();
910 if (
auto *DesugaredTypePtr = DesugaredType.getTypePtrOrNull()) {
911 if (
auto *ThisRecordType = dyn_cast<RecordType>(DesugaredTypePtr)) {
921bool Sema::isClassTemplateDecl() {
927 (isa<ClassTemplateDecl>(ThisDeclInfo->
CurrentDecl));
930bool Sema::isFunctionTemplateDecl() {
936 (isa<FunctionTemplateDecl>(ThisDeclInfo->
CurrentDecl));
939bool Sema::isObjCInterfaceDecl() {
948bool Sema::isObjCProtocolDecl() {
957ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
963void Sema::inspectThisDecl() {
964 ThisDeclInfo->
fill();
967unsigned Sema::resolveParmVarReference(StringRef Name,
968 ArrayRef<const ParmVarDecl *> ParamVars) {
969 for (
unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
970 const IdentifierInfo *II = ParamVars[i]->getIdentifier();
971 if (II && II->getName() == Name)
974 if (Name ==
"..." && isFunctionOrMethodVariadic())
980class SimpleTypoCorrector {
981 const NamedDecl *BestDecl;
984 const unsigned MaxEditDistance;
986 unsigned BestEditDistance;
991 explicit SimpleTypoCorrector(StringRef Typo)
992 : BestDecl(nullptr), Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3),
993 BestEditDistance(MaxEditDistance + 1), BestIndex(0), NextIndex(0) {}
995 void addDecl(
const NamedDecl *ND);
997 const NamedDecl *getBestDecl()
const {
998 if (BestEditDistance > MaxEditDistance)
1004 unsigned getBestDeclIndex()
const {
1005 assert(getBestDecl());
1010void SimpleTypoCorrector::addDecl(
const NamedDecl *ND) {
1011 unsigned CurrIndex = NextIndex++;
1013 const IdentifierInfo *II = ND->getIdentifier();
1017 StringRef Name = II->getName();
1018 unsigned MinPossibleEditDistance =
abs((
int)Name.size() - (
int)Typo.size());
1019 if (MinPossibleEditDistance > 0 &&
1020 Typo.size() / MinPossibleEditDistance < 3)
1023 unsigned EditDistance = Typo.edit_distance(Name,
true, MaxEditDistance);
1024 if (EditDistance < BestEditDistance) {
1025 BestEditDistance = EditDistance;
1027 BestIndex = CurrIndex;
1032unsigned Sema::correctTypoInParmVarReference(
1034 ArrayRef<const ParmVarDecl *> ParamVars) {
1035 SimpleTypoCorrector Corrector(Typo);
1036 for (
unsigned i = 0, e = ParamVars.size(); i != e; ++i)
1037 Corrector.addDecl(ParamVars[i]);
1038 if (Corrector.getBestDecl())
1039 return Corrector.getBestDeclIndex();
1045bool ResolveTParamReferenceHelper(
1047 const TemplateParameterList *TemplateParameters,
1048 SmallVectorImpl<unsigned> *Position) {
1049 for (
unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
1050 const NamedDecl *Param = TemplateParameters->getParam(i);
1051 const IdentifierInfo *II = Param->getIdentifier();
1052 if (II && II->getName() == Name) {
1053 Position->push_back(i);
1057 if (
const TemplateTemplateParmDecl *TTP =
1058 dyn_cast<TemplateTemplateParmDecl>(Param)) {
1059 Position->push_back(i);
1060 if (ResolveTParamReferenceHelper(Name, TTP->getTemplateParameters(),
1063 Position->pop_back();
1070bool Sema::resolveTParamReference(
1072 const TemplateParameterList *TemplateParameters,
1073 SmallVectorImpl<unsigned> *Position) {
1075 if (!TemplateParameters)
1078 return ResolveTParamReferenceHelper(Name, TemplateParameters, Position);
1082void CorrectTypoInTParamReferenceHelper(
1083 const TemplateParameterList *TemplateParameters,
1084 SimpleTypoCorrector &Corrector) {
1085 for (
unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
1086 const NamedDecl *Param = TemplateParameters->getParam(i);
1087 Corrector.addDecl(Param);
1089 if (
const TemplateTemplateParmDecl *TTP =
1090 dyn_cast<TemplateTemplateParmDecl>(Param))
1091 CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(),
1097StringRef Sema::correctTypoInTParamReference(
1099 const TemplateParameterList *TemplateParameters) {
1100 SimpleTypoCorrector Corrector(Typo);
1101 CorrectTypoInTParamReferenceHelper(TemplateParameters, Corrector);
1102 if (
const NamedDecl *ND = Corrector.getBestDecl()) {
1103 const IdentifierInfo *II = ND->getIdentifier();
1104 assert(II &&
"SimpleTypoCorrector should not return this decl");
1105 return II->getName();
1113 return llvm::StringSwitch<InlineCommandRenderKind>(Name)
Defines the C++ template declaration subclasses.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
Defines the clang::Preprocessor interface.
Defines the SourceManager interface.
__DEVICE__ long long abs(long long __n)
Decl - This represents one declaration (or definition), e.g.
Concrete class used by the front-end to report problems and issues.
static FixItHint CreateReplacement(CharSourceRange RemoveRange, StringRef Code)
Create a code modification hint that replaces the given source range with the given code string.
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.
One of these records is kept for each identifier that is lexed.
StringRef getName() const
Return the actual identifier string.
This represents a decl that may have a name.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
IdentifierInfo * getIdentifierInfo(StringRef Name) const
Return information about the specified preprocessor identifier token.
StringRef getLastMacroWithSpelling(SourceLocation Loc, ArrayRef< TokenValue > Tokens) const
Return the name of the macro defined before Loc that has spelling Tokens.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
This class handles loading and caching of source files into memory.
unsigned getPresumedLineNumber(SourceLocation Loc, bool *Invalid=nullptr) const
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
Stores a list of template parameters for a TemplateDecl and its derived classes.
NamedDecl * getParam(unsigned Idx)
@ Decl
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
The JSON file list parser is used to communicate input to InstallAPI.
LLVM_READONLY bool isWhitespace(unsigned char c)
Return true if this character is horizontal or vertical ASCII whitespace: ' ', '\t',...