17 #include "llvm/ADT/SmallString.h" 18 #include "llvm/ADT/StringSwitch.h" 24 #include "clang/AST/CommentHTMLTagsProperties.inc" 27 Sema::Sema(llvm::BumpPtrAllocator &Allocator,
const SourceManager &SourceMgr,
30 Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits),
31 PP(PP), ThisDeclInfo(nullptr), BriefCommand(nullptr),
32 HeaderfileCommand(nullptr) {
39 ThisDeclInfo =
new (Allocator)
DeclInfo;
90 diag::warn_doc_param_not_attached_to_a_function_decl)
104 case CommandTraits::KCI_function:
107 case CommandTraits::KCI_functiongroup:
110 case CommandTraits::KCI_method:
113 case CommandTraits::KCI_methodgroup:
116 case CommandTraits::KCI_callback:
124 Diag(Comment->
getLocation(), diag::warn_doc_function_method_decl_mismatch)
126 << (DiagSelect-1) << (DiagSelect-1)
136 case CommandTraits::KCI_class:
144 case CommandTraits::KCI_interface:
147 case CommandTraits::KCI_protocol:
150 case CommandTraits::KCI_struct:
153 case CommandTraits::KCI_union:
161 Diag(Comment->
getLocation(), diag::warn_doc_api_container_decl_mismatch)
163 << (DiagSelect-1) << (DiagSelect-1)
173 case CommandTraits::KCI_classdesign:
176 case CommandTraits::KCI_coclass:
179 case CommandTraits::KCI_dependency:
182 case CommandTraits::KCI_helper:
185 case CommandTraits::KCI_helperclass:
188 case CommandTraits::KCI_helps:
191 case CommandTraits::KCI_instancesize:
194 case CommandTraits::KCI_ownership:
197 case CommandTraits::KCI_performance:
200 case CommandTraits::KCI_security:
203 case CommandTraits::KCI_superclass:
211 Diag(Comment->
getLocation(), diag::warn_doc_container_decl_mismatch)
220 return llvm::StringSwitch<int>(Arg)
231 std::string ArgLower = Arg.lower();
234 if (Direction == -1) {
242 if (Direction != -1) {
245 Diag(ArgLocBegin, diag::warn_doc_param_spaces_in_direction)
248 Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction) << ArgRange;
268 Argument *A =
new (Allocator) Argument(
SourceRange(ArgLocBegin,
271 Command->
setArgs(llvm::makeArrayRef(A, 1));
291 diag::warn_doc_tparam_not_attached_to_a_template_decl)
306 Argument *A =
new (Allocator) Argument(
SourceRange(ArgLocBegin,
309 Command->
setArgs(llvm::makeArrayRef(A, 1));
324 Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate)
326 Diag(PrevCommand->
getLocation(), diag::note_doc_tparam_previous)
329 PrevCommand = Command;
334 Diag(ArgLocBegin, diag::warn_doc_tparam_not_found)
337 if (!TemplateParameters || TemplateParameters->
size() == 0)
340 StringRef CorrectedName;
341 if (TemplateParameters->
size() == 1) {
350 if (!CorrectedName.empty()) {
351 Diag(ArgLocBegin, diag::note_doc_tparam_name_suggestion)
365 unsigned CommandID) {
383 Argument *A =
new (Allocator) Argument(
SourceRange(ArgLocBegin,
393 llvm::makeArrayRef(A, 1));
398 StringRef CommandName) {
405 unsigned CommandID) {
408 LocBegin, LocEnd, CommandID,
416 return new (Allocator)
TextComment(LocBegin, LocEnd, Text);
420 unsigned CommandID) {
466 bool IsSelfClosing) {
471 else if (!isHTMLEndTagForbidden(Tag->
getTagName()))
472 HTMLOpenTags.push_back(Tag);
480 if (isHTMLEndTagForbidden(TagName)) {
481 Diag(HET->
getLocation(), diag::warn_doc_html_end_forbidden)
487 bool FoundOpen =
false;
489 I = HTMLOpenTags.rbegin(), E = HTMLOpenTags.rend();
491 if ((*I)->getTagName() == TagName) {
497 Diag(HET->
getLocation(), diag::warn_doc_html_end_unbalanced)
503 while (!HTMLOpenTags.empty()) {
505 StringRef LastNotClosedTagName = HST->
getTagName();
506 if (LastNotClosedTagName == TagName) {
513 if (isHTMLEndTagOptional(LastNotClosedTagName))
516 bool OpenLineInvalid;
520 bool CloseLineInvalid;
525 if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine) {
526 Diag(HST->
getLocation(), diag::warn_doc_html_start_end_mismatch)
531 Diag(HST->
getLocation(), diag::warn_doc_html_start_end_mismatch)
534 Diag(HET->
getLocation(), diag::note_doc_html_end_tag)
549 while (!HTMLOpenTags.empty()) {
554 Diag(HST->
getLocation(), diag::warn_doc_html_missing_end_tag)
573 Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
584 assert(ThisDeclInfo &&
"should not call this check on a bare comment");
600 case Decl::CXXConstructor:
603 case Decl::CXXDestructor:
608 diag::warn_doc_returns_attached_to_a_void_function)
618 diag::warn_doc_returns_not_attached_to_a_function_decl)
629 BriefCommand = Command;
632 PrevCommand = BriefCommand;
634 if (!HeaderfileCommand) {
635 HeaderfileCommand = Command;
638 PrevCommand = HeaderfileCommand;
645 Diag(Command->
getLocation(), diag::warn_doc_block_command_duplicate)
649 if (CommandName == PrevCommandName)
650 Diag(PrevCommand->
getLocation(), diag::note_doc_block_command_previous)
656 diag::note_doc_block_command_previous_alias)
666 assert(ThisDeclInfo &&
"should not call this check on a bare comment");
672 if (D->
hasAttr<DeprecatedAttr>() ||
673 D->
hasAttr<AvailabilityAttr>() ||
678 diag::warn_doc_deprecated_not_sync)
682 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
687 FD->doesThisDeclarationHaveABody())
690 StringRef AttributeSpelling =
"__attribute__((deprecated))";
693 tok::kw___attribute, tok::l_paren, tok::l_paren,
695 tok::r_paren, tok::r_paren
699 if (!MacroName.empty())
700 AttributeSpelling = MacroName;
704 TextToInsert += AttributeSpelling;
705 Diag(FD->getEndLoc(), diag::note_add_deprecation_attr)
725 ParamVarDocs.resize(ParamVars.size(),
nullptr);
743 UnresolvedParamCommands.push_back(PCC);
747 if (ParamVarDocs[ResolvedParamIndex]) {
749 Diag(ArgRange.
getBegin(), diag::warn_doc_param_duplicate)
750 << ParamName << ArgRange;
752 Diag(PrevCommand->getLocation(), diag::note_doc_param_previous)
753 << PrevCommand->getParamNameRange();
755 ParamVarDocs[ResolvedParamIndex] = PCC;
760 for (
unsigned i = 0, e = ParamVarDocs.size();
i != e; ++
i) {
761 if (!ParamVarDocs[
i])
762 OrphanedParamDecls.push_back(ParamVars[i]);
768 for (
unsigned i = 0, e = UnresolvedParamCommands.size();
i != e; ++
i) {
773 Diag(ArgRange.
getBegin(), diag::warn_doc_param_not_found)
774 << ParamName << ArgRange;
777 if (OrphanedParamDecls.size() == 0)
781 if (OrphanedParamDecls.size() == 1) {
784 CorrectedParamIndex = 0;
791 const ParmVarDecl *CorrectedPVD = OrphanedParamDecls[CorrectedParamIndex];
793 Diag(ArgRange.
getBegin(), diag::note_doc_param_name_suggestion)
794 << CorrectedII->getName()
818 return FD->isVariadic();
820 dyn_cast<FunctionTemplateDecl>(ThisDeclInfo->
CurrentDecl))
821 return FTD->getTemplatedDecl()->isVariadic();
823 dyn_cast<ObjCMethodDecl>(ThisDeclInfo->
CurrentDecl))
824 return MD->isVariadic();
826 dyn_cast<TypedefNameDecl>(ThisDeclInfo->
CurrentDecl)) {
831 return FT->isVariadic();
864 if (
const auto *VD = dyn_cast<DeclaratorDecl>(ThisDeclInfo->
CurrentDecl))
866 else if (
const auto *PD =
867 dyn_cast<ObjCPropertyDecl>(ThisDeclInfo->
CurrentDecl))
910 dyn_cast_or_null<RecordDecl>(ThisDeclInfo->
CurrentDecl))
911 return RD->isUnion();
931 (isa<ClassTemplateDecl>(ThisDeclInfo->
CurrentDecl));
940 (isa<FunctionTemplateDecl>(ThisDeclInfo->
CurrentDecl));
968 ThisDeclInfo->
fill();
973 for (
unsigned i = 0, e = ParamVars.size();
i != e; ++
i) {
975 if (II && II->
getName() == Name)
984 class SimpleTypoCorrector {
988 const unsigned MaxEditDistance;
990 unsigned BestEditDistance;
995 explicit SimpleTypoCorrector(StringRef Typo)
996 : BestDecl(
nullptr), Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3),
997 BestEditDistance(MaxEditDistance + 1), BestIndex(0), NextIndex(0) {}
1002 if (BestEditDistance > MaxEditDistance)
1008 unsigned getBestDeclIndex()
const {
1009 assert(getBestDecl());
1014 void SimpleTypoCorrector::addDecl(
const NamedDecl *ND) {
1015 unsigned CurrIndex = NextIndex++;
1021 StringRef Name = II->
getName();
1022 unsigned MinPossibleEditDistance =
abs((
int)Name.size() - (int)Typo.size());
1023 if (MinPossibleEditDistance > 0 &&
1024 Typo.size() / MinPossibleEditDistance < 3)
1027 unsigned EditDistance = Typo.edit_distance(Name,
true, MaxEditDistance);
1028 if (EditDistance < BestEditDistance) {
1029 BestEditDistance = EditDistance;
1031 BestIndex = CurrIndex;
1039 SimpleTypoCorrector Corrector(Typo);
1040 for (
unsigned i = 0, e = ParamVars.size();
i != e; ++
i)
1041 Corrector.addDecl(ParamVars[
i]);
1042 if (Corrector.getBestDecl())
1043 return Corrector.getBestDeclIndex();
1049 bool ResolveTParamReferenceHelper(
1053 for (
unsigned i = 0, e = TemplateParameters->
size();
i != e; ++
i) {
1056 if (II && II->
getName() == Name) {
1057 Position->push_back(
i);
1062 dyn_cast<TemplateTemplateParmDecl>(Param)) {
1063 Position->push_back(
i);
1064 if (ResolveTParamReferenceHelper(Name, TTP->getTemplateParameters(),
1067 Position->pop_back();
1079 if (!TemplateParameters)
1082 return ResolveTParamReferenceHelper(Name, TemplateParameters, Position);
1086 void CorrectTypoInTParamReferenceHelper(
1088 SimpleTypoCorrector &Corrector) {
1089 for (
unsigned i = 0, e = TemplateParameters->
size();
i != e; ++
i) {
1091 Corrector.addDecl(Param);
1094 dyn_cast<TemplateTemplateParmDecl>(Param))
1095 CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(),
1104 SimpleTypoCorrector Corrector(Typo);
1105 CorrectTypoInTParamReferenceHelper(TemplateParameters, Corrector);
1106 if (
const NamedDecl *ND = Corrector.getBestDecl()) {
1108 assert(II &&
"SimpleTypoCorrector should not return this decl");
1116 assert(Traits.getCommandInfo(Name)->IsInlineCommand);
1118 return llvm::StringSwitch<InlineCommandComment::RenderKind>(Name)
Represents a function declaration or definition.
SourceLocation getLocWithOffset(int Offset) const
Return a source location with the specified offset from this SourceLocation.
A (possibly-)qualified type.
bool isBlockPointerType() const
IdentifierInfo * getIdentifierInfo(StringRef Name) const
Return information about the specified preprocessor identifier token.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
Defines the SourceManager interface.
Decl - This represents one declaration (or definition), e.g.
__DEVICE__ long long abs(long long __n)
Defines the C++ template declaration subclasses.
The base class of the type hierarchy.
StringRef getLastMacroWithSpelling(SourceLocation Loc, ArrayRef< TokenValue > Tokens) const
Return the name of the macro defined before Loc that has spelling Tokens.
NamedDecl * getParam(unsigned Idx)
Represents a variable declaration or definition.
const T * getAs() const
Member-template getAs<specific type>'.
ObjCMethodDecl - Represents an instance or class method declaration.
Stores a list of template parameters for a TemplateDecl and its derived classes.
Represents a parameter to a function.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Represents a struct/union/class.
One of these records is kept for each identifier that is lexed.
LLVM_READONLY bool isWhitespace(unsigned char c)
Return true if this character is horizontal or vertical ASCII whitespace: ' ', '\t', '\f', '\v', '\n', '\r'.
Concrete class used by the front-end to report problems and issues.
Represents a prototype with parameter type info, e.g.
Defines the clang::Preprocessor interface.
Stores token information for comparing actual tokens with predefined values.
SourceLocation getEnd() const
TemplateTemplateParmDecl - Declares a template template parameter, e.g., "T" in.
unsigned getPresumedLineNumber(SourceLocation Loc, bool *Invalid=nullptr) const
Encodes a location in the source.
StringRef getName() const
Return the actual identifier string.
Base class for declarations which introduce a typedef-name.
Dataflow Directional Tag Classes.
bool isValid() const
Return true if this is a valid SourceLocation object.
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
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 represents a decl that may have a name.
bool isFunctionPointerType() const
SourceLocation getBegin() const
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.