1f4a2713aSLionel Sambuc //===--- CommentSema.cpp - Doxygen comment semantic analysis --------------===//
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc // The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc
10f4a2713aSLionel Sambuc #include "clang/AST/CommentSema.h"
11f4a2713aSLionel Sambuc #include "clang/AST/Attr.h"
12f4a2713aSLionel Sambuc #include "clang/AST/CommentCommandTraits.h"
13f4a2713aSLionel Sambuc #include "clang/AST/CommentDiagnostic.h"
14f4a2713aSLionel Sambuc #include "clang/AST/Decl.h"
15f4a2713aSLionel Sambuc #include "clang/AST/DeclTemplate.h"
16f4a2713aSLionel Sambuc #include "clang/Basic/SourceManager.h"
17f4a2713aSLionel Sambuc #include "clang/Lex/Preprocessor.h"
18f4a2713aSLionel Sambuc #include "llvm/ADT/SmallString.h"
19f4a2713aSLionel Sambuc #include "llvm/ADT/StringSwitch.h"
20f4a2713aSLionel Sambuc
21f4a2713aSLionel Sambuc namespace clang {
22f4a2713aSLionel Sambuc namespace comments {
23f4a2713aSLionel Sambuc
24f4a2713aSLionel Sambuc namespace {
25f4a2713aSLionel Sambuc #include "clang/AST/CommentHTMLTagsProperties.inc"
26f4a2713aSLionel Sambuc } // unnamed namespace
27f4a2713aSLionel Sambuc
Sema(llvm::BumpPtrAllocator & Allocator,const SourceManager & SourceMgr,DiagnosticsEngine & Diags,CommandTraits & Traits,const Preprocessor * PP)28f4a2713aSLionel Sambuc Sema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr,
29f4a2713aSLionel Sambuc DiagnosticsEngine &Diags, CommandTraits &Traits,
30f4a2713aSLionel Sambuc const Preprocessor *PP) :
31f4a2713aSLionel Sambuc Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits),
32*0a6a1f1dSLionel Sambuc PP(PP), ThisDeclInfo(nullptr), BriefCommand(nullptr),
33*0a6a1f1dSLionel Sambuc HeaderfileCommand(nullptr) {
34f4a2713aSLionel Sambuc }
35f4a2713aSLionel Sambuc
setDecl(const Decl * D)36f4a2713aSLionel Sambuc void Sema::setDecl(const Decl *D) {
37f4a2713aSLionel Sambuc if (!D)
38f4a2713aSLionel Sambuc return;
39f4a2713aSLionel Sambuc
40f4a2713aSLionel Sambuc ThisDeclInfo = new (Allocator) DeclInfo;
41f4a2713aSLionel Sambuc ThisDeclInfo->CommentDecl = D;
42f4a2713aSLionel Sambuc ThisDeclInfo->IsFilled = false;
43f4a2713aSLionel Sambuc }
44f4a2713aSLionel Sambuc
actOnParagraphComment(ArrayRef<InlineContentComment * > Content)45f4a2713aSLionel Sambuc ParagraphComment *Sema::actOnParagraphComment(
46f4a2713aSLionel Sambuc ArrayRef<InlineContentComment *> Content) {
47f4a2713aSLionel Sambuc return new (Allocator) ParagraphComment(Content);
48f4a2713aSLionel Sambuc }
49f4a2713aSLionel Sambuc
actOnBlockCommandStart(SourceLocation LocBegin,SourceLocation LocEnd,unsigned CommandID,CommandMarkerKind CommandMarker)50f4a2713aSLionel Sambuc BlockCommandComment *Sema::actOnBlockCommandStart(
51f4a2713aSLionel Sambuc SourceLocation LocBegin,
52f4a2713aSLionel Sambuc SourceLocation LocEnd,
53f4a2713aSLionel Sambuc unsigned CommandID,
54f4a2713aSLionel Sambuc CommandMarkerKind CommandMarker) {
55f4a2713aSLionel Sambuc BlockCommandComment *BC = new (Allocator) BlockCommandComment(LocBegin, LocEnd,
56f4a2713aSLionel Sambuc CommandID,
57f4a2713aSLionel Sambuc CommandMarker);
58f4a2713aSLionel Sambuc checkContainerDecl(BC);
59f4a2713aSLionel Sambuc return BC;
60f4a2713aSLionel Sambuc }
61f4a2713aSLionel Sambuc
actOnBlockCommandArgs(BlockCommandComment * Command,ArrayRef<BlockCommandComment::Argument> Args)62f4a2713aSLionel Sambuc void Sema::actOnBlockCommandArgs(BlockCommandComment *Command,
63f4a2713aSLionel Sambuc ArrayRef<BlockCommandComment::Argument> Args) {
64f4a2713aSLionel Sambuc Command->setArgs(Args);
65f4a2713aSLionel Sambuc }
66f4a2713aSLionel Sambuc
actOnBlockCommandFinish(BlockCommandComment * Command,ParagraphComment * Paragraph)67f4a2713aSLionel Sambuc void Sema::actOnBlockCommandFinish(BlockCommandComment *Command,
68f4a2713aSLionel Sambuc ParagraphComment *Paragraph) {
69f4a2713aSLionel Sambuc Command->setParagraph(Paragraph);
70f4a2713aSLionel Sambuc checkBlockCommandEmptyParagraph(Command);
71f4a2713aSLionel Sambuc checkBlockCommandDuplicate(Command);
72*0a6a1f1dSLionel Sambuc if (ThisDeclInfo) {
73*0a6a1f1dSLionel Sambuc // These checks only make sense if the comment is attached to a
74*0a6a1f1dSLionel Sambuc // declaration.
75f4a2713aSLionel Sambuc checkReturnsCommand(Command);
76f4a2713aSLionel Sambuc checkDeprecatedCommand(Command);
77f4a2713aSLionel Sambuc }
78*0a6a1f1dSLionel Sambuc }
79f4a2713aSLionel Sambuc
actOnParamCommandStart(SourceLocation LocBegin,SourceLocation LocEnd,unsigned CommandID,CommandMarkerKind CommandMarker)80f4a2713aSLionel Sambuc ParamCommandComment *Sema::actOnParamCommandStart(
81f4a2713aSLionel Sambuc SourceLocation LocBegin,
82f4a2713aSLionel Sambuc SourceLocation LocEnd,
83f4a2713aSLionel Sambuc unsigned CommandID,
84f4a2713aSLionel Sambuc CommandMarkerKind CommandMarker) {
85f4a2713aSLionel Sambuc ParamCommandComment *Command =
86f4a2713aSLionel Sambuc new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID,
87f4a2713aSLionel Sambuc CommandMarker);
88f4a2713aSLionel Sambuc
89f4a2713aSLionel Sambuc if (!isFunctionDecl())
90f4a2713aSLionel Sambuc Diag(Command->getLocation(),
91f4a2713aSLionel Sambuc diag::warn_doc_param_not_attached_to_a_function_decl)
92f4a2713aSLionel Sambuc << CommandMarker
93f4a2713aSLionel Sambuc << Command->getCommandNameRange(Traits);
94f4a2713aSLionel Sambuc
95f4a2713aSLionel Sambuc return Command;
96f4a2713aSLionel Sambuc }
97f4a2713aSLionel Sambuc
checkFunctionDeclVerbatimLine(const BlockCommandComment * Comment)98f4a2713aSLionel Sambuc void Sema::checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment) {
99f4a2713aSLionel Sambuc const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
100f4a2713aSLionel Sambuc if (!Info->IsFunctionDeclarationCommand)
101f4a2713aSLionel Sambuc return;
102f4a2713aSLionel Sambuc
103f4a2713aSLionel Sambuc unsigned DiagSelect;
104f4a2713aSLionel Sambuc switch (Comment->getCommandID()) {
105f4a2713aSLionel Sambuc case CommandTraits::KCI_function:
106f4a2713aSLionel Sambuc DiagSelect = (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 1 : 0;
107f4a2713aSLionel Sambuc break;
108f4a2713aSLionel Sambuc case CommandTraits::KCI_functiongroup:
109f4a2713aSLionel Sambuc DiagSelect = (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 2 : 0;
110f4a2713aSLionel Sambuc break;
111f4a2713aSLionel Sambuc case CommandTraits::KCI_method:
112f4a2713aSLionel Sambuc DiagSelect = !isObjCMethodDecl() ? 3 : 0;
113f4a2713aSLionel Sambuc break;
114f4a2713aSLionel Sambuc case CommandTraits::KCI_methodgroup:
115f4a2713aSLionel Sambuc DiagSelect = !isObjCMethodDecl() ? 4 : 0;
116f4a2713aSLionel Sambuc break;
117f4a2713aSLionel Sambuc case CommandTraits::KCI_callback:
118f4a2713aSLionel Sambuc DiagSelect = !isFunctionPointerVarDecl() ? 5 : 0;
119f4a2713aSLionel Sambuc break;
120f4a2713aSLionel Sambuc default:
121f4a2713aSLionel Sambuc DiagSelect = 0;
122f4a2713aSLionel Sambuc break;
123f4a2713aSLionel Sambuc }
124f4a2713aSLionel Sambuc if (DiagSelect)
125f4a2713aSLionel Sambuc Diag(Comment->getLocation(), diag::warn_doc_function_method_decl_mismatch)
126f4a2713aSLionel Sambuc << Comment->getCommandMarker()
127f4a2713aSLionel Sambuc << (DiagSelect-1) << (DiagSelect-1)
128f4a2713aSLionel Sambuc << Comment->getSourceRange();
129f4a2713aSLionel Sambuc }
130f4a2713aSLionel Sambuc
checkContainerDeclVerbatimLine(const BlockCommandComment * Comment)131f4a2713aSLionel Sambuc void Sema::checkContainerDeclVerbatimLine(const BlockCommandComment *Comment) {
132f4a2713aSLionel Sambuc const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
133f4a2713aSLionel Sambuc if (!Info->IsRecordLikeDeclarationCommand)
134f4a2713aSLionel Sambuc return;
135f4a2713aSLionel Sambuc unsigned DiagSelect;
136f4a2713aSLionel Sambuc switch (Comment->getCommandID()) {
137f4a2713aSLionel Sambuc case CommandTraits::KCI_class:
138f4a2713aSLionel Sambuc DiagSelect = (!isClassOrStructDecl() && !isClassTemplateDecl()) ? 1 : 0;
139f4a2713aSLionel Sambuc // Allow @class command on @interface declarations.
140f4a2713aSLionel Sambuc // FIXME. Currently, \class and @class are indistinguishable. So,
141f4a2713aSLionel Sambuc // \class is also allowed on an @interface declaration
142f4a2713aSLionel Sambuc if (DiagSelect && Comment->getCommandMarker() && isObjCInterfaceDecl())
143f4a2713aSLionel Sambuc DiagSelect = 0;
144f4a2713aSLionel Sambuc break;
145f4a2713aSLionel Sambuc case CommandTraits::KCI_interface:
146f4a2713aSLionel Sambuc DiagSelect = !isObjCInterfaceDecl() ? 2 : 0;
147f4a2713aSLionel Sambuc break;
148f4a2713aSLionel Sambuc case CommandTraits::KCI_protocol:
149f4a2713aSLionel Sambuc DiagSelect = !isObjCProtocolDecl() ? 3 : 0;
150f4a2713aSLionel Sambuc break;
151f4a2713aSLionel Sambuc case CommandTraits::KCI_struct:
152f4a2713aSLionel Sambuc DiagSelect = !isClassOrStructDecl() ? 4 : 0;
153f4a2713aSLionel Sambuc break;
154f4a2713aSLionel Sambuc case CommandTraits::KCI_union:
155f4a2713aSLionel Sambuc DiagSelect = !isUnionDecl() ? 5 : 0;
156f4a2713aSLionel Sambuc break;
157f4a2713aSLionel Sambuc default:
158f4a2713aSLionel Sambuc DiagSelect = 0;
159f4a2713aSLionel Sambuc break;
160f4a2713aSLionel Sambuc }
161f4a2713aSLionel Sambuc if (DiagSelect)
162f4a2713aSLionel Sambuc Diag(Comment->getLocation(), diag::warn_doc_api_container_decl_mismatch)
163f4a2713aSLionel Sambuc << Comment->getCommandMarker()
164f4a2713aSLionel Sambuc << (DiagSelect-1) << (DiagSelect-1)
165f4a2713aSLionel Sambuc << Comment->getSourceRange();
166f4a2713aSLionel Sambuc }
167f4a2713aSLionel Sambuc
checkContainerDecl(const BlockCommandComment * Comment)168f4a2713aSLionel Sambuc void Sema::checkContainerDecl(const BlockCommandComment *Comment) {
169f4a2713aSLionel Sambuc const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
170f4a2713aSLionel Sambuc if (!Info->IsRecordLikeDetailCommand || isRecordLikeDecl())
171f4a2713aSLionel Sambuc return;
172f4a2713aSLionel Sambuc unsigned DiagSelect;
173f4a2713aSLionel Sambuc switch (Comment->getCommandID()) {
174f4a2713aSLionel Sambuc case CommandTraits::KCI_classdesign:
175f4a2713aSLionel Sambuc DiagSelect = 1;
176f4a2713aSLionel Sambuc break;
177f4a2713aSLionel Sambuc case CommandTraits::KCI_coclass:
178f4a2713aSLionel Sambuc DiagSelect = 2;
179f4a2713aSLionel Sambuc break;
180f4a2713aSLionel Sambuc case CommandTraits::KCI_dependency:
181f4a2713aSLionel Sambuc DiagSelect = 3;
182f4a2713aSLionel Sambuc break;
183f4a2713aSLionel Sambuc case CommandTraits::KCI_helper:
184f4a2713aSLionel Sambuc DiagSelect = 4;
185f4a2713aSLionel Sambuc break;
186f4a2713aSLionel Sambuc case CommandTraits::KCI_helperclass:
187f4a2713aSLionel Sambuc DiagSelect = 5;
188f4a2713aSLionel Sambuc break;
189f4a2713aSLionel Sambuc case CommandTraits::KCI_helps:
190f4a2713aSLionel Sambuc DiagSelect = 6;
191f4a2713aSLionel Sambuc break;
192f4a2713aSLionel Sambuc case CommandTraits::KCI_instancesize:
193f4a2713aSLionel Sambuc DiagSelect = 7;
194f4a2713aSLionel Sambuc break;
195f4a2713aSLionel Sambuc case CommandTraits::KCI_ownership:
196f4a2713aSLionel Sambuc DiagSelect = 8;
197f4a2713aSLionel Sambuc break;
198f4a2713aSLionel Sambuc case CommandTraits::KCI_performance:
199f4a2713aSLionel Sambuc DiagSelect = 9;
200f4a2713aSLionel Sambuc break;
201f4a2713aSLionel Sambuc case CommandTraits::KCI_security:
202f4a2713aSLionel Sambuc DiagSelect = 10;
203f4a2713aSLionel Sambuc break;
204f4a2713aSLionel Sambuc case CommandTraits::KCI_superclass:
205f4a2713aSLionel Sambuc DiagSelect = 11;
206f4a2713aSLionel Sambuc break;
207f4a2713aSLionel Sambuc default:
208f4a2713aSLionel Sambuc DiagSelect = 0;
209f4a2713aSLionel Sambuc break;
210f4a2713aSLionel Sambuc }
211f4a2713aSLionel Sambuc if (DiagSelect)
212f4a2713aSLionel Sambuc Diag(Comment->getLocation(), diag::warn_doc_container_decl_mismatch)
213f4a2713aSLionel Sambuc << Comment->getCommandMarker()
214f4a2713aSLionel Sambuc << (DiagSelect-1)
215f4a2713aSLionel Sambuc << Comment->getSourceRange();
216f4a2713aSLionel Sambuc }
217f4a2713aSLionel Sambuc
218f4a2713aSLionel Sambuc /// \brief Turn a string into the corresponding PassDirection or -1 if it's not
219f4a2713aSLionel Sambuc /// valid.
getParamPassDirection(StringRef Arg)220f4a2713aSLionel Sambuc static int getParamPassDirection(StringRef Arg) {
221f4a2713aSLionel Sambuc return llvm::StringSwitch<int>(Arg)
222f4a2713aSLionel Sambuc .Case("[in]", ParamCommandComment::In)
223f4a2713aSLionel Sambuc .Case("[out]", ParamCommandComment::Out)
224f4a2713aSLionel Sambuc .Cases("[in,out]", "[out,in]", ParamCommandComment::InOut)
225f4a2713aSLionel Sambuc .Default(-1);
226f4a2713aSLionel Sambuc }
227f4a2713aSLionel Sambuc
actOnParamCommandDirectionArg(ParamCommandComment * Command,SourceLocation ArgLocBegin,SourceLocation ArgLocEnd,StringRef Arg)228f4a2713aSLionel Sambuc void Sema::actOnParamCommandDirectionArg(ParamCommandComment *Command,
229f4a2713aSLionel Sambuc SourceLocation ArgLocBegin,
230f4a2713aSLionel Sambuc SourceLocation ArgLocEnd,
231f4a2713aSLionel Sambuc StringRef Arg) {
232f4a2713aSLionel Sambuc std::string ArgLower = Arg.lower();
233f4a2713aSLionel Sambuc int Direction = getParamPassDirection(ArgLower);
234f4a2713aSLionel Sambuc
235f4a2713aSLionel Sambuc if (Direction == -1) {
236f4a2713aSLionel Sambuc // Try again with whitespace removed.
237f4a2713aSLionel Sambuc ArgLower.erase(
238f4a2713aSLionel Sambuc std::remove_if(ArgLower.begin(), ArgLower.end(), clang::isWhitespace),
239f4a2713aSLionel Sambuc ArgLower.end());
240f4a2713aSLionel Sambuc Direction = getParamPassDirection(ArgLower);
241f4a2713aSLionel Sambuc
242f4a2713aSLionel Sambuc SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
243f4a2713aSLionel Sambuc if (Direction != -1) {
244f4a2713aSLionel Sambuc const char *FixedName = ParamCommandComment::getDirectionAsString(
245f4a2713aSLionel Sambuc (ParamCommandComment::PassDirection)Direction);
246f4a2713aSLionel Sambuc Diag(ArgLocBegin, diag::warn_doc_param_spaces_in_direction)
247f4a2713aSLionel Sambuc << ArgRange << FixItHint::CreateReplacement(ArgRange, FixedName);
248f4a2713aSLionel Sambuc } else {
249f4a2713aSLionel Sambuc Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction) << ArgRange;
250f4a2713aSLionel Sambuc Direction = ParamCommandComment::In; // Sane fall back.
251f4a2713aSLionel Sambuc }
252f4a2713aSLionel Sambuc }
253f4a2713aSLionel Sambuc Command->setDirection((ParamCommandComment::PassDirection)Direction,
254f4a2713aSLionel Sambuc /*Explicit=*/true);
255f4a2713aSLionel Sambuc }
256f4a2713aSLionel Sambuc
actOnParamCommandParamNameArg(ParamCommandComment * Command,SourceLocation ArgLocBegin,SourceLocation ArgLocEnd,StringRef Arg)257f4a2713aSLionel Sambuc void Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command,
258f4a2713aSLionel Sambuc SourceLocation ArgLocBegin,
259f4a2713aSLionel Sambuc SourceLocation ArgLocEnd,
260f4a2713aSLionel Sambuc StringRef Arg) {
261f4a2713aSLionel Sambuc // Parser will not feed us more arguments than needed.
262f4a2713aSLionel Sambuc assert(Command->getNumArgs() == 0);
263f4a2713aSLionel Sambuc
264f4a2713aSLionel Sambuc if (!Command->isDirectionExplicit()) {
265f4a2713aSLionel Sambuc // User didn't provide a direction argument.
266f4a2713aSLionel Sambuc Command->setDirection(ParamCommandComment::In, /* Explicit = */ false);
267f4a2713aSLionel Sambuc }
268f4a2713aSLionel Sambuc typedef BlockCommandComment::Argument Argument;
269f4a2713aSLionel Sambuc Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
270f4a2713aSLionel Sambuc ArgLocEnd),
271f4a2713aSLionel Sambuc Arg);
272f4a2713aSLionel Sambuc Command->setArgs(llvm::makeArrayRef(A, 1));
273f4a2713aSLionel Sambuc }
274f4a2713aSLionel Sambuc
actOnParamCommandFinish(ParamCommandComment * Command,ParagraphComment * Paragraph)275f4a2713aSLionel Sambuc void Sema::actOnParamCommandFinish(ParamCommandComment *Command,
276f4a2713aSLionel Sambuc ParagraphComment *Paragraph) {
277f4a2713aSLionel Sambuc Command->setParagraph(Paragraph);
278f4a2713aSLionel Sambuc checkBlockCommandEmptyParagraph(Command);
279f4a2713aSLionel Sambuc }
280f4a2713aSLionel Sambuc
actOnTParamCommandStart(SourceLocation LocBegin,SourceLocation LocEnd,unsigned CommandID,CommandMarkerKind CommandMarker)281f4a2713aSLionel Sambuc TParamCommandComment *Sema::actOnTParamCommandStart(
282f4a2713aSLionel Sambuc SourceLocation LocBegin,
283f4a2713aSLionel Sambuc SourceLocation LocEnd,
284f4a2713aSLionel Sambuc unsigned CommandID,
285f4a2713aSLionel Sambuc CommandMarkerKind CommandMarker) {
286f4a2713aSLionel Sambuc TParamCommandComment *Command =
287f4a2713aSLionel Sambuc new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID,
288f4a2713aSLionel Sambuc CommandMarker);
289f4a2713aSLionel Sambuc
290f4a2713aSLionel Sambuc if (!isTemplateOrSpecialization())
291f4a2713aSLionel Sambuc Diag(Command->getLocation(),
292f4a2713aSLionel Sambuc diag::warn_doc_tparam_not_attached_to_a_template_decl)
293f4a2713aSLionel Sambuc << CommandMarker
294f4a2713aSLionel Sambuc << Command->getCommandNameRange(Traits);
295f4a2713aSLionel Sambuc
296f4a2713aSLionel Sambuc return Command;
297f4a2713aSLionel Sambuc }
298f4a2713aSLionel Sambuc
actOnTParamCommandParamNameArg(TParamCommandComment * Command,SourceLocation ArgLocBegin,SourceLocation ArgLocEnd,StringRef Arg)299f4a2713aSLionel Sambuc void Sema::actOnTParamCommandParamNameArg(TParamCommandComment *Command,
300f4a2713aSLionel Sambuc SourceLocation ArgLocBegin,
301f4a2713aSLionel Sambuc SourceLocation ArgLocEnd,
302f4a2713aSLionel Sambuc StringRef Arg) {
303f4a2713aSLionel Sambuc // Parser will not feed us more arguments than needed.
304f4a2713aSLionel Sambuc assert(Command->getNumArgs() == 0);
305f4a2713aSLionel Sambuc
306f4a2713aSLionel Sambuc typedef BlockCommandComment::Argument Argument;
307f4a2713aSLionel Sambuc Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
308f4a2713aSLionel Sambuc ArgLocEnd),
309f4a2713aSLionel Sambuc Arg);
310f4a2713aSLionel Sambuc Command->setArgs(llvm::makeArrayRef(A, 1));
311f4a2713aSLionel Sambuc
312f4a2713aSLionel Sambuc if (!isTemplateOrSpecialization()) {
313f4a2713aSLionel Sambuc // We already warned that this \\tparam is not attached to a template decl.
314f4a2713aSLionel Sambuc return;
315f4a2713aSLionel Sambuc }
316f4a2713aSLionel Sambuc
317f4a2713aSLionel Sambuc const TemplateParameterList *TemplateParameters =
318f4a2713aSLionel Sambuc ThisDeclInfo->TemplateParameters;
319f4a2713aSLionel Sambuc SmallVector<unsigned, 2> Position;
320f4a2713aSLionel Sambuc if (resolveTParamReference(Arg, TemplateParameters, &Position)) {
321f4a2713aSLionel Sambuc Command->setPosition(copyArray(llvm::makeArrayRef(Position)));
322f4a2713aSLionel Sambuc TParamCommandComment *&PrevCommand = TemplateParameterDocs[Arg];
323f4a2713aSLionel Sambuc if (PrevCommand) {
324f4a2713aSLionel Sambuc SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
325f4a2713aSLionel Sambuc Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate)
326f4a2713aSLionel Sambuc << Arg << ArgRange;
327f4a2713aSLionel Sambuc Diag(PrevCommand->getLocation(), diag::note_doc_tparam_previous)
328f4a2713aSLionel Sambuc << PrevCommand->getParamNameRange();
329f4a2713aSLionel Sambuc }
330f4a2713aSLionel Sambuc PrevCommand = Command;
331f4a2713aSLionel Sambuc return;
332f4a2713aSLionel Sambuc }
333f4a2713aSLionel Sambuc
334f4a2713aSLionel Sambuc SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
335f4a2713aSLionel Sambuc Diag(ArgLocBegin, diag::warn_doc_tparam_not_found)
336f4a2713aSLionel Sambuc << Arg << ArgRange;
337f4a2713aSLionel Sambuc
338f4a2713aSLionel Sambuc if (!TemplateParameters || TemplateParameters->size() == 0)
339f4a2713aSLionel Sambuc return;
340f4a2713aSLionel Sambuc
341f4a2713aSLionel Sambuc StringRef CorrectedName;
342f4a2713aSLionel Sambuc if (TemplateParameters->size() == 1) {
343f4a2713aSLionel Sambuc const NamedDecl *Param = TemplateParameters->getParam(0);
344f4a2713aSLionel Sambuc const IdentifierInfo *II = Param->getIdentifier();
345f4a2713aSLionel Sambuc if (II)
346f4a2713aSLionel Sambuc CorrectedName = II->getName();
347f4a2713aSLionel Sambuc } else {
348f4a2713aSLionel Sambuc CorrectedName = correctTypoInTParamReference(Arg, TemplateParameters);
349f4a2713aSLionel Sambuc }
350f4a2713aSLionel Sambuc
351f4a2713aSLionel Sambuc if (!CorrectedName.empty()) {
352f4a2713aSLionel Sambuc Diag(ArgLocBegin, diag::note_doc_tparam_name_suggestion)
353f4a2713aSLionel Sambuc << CorrectedName
354f4a2713aSLionel Sambuc << FixItHint::CreateReplacement(ArgRange, CorrectedName);
355f4a2713aSLionel Sambuc }
356f4a2713aSLionel Sambuc
357f4a2713aSLionel Sambuc return;
358f4a2713aSLionel Sambuc }
359f4a2713aSLionel Sambuc
actOnTParamCommandFinish(TParamCommandComment * Command,ParagraphComment * Paragraph)360f4a2713aSLionel Sambuc void Sema::actOnTParamCommandFinish(TParamCommandComment *Command,
361f4a2713aSLionel Sambuc ParagraphComment *Paragraph) {
362f4a2713aSLionel Sambuc Command->setParagraph(Paragraph);
363f4a2713aSLionel Sambuc checkBlockCommandEmptyParagraph(Command);
364f4a2713aSLionel Sambuc }
365f4a2713aSLionel Sambuc
actOnInlineCommand(SourceLocation CommandLocBegin,SourceLocation CommandLocEnd,unsigned CommandID)366f4a2713aSLionel Sambuc InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
367f4a2713aSLionel Sambuc SourceLocation CommandLocEnd,
368f4a2713aSLionel Sambuc unsigned CommandID) {
369f4a2713aSLionel Sambuc ArrayRef<InlineCommandComment::Argument> Args;
370f4a2713aSLionel Sambuc StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
371f4a2713aSLionel Sambuc return new (Allocator) InlineCommandComment(
372f4a2713aSLionel Sambuc CommandLocBegin,
373f4a2713aSLionel Sambuc CommandLocEnd,
374f4a2713aSLionel Sambuc CommandID,
375f4a2713aSLionel Sambuc getInlineCommandRenderKind(CommandName),
376f4a2713aSLionel Sambuc Args);
377f4a2713aSLionel Sambuc }
378f4a2713aSLionel Sambuc
actOnInlineCommand(SourceLocation CommandLocBegin,SourceLocation CommandLocEnd,unsigned CommandID,SourceLocation ArgLocBegin,SourceLocation ArgLocEnd,StringRef Arg)379f4a2713aSLionel Sambuc InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
380f4a2713aSLionel Sambuc SourceLocation CommandLocEnd,
381f4a2713aSLionel Sambuc unsigned CommandID,
382f4a2713aSLionel Sambuc SourceLocation ArgLocBegin,
383f4a2713aSLionel Sambuc SourceLocation ArgLocEnd,
384f4a2713aSLionel Sambuc StringRef Arg) {
385f4a2713aSLionel Sambuc typedef InlineCommandComment::Argument Argument;
386f4a2713aSLionel Sambuc Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
387f4a2713aSLionel Sambuc ArgLocEnd),
388f4a2713aSLionel Sambuc Arg);
389f4a2713aSLionel Sambuc StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
390f4a2713aSLionel Sambuc
391f4a2713aSLionel Sambuc return new (Allocator) InlineCommandComment(
392f4a2713aSLionel Sambuc CommandLocBegin,
393f4a2713aSLionel Sambuc CommandLocEnd,
394f4a2713aSLionel Sambuc CommandID,
395f4a2713aSLionel Sambuc getInlineCommandRenderKind(CommandName),
396f4a2713aSLionel Sambuc llvm::makeArrayRef(A, 1));
397f4a2713aSLionel Sambuc }
398f4a2713aSLionel Sambuc
actOnUnknownCommand(SourceLocation LocBegin,SourceLocation LocEnd,StringRef CommandName)399f4a2713aSLionel Sambuc InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
400f4a2713aSLionel Sambuc SourceLocation LocEnd,
401f4a2713aSLionel Sambuc StringRef CommandName) {
402f4a2713aSLionel Sambuc unsigned CommandID = Traits.registerUnknownCommand(CommandName)->getID();
403f4a2713aSLionel Sambuc return actOnUnknownCommand(LocBegin, LocEnd, CommandID);
404f4a2713aSLionel Sambuc }
405f4a2713aSLionel Sambuc
actOnUnknownCommand(SourceLocation LocBegin,SourceLocation LocEnd,unsigned CommandID)406f4a2713aSLionel Sambuc InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
407f4a2713aSLionel Sambuc SourceLocation LocEnd,
408f4a2713aSLionel Sambuc unsigned CommandID) {
409f4a2713aSLionel Sambuc ArrayRef<InlineCommandComment::Argument> Args;
410f4a2713aSLionel Sambuc return new (Allocator) InlineCommandComment(
411f4a2713aSLionel Sambuc LocBegin, LocEnd, CommandID,
412f4a2713aSLionel Sambuc InlineCommandComment::RenderNormal,
413f4a2713aSLionel Sambuc Args);
414f4a2713aSLionel Sambuc }
415f4a2713aSLionel Sambuc
actOnText(SourceLocation LocBegin,SourceLocation LocEnd,StringRef Text)416f4a2713aSLionel Sambuc TextComment *Sema::actOnText(SourceLocation LocBegin,
417f4a2713aSLionel Sambuc SourceLocation LocEnd,
418f4a2713aSLionel Sambuc StringRef Text) {
419f4a2713aSLionel Sambuc return new (Allocator) TextComment(LocBegin, LocEnd, Text);
420f4a2713aSLionel Sambuc }
421f4a2713aSLionel Sambuc
actOnVerbatimBlockStart(SourceLocation Loc,unsigned CommandID)422f4a2713aSLionel Sambuc VerbatimBlockComment *Sema::actOnVerbatimBlockStart(SourceLocation Loc,
423f4a2713aSLionel Sambuc unsigned CommandID) {
424f4a2713aSLionel Sambuc StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
425f4a2713aSLionel Sambuc return new (Allocator) VerbatimBlockComment(
426f4a2713aSLionel Sambuc Loc,
427f4a2713aSLionel Sambuc Loc.getLocWithOffset(1 + CommandName.size()),
428f4a2713aSLionel Sambuc CommandID);
429f4a2713aSLionel Sambuc }
430f4a2713aSLionel Sambuc
actOnVerbatimBlockLine(SourceLocation Loc,StringRef Text)431f4a2713aSLionel Sambuc VerbatimBlockLineComment *Sema::actOnVerbatimBlockLine(SourceLocation Loc,
432f4a2713aSLionel Sambuc StringRef Text) {
433f4a2713aSLionel Sambuc return new (Allocator) VerbatimBlockLineComment(Loc, Text);
434f4a2713aSLionel Sambuc }
435f4a2713aSLionel Sambuc
actOnVerbatimBlockFinish(VerbatimBlockComment * Block,SourceLocation CloseNameLocBegin,StringRef CloseName,ArrayRef<VerbatimBlockLineComment * > Lines)436f4a2713aSLionel Sambuc void Sema::actOnVerbatimBlockFinish(
437f4a2713aSLionel Sambuc VerbatimBlockComment *Block,
438f4a2713aSLionel Sambuc SourceLocation CloseNameLocBegin,
439f4a2713aSLionel Sambuc StringRef CloseName,
440f4a2713aSLionel Sambuc ArrayRef<VerbatimBlockLineComment *> Lines) {
441f4a2713aSLionel Sambuc Block->setCloseName(CloseName, CloseNameLocBegin);
442f4a2713aSLionel Sambuc Block->setLines(Lines);
443f4a2713aSLionel Sambuc }
444f4a2713aSLionel Sambuc
actOnVerbatimLine(SourceLocation LocBegin,unsigned CommandID,SourceLocation TextBegin,StringRef Text)445f4a2713aSLionel Sambuc VerbatimLineComment *Sema::actOnVerbatimLine(SourceLocation LocBegin,
446f4a2713aSLionel Sambuc unsigned CommandID,
447f4a2713aSLionel Sambuc SourceLocation TextBegin,
448f4a2713aSLionel Sambuc StringRef Text) {
449f4a2713aSLionel Sambuc VerbatimLineComment *VL = new (Allocator) VerbatimLineComment(
450f4a2713aSLionel Sambuc LocBegin,
451f4a2713aSLionel Sambuc TextBegin.getLocWithOffset(Text.size()),
452f4a2713aSLionel Sambuc CommandID,
453f4a2713aSLionel Sambuc TextBegin,
454f4a2713aSLionel Sambuc Text);
455f4a2713aSLionel Sambuc checkFunctionDeclVerbatimLine(VL);
456f4a2713aSLionel Sambuc checkContainerDeclVerbatimLine(VL);
457f4a2713aSLionel Sambuc return VL;
458f4a2713aSLionel Sambuc }
459f4a2713aSLionel Sambuc
actOnHTMLStartTagStart(SourceLocation LocBegin,StringRef TagName)460f4a2713aSLionel Sambuc HTMLStartTagComment *Sema::actOnHTMLStartTagStart(SourceLocation LocBegin,
461f4a2713aSLionel Sambuc StringRef TagName) {
462f4a2713aSLionel Sambuc return new (Allocator) HTMLStartTagComment(LocBegin, TagName);
463f4a2713aSLionel Sambuc }
464f4a2713aSLionel Sambuc
actOnHTMLStartTagFinish(HTMLStartTagComment * Tag,ArrayRef<HTMLStartTagComment::Attribute> Attrs,SourceLocation GreaterLoc,bool IsSelfClosing)465f4a2713aSLionel Sambuc void Sema::actOnHTMLStartTagFinish(
466f4a2713aSLionel Sambuc HTMLStartTagComment *Tag,
467f4a2713aSLionel Sambuc ArrayRef<HTMLStartTagComment::Attribute> Attrs,
468f4a2713aSLionel Sambuc SourceLocation GreaterLoc,
469f4a2713aSLionel Sambuc bool IsSelfClosing) {
470f4a2713aSLionel Sambuc Tag->setAttrs(Attrs);
471f4a2713aSLionel Sambuc Tag->setGreaterLoc(GreaterLoc);
472f4a2713aSLionel Sambuc if (IsSelfClosing)
473f4a2713aSLionel Sambuc Tag->setSelfClosing();
474f4a2713aSLionel Sambuc else if (!isHTMLEndTagForbidden(Tag->getTagName()))
475f4a2713aSLionel Sambuc HTMLOpenTags.push_back(Tag);
476f4a2713aSLionel Sambuc }
477f4a2713aSLionel Sambuc
actOnHTMLEndTag(SourceLocation LocBegin,SourceLocation LocEnd,StringRef TagName)478f4a2713aSLionel Sambuc HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin,
479f4a2713aSLionel Sambuc SourceLocation LocEnd,
480f4a2713aSLionel Sambuc StringRef TagName) {
481f4a2713aSLionel Sambuc HTMLEndTagComment *HET =
482f4a2713aSLionel Sambuc new (Allocator) HTMLEndTagComment(LocBegin, LocEnd, TagName);
483f4a2713aSLionel Sambuc if (isHTMLEndTagForbidden(TagName)) {
484f4a2713aSLionel Sambuc Diag(HET->getLocation(), diag::warn_doc_html_end_forbidden)
485f4a2713aSLionel Sambuc << TagName << HET->getSourceRange();
486*0a6a1f1dSLionel Sambuc HET->setIsMalformed();
487f4a2713aSLionel Sambuc return HET;
488f4a2713aSLionel Sambuc }
489f4a2713aSLionel Sambuc
490f4a2713aSLionel Sambuc bool FoundOpen = false;
491f4a2713aSLionel Sambuc for (SmallVectorImpl<HTMLStartTagComment *>::const_reverse_iterator
492f4a2713aSLionel Sambuc I = HTMLOpenTags.rbegin(), E = HTMLOpenTags.rend();
493f4a2713aSLionel Sambuc I != E; ++I) {
494f4a2713aSLionel Sambuc if ((*I)->getTagName() == TagName) {
495f4a2713aSLionel Sambuc FoundOpen = true;
496f4a2713aSLionel Sambuc break;
497f4a2713aSLionel Sambuc }
498f4a2713aSLionel Sambuc }
499f4a2713aSLionel Sambuc if (!FoundOpen) {
500f4a2713aSLionel Sambuc Diag(HET->getLocation(), diag::warn_doc_html_end_unbalanced)
501f4a2713aSLionel Sambuc << HET->getSourceRange();
502*0a6a1f1dSLionel Sambuc HET->setIsMalformed();
503f4a2713aSLionel Sambuc return HET;
504f4a2713aSLionel Sambuc }
505f4a2713aSLionel Sambuc
506f4a2713aSLionel Sambuc while (!HTMLOpenTags.empty()) {
507*0a6a1f1dSLionel Sambuc HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
508f4a2713aSLionel Sambuc StringRef LastNotClosedTagName = HST->getTagName();
509*0a6a1f1dSLionel Sambuc if (LastNotClosedTagName == TagName) {
510*0a6a1f1dSLionel Sambuc // If the start tag is malformed, end tag is malformed as well.
511*0a6a1f1dSLionel Sambuc if (HST->isMalformed())
512*0a6a1f1dSLionel Sambuc HET->setIsMalformed();
513f4a2713aSLionel Sambuc break;
514*0a6a1f1dSLionel Sambuc }
515f4a2713aSLionel Sambuc
516f4a2713aSLionel Sambuc if (isHTMLEndTagOptional(LastNotClosedTagName))
517f4a2713aSLionel Sambuc continue;
518f4a2713aSLionel Sambuc
519f4a2713aSLionel Sambuc bool OpenLineInvalid;
520f4a2713aSLionel Sambuc const unsigned OpenLine = SourceMgr.getPresumedLineNumber(
521f4a2713aSLionel Sambuc HST->getLocation(),
522f4a2713aSLionel Sambuc &OpenLineInvalid);
523f4a2713aSLionel Sambuc bool CloseLineInvalid;
524f4a2713aSLionel Sambuc const unsigned CloseLine = SourceMgr.getPresumedLineNumber(
525f4a2713aSLionel Sambuc HET->getLocation(),
526f4a2713aSLionel Sambuc &CloseLineInvalid);
527f4a2713aSLionel Sambuc
528*0a6a1f1dSLionel Sambuc if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine) {
529f4a2713aSLionel Sambuc Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
530f4a2713aSLionel Sambuc << HST->getTagName() << HET->getTagName()
531f4a2713aSLionel Sambuc << HST->getSourceRange() << HET->getSourceRange();
532*0a6a1f1dSLionel Sambuc HST->setIsMalformed();
533*0a6a1f1dSLionel Sambuc } else {
534f4a2713aSLionel Sambuc Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
535f4a2713aSLionel Sambuc << HST->getTagName() << HET->getTagName()
536f4a2713aSLionel Sambuc << HST->getSourceRange();
537f4a2713aSLionel Sambuc Diag(HET->getLocation(), diag::note_doc_html_end_tag)
538f4a2713aSLionel Sambuc << HET->getSourceRange();
539*0a6a1f1dSLionel Sambuc HST->setIsMalformed();
540f4a2713aSLionel Sambuc }
541f4a2713aSLionel Sambuc }
542f4a2713aSLionel Sambuc
543f4a2713aSLionel Sambuc return HET;
544f4a2713aSLionel Sambuc }
545f4a2713aSLionel Sambuc
actOnFullComment(ArrayRef<BlockContentComment * > Blocks)546f4a2713aSLionel Sambuc FullComment *Sema::actOnFullComment(
547f4a2713aSLionel Sambuc ArrayRef<BlockContentComment *> Blocks) {
548f4a2713aSLionel Sambuc FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo);
549f4a2713aSLionel Sambuc resolveParamCommandIndexes(FC);
550*0a6a1f1dSLionel Sambuc
551*0a6a1f1dSLionel Sambuc // Complain about HTML tags that are not closed.
552*0a6a1f1dSLionel Sambuc while (!HTMLOpenTags.empty()) {
553*0a6a1f1dSLionel Sambuc HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
554*0a6a1f1dSLionel Sambuc if (isHTMLEndTagOptional(HST->getTagName()))
555*0a6a1f1dSLionel Sambuc continue;
556*0a6a1f1dSLionel Sambuc
557*0a6a1f1dSLionel Sambuc Diag(HST->getLocation(), diag::warn_doc_html_missing_end_tag)
558*0a6a1f1dSLionel Sambuc << HST->getTagName() << HST->getSourceRange();
559*0a6a1f1dSLionel Sambuc HST->setIsMalformed();
560*0a6a1f1dSLionel Sambuc }
561*0a6a1f1dSLionel Sambuc
562f4a2713aSLionel Sambuc return FC;
563f4a2713aSLionel Sambuc }
564f4a2713aSLionel Sambuc
checkBlockCommandEmptyParagraph(BlockCommandComment * Command)565f4a2713aSLionel Sambuc void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) {
566f4a2713aSLionel Sambuc if (Traits.getCommandInfo(Command->getCommandID())->IsEmptyParagraphAllowed)
567f4a2713aSLionel Sambuc return;
568f4a2713aSLionel Sambuc
569f4a2713aSLionel Sambuc ParagraphComment *Paragraph = Command->getParagraph();
570f4a2713aSLionel Sambuc if (Paragraph->isWhitespace()) {
571f4a2713aSLionel Sambuc SourceLocation DiagLoc;
572f4a2713aSLionel Sambuc if (Command->getNumArgs() > 0)
573f4a2713aSLionel Sambuc DiagLoc = Command->getArgRange(Command->getNumArgs() - 1).getEnd();
574f4a2713aSLionel Sambuc if (!DiagLoc.isValid())
575f4a2713aSLionel Sambuc DiagLoc = Command->getCommandNameRange(Traits).getEnd();
576f4a2713aSLionel Sambuc Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
577f4a2713aSLionel Sambuc << Command->getCommandMarker()
578f4a2713aSLionel Sambuc << Command->getCommandName(Traits)
579f4a2713aSLionel Sambuc << Command->getSourceRange();
580f4a2713aSLionel Sambuc }
581f4a2713aSLionel Sambuc }
582f4a2713aSLionel Sambuc
checkReturnsCommand(const BlockCommandComment * Command)583f4a2713aSLionel Sambuc void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
584f4a2713aSLionel Sambuc if (!Traits.getCommandInfo(Command->getCommandID())->IsReturnsCommand)
585f4a2713aSLionel Sambuc return;
586*0a6a1f1dSLionel Sambuc
587*0a6a1f1dSLionel Sambuc assert(ThisDeclInfo && "should not call this check on a bare comment");
588*0a6a1f1dSLionel Sambuc
589f4a2713aSLionel Sambuc if (isFunctionDecl()) {
590*0a6a1f1dSLionel Sambuc if (ThisDeclInfo->ReturnType->isVoidType()) {
591f4a2713aSLionel Sambuc unsigned DiagKind;
592f4a2713aSLionel Sambuc switch (ThisDeclInfo->CommentDecl->getKind()) {
593f4a2713aSLionel Sambuc default:
594f4a2713aSLionel Sambuc if (ThisDeclInfo->IsObjCMethod)
595f4a2713aSLionel Sambuc DiagKind = 3;
596f4a2713aSLionel Sambuc else
597f4a2713aSLionel Sambuc DiagKind = 0;
598f4a2713aSLionel Sambuc break;
599f4a2713aSLionel Sambuc case Decl::CXXConstructor:
600f4a2713aSLionel Sambuc DiagKind = 1;
601f4a2713aSLionel Sambuc break;
602f4a2713aSLionel Sambuc case Decl::CXXDestructor:
603f4a2713aSLionel Sambuc DiagKind = 2;
604f4a2713aSLionel Sambuc break;
605f4a2713aSLionel Sambuc }
606f4a2713aSLionel Sambuc Diag(Command->getLocation(),
607f4a2713aSLionel Sambuc diag::warn_doc_returns_attached_to_a_void_function)
608f4a2713aSLionel Sambuc << Command->getCommandMarker()
609f4a2713aSLionel Sambuc << Command->getCommandName(Traits)
610f4a2713aSLionel Sambuc << DiagKind
611f4a2713aSLionel Sambuc << Command->getSourceRange();
612f4a2713aSLionel Sambuc }
613f4a2713aSLionel Sambuc return;
614f4a2713aSLionel Sambuc }
615f4a2713aSLionel Sambuc else if (isObjCPropertyDecl())
616f4a2713aSLionel Sambuc return;
617f4a2713aSLionel Sambuc
618f4a2713aSLionel Sambuc Diag(Command->getLocation(),
619f4a2713aSLionel Sambuc diag::warn_doc_returns_not_attached_to_a_function_decl)
620f4a2713aSLionel Sambuc << Command->getCommandMarker()
621f4a2713aSLionel Sambuc << Command->getCommandName(Traits)
622f4a2713aSLionel Sambuc << Command->getSourceRange();
623f4a2713aSLionel Sambuc }
624f4a2713aSLionel Sambuc
checkBlockCommandDuplicate(const BlockCommandComment * Command)625f4a2713aSLionel Sambuc void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) {
626f4a2713aSLionel Sambuc const CommandInfo *Info = Traits.getCommandInfo(Command->getCommandID());
627*0a6a1f1dSLionel Sambuc const BlockCommandComment *PrevCommand = nullptr;
628f4a2713aSLionel Sambuc if (Info->IsBriefCommand) {
629f4a2713aSLionel Sambuc if (!BriefCommand) {
630f4a2713aSLionel Sambuc BriefCommand = Command;
631f4a2713aSLionel Sambuc return;
632f4a2713aSLionel Sambuc }
633f4a2713aSLionel Sambuc PrevCommand = BriefCommand;
634f4a2713aSLionel Sambuc } else if (Info->IsHeaderfileCommand) {
635f4a2713aSLionel Sambuc if (!HeaderfileCommand) {
636f4a2713aSLionel Sambuc HeaderfileCommand = Command;
637f4a2713aSLionel Sambuc return;
638f4a2713aSLionel Sambuc }
639f4a2713aSLionel Sambuc PrevCommand = HeaderfileCommand;
640f4a2713aSLionel Sambuc } else {
641f4a2713aSLionel Sambuc // We don't want to check this command for duplicates.
642f4a2713aSLionel Sambuc return;
643f4a2713aSLionel Sambuc }
644f4a2713aSLionel Sambuc StringRef CommandName = Command->getCommandName(Traits);
645f4a2713aSLionel Sambuc StringRef PrevCommandName = PrevCommand->getCommandName(Traits);
646f4a2713aSLionel Sambuc Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate)
647f4a2713aSLionel Sambuc << Command->getCommandMarker()
648f4a2713aSLionel Sambuc << CommandName
649f4a2713aSLionel Sambuc << Command->getSourceRange();
650f4a2713aSLionel Sambuc if (CommandName == PrevCommandName)
651f4a2713aSLionel Sambuc Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous)
652f4a2713aSLionel Sambuc << PrevCommand->getCommandMarker()
653f4a2713aSLionel Sambuc << PrevCommandName
654f4a2713aSLionel Sambuc << PrevCommand->getSourceRange();
655f4a2713aSLionel Sambuc else
656f4a2713aSLionel Sambuc Diag(PrevCommand->getLocation(),
657f4a2713aSLionel Sambuc diag::note_doc_block_command_previous_alias)
658f4a2713aSLionel Sambuc << PrevCommand->getCommandMarker()
659f4a2713aSLionel Sambuc << PrevCommandName
660f4a2713aSLionel Sambuc << CommandName;
661f4a2713aSLionel Sambuc }
662f4a2713aSLionel Sambuc
checkDeprecatedCommand(const BlockCommandComment * Command)663f4a2713aSLionel Sambuc void Sema::checkDeprecatedCommand(const BlockCommandComment *Command) {
664f4a2713aSLionel Sambuc if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand)
665f4a2713aSLionel Sambuc return;
666f4a2713aSLionel Sambuc
667*0a6a1f1dSLionel Sambuc assert(ThisDeclInfo && "should not call this check on a bare comment");
668*0a6a1f1dSLionel Sambuc
669f4a2713aSLionel Sambuc const Decl *D = ThisDeclInfo->CommentDecl;
670f4a2713aSLionel Sambuc if (!D)
671f4a2713aSLionel Sambuc return;
672f4a2713aSLionel Sambuc
673f4a2713aSLionel Sambuc if (D->hasAttr<DeprecatedAttr>() ||
674f4a2713aSLionel Sambuc D->hasAttr<AvailabilityAttr>() ||
675f4a2713aSLionel Sambuc D->hasAttr<UnavailableAttr>())
676f4a2713aSLionel Sambuc return;
677f4a2713aSLionel Sambuc
678f4a2713aSLionel Sambuc Diag(Command->getLocation(),
679f4a2713aSLionel Sambuc diag::warn_doc_deprecated_not_sync)
680f4a2713aSLionel Sambuc << Command->getSourceRange();
681f4a2713aSLionel Sambuc
682f4a2713aSLionel Sambuc // Try to emit a fixit with a deprecation attribute.
683f4a2713aSLionel Sambuc if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
684f4a2713aSLionel Sambuc // Don't emit a Fix-It for non-member function definitions. GCC does not
685f4a2713aSLionel Sambuc // accept attributes on them.
686f4a2713aSLionel Sambuc const DeclContext *Ctx = FD->getDeclContext();
687f4a2713aSLionel Sambuc if ((!Ctx || !Ctx->isRecord()) &&
688f4a2713aSLionel Sambuc FD->doesThisDeclarationHaveABody())
689f4a2713aSLionel Sambuc return;
690f4a2713aSLionel Sambuc
691f4a2713aSLionel Sambuc StringRef AttributeSpelling = "__attribute__((deprecated))";
692f4a2713aSLionel Sambuc if (PP) {
693f4a2713aSLionel Sambuc TokenValue Tokens[] = {
694f4a2713aSLionel Sambuc tok::kw___attribute, tok::l_paren, tok::l_paren,
695f4a2713aSLionel Sambuc PP->getIdentifierInfo("deprecated"),
696f4a2713aSLionel Sambuc tok::r_paren, tok::r_paren
697f4a2713aSLionel Sambuc };
698f4a2713aSLionel Sambuc StringRef MacroName = PP->getLastMacroWithSpelling(FD->getLocation(),
699f4a2713aSLionel Sambuc Tokens);
700f4a2713aSLionel Sambuc if (!MacroName.empty())
701f4a2713aSLionel Sambuc AttributeSpelling = MacroName;
702f4a2713aSLionel Sambuc }
703f4a2713aSLionel Sambuc
704f4a2713aSLionel Sambuc SmallString<64> TextToInsert(" ");
705f4a2713aSLionel Sambuc TextToInsert += AttributeSpelling;
706f4a2713aSLionel Sambuc Diag(FD->getLocEnd(),
707f4a2713aSLionel Sambuc diag::note_add_deprecation_attr)
708f4a2713aSLionel Sambuc << FixItHint::CreateInsertion(FD->getLocEnd().getLocWithOffset(1),
709f4a2713aSLionel Sambuc TextToInsert);
710f4a2713aSLionel Sambuc }
711f4a2713aSLionel Sambuc }
712f4a2713aSLionel Sambuc
resolveParamCommandIndexes(const FullComment * FC)713f4a2713aSLionel Sambuc void Sema::resolveParamCommandIndexes(const FullComment *FC) {
714f4a2713aSLionel Sambuc if (!isFunctionDecl()) {
715f4a2713aSLionel Sambuc // We already warned that \\param commands are not attached to a function
716f4a2713aSLionel Sambuc // decl.
717f4a2713aSLionel Sambuc return;
718f4a2713aSLionel Sambuc }
719f4a2713aSLionel Sambuc
720f4a2713aSLionel Sambuc SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands;
721f4a2713aSLionel Sambuc
722f4a2713aSLionel Sambuc // Comment AST nodes that correspond to \c ParamVars for which we have
723f4a2713aSLionel Sambuc // found a \\param command or NULL if no documentation was found so far.
724f4a2713aSLionel Sambuc SmallVector<ParamCommandComment *, 8> ParamVarDocs;
725f4a2713aSLionel Sambuc
726f4a2713aSLionel Sambuc ArrayRef<const ParmVarDecl *> ParamVars = getParamVars();
727*0a6a1f1dSLionel Sambuc ParamVarDocs.resize(ParamVars.size(), nullptr);
728f4a2713aSLionel Sambuc
729f4a2713aSLionel Sambuc // First pass over all \\param commands: resolve all parameter names.
730f4a2713aSLionel Sambuc for (Comment::child_iterator I = FC->child_begin(), E = FC->child_end();
731f4a2713aSLionel Sambuc I != E; ++I) {
732f4a2713aSLionel Sambuc ParamCommandComment *PCC = dyn_cast<ParamCommandComment>(*I);
733f4a2713aSLionel Sambuc if (!PCC || !PCC->hasParamName())
734f4a2713aSLionel Sambuc continue;
735f4a2713aSLionel Sambuc StringRef ParamName = PCC->getParamNameAsWritten();
736f4a2713aSLionel Sambuc
737f4a2713aSLionel Sambuc // Check that referenced parameter name is in the function decl.
738f4a2713aSLionel Sambuc const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName,
739f4a2713aSLionel Sambuc ParamVars);
740f4a2713aSLionel Sambuc if (ResolvedParamIndex == ParamCommandComment::VarArgParamIndex) {
741f4a2713aSLionel Sambuc PCC->setIsVarArgParam();
742f4a2713aSLionel Sambuc continue;
743f4a2713aSLionel Sambuc }
744f4a2713aSLionel Sambuc if (ResolvedParamIndex == ParamCommandComment::InvalidParamIndex) {
745f4a2713aSLionel Sambuc UnresolvedParamCommands.push_back(PCC);
746f4a2713aSLionel Sambuc continue;
747f4a2713aSLionel Sambuc }
748f4a2713aSLionel Sambuc PCC->setParamIndex(ResolvedParamIndex);
749f4a2713aSLionel Sambuc if (ParamVarDocs[ResolvedParamIndex]) {
750f4a2713aSLionel Sambuc SourceRange ArgRange = PCC->getParamNameRange();
751f4a2713aSLionel Sambuc Diag(ArgRange.getBegin(), diag::warn_doc_param_duplicate)
752f4a2713aSLionel Sambuc << ParamName << ArgRange;
753f4a2713aSLionel Sambuc ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex];
754f4a2713aSLionel Sambuc Diag(PrevCommand->getLocation(), diag::note_doc_param_previous)
755f4a2713aSLionel Sambuc << PrevCommand->getParamNameRange();
756f4a2713aSLionel Sambuc }
757f4a2713aSLionel Sambuc ParamVarDocs[ResolvedParamIndex] = PCC;
758f4a2713aSLionel Sambuc }
759f4a2713aSLionel Sambuc
760f4a2713aSLionel Sambuc // Find parameter declarations that have no corresponding \\param.
761f4a2713aSLionel Sambuc SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls;
762f4a2713aSLionel Sambuc for (unsigned i = 0, e = ParamVarDocs.size(); i != e; ++i) {
763f4a2713aSLionel Sambuc if (!ParamVarDocs[i])
764f4a2713aSLionel Sambuc OrphanedParamDecls.push_back(ParamVars[i]);
765f4a2713aSLionel Sambuc }
766f4a2713aSLionel Sambuc
767f4a2713aSLionel Sambuc // Second pass over unresolved \\param commands: do typo correction.
768f4a2713aSLionel Sambuc // Suggest corrections from a set of parameter declarations that have no
769f4a2713aSLionel Sambuc // corresponding \\param.
770f4a2713aSLionel Sambuc for (unsigned i = 0, e = UnresolvedParamCommands.size(); i != e; ++i) {
771f4a2713aSLionel Sambuc const ParamCommandComment *PCC = UnresolvedParamCommands[i];
772f4a2713aSLionel Sambuc
773f4a2713aSLionel Sambuc SourceRange ArgRange = PCC->getParamNameRange();
774f4a2713aSLionel Sambuc StringRef ParamName = PCC->getParamNameAsWritten();
775f4a2713aSLionel Sambuc Diag(ArgRange.getBegin(), diag::warn_doc_param_not_found)
776f4a2713aSLionel Sambuc << ParamName << ArgRange;
777f4a2713aSLionel Sambuc
778f4a2713aSLionel Sambuc // All parameters documented -- can't suggest a correction.
779f4a2713aSLionel Sambuc if (OrphanedParamDecls.size() == 0)
780f4a2713aSLionel Sambuc continue;
781f4a2713aSLionel Sambuc
782f4a2713aSLionel Sambuc unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex;
783f4a2713aSLionel Sambuc if (OrphanedParamDecls.size() == 1) {
784f4a2713aSLionel Sambuc // If one parameter is not documented then that parameter is the only
785f4a2713aSLionel Sambuc // possible suggestion.
786f4a2713aSLionel Sambuc CorrectedParamIndex = 0;
787f4a2713aSLionel Sambuc } else {
788f4a2713aSLionel Sambuc // Do typo correction.
789f4a2713aSLionel Sambuc CorrectedParamIndex = correctTypoInParmVarReference(ParamName,
790f4a2713aSLionel Sambuc OrphanedParamDecls);
791f4a2713aSLionel Sambuc }
792f4a2713aSLionel Sambuc if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) {
793f4a2713aSLionel Sambuc const ParmVarDecl *CorrectedPVD = OrphanedParamDecls[CorrectedParamIndex];
794f4a2713aSLionel Sambuc if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier())
795f4a2713aSLionel Sambuc Diag(ArgRange.getBegin(), diag::note_doc_param_name_suggestion)
796f4a2713aSLionel Sambuc << CorrectedII->getName()
797f4a2713aSLionel Sambuc << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName());
798f4a2713aSLionel Sambuc }
799f4a2713aSLionel Sambuc }
800f4a2713aSLionel Sambuc }
801f4a2713aSLionel Sambuc
isFunctionDecl()802f4a2713aSLionel Sambuc bool Sema::isFunctionDecl() {
803f4a2713aSLionel Sambuc if (!ThisDeclInfo)
804f4a2713aSLionel Sambuc return false;
805f4a2713aSLionel Sambuc if (!ThisDeclInfo->IsFilled)
806f4a2713aSLionel Sambuc inspectThisDecl();
807f4a2713aSLionel Sambuc return ThisDeclInfo->getKind() == DeclInfo::FunctionKind;
808f4a2713aSLionel Sambuc }
809f4a2713aSLionel Sambuc
isAnyFunctionDecl()810f4a2713aSLionel Sambuc bool Sema::isAnyFunctionDecl() {
811f4a2713aSLionel Sambuc return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
812f4a2713aSLionel Sambuc isa<FunctionDecl>(ThisDeclInfo->CurrentDecl);
813f4a2713aSLionel Sambuc }
814f4a2713aSLionel Sambuc
isFunctionOrMethodVariadic()815f4a2713aSLionel Sambuc bool Sema::isFunctionOrMethodVariadic() {
816*0a6a1f1dSLionel Sambuc if (!isAnyFunctionDecl() && !isObjCMethodDecl() && !isFunctionTemplateDecl())
817f4a2713aSLionel Sambuc return false;
818f4a2713aSLionel Sambuc if (const FunctionDecl *FD =
819f4a2713aSLionel Sambuc dyn_cast<FunctionDecl>(ThisDeclInfo->CurrentDecl))
820f4a2713aSLionel Sambuc return FD->isVariadic();
821*0a6a1f1dSLionel Sambuc if (const FunctionTemplateDecl *FTD =
822*0a6a1f1dSLionel Sambuc dyn_cast<FunctionTemplateDecl>(ThisDeclInfo->CurrentDecl))
823*0a6a1f1dSLionel Sambuc return FTD->getTemplatedDecl()->isVariadic();
824f4a2713aSLionel Sambuc if (const ObjCMethodDecl *MD =
825f4a2713aSLionel Sambuc dyn_cast<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl))
826f4a2713aSLionel Sambuc return MD->isVariadic();
827f4a2713aSLionel Sambuc return false;
828f4a2713aSLionel Sambuc }
829f4a2713aSLionel Sambuc
isObjCMethodDecl()830f4a2713aSLionel Sambuc bool Sema::isObjCMethodDecl() {
831f4a2713aSLionel Sambuc return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
832f4a2713aSLionel Sambuc isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl);
833f4a2713aSLionel Sambuc }
834f4a2713aSLionel Sambuc
isFunctionPointerVarDecl()835f4a2713aSLionel Sambuc bool Sema::isFunctionPointerVarDecl() {
836f4a2713aSLionel Sambuc if (!ThisDeclInfo)
837f4a2713aSLionel Sambuc return false;
838f4a2713aSLionel Sambuc if (!ThisDeclInfo->IsFilled)
839f4a2713aSLionel Sambuc inspectThisDecl();
840f4a2713aSLionel Sambuc if (ThisDeclInfo->getKind() == DeclInfo::VariableKind) {
841f4a2713aSLionel Sambuc if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(ThisDeclInfo->CurrentDecl)) {
842f4a2713aSLionel Sambuc QualType QT = VD->getType();
843f4a2713aSLionel Sambuc return QT->isFunctionPointerType();
844f4a2713aSLionel Sambuc }
845f4a2713aSLionel Sambuc }
846f4a2713aSLionel Sambuc return false;
847f4a2713aSLionel Sambuc }
848f4a2713aSLionel Sambuc
isObjCPropertyDecl()849f4a2713aSLionel Sambuc bool Sema::isObjCPropertyDecl() {
850f4a2713aSLionel Sambuc if (!ThisDeclInfo)
851f4a2713aSLionel Sambuc return false;
852f4a2713aSLionel Sambuc if (!ThisDeclInfo->IsFilled)
853f4a2713aSLionel Sambuc inspectThisDecl();
854f4a2713aSLionel Sambuc return ThisDeclInfo->CurrentDecl->getKind() == Decl::ObjCProperty;
855f4a2713aSLionel Sambuc }
856f4a2713aSLionel Sambuc
isTemplateOrSpecialization()857f4a2713aSLionel Sambuc bool Sema::isTemplateOrSpecialization() {
858f4a2713aSLionel Sambuc if (!ThisDeclInfo)
859f4a2713aSLionel Sambuc return false;
860f4a2713aSLionel Sambuc if (!ThisDeclInfo->IsFilled)
861f4a2713aSLionel Sambuc inspectThisDecl();
862f4a2713aSLionel Sambuc return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate;
863f4a2713aSLionel Sambuc }
864f4a2713aSLionel Sambuc
isRecordLikeDecl()865f4a2713aSLionel Sambuc bool Sema::isRecordLikeDecl() {
866f4a2713aSLionel Sambuc if (!ThisDeclInfo)
867f4a2713aSLionel Sambuc return false;
868f4a2713aSLionel Sambuc if (!ThisDeclInfo->IsFilled)
869f4a2713aSLionel Sambuc inspectThisDecl();
870*0a6a1f1dSLionel Sambuc return isUnionDecl() || isClassOrStructDecl() || isObjCInterfaceDecl() ||
871*0a6a1f1dSLionel Sambuc isObjCProtocolDecl();
872f4a2713aSLionel Sambuc }
873f4a2713aSLionel Sambuc
isUnionDecl()874f4a2713aSLionel Sambuc bool Sema::isUnionDecl() {
875f4a2713aSLionel Sambuc if (!ThisDeclInfo)
876f4a2713aSLionel Sambuc return false;
877f4a2713aSLionel Sambuc if (!ThisDeclInfo->IsFilled)
878f4a2713aSLionel Sambuc inspectThisDecl();
879f4a2713aSLionel Sambuc if (const RecordDecl *RD =
880f4a2713aSLionel Sambuc dyn_cast_or_null<RecordDecl>(ThisDeclInfo->CurrentDecl))
881f4a2713aSLionel Sambuc return RD->isUnion();
882f4a2713aSLionel Sambuc return false;
883f4a2713aSLionel Sambuc }
884f4a2713aSLionel Sambuc
isClassOrStructDecl()885f4a2713aSLionel Sambuc bool Sema::isClassOrStructDecl() {
886f4a2713aSLionel Sambuc if (!ThisDeclInfo)
887f4a2713aSLionel Sambuc return false;
888f4a2713aSLionel Sambuc if (!ThisDeclInfo->IsFilled)
889f4a2713aSLionel Sambuc inspectThisDecl();
890f4a2713aSLionel Sambuc return ThisDeclInfo->CurrentDecl &&
891f4a2713aSLionel Sambuc isa<RecordDecl>(ThisDeclInfo->CurrentDecl) &&
892f4a2713aSLionel Sambuc !isUnionDecl();
893f4a2713aSLionel Sambuc }
894f4a2713aSLionel Sambuc
isClassTemplateDecl()895f4a2713aSLionel Sambuc bool Sema::isClassTemplateDecl() {
896f4a2713aSLionel Sambuc if (!ThisDeclInfo)
897f4a2713aSLionel Sambuc return false;
898f4a2713aSLionel Sambuc if (!ThisDeclInfo->IsFilled)
899f4a2713aSLionel Sambuc inspectThisDecl();
900f4a2713aSLionel Sambuc return ThisDeclInfo->CurrentDecl &&
901f4a2713aSLionel Sambuc (isa<ClassTemplateDecl>(ThisDeclInfo->CurrentDecl));
902f4a2713aSLionel Sambuc }
903f4a2713aSLionel Sambuc
isFunctionTemplateDecl()904f4a2713aSLionel Sambuc bool Sema::isFunctionTemplateDecl() {
905f4a2713aSLionel Sambuc if (!ThisDeclInfo)
906f4a2713aSLionel Sambuc return false;
907f4a2713aSLionel Sambuc if (!ThisDeclInfo->IsFilled)
908f4a2713aSLionel Sambuc inspectThisDecl();
909f4a2713aSLionel Sambuc return ThisDeclInfo->CurrentDecl &&
910f4a2713aSLionel Sambuc (isa<FunctionTemplateDecl>(ThisDeclInfo->CurrentDecl));
911f4a2713aSLionel Sambuc }
912f4a2713aSLionel Sambuc
isObjCInterfaceDecl()913f4a2713aSLionel Sambuc bool Sema::isObjCInterfaceDecl() {
914f4a2713aSLionel Sambuc if (!ThisDeclInfo)
915f4a2713aSLionel Sambuc return false;
916f4a2713aSLionel Sambuc if (!ThisDeclInfo->IsFilled)
917f4a2713aSLionel Sambuc inspectThisDecl();
918f4a2713aSLionel Sambuc return ThisDeclInfo->CurrentDecl &&
919f4a2713aSLionel Sambuc isa<ObjCInterfaceDecl>(ThisDeclInfo->CurrentDecl);
920f4a2713aSLionel Sambuc }
921f4a2713aSLionel Sambuc
isObjCProtocolDecl()922f4a2713aSLionel Sambuc bool Sema::isObjCProtocolDecl() {
923f4a2713aSLionel Sambuc if (!ThisDeclInfo)
924f4a2713aSLionel Sambuc return false;
925f4a2713aSLionel Sambuc if (!ThisDeclInfo->IsFilled)
926f4a2713aSLionel Sambuc inspectThisDecl();
927f4a2713aSLionel Sambuc return ThisDeclInfo->CurrentDecl &&
928f4a2713aSLionel Sambuc isa<ObjCProtocolDecl>(ThisDeclInfo->CurrentDecl);
929f4a2713aSLionel Sambuc }
930f4a2713aSLionel Sambuc
getParamVars()931f4a2713aSLionel Sambuc ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
932f4a2713aSLionel Sambuc if (!ThisDeclInfo->IsFilled)
933f4a2713aSLionel Sambuc inspectThisDecl();
934f4a2713aSLionel Sambuc return ThisDeclInfo->ParamVars;
935f4a2713aSLionel Sambuc }
936f4a2713aSLionel Sambuc
inspectThisDecl()937f4a2713aSLionel Sambuc void Sema::inspectThisDecl() {
938f4a2713aSLionel Sambuc ThisDeclInfo->fill();
939f4a2713aSLionel Sambuc }
940f4a2713aSLionel Sambuc
resolveParmVarReference(StringRef Name,ArrayRef<const ParmVarDecl * > ParamVars)941f4a2713aSLionel Sambuc unsigned Sema::resolveParmVarReference(StringRef Name,
942f4a2713aSLionel Sambuc ArrayRef<const ParmVarDecl *> ParamVars) {
943f4a2713aSLionel Sambuc for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
944f4a2713aSLionel Sambuc const IdentifierInfo *II = ParamVars[i]->getIdentifier();
945f4a2713aSLionel Sambuc if (II && II->getName() == Name)
946f4a2713aSLionel Sambuc return i;
947f4a2713aSLionel Sambuc }
948f4a2713aSLionel Sambuc if (Name == "..." && isFunctionOrMethodVariadic())
949f4a2713aSLionel Sambuc return ParamCommandComment::VarArgParamIndex;
950f4a2713aSLionel Sambuc return ParamCommandComment::InvalidParamIndex;
951f4a2713aSLionel Sambuc }
952f4a2713aSLionel Sambuc
953f4a2713aSLionel Sambuc namespace {
954f4a2713aSLionel Sambuc class SimpleTypoCorrector {
955f4a2713aSLionel Sambuc StringRef Typo;
956f4a2713aSLionel Sambuc const unsigned MaxEditDistance;
957f4a2713aSLionel Sambuc
958f4a2713aSLionel Sambuc const NamedDecl *BestDecl;
959f4a2713aSLionel Sambuc unsigned BestEditDistance;
960f4a2713aSLionel Sambuc unsigned BestIndex;
961f4a2713aSLionel Sambuc unsigned NextIndex;
962f4a2713aSLionel Sambuc
963f4a2713aSLionel Sambuc public:
SimpleTypoCorrector(StringRef Typo)964f4a2713aSLionel Sambuc SimpleTypoCorrector(StringRef Typo) :
965f4a2713aSLionel Sambuc Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3),
966*0a6a1f1dSLionel Sambuc BestDecl(nullptr), BestEditDistance(MaxEditDistance + 1),
967f4a2713aSLionel Sambuc BestIndex(0), NextIndex(0)
968f4a2713aSLionel Sambuc { }
969f4a2713aSLionel Sambuc
970f4a2713aSLionel Sambuc void addDecl(const NamedDecl *ND);
971f4a2713aSLionel Sambuc
getBestDecl() const972f4a2713aSLionel Sambuc const NamedDecl *getBestDecl() const {
973f4a2713aSLionel Sambuc if (BestEditDistance > MaxEditDistance)
974*0a6a1f1dSLionel Sambuc return nullptr;
975f4a2713aSLionel Sambuc
976f4a2713aSLionel Sambuc return BestDecl;
977f4a2713aSLionel Sambuc }
978f4a2713aSLionel Sambuc
getBestDeclIndex() const979f4a2713aSLionel Sambuc unsigned getBestDeclIndex() const {
980f4a2713aSLionel Sambuc assert(getBestDecl());
981f4a2713aSLionel Sambuc return BestIndex;
982f4a2713aSLionel Sambuc }
983f4a2713aSLionel Sambuc };
984f4a2713aSLionel Sambuc
addDecl(const NamedDecl * ND)985f4a2713aSLionel Sambuc void SimpleTypoCorrector::addDecl(const NamedDecl *ND) {
986f4a2713aSLionel Sambuc unsigned CurrIndex = NextIndex++;
987f4a2713aSLionel Sambuc
988f4a2713aSLionel Sambuc const IdentifierInfo *II = ND->getIdentifier();
989f4a2713aSLionel Sambuc if (!II)
990f4a2713aSLionel Sambuc return;
991f4a2713aSLionel Sambuc
992f4a2713aSLionel Sambuc StringRef Name = II->getName();
993f4a2713aSLionel Sambuc unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());
994f4a2713aSLionel Sambuc if (MinPossibleEditDistance > 0 &&
995f4a2713aSLionel Sambuc Typo.size() / MinPossibleEditDistance < 3)
996f4a2713aSLionel Sambuc return;
997f4a2713aSLionel Sambuc
998f4a2713aSLionel Sambuc unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
999f4a2713aSLionel Sambuc if (EditDistance < BestEditDistance) {
1000f4a2713aSLionel Sambuc BestEditDistance = EditDistance;
1001f4a2713aSLionel Sambuc BestDecl = ND;
1002f4a2713aSLionel Sambuc BestIndex = CurrIndex;
1003f4a2713aSLionel Sambuc }
1004f4a2713aSLionel Sambuc }
1005f4a2713aSLionel Sambuc } // unnamed namespace
1006f4a2713aSLionel Sambuc
correctTypoInParmVarReference(StringRef Typo,ArrayRef<const ParmVarDecl * > ParamVars)1007f4a2713aSLionel Sambuc unsigned Sema::correctTypoInParmVarReference(
1008f4a2713aSLionel Sambuc StringRef Typo,
1009f4a2713aSLionel Sambuc ArrayRef<const ParmVarDecl *> ParamVars) {
1010f4a2713aSLionel Sambuc SimpleTypoCorrector Corrector(Typo);
1011f4a2713aSLionel Sambuc for (unsigned i = 0, e = ParamVars.size(); i != e; ++i)
1012f4a2713aSLionel Sambuc Corrector.addDecl(ParamVars[i]);
1013f4a2713aSLionel Sambuc if (Corrector.getBestDecl())
1014f4a2713aSLionel Sambuc return Corrector.getBestDeclIndex();
1015f4a2713aSLionel Sambuc else
1016f4a2713aSLionel Sambuc return ParamCommandComment::InvalidParamIndex;
1017f4a2713aSLionel Sambuc }
1018f4a2713aSLionel Sambuc
1019f4a2713aSLionel Sambuc namespace {
ResolveTParamReferenceHelper(StringRef Name,const TemplateParameterList * TemplateParameters,SmallVectorImpl<unsigned> * Position)1020f4a2713aSLionel Sambuc bool ResolveTParamReferenceHelper(
1021f4a2713aSLionel Sambuc StringRef Name,
1022f4a2713aSLionel Sambuc const TemplateParameterList *TemplateParameters,
1023f4a2713aSLionel Sambuc SmallVectorImpl<unsigned> *Position) {
1024f4a2713aSLionel Sambuc for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
1025f4a2713aSLionel Sambuc const NamedDecl *Param = TemplateParameters->getParam(i);
1026f4a2713aSLionel Sambuc const IdentifierInfo *II = Param->getIdentifier();
1027f4a2713aSLionel Sambuc if (II && II->getName() == Name) {
1028f4a2713aSLionel Sambuc Position->push_back(i);
1029f4a2713aSLionel Sambuc return true;
1030f4a2713aSLionel Sambuc }
1031f4a2713aSLionel Sambuc
1032f4a2713aSLionel Sambuc if (const TemplateTemplateParmDecl *TTP =
1033f4a2713aSLionel Sambuc dyn_cast<TemplateTemplateParmDecl>(Param)) {
1034f4a2713aSLionel Sambuc Position->push_back(i);
1035f4a2713aSLionel Sambuc if (ResolveTParamReferenceHelper(Name, TTP->getTemplateParameters(),
1036f4a2713aSLionel Sambuc Position))
1037f4a2713aSLionel Sambuc return true;
1038f4a2713aSLionel Sambuc Position->pop_back();
1039f4a2713aSLionel Sambuc }
1040f4a2713aSLionel Sambuc }
1041f4a2713aSLionel Sambuc return false;
1042f4a2713aSLionel Sambuc }
1043f4a2713aSLionel Sambuc } // unnamed namespace
1044f4a2713aSLionel Sambuc
resolveTParamReference(StringRef Name,const TemplateParameterList * TemplateParameters,SmallVectorImpl<unsigned> * Position)1045f4a2713aSLionel Sambuc bool Sema::resolveTParamReference(
1046f4a2713aSLionel Sambuc StringRef Name,
1047f4a2713aSLionel Sambuc const TemplateParameterList *TemplateParameters,
1048f4a2713aSLionel Sambuc SmallVectorImpl<unsigned> *Position) {
1049f4a2713aSLionel Sambuc Position->clear();
1050f4a2713aSLionel Sambuc if (!TemplateParameters)
1051f4a2713aSLionel Sambuc return false;
1052f4a2713aSLionel Sambuc
1053f4a2713aSLionel Sambuc return ResolveTParamReferenceHelper(Name, TemplateParameters, Position);
1054f4a2713aSLionel Sambuc }
1055f4a2713aSLionel Sambuc
1056f4a2713aSLionel Sambuc namespace {
CorrectTypoInTParamReferenceHelper(const TemplateParameterList * TemplateParameters,SimpleTypoCorrector & Corrector)1057f4a2713aSLionel Sambuc void CorrectTypoInTParamReferenceHelper(
1058f4a2713aSLionel Sambuc const TemplateParameterList *TemplateParameters,
1059f4a2713aSLionel Sambuc SimpleTypoCorrector &Corrector) {
1060f4a2713aSLionel Sambuc for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
1061f4a2713aSLionel Sambuc const NamedDecl *Param = TemplateParameters->getParam(i);
1062f4a2713aSLionel Sambuc Corrector.addDecl(Param);
1063f4a2713aSLionel Sambuc
1064f4a2713aSLionel Sambuc if (const TemplateTemplateParmDecl *TTP =
1065f4a2713aSLionel Sambuc dyn_cast<TemplateTemplateParmDecl>(Param))
1066f4a2713aSLionel Sambuc CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(),
1067f4a2713aSLionel Sambuc Corrector);
1068f4a2713aSLionel Sambuc }
1069f4a2713aSLionel Sambuc }
1070f4a2713aSLionel Sambuc } // unnamed namespace
1071f4a2713aSLionel Sambuc
correctTypoInTParamReference(StringRef Typo,const TemplateParameterList * TemplateParameters)1072f4a2713aSLionel Sambuc StringRef Sema::correctTypoInTParamReference(
1073f4a2713aSLionel Sambuc StringRef Typo,
1074f4a2713aSLionel Sambuc const TemplateParameterList *TemplateParameters) {
1075f4a2713aSLionel Sambuc SimpleTypoCorrector Corrector(Typo);
1076f4a2713aSLionel Sambuc CorrectTypoInTParamReferenceHelper(TemplateParameters, Corrector);
1077f4a2713aSLionel Sambuc if (const NamedDecl *ND = Corrector.getBestDecl()) {
1078f4a2713aSLionel Sambuc const IdentifierInfo *II = ND->getIdentifier();
1079f4a2713aSLionel Sambuc assert(II && "SimpleTypoCorrector should not return this decl");
1080f4a2713aSLionel Sambuc return II->getName();
1081f4a2713aSLionel Sambuc }
1082f4a2713aSLionel Sambuc return StringRef();
1083f4a2713aSLionel Sambuc }
1084f4a2713aSLionel Sambuc
1085f4a2713aSLionel Sambuc InlineCommandComment::RenderKind
getInlineCommandRenderKind(StringRef Name) const1086f4a2713aSLionel Sambuc Sema::getInlineCommandRenderKind(StringRef Name) const {
1087f4a2713aSLionel Sambuc assert(Traits.getCommandInfo(Name)->IsInlineCommand);
1088f4a2713aSLionel Sambuc
1089f4a2713aSLionel Sambuc return llvm::StringSwitch<InlineCommandComment::RenderKind>(Name)
1090f4a2713aSLionel Sambuc .Case("b", InlineCommandComment::RenderBold)
1091f4a2713aSLionel Sambuc .Cases("c", "p", InlineCommandComment::RenderMonospaced)
1092f4a2713aSLionel Sambuc .Cases("a", "e", "em", InlineCommandComment::RenderEmphasized)
1093f4a2713aSLionel Sambuc .Default(InlineCommandComment::RenderNormal);
1094f4a2713aSLionel Sambuc }
1095f4a2713aSLionel Sambuc
1096f4a2713aSLionel Sambuc } // end namespace comments
1097f4a2713aSLionel Sambuc } // end namespace clang
1098f4a2713aSLionel Sambuc
1099