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 if (!isObjCMethodDecl())
115 DiagSelect = diag::CallableKind::Method;
117 case CommandTraits::KCI_methodgroup:
118 if (!isObjCMethodDecl())
119 DiagSelect = diag::CallableKind::MethodGroup;
121 case CommandTraits::KCI_callback:
122 if (!isFunctionPointerVarDecl())
123 DiagSelect = diag::CallableKind::Callback;
127 Diag(Comment->
getLocation(), diag::warn_doc_function_method_decl_mismatch)
132void Sema::checkContainerDeclVerbatimLine(
const BlockCommandComment *Comment) {
133 const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
134 if (!Info->IsRecordLikeDeclarationCommand)
136 std::optional<unsigned> DiagSelect;
137 switch (Comment->getCommandID()) {
138 case CommandTraits::KCI_class:
139 if (!isClassOrStructOrTagTypedefDecl() && !isClassTemplateDecl())
140 DiagSelect = diag::DeclContainerKind::Class;
145 if (DiagSelect && Comment->getCommandMarker() && isObjCInterfaceDecl())
146 DiagSelect = std::nullopt;
148 case CommandTraits::KCI_interface:
149 if (!isObjCInterfaceDecl())
150 DiagSelect = diag::DeclContainerKind::Interface;
152 case CommandTraits::KCI_protocol:
153 if (!isObjCProtocolDecl())
154 DiagSelect = diag::DeclContainerKind::Protocol;
156 case CommandTraits::KCI_struct:
157 if (!isClassOrStructOrTagTypedefDecl())
158 DiagSelect = diag::DeclContainerKind::Struct;
160 case CommandTraits::KCI_union:
162 DiagSelect = diag::DeclContainerKind::Union;
165 DiagSelect = std::nullopt;
169 Diag(Comment->getLocation(), diag::warn_doc_api_container_decl_mismatch)
170 << Comment->getCommandMarker() << (*DiagSelect) << (*DiagSelect)
171 << Comment->getSourceRange();
175 const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
176 if (!Info->IsRecordLikeDetailCommand || isRecordLikeDecl())
178 std::optional<unsigned> DiagSelect;
179 switch (Comment->getCommandID()) {
180 case CommandTraits::KCI_classdesign:
181 DiagSelect = diag::DocCommandKind::ClassDesign;
183 case CommandTraits::KCI_coclass:
184 DiagSelect = diag::DocCommandKind::CoClass;
186 case CommandTraits::KCI_dependency:
187 DiagSelect = diag::DocCommandKind::Dependency;
189 case CommandTraits::KCI_helper:
190 DiagSelect = diag::DocCommandKind::Helper;
192 case CommandTraits::KCI_helperclass:
193 DiagSelect = diag::DocCommandKind::HelperClass;
195 case CommandTraits::KCI_helps:
196 DiagSelect = diag::DocCommandKind::Helps;
198 case CommandTraits::KCI_instancesize:
199 DiagSelect = diag::DocCommandKind::InstanceSize;
201 case CommandTraits::KCI_ownership:
202 DiagSelect = diag::DocCommandKind::Ownership;
204 case CommandTraits::KCI_performance:
205 DiagSelect = diag::DocCommandKind::Performance;
207 case CommandTraits::KCI_security:
208 DiagSelect = diag::DocCommandKind::Security;
210 case CommandTraits::KCI_superclass:
211 DiagSelect = diag::DocCommandKind::Superclass;
214 DiagSelect = std::nullopt;
218 Diag(Comment->getLocation(), diag::warn_doc_container_decl_mismatch)
219 << Comment->getCommandMarker() << (*DiagSelect)
220 << Comment->getSourceRange();
226 return llvm::StringSwitch<ParamCommandPassDirection>(Arg)
237 std::string ArgLower = Arg.lower();
247 const char *FixedName =
249 Diag(ArgLocBegin, diag::warn_doc_param_spaces_in_direction)
252 Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction) << ArgRange;
272 auto *A =
new (Allocator)
280 checkBlockCommandEmptyParagraph(Command);
292 if (isExplicitFunctionTemplateInstantiation()) {
298 if (!isTemplateOrSpecialization())
300 diag::warn_doc_tparam_not_attached_to_a_template_decl)
314 auto *A =
new (Allocator)
318 if (!isTemplateOrSpecialization()) {
324 ThisDeclInfo->TemplateParameters;
326 if (resolveTParamReference(Arg, TemplateParameters, &Position)) {
331 Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate)
333 Diag(PrevCommand->
getLocation(), diag::note_doc_tparam_previous)
336 PrevCommand = Command;
341 Diag(ArgLocBegin, diag::warn_doc_tparam_not_found)
344 if (!TemplateParameters || TemplateParameters->
size() == 0)
347 StringRef CorrectedName;
348 if (TemplateParameters->
size() == 1) {
354 CorrectedName = correctTypoInTParamReference(Arg, TemplateParameters);
357 if (!CorrectedName.empty()) {
358 Diag(ArgLocBegin, diag::note_doc_tparam_name_suggestion)
367 checkBlockCommandEmptyParagraph(Command);
375 StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
378 CommandLocBegin, CommandLocEnd, CommandID,
379 getInlineCommandRenderKind(CommandName), CommandMarker, Args);
384 StringRef CommandName,
386 unsigned CommandID = Traits.registerUnknownCommand(CommandName)->getID();
396 CommandMarker, Args);
406 unsigned CommandID) {
407 StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
424 Block->setCloseName(CloseName, CloseNameLocBegin);
425 Block->setLines(Lines);
438 checkFunctionDeclVerbatimLine(VL);
439 checkContainerDeclVerbatimLine(VL);
452 bool IsSelfClosing) {
454 Tag->setGreaterLoc(GreaterLoc);
456 Tag->setSelfClosing();
457 else if (!isHTMLEndTagForbidden(Tag->getTagName()))
458 HTMLOpenTags.push_back(Tag);
466 if (isHTMLEndTagForbidden(TagName)) {
467 Diag(HET->
getLocation(), diag::warn_doc_html_end_forbidden)
473 bool FoundOpen =
false;
475 I = HTMLOpenTags.rbegin(), E = HTMLOpenTags.rend();
477 if ((*I)->getTagName() == TagName) {
483 Diag(HET->
getLocation(), diag::warn_doc_html_end_unbalanced)
489 while (!HTMLOpenTags.empty()) {
491 StringRef LastNotClosedTagName = HST->
getTagName();
492 if (LastNotClosedTagName == TagName) {
499 if (isHTMLEndTagOptional(LastNotClosedTagName))
502 bool OpenLineInvalid;
503 const unsigned OpenLine = SourceMgr.getPresumedLineNumber(
506 bool CloseLineInvalid;
507 const unsigned CloseLine = SourceMgr.getPresumedLineNumber(
511 if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine) {
512 Diag(HST->
getLocation(), diag::warn_doc_html_start_end_mismatch)
517 Diag(HST->
getLocation(), diag::warn_doc_html_start_end_mismatch)
520 Diag(HET->
getLocation(), diag::note_doc_html_end_tag)
532 resolveParamCommandIndexes(FC);
535 while (!HTMLOpenTags.empty()) {
540 Diag(HST->
getLocation(), diag::warn_doc_html_missing_end_tag)
549 if (Traits.getCommandInfo(Command->
getCommandID())->IsEmptyParagraphAllowed)
559 Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
566void Sema::checkReturnsCommand(
const BlockCommandComment *Command) {
567 if (!Traits.getCommandInfo(Command->getCommandID())->IsReturnsCommand)
570 assert(ThisDeclInfo &&
"should not call this check on a bare comment");
574 if (isObjCPropertyDecl())
576 if (involvesFunctionType()) {
578 "should have a valid return type");
588 case Decl::CXXConstructor:
591 case Decl::CXXDestructor:
595 Diag(Command->getLocation(),
596 diag::warn_doc_returns_attached_to_a_void_function)
597 << Command->getCommandMarker()
598 << Command->getCommandName(Traits)
600 << Command->getSourceRange();
605 Diag(Command->getLocation(),
606 diag::warn_doc_returns_not_attached_to_a_function_decl)
607 << Command->getCommandMarker()
608 << Command->getCommandName(Traits)
609 << Command->getSourceRange();
613 const CommandInfo *Info = Traits.getCommandInfo(Command->getCommandID());
614 const BlockCommandComment *PrevCommand =
nullptr;
615 if (Info->IsBriefCommand) {
617 BriefCommand = Command;
620 PrevCommand = BriefCommand;
621 }
else if (Info->IsHeaderfileCommand) {
622 if (!HeaderfileCommand) {
623 HeaderfileCommand = Command;
626 PrevCommand = HeaderfileCommand;
631 StringRef CommandName = Command->getCommandName(Traits);
632 StringRef PrevCommandName = PrevCommand->getCommandName(Traits);
633 Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate)
634 << Command->getCommandMarker()
636 << Command->getSourceRange();
637 if (CommandName == PrevCommandName)
638 Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous)
639 << PrevCommand->getCommandMarker()
641 << PrevCommand->getSourceRange();
643 Diag(PrevCommand->getLocation(),
644 diag::note_doc_block_command_previous_alias)
645 << PrevCommand->getCommandMarker()
651 if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand)
654 assert(ThisDeclInfo &&
"should not call this check on a bare comment");
656 const Decl *D = ThisDeclInfo->CommentDecl;
660 if (D->hasAttr<DeprecatedAttr>() ||
661 D->hasAttr<AvailabilityAttr>() ||
662 D->hasAttr<UnavailableAttr>())
665 Diag(Command->getLocation(), diag::warn_doc_deprecated_not_sync)
666 << Command->getSourceRange() << Command->getCommandMarker();
669 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
672 const DeclContext *Ctx = FD->getDeclContext();
673 if ((!Ctx || !Ctx->isRecord()) &&
674 FD->doesThisDeclarationHaveABody())
677 const LangOptions &LO = FD->getLangOpts();
678 const bool DoubleSquareBracket = LO.CPlusPlus14 || LO.C23;
679 StringRef AttributeSpelling =
680 DoubleSquareBracket ?
"[[deprecated]]" :
"__attribute__((deprecated))";
686 if (DoubleSquareBracket) {
687 TokenValue Tokens[] = {tok::l_square, tok::l_square,
688 PP->getIdentifierInfo(
"deprecated"),
689 tok::r_square, tok::r_square};
690 MacroName = PP->getLastMacroWithSpelling(FD->getLocation(), Tokens);
691 if (!MacroName.empty())
692 AttributeSpelling = MacroName;
695 if (MacroName.empty()) {
696 TokenValue Tokens[] = {
697 tok::kw___attribute, tok::l_paren,
698 tok::l_paren, PP->getIdentifierInfo(
"deprecated"),
699 tok::r_paren, tok::r_paren};
700 StringRef MacroName =
701 PP->getLastMacroWithSpelling(FD->getLocation(), Tokens);
702 if (!MacroName.empty())
703 AttributeSpelling = MacroName;
707 SmallString<64> TextToInsert = AttributeSpelling;
709 SourceLocation Loc = FD->getSourceRange().getBegin();
710 Diag(Loc, diag::note_add_deprecation_attr)
715void Sema::resolveParamCommandIndexes(
const FullComment *FC) {
716 if (!involvesFunctionType()) {
722 SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands;
726 SmallVector<ParamCommandComment *, 8> ParamVarDocs;
728 ArrayRef<const ParmVarDecl *> ParamVars = getParamVars();
729 ParamVarDocs.resize(ParamVars.size(),
nullptr);
734 ParamCommandComment *PCC = dyn_cast<ParamCommandComment>(*I);
735 if (!PCC || !PCC->hasParamName())
737 StringRef ParamName = PCC->getParamNameAsWritten();
740 const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName,
743 PCC->setIsVarArgParam();
747 UnresolvedParamCommands.push_back(PCC);
750 PCC->setParamIndex(ResolvedParamIndex);
751 if (ParamVarDocs[ResolvedParamIndex]) {
752 SourceRange ArgRange = PCC->getParamNameRange();
753 Diag(ArgRange.getBegin(), diag::warn_doc_param_duplicate)
754 << ParamName << ArgRange;
755 ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex];
756 Diag(PrevCommand->getLocation(), diag::note_doc_param_previous)
757 << PrevCommand->getParamNameRange();
759 ParamVarDocs[ResolvedParamIndex] = PCC;
763 SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls;
764 for (
unsigned i = 0, e = ParamVarDocs.size(); i != e; ++i) {
765 if (!ParamVarDocs[i])
766 OrphanedParamDecls.push_back(ParamVars[i]);
772 for (
unsigned i = 0, e = UnresolvedParamCommands.size(); i != e; ++i) {
773 const ParamCommandComment *PCC = UnresolvedParamCommands[i];
775 SourceRange ArgRange = PCC->getParamNameRange();
776 StringRef ParamName = PCC->getParamNameAsWritten();
777 Diag(ArgRange.getBegin(), diag::warn_doc_param_not_found)
778 << ParamName << ArgRange;
781 if (OrphanedParamDecls.size() == 0)
785 if (OrphanedParamDecls.size() == 1) {
788 CorrectedParamIndex = 0;
791 CorrectedParamIndex = correctTypoInParmVarReference(ParamName,
795 const ParmVarDecl *CorrectedPVD = OrphanedParamDecls[CorrectedParamIndex];
796 if (
const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier())
797 Diag(ArgRange.getBegin(), diag::note_doc_param_name_suggestion)
798 << CorrectedII->getName()
804bool Sema::involvesFunctionType() {
807 if (!ThisDeclInfo->IsFilled)
809 return ThisDeclInfo->involvesFunctionType();
812bool Sema::isFunctionDecl() {
815 if (!ThisDeclInfo->IsFilled)
820bool Sema::isAnyFunctionDecl() {
821 return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
825bool Sema::isFunctionOrMethodVariadic() {
828 if (!ThisDeclInfo->IsFilled)
830 return ThisDeclInfo->IsVariadic;
833bool Sema::isObjCMethodDecl() {
834 return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
838bool Sema::isFunctionPointerVarDecl() {
841 if (!ThisDeclInfo->IsFilled)
844 if (
const VarDecl *VD = dyn_cast_or_null<VarDecl>(ThisDeclInfo->CurrentDecl)) {
845 QualType QT = VD->getType();
846 return QT->isFunctionPointerType();
852bool Sema::isObjCPropertyDecl() {
855 if (!ThisDeclInfo->IsFilled)
857 return ThisDeclInfo->CurrentDecl->getKind() == Decl::ObjCProperty;
860bool Sema::isTemplateOrSpecialization() {
863 if (!ThisDeclInfo->IsFilled)
868bool Sema::isExplicitFunctionTemplateInstantiation() {
871 if (!ThisDeclInfo->IsFilled)
873 if (
const auto *FD = dyn_cast<FunctionDecl>(ThisDeclInfo->CurrentDecl)) {
881bool Sema::isRecordLikeDecl() {
884 if (!ThisDeclInfo->IsFilled)
886 return isUnionDecl() || isClassOrStructDecl() || isObjCInterfaceDecl() ||
887 isObjCProtocolDecl();
890bool Sema::isUnionDecl() {
893 if (!ThisDeclInfo->IsFilled)
895 if (
const RecordDecl *RD =
896 dyn_cast_or_null<RecordDecl>(ThisDeclInfo->CurrentDecl))
897 return RD->isUnion();
901 if (
auto *record = dyn_cast_or_null<RecordDecl>(D))
902 return !record->isUnion();
907bool Sema::isClassOrStructDecl() {
919bool Sema::isClassOrStructOrTagTypedefDecl() {
931 if (
auto *ThisTypedefDecl = dyn_cast<TypedefDecl>(ThisDeclInfo->
CurrentDecl))
932 if (
auto *D = ThisTypedefDecl->getUnderlyingType()->getAsRecordDecl())
938bool Sema::isClassTemplateDecl() {
941 if (!ThisDeclInfo->IsFilled)
943 return ThisDeclInfo->CurrentDecl &&
947bool Sema::isFunctionTemplateDecl() {
950 if (!ThisDeclInfo->IsFilled)
952 return ThisDeclInfo->CurrentDecl &&
956bool Sema::isObjCInterfaceDecl() {
959 if (!ThisDeclInfo->IsFilled)
961 return ThisDeclInfo->CurrentDecl &&
965bool Sema::isObjCProtocolDecl() {
968 if (!ThisDeclInfo->IsFilled)
970 return ThisDeclInfo->CurrentDecl &&
974ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
975 if (!ThisDeclInfo->IsFilled)
977 return ThisDeclInfo->ParamVars;
980void Sema::inspectThisDecl() {
981 ThisDeclInfo->fill();
984unsigned Sema::resolveParmVarReference(StringRef Name,
985 ArrayRef<const ParmVarDecl *> ParamVars) {
986 for (
unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
987 const IdentifierInfo *II = ParamVars[i]->getIdentifier();
988 if (II && II->getName() == Name)
991 if (Name ==
"..." && isFunctionOrMethodVariadic())
997Sema::correctTypoInParmVarReference(StringRef Typo,
998 ArrayRef<const ParmVarDecl *> ParamVars) {
999 SimpleTypoCorrection STC(Typo);
1000 for (
unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
1001 const ParmVarDecl *Param = ParamVars[i];
1005 STC.add(Param->getIdentifier());
1008 if (STC.hasCorrection())
1009 return STC.getCorrectionIndex();
1015bool ResolveTParamReferenceHelper(
1017 const TemplateParameterList *TemplateParameters,
1018 SmallVectorImpl<unsigned> *Position) {
1019 for (
unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
1020 const NamedDecl *Param = TemplateParameters->getParam(i);
1021 const IdentifierInfo *II = Param->getIdentifier();
1022 if (II && II->getName() == Name) {
1023 Position->push_back(i);
1027 if (
const TemplateTemplateParmDecl *TTP =
1028 dyn_cast<TemplateTemplateParmDecl>(Param)) {
1029 Position->push_back(i);
1030 if (ResolveTParamReferenceHelper(Name, TTP->getTemplateParameters(),
1033 Position->pop_back();
1040bool Sema::resolveTParamReference(
1042 const TemplateParameterList *TemplateParameters,
1043 SmallVectorImpl<unsigned> *Position) {
1045 if (!TemplateParameters)
1048 return ResolveTParamReferenceHelper(Name, TemplateParameters, Position);
1052void CorrectTypoInTParamReferenceHelper(
1053 const TemplateParameterList *TemplateParameters,
1054 SimpleTypoCorrection &STC) {
1055 for (
unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
1056 const NamedDecl *Param = TemplateParameters->getParam(i);
1060 STC.add(Param->getIdentifier());
1062 if (
const TemplateTemplateParmDecl *TTP =
1063 dyn_cast<TemplateTemplateParmDecl>(Param))
1064 CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(), STC);
1069StringRef Sema::correctTypoInTParamReference(
1071 const TemplateParameterList *TemplateParameters) {
1072 SimpleTypoCorrection STC(Typo);
1073 CorrectTypoInTParamReferenceHelper(TemplateParameters, STC);
1075 if (
auto CorrectedTParamReference = STC.getCorrection())
1076 return *CorrectedTParamReference;
1082 assert(Traits.getCommandInfo(Name)->IsInlineCommand);
1084 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.
Top level wrappers for InstallAPI frontend operations.
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...