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),
40 ThisDeclInfo =
new (Allocator)
DeclInfo;
42 ThisDeclInfo->IsFilled =
false;
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)
103 std::optional<unsigned> DiagSelect;
104 switch (
Comment->getCommandID()) {
105 case CommandTraits::KCI_function:
106 if (!isAnyFunctionDecl() && !isFunctionTemplateDecl())
107 DiagSelect = diag::CallableKind::Function;
109 case CommandTraits::KCI_functiongroup:
110 if (!isAnyFunctionDecl() && !isFunctionTemplateDecl())
111 DiagSelect = diag::CallableKind::FunctionGroup;
113 case CommandTraits::KCI_method:
114 DiagSelect = diag::CallableKind::Method;
116 case CommandTraits::KCI_methodgroup:
117 DiagSelect = diag::CallableKind::MethodGroup;
119 case CommandTraits::KCI_callback:
120 DiagSelect = diag::CallableKind::Callback;
124 Diag(Comment->
getLocation(), diag::warn_doc_function_method_decl_mismatch)
129void Sema::checkContainerDeclVerbatimLine(
const BlockCommandComment *Comment) {
130 const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
131 if (!Info->IsRecordLikeDeclarationCommand)
133 std::optional<unsigned> DiagSelect;
134 switch (Comment->getCommandID()) {
135 case CommandTraits::KCI_class:
136 if (!isClassOrStructOrTagTypedefDecl() && !isClassTemplateDecl())
137 DiagSelect = diag::DeclContainerKind::Class;
142 if (DiagSelect && Comment->getCommandMarker() && isObjCInterfaceDecl())
143 DiagSelect = std::nullopt;
145 case CommandTraits::KCI_interface:
146 if (!isObjCInterfaceDecl())
147 DiagSelect = diag::DeclContainerKind::Interface;
149 case CommandTraits::KCI_protocol:
150 if (!isObjCProtocolDecl())
151 DiagSelect = diag::DeclContainerKind::Protocol;
153 case CommandTraits::KCI_struct:
154 if (!isClassOrStructOrTagTypedefDecl())
155 DiagSelect = diag::DeclContainerKind::Struct;
157 case CommandTraits::KCI_union:
159 DiagSelect = diag::DeclContainerKind::Union;
162 DiagSelect = std::nullopt;
166 Diag(Comment->getLocation(), diag::warn_doc_api_container_decl_mismatch)
167 << Comment->getCommandMarker() << (*DiagSelect) << (*DiagSelect)
168 << Comment->getSourceRange();
172 const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
173 if (!Info->IsRecordLikeDetailCommand || isRecordLikeDecl())
175 std::optional<unsigned> DiagSelect;
176 switch (Comment->getCommandID()) {
177 case CommandTraits::KCI_classdesign:
178 DiagSelect = diag::DocCommandKind::ClassDesign;
180 case CommandTraits::KCI_coclass:
181 DiagSelect = diag::DocCommandKind::CoClass;
183 case CommandTraits::KCI_dependency:
184 DiagSelect = diag::DocCommandKind::Dependency;
186 case CommandTraits::KCI_helper:
187 DiagSelect = diag::DocCommandKind::Helper;
189 case CommandTraits::KCI_helperclass:
190 DiagSelect = diag::DocCommandKind::HelperClass;
192 case CommandTraits::KCI_helps:
193 DiagSelect = diag::DocCommandKind::Helps;
195 case CommandTraits::KCI_instancesize:
196 DiagSelect = diag::DocCommandKind::InstanceSize;
198 case CommandTraits::KCI_ownership:
199 DiagSelect = diag::DocCommandKind::Ownership;
201 case CommandTraits::KCI_performance:
202 DiagSelect = diag::DocCommandKind::Performance;
204 case CommandTraits::KCI_security:
205 DiagSelect = diag::DocCommandKind::Security;
207 case CommandTraits::KCI_superclass:
208 DiagSelect = diag::DocCommandKind::Superclass;
211 DiagSelect = std::nullopt;
215 Diag(Comment->getLocation(), diag::warn_doc_container_decl_mismatch)
216 << Comment->getCommandMarker() << (*DiagSelect)
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 (isExplicitFunctionTemplateInstantiation()) {
295 if (!isTemplateOrSpecialization())
297 diag::warn_doc_tparam_not_attached_to_a_template_decl)
311 auto *A =
new (Allocator)
315 if (!isTemplateOrSpecialization()) {
321 ThisDeclInfo->TemplateParameters;
323 if (resolveTParamReference(Arg, TemplateParameters, &Position)) {
328 Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate)
330 Diag(PrevCommand->
getLocation(), diag::note_doc_tparam_previous)
333 PrevCommand = Command;
338 Diag(ArgLocBegin, diag::warn_doc_tparam_not_found)
341 if (!TemplateParameters || TemplateParameters->
size() == 0)
344 StringRef CorrectedName;
345 if (TemplateParameters->
size() == 1) {
351 CorrectedName = correctTypoInTParamReference(Arg, TemplateParameters);
354 if (!CorrectedName.empty()) {
355 Diag(ArgLocBegin, diag::note_doc_tparam_name_suggestion)
364 checkBlockCommandEmptyParagraph(Command);
372 StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
375 CommandLocBegin, CommandLocEnd, CommandID,
376 getInlineCommandRenderKind(CommandName), CommandMarker, Args);
381 StringRef CommandName,
383 unsigned CommandID = Traits.registerUnknownCommand(CommandName)->getID();
393 CommandMarker, Args);
403 unsigned CommandID) {
404 StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
421 Block->setCloseName(CloseName, CloseNameLocBegin);
422 Block->setLines(Lines);
435 checkFunctionDeclVerbatimLine(VL);
436 checkContainerDeclVerbatimLine(VL);
449 bool IsSelfClosing) {
451 Tag->setGreaterLoc(GreaterLoc);
453 Tag->setSelfClosing();
454 else if (!isHTMLEndTagForbidden(Tag->getTagName()))
455 HTMLOpenTags.push_back(Tag);
463 if (isHTMLEndTagForbidden(TagName)) {
464 Diag(HET->
getLocation(), diag::warn_doc_html_end_forbidden)
470 bool FoundOpen =
false;
472 I = HTMLOpenTags.rbegin(), E = HTMLOpenTags.rend();
474 if ((*I)->getTagName() == TagName) {
480 Diag(HET->
getLocation(), diag::warn_doc_html_end_unbalanced)
486 while (!HTMLOpenTags.empty()) {
488 StringRef LastNotClosedTagName = HST->
getTagName();
489 if (LastNotClosedTagName == TagName) {
496 if (isHTMLEndTagOptional(LastNotClosedTagName))
499 bool OpenLineInvalid;
500 const unsigned OpenLine = SourceMgr.getPresumedLineNumber(
503 bool CloseLineInvalid;
504 const unsigned CloseLine = SourceMgr.getPresumedLineNumber(
508 if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine) {
509 Diag(HST->
getLocation(), diag::warn_doc_html_start_end_mismatch)
514 Diag(HST->
getLocation(), diag::warn_doc_html_start_end_mismatch)
517 Diag(HET->
getLocation(), diag::note_doc_html_end_tag)
529 resolveParamCommandIndexes(FC);
532 while (!HTMLOpenTags.empty()) {
537 Diag(HST->
getLocation(), diag::warn_doc_html_missing_end_tag)
546 if (Traits.getCommandInfo(Command->
getCommandID())->IsEmptyParagraphAllowed)
556 Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
563void Sema::checkReturnsCommand(
const BlockCommandComment *Command) {
564 if (!Traits.getCommandInfo(Command->getCommandID())->IsReturnsCommand)
567 assert(ThisDeclInfo &&
"should not call this check on a bare comment");
571 if (isObjCPropertyDecl())
573 if (involvesFunctionType()) {
575 "should have a valid return type");
585 case Decl::CXXConstructor:
588 case Decl::CXXDestructor:
592 Diag(Command->getLocation(),
593 diag::warn_doc_returns_attached_to_a_void_function)
594 << Command->getCommandMarker()
595 << Command->getCommandName(Traits)
597 << Command->getSourceRange();
602 Diag(Command->getLocation(),
603 diag::warn_doc_returns_not_attached_to_a_function_decl)
604 << Command->getCommandMarker()
605 << Command->getCommandName(Traits)
606 << Command->getSourceRange();
610 const CommandInfo *Info = Traits.getCommandInfo(Command->getCommandID());
611 const BlockCommandComment *PrevCommand =
nullptr;
612 if (Info->IsBriefCommand) {
614 BriefCommand = Command;
617 PrevCommand = BriefCommand;
618 }
else if (Info->IsHeaderfileCommand) {
619 if (!HeaderfileCommand) {
620 HeaderfileCommand = Command;
623 PrevCommand = HeaderfileCommand;
628 StringRef CommandName = Command->getCommandName(Traits);
629 StringRef PrevCommandName = PrevCommand->getCommandName(Traits);
630 Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate)
631 << Command->getCommandMarker()
633 << Command->getSourceRange();
634 if (CommandName == PrevCommandName)
635 Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous)
636 << PrevCommand->getCommandMarker()
638 << PrevCommand->getSourceRange();
640 Diag(PrevCommand->getLocation(),
641 diag::note_doc_block_command_previous_alias)
642 << PrevCommand->getCommandMarker()
648 if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand)
651 assert(ThisDeclInfo &&
"should not call this check on a bare comment");
653 const Decl *D = ThisDeclInfo->CommentDecl;
657 if (D->hasAttr<DeprecatedAttr>() ||
658 D->hasAttr<AvailabilityAttr>() ||
659 D->hasAttr<UnavailableAttr>())
662 Diag(Command->getLocation(), diag::warn_doc_deprecated_not_sync)
663 << Command->getSourceRange() << Command->getCommandMarker();
666 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
669 const DeclContext *Ctx = FD->getDeclContext();
670 if ((!Ctx || !Ctx->isRecord()) &&
671 FD->doesThisDeclarationHaveABody())
674 const LangOptions &LO = FD->getLangOpts();
675 const bool DoubleSquareBracket = LO.CPlusPlus14 || LO.C23;
676 StringRef AttributeSpelling =
677 DoubleSquareBracket ?
"[[deprecated]]" :
"__attribute__((deprecated))";
683 if (DoubleSquareBracket) {
684 TokenValue Tokens[] = {tok::l_square, tok::l_square,
685 PP->getIdentifierInfo(
"deprecated"),
686 tok::r_square, tok::r_square};
687 MacroName = PP->getLastMacroWithSpelling(FD->getLocation(), Tokens);
688 if (!MacroName.empty())
689 AttributeSpelling = MacroName;
692 if (MacroName.empty()) {
693 TokenValue Tokens[] = {
694 tok::kw___attribute, tok::l_paren,
695 tok::l_paren, PP->getIdentifierInfo(
"deprecated"),
696 tok::r_paren, tok::r_paren};
697 StringRef MacroName =
698 PP->getLastMacroWithSpelling(FD->getLocation(), Tokens);
699 if (!MacroName.empty())
700 AttributeSpelling = MacroName;
704 SmallString<64> TextToInsert = AttributeSpelling;
706 SourceLocation Loc = FD->getSourceRange().getBegin();
707 Diag(Loc, diag::note_add_deprecation_attr)
712void Sema::resolveParamCommandIndexes(
const FullComment *FC) {
713 if (!involvesFunctionType()) {
719 SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands;
723 SmallVector<ParamCommandComment *, 8> ParamVarDocs;
725 ArrayRef<const ParmVarDecl *> ParamVars = getParamVars();
726 ParamVarDocs.resize(ParamVars.size(),
nullptr);
731 ParamCommandComment *PCC = dyn_cast<ParamCommandComment>(*I);
732 if (!PCC || !PCC->hasParamName())
734 StringRef ParamName = PCC->getParamNameAsWritten();
737 const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName,
740 PCC->setIsVarArgParam();
744 UnresolvedParamCommands.push_back(PCC);
747 PCC->setParamIndex(ResolvedParamIndex);
748 if (ParamVarDocs[ResolvedParamIndex]) {
749 SourceRange ArgRange = PCC->getParamNameRange();
750 Diag(ArgRange.getBegin(), diag::warn_doc_param_duplicate)
751 << ParamName << ArgRange;
752 ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex];
753 Diag(PrevCommand->getLocation(), diag::note_doc_param_previous)
754 << PrevCommand->getParamNameRange();
756 ParamVarDocs[ResolvedParamIndex] = PCC;
760 SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls;
761 for (
unsigned i = 0, e = ParamVarDocs.size(); i != e; ++i) {
762 if (!ParamVarDocs[i])
763 OrphanedParamDecls.push_back(ParamVars[i]);
769 for (
unsigned i = 0, e = UnresolvedParamCommands.size(); i != e; ++i) {
770 const ParamCommandComment *PCC = UnresolvedParamCommands[i];
772 SourceRange ArgRange = PCC->getParamNameRange();
773 StringRef ParamName = PCC->getParamNameAsWritten();
774 Diag(ArgRange.getBegin(), diag::warn_doc_param_not_found)
775 << ParamName << ArgRange;
778 if (OrphanedParamDecls.size() == 0)
782 if (OrphanedParamDecls.size() == 1) {
785 CorrectedParamIndex = 0;
788 CorrectedParamIndex = correctTypoInParmVarReference(ParamName,
792 const ParmVarDecl *CorrectedPVD = OrphanedParamDecls[CorrectedParamIndex];
793 if (
const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier())
794 Diag(ArgRange.getBegin(), diag::note_doc_param_name_suggestion)
795 << CorrectedII->getName()
801bool Sema::involvesFunctionType() {
804 if (!ThisDeclInfo->IsFilled)
806 return ThisDeclInfo->involvesFunctionType();
809bool Sema::isFunctionDecl() {
812 if (!ThisDeclInfo->IsFilled)
817bool Sema::isAnyFunctionDecl() {
818 return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
822bool Sema::isFunctionOrMethodVariadic() {
825 if (!ThisDeclInfo->IsFilled)
827 return ThisDeclInfo->IsVariadic;
830bool Sema::isObjCMethodDecl() {
831 return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
835bool Sema::isFunctionPointerVarDecl() {
838 if (!ThisDeclInfo->IsFilled)
841 if (
const VarDecl *VD = dyn_cast_or_null<VarDecl>(ThisDeclInfo->CurrentDecl)) {
842 QualType QT = VD->getType();
843 return QT->isFunctionPointerType();
849bool Sema::isObjCPropertyDecl() {
852 if (!ThisDeclInfo->IsFilled)
854 return ThisDeclInfo->CurrentDecl->getKind() == Decl::ObjCProperty;
857bool Sema::isTemplateOrSpecialization() {
860 if (!ThisDeclInfo->IsFilled)
865bool Sema::isExplicitFunctionTemplateInstantiation() {
868 if (!ThisDeclInfo->IsFilled)
870 if (
const auto *FD = dyn_cast<FunctionDecl>(ThisDeclInfo->CurrentDecl)) {
878bool Sema::isRecordLikeDecl() {
881 if (!ThisDeclInfo->IsFilled)
883 return isUnionDecl() || isClassOrStructDecl() || isObjCInterfaceDecl() ||
884 isObjCProtocolDecl();
887bool Sema::isUnionDecl() {
890 if (!ThisDeclInfo->IsFilled)
892 if (
const RecordDecl *RD =
893 dyn_cast_or_null<RecordDecl>(ThisDeclInfo->CurrentDecl))
894 return RD->isUnion();
898 if (
auto *record = dyn_cast_or_null<RecordDecl>(D))
899 return !record->isUnion();
904bool Sema::isClassOrStructDecl() {
916bool Sema::isClassOrStructOrTagTypedefDecl() {
928 if (
auto *ThisTypedefDecl = dyn_cast<TypedefDecl>(ThisDeclInfo->
CurrentDecl))
929 if (
auto *D = ThisTypedefDecl->getUnderlyingType()->getAsRecordDecl())
935bool Sema::isClassTemplateDecl() {
938 if (!ThisDeclInfo->IsFilled)
940 return ThisDeclInfo->CurrentDecl &&
944bool Sema::isFunctionTemplateDecl() {
947 if (!ThisDeclInfo->IsFilled)
949 return ThisDeclInfo->CurrentDecl &&
953bool Sema::isObjCInterfaceDecl() {
956 if (!ThisDeclInfo->IsFilled)
958 return ThisDeclInfo->CurrentDecl &&
962bool Sema::isObjCProtocolDecl() {
965 if (!ThisDeclInfo->IsFilled)
967 return ThisDeclInfo->CurrentDecl &&
971ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
972 if (!ThisDeclInfo->IsFilled)
974 return ThisDeclInfo->ParamVars;
977void Sema::inspectThisDecl() {
978 ThisDeclInfo->fill();
981unsigned Sema::resolveParmVarReference(StringRef Name,
982 ArrayRef<const ParmVarDecl *> ParamVars) {
983 for (
unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
984 const IdentifierInfo *II = ParamVars[i]->getIdentifier();
985 if (II && II->getName() == Name)
988 if (Name ==
"..." && isFunctionOrMethodVariadic())
994Sema::correctTypoInParmVarReference(StringRef Typo,
995 ArrayRef<const ParmVarDecl *> ParamVars) {
996 SimpleTypoCorrection STC(Typo);
997 for (
unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
998 const ParmVarDecl *Param = ParamVars[i];
1002 STC.add(Param->getIdentifier());
1005 if (STC.hasCorrection())
1006 return STC.getCorrectionIndex();
1012bool ResolveTParamReferenceHelper(
1014 const TemplateParameterList *TemplateParameters,
1015 SmallVectorImpl<unsigned> *Position) {
1016 for (
unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
1017 const NamedDecl *Param = TemplateParameters->getParam(i);
1018 const IdentifierInfo *II = Param->getIdentifier();
1019 if (II && II->getName() == Name) {
1020 Position->push_back(i);
1024 if (
const TemplateTemplateParmDecl *TTP =
1025 dyn_cast<TemplateTemplateParmDecl>(Param)) {
1026 Position->push_back(i);
1027 if (ResolveTParamReferenceHelper(Name, TTP->getTemplateParameters(),
1030 Position->pop_back();
1037bool Sema::resolveTParamReference(
1039 const TemplateParameterList *TemplateParameters,
1040 SmallVectorImpl<unsigned> *Position) {
1042 if (!TemplateParameters)
1045 return ResolveTParamReferenceHelper(Name, TemplateParameters, Position);
1049void CorrectTypoInTParamReferenceHelper(
1050 const TemplateParameterList *TemplateParameters,
1051 SimpleTypoCorrection &STC) {
1052 for (
unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
1053 const NamedDecl *Param = TemplateParameters->getParam(i);
1057 STC.add(Param->getIdentifier());
1059 if (
const TemplateTemplateParmDecl *TTP =
1060 dyn_cast<TemplateTemplateParmDecl>(Param))
1061 CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(), STC);
1066StringRef Sema::correctTypoInTParamReference(
1068 const TemplateParameterList *TemplateParameters) {
1069 SimpleTypoCorrection STC(Typo);
1070 CorrectTypoInTParamReferenceHelper(TemplateParameters, STC);
1072 if (
auto CorrectedTParamReference = STC.getCorrection())
1073 return *CorrectedTParamReference;
1079 assert(Traits.getCommandInfo(Name)->IsInlineCommand);
1081 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.
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
Defines the clang::Preprocessor interface.
Defines the SourceManager interface.
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.
Engages in a tight little dance with the lexer to efficiently preprocess 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.
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)
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
@ Default
Set to the current date and time.
LLVM_READONLY bool isWhitespace(unsigned char c)
Return true if this character is horizontal or vertical ASCII whitespace: ' ', '\t',...
TemplateSpecializationKind
Describes the kind of template specialization that a particular template specialization declaration r...
@ TSK_ExplicitInstantiationDefinition
This template specialization was instantiated from a template due to an explicit instantiation defini...
@ TSK_ExplicitInstantiationDeclaration
This template specialization was instantiated from a template due to an explicit instantiation declar...