1 /******************************************************************************
3 * Copyright (C) 1997-2020 by Dimitri van Heesch.
5 * Permission to use, copy, modify, and distribute this software and its
6 * documentation under the terms of the GNU General Public License is hereby
7 * granted. No representations are made about the suitability of this software
8 * for any purpose. It is provided "as is" without express or implied warranty.
9 * See the GNU General Public License for more details.
11 * Documents produced by Doxygen are derivative works derived from the
12 * input used in their production; they are not affected by this license.
15 %option never-interactive
16 %option prefix="codeYY"
18 %option extra-type="struct codeYY_state *"
21 // forward declare yyscan_t to improve type safety
22 #define YY_TYPEDEF_YY_SCANNER_T
24 typedef yyguts_t *yyscan_t;
36 #include <unordered_map>
37 #include <unordered_set>
52 #include "outputlist.h"
54 #include "membername.h"
55 #include "searchindex.h"
56 #include "arguments.h"
59 #include "classlist.h"
62 #include "namespacedef.h"
64 #include "scopedtypevariant.h"
65 #include "symbolresolver.h"
68 // Toggle for some debugging info
69 //#define DBG_CTX(x) fprintf x
70 #define DBG_CTX(x) do { } while(0)
72 #define YY_NO_UNISTD_H 1
78 #define USE_STATE2STRING 0
80 // context for an Objective-C method call
85 QCString objectTypeOrName;
87 const ClassDef *objectType;
88 const MemberDef *objectVar;
89 const MemberDef *method;
97 CodeOutputInterface * code = 0;
99 std::unordered_map< std::string, ScopedTypeVariant > codeClassMap;
100 QCString curClassName;
101 StringVector curClassBases;
106 bool beginCodeLine = true; //!< signals whether or not we should with the first line
107 //!< write a start line code or not. Essential
108 //!< when this code parser is called from another
111 const char * inputString = 0; //!< the code fragment as text
112 yy_size_t inputPosition = 0; //!< read offset during parsing
113 int inputLines = 0; //!< number of line in the code fragment
114 int yyLineNr = 0; //!< current line number
115 yy_size_t yyColNr = 0; //!< current column number
116 bool needsTermination = FALSE;
118 bool exampleBlock = FALSE;
119 QCString exampleName;
120 QCString exampleFile;
122 bool insideTemplate = FALSE;
128 std::stack<int> scopeStack; //!< 1 if bracket starts a scope,
129 // 2 for internal blocks
131 const FileDef * sourceFileDef = 0;
132 bool lineNumbers = FALSE;
133 const Definition * currentDefinition = 0;
134 const MemberDef * currentMemberDef = 0;
135 bool includeCodeFragment = FALSE;
136 const char * currentFontClass = 0;
137 bool searchingForBody = FALSE;
138 bool insideBody = FALSE;
139 int bodyCurlyCount = 0;
144 int bracketCount = 0;
147 bool inFunctionTryBlock = FALSE;
148 bool inForEachExpression = FALSE;
150 int lastTemplCastContext = 0;
151 int lastSpecialCContext = 0;
152 int lastStringContext = 0;
153 int lastSkipCppContext = 0;
154 int lastVerbStringContext = 0;
155 int lastObjCCallContext = 0;
156 int memCallContext = 0;
157 int lastCContext = 0;
158 int skipInlineInitContext = 0;
160 SrcLangExt lang = SrcLangExt_Unknown;
161 bool insideObjC = FALSE;
162 bool insideProtocolList = FALSE;
164 bool lexInit = FALSE;
166 std::stack<int> classScopeLengthStack;
168 int isPrefixedWithThis = FALSE;
169 const Definition *searchCtx = 0;
170 bool collectXRefs = FALSE;
172 ObjCCallCtx * currentCtx=0;
177 int currentCommentId=0;
178 std::stack<ObjCCallCtx*> contextStack;
179 std::unordered_map< int,std::unique_ptr<ObjCCallCtx> > contextMap;
180 std::unordered_map< int, QCString> nameMap;
181 std::unordered_map< int, QCString> objectMap;
182 std::unordered_map< int, QCString> wordMap;
183 std::unordered_map< int, QCString> commentMap;
186 VariableContext theVarContext;
187 CallContext theCallContext;
188 SymbolResolver symbolResolver;
189 TooltipManager tooltipManager;
192 static bool isCastKeyword(const char *s);
194 //-------------------------------------------------------------------
196 static const char *stateToString(yyscan_t yyscanner,int state);
199 static void saveObjCContext(yyscan_t yyscanner);
200 static void restoreObjCContext(yyscan_t yyscanner);
201 static void pushScope(yyscan_t yyscanner,const QCString &s);
202 static void popScope(yyscan_t yyscanner);
203 static void setCurrentDoc(yyscan_t yyscanner,const QCString &anchor);
204 static void addToSearchIndex(yyscan_t yyscanner,const QCString &text);
205 static void addToSearchIndex(yyscan_t yyscanner,const char *text);
206 static void setClassScope(yyscan_t yyscanner,const QCString &name);
207 static void startCodeLine(yyscan_t yyscanner);
208 static void endCodeLine(yyscan_t yyscanner);
209 static void nextCodeLine(yyscan_t yyscanner);
210 static void startFontClass(yyscan_t yyscanner,const char *s);
211 static void endFontClass(yyscan_t yyscanner);
212 static void codifyLines(yyscan_t yyscanner,const QCString &text);
213 static void codifyLines(yyscan_t yyscanner,const char *text);
214 static void incrementFlowKeyWordCount(yyscan_t yyscanner);
215 static void writeMultiLineCodeLink(yyscan_t yyscanner,CodeOutputInterface &ol,
217 const QCString &text);
218 static void addType(yyscan_t yyscanner);
219 static void addParmType(yyscan_t yyscanner);
220 static void addUsingDirective(yyscan_t yyscanner,const char *name);
221 static void setParameterList(yyscan_t yyscanner,const MemberDef *md);
222 static const ClassDef *stripClassName(yyscan_t yyscanner,const QCString &s,const Definition *d);
223 static const MemberDef *setCallContextForVar(yyscan_t yyscanner,const QCString &name);
224 static void updateCallContextForSmartPointer(yyscan_t yyscanner);
225 static bool getLinkInScope(yyscan_t yyscanner,const QCString &c, // scope
226 const QCString &m, // member
227 const QCString &memberText, // exact text
228 CodeOutputInterface &ol,
229 const QCString &text,
232 static bool getLink(yyscan_t yyscanner,const QCString &className,
233 const QCString &memberName,
234 CodeOutputInterface &ol,
235 const QCString &text=QCString(),
237 static void generateClassOrGlobalLink(yyscan_t yyscanner,CodeOutputInterface &ol,const QCString &clName,
238 bool typeOnly=FALSE,bool varOnly=FALSE);
239 static void generateClassOrGlobalLink(yyscan_t yyscanner,CodeOutputInterface &ol,const char *clName,
240 bool typeOnly=FALSE,bool varOnly=FALSE);
241 static bool generateClassMemberLink(yyscan_t yyscanner,CodeOutputInterface &ol,const MemberDef *xmd,const QCString &memName);
242 static bool generateClassMemberLink(yyscan_t yyscanner,CodeOutputInterface &ol,const Definition *def,const QCString &memName);
243 static void generateMemberLink(yyscan_t yyscanner,CodeOutputInterface &ol,const QCString &varName,
244 const QCString &memName);
245 static void generatePHPVariableLink(yyscan_t yyscanner,CodeOutputInterface &ol,const char *varName);
246 static void generateFunctionLink(yyscan_t yyscanner,CodeOutputInterface &ol,const QCString &funcName);
247 static void generateFunctionLink(yyscan_t yyscanner,CodeOutputInterface &ol,const char *funcName);
248 static int countLines(yyscan_t yyscanner);
249 static void writeObjCMethodCall(yyscan_t yyscanner,ObjCCallCtx *ctx);
250 static QCString escapeName(yyscan_t yyscanner,const char *s);
251 static QCString escapeObject(yyscan_t yyscanner,const char *s);
252 static QCString escapeWord(yyscan_t yyscanner,const char *s);
253 static QCString escapeComment(yyscan_t yyscanner,const char *s);
254 static bool skipLanguageSpecificKeyword(yyscan_t yyscanner,const char *kw);
255 static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size);
256 static void addVariable(yyscan_t yyscanner,QCString type,QCString name);
257 static bool startsWithKeyword(const QCString &str,const QCString &kw);
259 //-------------------------------------------------------------------
261 static std::mutex g_searchIndexMutex;
262 static std::mutex g_docCrossReferenceMutex;
263 static std::mutex g_addExampleMutex;
264 static std::mutex g_countFlowKeywordsMutex;
265 static std::mutex g_usingDirectiveMutex;
267 /* -----------------------------------------------------------------
270 #define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size);
278 ID [$a-z_A-Z\x80-\xFF][$a-z_A-Z0-9\x80-\xFF]*
280 SCOPENAME ({SEP}{BN}*)?({ID}{BN}*{SEP}{BN}*)*("~"{BN}*)?{ID}
281 TEMPLIST "<"[^\"\}\{\(\)\/\n>]*">"
282 SCOPETNAME (((({ID}{TEMPLIST}?){BN}*)?{SEP}{BN}*)*)((~{BN}*)?{ID})
283 SCOPEPREFIX ({ID}{TEMPLIST}?{BN}*{SEP}{BN}*)+
284 KEYWORD_OBJC ("@public"|"@private"|"@protected"|"@class"|"@implementation"|"@interface"|"@end"|"@selector"|"@protocol"|"@optional"|"@required"|"@throw"|"@synthesize"|"@property")
285 /* please also pay attention to skipLanguageSpecificKeyword when changing the list of keywords. */
286 KEYWORD ("asm"|"__assume"|"auto"|"class"|"const"|"delete"|"enum"|"explicit"|"extern"|"false"|"friend"|"gcnew"|"gcroot"|"set"|"get"|"inline"|"internal"|"mutable"|"namespace"|"new"|"null"|"nullptr"|"override"|"operator"|"pin_ptr"|"private"|"protected"|"public"|"raise"|"register"|"remove"|"self"|"sizeof"|"static"|"struct"|"__super"|"function"|"template"|"generic"|"this"|"true"|"typedef"|"typeid"|"typename"|"union"|"using"|"virtual"|"volatile"|"abstract"|"final"|"import"|"synchronized"|"transient"|"alignas"|"alignof"|"concept"|"requires"|"decltype"|{KEYWORD_OBJC}|"constexpr"|"consteval"|"constinit"|"co_await"|"co_return"|"co_yield"|"static_assert"|"noexcept"|"thread_local")
287 FLOWKW ("break"|"catch"|"continue"|"default"|"do"|"else"|"finally"|"return"|"switch"|"throw"|"throws"|"@catch"|"@finally")
288 FLOWCONDITION ("case"|"for"|"foreach"|"for each"|"goto"|"if"|"try"|"while"|"@try")
289 TYPEKW ("bool"|"byte"|"char"|"char8_t"|"char16_t"|"char32_t"|"double"|"float"|"int"|"long"|"object"|"short"|"signed"|"unsigned"|"void"|"wchar_t"|"size_t"|"boolean"|"id"|"SEL"|"string"|"nullptr")
290 TYPEKWSL ("LocalObject"|"Object"|"Value")
291 CASTKW ("const_cast"|"dynamic_cast"|"reinterpret_cast"|"static_cast")
292 CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^' \\\n]{1,4}"'"))
293 ARITHOP "+"|"-"|"/"|"*"|"%"|"--"|"++"
294 ASSIGNOP "="|"*="|"/="|"%="|"+="|"-="|"<<="|">>="|"&="|"^="|"|="
295 LOGICOP "=="|"!="|">"|"<"|">="|"<="|"&&"|"||"|"!"|"<=>"
296 BITOP "&"|"|"|"^"|"<<"|">>"|"~"
297 OPERATOR {ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP}
298 RAWBEGIN (u|U|L|u8)?R\"[^ \t\(\)\\]{0,16}"("
299 RAWEND ")"[^ \t\(\)\\]{0,16}\"
301 /* no comment start / end signs inside square brackets */
303 //- start: NUMBER -------------------------------------------------------------------------
304 // Note same defines in commentcnv.l: keep in sync
305 DECIMAL_INTEGER [1-9][0-9']*[0-9]?[uU]?[lL]?[lL]?
306 HEXADECIMAL_INTEGER "0"[xX][0-9a-zA-Z']+[0-9a-zA-Z]?
307 OCTAL_INTEGER "0"[0-7][0-7']+[0-7]?
308 BINARY_INTEGER "0"[bB][01][01']*[01]?
309 INTEGER_NUMBER {DECIMAL_INTEGER}|{HEXADECIMAL_INTEGER}|{OCTAL_INTEGER}|{BINARY_INTEGER}
313 DIGIT_SEQ [0-9][0-9']*[0-9]?
314 FRAC_CONST {DIGIT_SEQ}"."|{DIGIT_SEQ}?"."{DIGIT_SEQ}
315 FP_EXP [eE][+-]?{DIGIT_SEQ}
316 DEC_FP1 {FRAC_CONST}{FP_EXP}?{FP_SUF}?
317 DEC_FP2 {DIGIT_SEQ}{FP_EXP}{FP_SUF}
319 HEX_DIGIT_SEQ [0-9a-fA-F][0-9a-fA-F']*[0-9a-fA-F]?
320 HEX_FRAC_CONST {HEX_DIGIT_SEQ}"."|{HEX_DIGIT_SEQ}?"."{HEX_DIGIT_SEQ}
321 BIN_EXP [pP][+-]?{DIGIT_SEQ}
322 HEX_FP1 "0"[xX]{HEX_FRAC_CONST}{BIN_EXP}{FP_SUF}?
323 HEX_FP2 "0"[xX]{HEX_DIGIT_SEQ}{BIN_EXP}{FP_SUF}?
325 FLOAT_DECIMAL {DEC_FP1}|{DEC_FP2}
326 FLOAT_HEXADECIMAL {HEX_FP1}|{HEX_FP2}
327 FLOAT_NUMBER {FLOAT_DECIMAL}|{FLOAT_HEXADECIMAL}
328 NUMBER {INTEGER_NUMBER}|{FLOAT_NUMBER}
329 //- end: NUMBER ---------------------------------------------------------------------------
340 // Optional end qualifiers
341 ENDQopt ("const"|"volatile"|"sealed"|"override")({BN}+("const"|"volatile"|"sealed"|"override"))*
351 %x RemoveSpecialCComment
362 %x CppCliTypeModifierFollowup
385 <Body>^([ \t]*"#"[ \t]*("include"|"import")[ \t]*)("<"|"\"") {
386 startFontClass(yyscanner,"preprocessor");
387 yyextra->code->codify(yytext);
388 BEGIN( ReadInclude );
390 <Body>("@interface"|"@implementation"|"@protocol")[ \t\n]+ {
391 yyextra->insideObjC=TRUE;
392 startFontClass(yyscanner,"keyword");
393 codifyLines(yyscanner,yytext);
394 endFontClass(yyscanner);
395 if (!yyextra->insideTemplate)
398 <Body>(("public"|"private"){B}+)?("ref"|"value"|"interface"|"enum"){B}+("class"|"struct") {
399 if (yyextra->insideTemplate) REJECT;
400 startFontClass(yyscanner,"keyword");
401 codifyLines(yyscanner,yytext);
402 endFontClass(yyscanner);
405 <Body>"property"|"event"/{BN}* {
406 if (yyextra->insideTemplate) REJECT;
407 startFontClass(yyscanner,"keyword");
408 codifyLines(yyscanner,yytext);
409 endFontClass(yyscanner);
411 <Body>("partial"{B}+)?("class"|"struct"|"union"|"namespace"|"interface"){B}+ {
412 startFontClass(yyscanner,"keyword");
413 codifyLines(yyscanner,yytext);
414 endFontClass(yyscanner);
415 if (!yyextra->insideTemplate)
418 <Body>("package")[ \t\n]+ {
419 startFontClass(yyscanner,"keyword");
420 codifyLines(yyscanner,yytext);
421 endFontClass(yyscanner);
422 BEGIN( PackageName );
425 if (!yyextra->insideObjC) REJECT;
426 codifyLines(yyscanner,yytext);
429 <Body,ClassVar,Bases>"-"|"+" {
430 if (!yyextra->insideObjC || yyextra->insideBody)
432 yyextra->code->codify(yytext);
434 else // Start of Objective-C method
436 DBG_CTX((stderr,"Start of Objective-C method!\n"));
437 yyextra->code->codify(yytext);
442 yyextra->code->codify(yytext);
446 yyextra->code->codify(yytext);
447 BEGIN(ObjCParamType);
449 <ObjCParams,ObjCMethod>";"|"{" {
450 yyextra->code->codify(yytext);
453 if (yyextra->searchingForBody)
455 yyextra->searchingForBody=FALSE;
456 yyextra->insideBody=TRUE;
458 if (yyextra->insideBody) yyextra->bodyCurlyCount++;
459 if (!yyextra->curClassName.isEmpty()) // valid class name
461 pushScope(yyscanner,yyextra->curClassName);
462 DBG_CTX((stderr,"** scope stack push SCOPEBLOCK\n"));
463 yyextra->scopeStack.push(SCOPEBLOCK);
466 yyextra->type.resize(0);
467 yyextra->name.resize(0);
470 <ObjCParams>{ID}{B}*":" {
471 yyextra->code->codify(yytext);
473 <ObjCParamType>{TYPEKW} {
474 startFontClass(yyscanner,"keywordtype");
475 yyextra->code->codify(yytext);
476 endFontClass(yyscanner);
477 yyextra->parmType=yytext;
479 <ObjCParamType>{ID} {
480 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
481 yyextra->parmType=yytext;
484 yyextra->code->codify(yytext);
488 yyextra->code->codify(yytext);
489 yyextra->parmName=yytext;
490 addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
491 yyextra->parmType.resize(0);yyextra->parmName.resize(0);
493 <ObjCMethod,ObjCParams,ObjCParamType>{ID} {
494 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
496 <ObjCMethod,ObjCParams,ObjCParamType>. {
497 yyextra->code->codify(yytext);
499 <ObjCMethod,ObjCParams,ObjCParamType>\n {
500 codifyLines(yyscanner,yytext);
502 <ReadInclude>[^\n\">]+/(">"|"\"") {
507 const FileDef *fd=findFileDef(Doxygen::inputNameLinkedMap,yytext,ambig);
508 //printf("looking for include %s -> %s fd=%p\n",yytext,qPrint(absPath),fd);
509 if (fd && fd->isLinkable())
511 if (ambig) // multiple input files match the name
513 DBG_CTX((stderr,"===== yes %s is ambiguous\n",yytext));
514 QCString name(Dir::cleanDirPath(yytext));
515 if (!name.isEmpty() && yyextra->sourceFileDef)
517 const FileName *fn = Doxygen::inputNameLinkedMap->find(name);
520 // see if this source file actually includes the file
521 auto it = std::find_if(fn->begin(),
523 [&sfd=yyextra->sourceFileDef]
525 { return sfd->isIncluded(lfd->absFilePath()); });
526 found = it!=fn->end();
530 else // not ambiguous
535 DBG_CTX((stderr," include file %s found=%d\n",fd ? qPrint(fd->absFilePath()) : "<none>",found));
538 writeMultiLineCodeLink(yyscanner,*yyextra->code,fd,yytext);
542 yyextra->code->codify(yytext);
544 char c=(char)yyinput(yyscanner);
547 yyextra->code->codify(text);
548 endFontClass(yyscanner);
551 <Body,Bases>^[ \t]*"#" {
552 startFontClass(yyscanner,"preprocessor");
553 yyextra->lastSkipCppContext = YY_START;
554 yyextra->code->codify(yytext);
558 yyextra->code->codify(yytext);
559 yyextra->lastStringContext=YY_START;
560 BEGIN( SkipString ) ;
563 yyextra->code->codify(yytext);
565 <SkipCPP>[^\n\/\\\"]+ {
566 yyextra->code->codify(yytext);
569 codifyLines(yyscanner,yytext);
571 <SkipCPP>{CPPC}/[^/!] {
575 yyextra->theVarContext.pushScope();
577 DBG_CTX((stderr,"** scope stack push INNERBLOCK\n"));
578 yyextra->scopeStack.push(INNERBLOCK);
580 if (yyextra->searchingForBody)
582 yyextra->searchingForBody=FALSE;
583 yyextra->insideBody=TRUE;
585 yyextra->code->codify(yytext);
586 if (yyextra->insideBody)
588 yyextra->bodyCurlyCount++;
590 yyextra->type.resize(0);
591 yyextra->name.resize(0);
594 <Body,FuncCall,MemberCall,MemberCall2>"}" {
595 yyextra->theVarContext.popScope();
596 yyextra->type.resize(0);
597 yyextra->name.resize(0);
599 if (!yyextra->scopeStack.empty())
601 int scope = yyextra->scopeStack.top();
602 yyextra->scopeStack.pop();
603 DBG_CTX((stderr,"** scope stack pop SCOPEBLOCK=%d\n",scope==SCOPEBLOCK));
604 if (scope==SCOPEBLOCK || scope==CLASSBLOCK)
610 yyextra->code->codify(yytext);
612 DBG_CTX((stderr,"yyextra->bodyCurlyCount=%d\n",yyextra->bodyCurlyCount));
613 if (--yyextra->bodyCurlyCount<=0)
615 yyextra->insideBody=FALSE;
616 yyextra->currentMemberDef=0;
617 if (yyextra->currentDefinition)
618 yyextra->currentDefinition=yyextra->currentDefinition->getOuterScope();
622 <Body,ClassVar>"@end" {
623 DBG_CTX((stderr,"End of objc scope fd=%s\n",qPrint(yyextra->sourceFileDef->name())));
624 if (yyextra->sourceFileDef)
626 const FileDef *fd=yyextra->sourceFileDef;
627 yyextra->insideObjC = fd->name().lower().right(2)==".m" ||
628 fd->name().lower().right(3)==".mm";
629 DBG_CTX((stderr,"insideObjC=%d\n",yyextra->insideObjC));
633 yyextra->insideObjC = FALSE;
635 if (yyextra->insideBody)
637 yyextra->theVarContext.popScope();
639 if (!yyextra->scopeStack.empty())
641 int scope = yyextra->scopeStack.top();
642 yyextra->scopeStack.pop();
643 DBG_CTX((stderr,"** scope stack pop SCOPEBLOCK=%d\n",scope==SCOPEBLOCK));
644 if (scope==SCOPEBLOCK || scope==CLASSBLOCK)
649 yyextra->insideBody=FALSE;
652 startFontClass(yyscanner,"keyword");
653 yyextra->code->codify(yytext);
654 endFontClass(yyscanner);
656 yyextra->currentMemberDef=0;
657 if (yyextra->currentDefinition)
658 yyextra->currentDefinition=yyextra->currentDefinition->getOuterScope();
661 <ClassName,ClassVar>";" {
662 yyextra->code->codify(yytext);
663 yyextra->searchingForBody=FALSE;
666 <ClassName,ClassVar>[*&^%]+ {
667 yyextra->type=yyextra->curClassName;
668 yyextra->name.resize(0);
669 yyextra->code->codify(yytext);
670 BEGIN( Body ); // variable of type struct *
672 <ClassName>"__declspec"{B}*"("{B}*{ID}{B}*")" {
673 startFontClass(yyscanner,"keyword");
674 yyextra->code->codify(yytext);
675 endFontClass(yyscanner);
677 <ClassName>{ID}("."{ID})* |
678 <ClassName>{ID}("::"{ID})* {
679 if (yyextra->lang==SrcLangExt_CSharp)
680 yyextra->curClassName=substitute(yytext,".","::");
682 yyextra->curClassName=yytext;
684 if (yyextra->curClassName=="alignas")
686 startFontClass(yyscanner,"keyword");
687 yyextra->code->codify(yytext);
688 endFontClass(yyscanner);
693 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
698 yyextra->bracketCount=1;
699 yyextra->code->codify(yytext);
702 <AlignAs>\n { yyextra->yyLineNr++;
703 codifyLines(yyscanner,yytext);
705 <AlignAs>. { yyextra->code->codify(yytext); }
706 <AlignAsEnd>"(" { yyextra->code->codify(yytext);
707 yyextra->bracketCount++;
710 yyextra->code->codify(yytext);
711 if (--yyextra->bracketCount<=0)
716 <AlignAsEnd>\n { yyextra->yyLineNr++;
717 codifyLines(yyscanner,yytext);
719 <AlignAsEnd>. { yyextra->code->codify(yytext); }
720 <ClassName>{ID}("\\"{ID})* { // PHP namespace
721 yyextra->curClassName=substitute(yytext,"\\","::");
722 yyextra->scopeStack.push(CLASSBLOCK);
723 pushScope(yyscanner,yyextra->curClassName);
725 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
728 <ClassName>{ID}{B}*"("{ID}")" { // Obj-C category
729 yyextra->curClassName=removeRedundantWhiteSpace(yytext);
730 yyextra->scopeStack.push(CLASSBLOCK);
731 pushScope(yyscanner,yyextra->curClassName);
733 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
736 <PackageName>{ID}("."{ID})* {
737 yyextra->curClassName=substitute(yytext,".","::");
738 DBG_CTX((stderr,"found package: %s\n",qPrint(yyextra->curClassName)));
740 codifyLines(yyscanner,yytext);
746 <ClassVar>("extends"|"implements") { // Java, Slice
747 startFontClass(yyscanner,"keyword");
748 codifyLines(yyscanner,yytext);
749 endFontClass(yyscanner);
750 yyextra->curClassBases.clear();
753 <ClassVar>("sealed"|"abstract")/{BN}*(":"|"{") {
754 DBG_CTX((stderr,"***** C++/CLI modifier %s on yyextra->curClassName=%s\n",yytext,qPrint(yyextra->curClassName)));
755 startFontClass(yyscanner,"keyword");
756 codifyLines(yyscanner,yytext);
757 endFontClass(yyscanner);
758 BEGIN( CppCliTypeModifierFollowup );
761 yyextra->type = yyextra->curClassName;
762 yyextra->name = yytext;
763 if (yyextra->insideBody)
765 addVariable(yyscanner,yyextra->type,yyextra->name);
767 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
769 <ClassName,ClassVar,CppCliTypeModifierFollowup>{B}*":"{B}* {
770 codifyLines(yyscanner,yytext);
771 yyextra->curClassBases.clear();
774 <PackageName>[ \t]*";" |
775 <Bases>^{Bopt}/"@"{ID} | // Objective-C interface
776 <Bases,ClassName,ClassVar,CppCliTypeModifierFollowup>{B}*"{"{B}* {
777 yyextra->theVarContext.pushScope();
778 yyextra->code->codify(yytext);
779 if (YY_START==ClassVar && yyextra->curClassName.isEmpty())
781 yyextra->curClassName = yyextra->name;
783 if (yyextra->searchingForBody)
785 yyextra->searchingForBody=FALSE;
786 yyextra->insideBody=TRUE;
788 if (yyextra->insideBody) yyextra->bodyCurlyCount++;
789 if (!yyextra->curClassName.isEmpty()) // valid class name
791 DBG_CTX((stderr,"** scope stack push CLASSBLOCK\n"));
792 yyextra->scopeStack.push(CLASSBLOCK);
793 pushScope(yyscanner,yyextra->curClassName);
794 DBG_CTX((stderr,"***** yyextra->curClassName=%s\n",qPrint(yyextra->curClassName)));
795 if (yyextra->symbolResolver.resolveClass(yyextra->currentDefinition,yyextra->curClassName)==0)
797 DBG_CTX((stderr,"Adding new class %s\n",qPrint(yyextra->curClassName)));
798 ScopedTypeVariant var(yyextra->curClassName);
799 // insert base classes.
800 for (const auto &s : yyextra->curClassBases)
802 const ClassDef *bcd=0;
803 auto it = yyextra->codeClassMap.find(s);
804 if (it!=yyextra->codeClassMap.end())
806 bcd = toClassDef(it->second.globalDef());
808 if (bcd==0) bcd=yyextra->symbolResolver.resolveClass(yyextra->currentDefinition,QCString(s));
809 if (bcd && bcd->name()!=yyextra->curClassName)
811 var.localDef()->insertBaseClass(bcd->name());
814 yyextra->codeClassMap.emplace(std::make_pair(yyextra->curClassName.str(),std::move(var)));
816 //printf("yyextra->codeClassList.count()=%d\n",yyextra->codeClassList.count());
818 else // not a class name -> assume inner block
820 DBG_CTX((stderr,"** scope stack push INNERBLOCK\n"));
821 yyextra->scopeStack.push(INNERBLOCK);
823 yyextra->curClassName.resize(0);
824 yyextra->curClassBases.clear();
827 <Bases>"virtual"|"public"|"protected"|"private"|"@public"|"@private"|"@protected" {
828 startFontClass(yyscanner,"keyword");
829 yyextra->code->codify(yytext);
830 endFontClass(yyscanner);
832 <Bases>{SEP}?({ID}{SEP})*{ID} {
833 DBG_CTX((stderr,"%s:addBase(%s)\n",qPrint(yyextra->curClassName),yytext));
834 yyextra->curClassBases.push_back(yytext);
835 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
838 yyextra->code->codify(yytext);
839 if (!yyextra->insideObjC)
841 yyextra->sharpCount=1;
846 yyextra->insideProtocolList=TRUE;
850 yyextra->code->codify(yytext);
851 yyextra->insideProtocolList=FALSE;
854 yyextra->code->codify(yytext);
855 ++yyextra->sharpCount;
858 yyextra->code->codify(yytext);
859 if (--yyextra->sharpCount<=0)
863 yyextra->code->codify(yytext);
864 yyextra->lastStringContext=YY_START;
868 yyextra->code->codify(yytext);
869 yyextra->lastStringContext=YY_START;
873 yyextra->code->codify(yytext);
874 yyextra->sharpCount=1;
878 yyextra->code->codify(yytext);
879 ++yyextra->sharpCount;
882 yyextra->code->codify(yytext);
883 if (--yyextra->sharpCount<=0)
889 yyextra->code->codify(yytext);
893 <Body>{SCOPEPREFIX}?"operator"{B}*"()"{Bopt}/"(" {
895 generateFunctionLink(yyscanner,*yyextra->code,yytext);
896 yyextra->bracketCount=0;
897 yyextra->args.resize(0);
898 yyextra->name+=yytext;
901 <Body>{SCOPEPREFIX}?"operator"/"(" {
903 generateFunctionLink(yyscanner,*yyextra->code,yytext);
904 yyextra->bracketCount=0;
905 yyextra->args.resize(0);
906 yyextra->name+=yytext;
909 <Body>{SCOPEPREFIX}?"operator"[^a-z_A-Z0-9\(\n]+/"(" {
911 generateFunctionLink(yyscanner,*yyextra->code,yytext);
912 yyextra->bracketCount=0;
913 yyextra->args.resize(0);
914 yyextra->name+=yytext;
917 <Body,TemplDecl>("template"|"generic")/([^a-zA-Z0-9]) {
918 startFontClass(yyscanner,"keyword");
919 codifyLines(yyscanner,yytext);
920 endFontClass(yyscanner);
921 yyextra->insideTemplate=TRUE;
922 yyextra->sharpCount=0;
924 <Body>"concept"{BN}+ {
925 startFontClass(yyscanner,"keyword");
926 codifyLines(yyscanner,yytext);
927 endFontClass(yyscanner);
930 <Body>"using"{BN}+"namespace"{BN}+ {
931 startFontClass(yyscanner,"keyword");
932 codifyLines(yyscanner,yytext);
933 endFontClass(yyscanner);
936 <ConceptName>{ID}("::"{ID})* {
937 addUsingDirective(yyscanner,yytext);
938 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
940 <ConceptName>"=" { codifyLines(yyscanner,yytext); BEGIN(Body); }
941 <UsingName>{ID}("::"{ID})* {
942 addUsingDirective(yyscanner,yytext);
943 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
946 <UsingName>\n { codifyLines(yyscanner,yytext); BEGIN(Body); }
947 <UsingName>. { codifyLines(yyscanner,yytext); BEGIN(Body); }
948 <Body,FuncCall>"$"?"this"("->"|".") { yyextra->code->codify(yytext); // this-> for C++, this. for C#
949 yyextra->isPrefixedWithThis = TRUE;
951 <Body>{KEYWORD}/([^a-z_A-Z0-9]) {
952 if (yyextra->lang==SrcLangExt_Java && qstrcmp("internal",yytext) ==0) REJECT;
953 if (skipLanguageSpecificKeyword(yyscanner,yytext)) REJECT;
954 startFontClass(yyscanner,"keyword");
955 codifyLines(yyscanner,yytext);
956 if (QCString(yytext)=="typedef")
959 yyextra->name+=yytext;
961 endFontClass(yyscanner);
963 <Body>{KEYWORD}/{B}* {
964 if (skipLanguageSpecificKeyword(yyscanner,yytext)) REJECT;
965 startFontClass(yyscanner,"keyword");
966 codifyLines(yyscanner,yytext);
967 endFontClass(yyscanner);
969 <Body>{KEYWORD}/{BN}*"(" {
970 if (skipLanguageSpecificKeyword(yyscanner,yytext)) REJECT;
971 startFontClass(yyscanner,"keyword");
972 codifyLines(yyscanner,yytext);
973 endFontClass(yyscanner);
974 yyextra->name.resize(0);yyextra->type.resize(0);
976 <FuncCall>"in"/{BN}* {
977 if (!yyextra->inForEachExpression) REJECT;
978 startFontClass(yyscanner,"keywordflow");
979 codifyLines(yyscanner,yytext);
980 endFontClass(yyscanner);
981 // insert the variable in the parent scope, see bug 546158
982 yyextra->theVarContext.popScope();
983 addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
984 yyextra->theVarContext.pushScope();
985 yyextra->name.resize(0);yyextra->type.resize(0);
987 <Body>{FLOWKW}/{BN}*"(" {
988 startFontClass(yyscanner,"keywordflow");
989 codifyLines(yyscanner,yytext);
990 endFontClass(yyscanner);
991 yyextra->name.resize(0);yyextra->type.resize(0);
992 yyextra->inForEachExpression = (qstrcmp(yytext,"for each")==0 || qstrcmp(yytext, "foreach")==0);
995 <Body>{FLOWCONDITION}/{BN}*"(" {
996 incrementFlowKeyWordCount(yyscanner);
997 startFontClass(yyscanner,"keywordflow");
998 codifyLines(yyscanner,yytext);
999 endFontClass(yyscanner);
1000 yyextra->name.resize(0);yyextra->type.resize(0);
1001 yyextra->inForEachExpression = (strcmp(yytext,"for each")==0 || strcmp(yytext, "foreach")==0);
1004 <Body>{FLOWKW}/([^a-z_A-Z0-9]) {
1005 startFontClass(yyscanner,"keywordflow");
1006 codifyLines(yyscanner,yytext);
1007 endFontClass(yyscanner);
1008 if (yyextra->inFunctionTryBlock && (qstrcmp(yytext,"catch")==0 || qstrcmp(yytext,"finally")==0))
1010 yyextra->inFunctionTryBlock=FALSE;
1013 <Body>{FLOWCONDITION}/([^a-z_A-Z0-9]) {
1014 incrementFlowKeyWordCount(yyscanner);
1015 startFontClass(yyscanner,"keywordflow");
1016 codifyLines(yyscanner,yytext);
1017 endFontClass(yyscanner);
1018 if (yyextra->inFunctionTryBlock && (strcmp(yytext,"catch")==0 || strcmp(yytext,"finally")==0))
1020 yyextra->inFunctionTryBlock=FALSE;
1023 <Body>{FLOWKW}/{B}* {
1024 startFontClass(yyscanner,"keywordflow");
1025 codifyLines(yyscanner,yytext);
1026 endFontClass(yyscanner);
1028 <Body>{FLOWCONDITION}/{B}* {
1029 incrementFlowKeyWordCount(yyscanner);
1030 startFontClass(yyscanner,"keywordflow");
1031 codifyLines(yyscanner,yytext);
1032 endFontClass(yyscanner);
1034 <Body>"*"{B}*")" { // end of cast?
1035 yyextra->code->codify(yytext);
1036 yyextra->theCallContext.popScope(yyextra->name, yyextra->type);
1037 yyextra->bracketCount--;
1038 yyextra->parmType = yyextra->name;
1042 yyextra->code->codify(yytext);
1044 <Body>[\\|\)\+\-\/\%\~\!] {
1045 yyextra->code->codify(yytext);
1046 yyextra->name.resize(0);yyextra->type.resize(0);
1049 yyextra->theCallContext.popScope(yyextra->name, yyextra->type);
1050 yyextra->bracketCount--;
1054 <Body,TemplDecl,ObjCMethod>{TYPEKW}/{B}* {
1055 startFontClass(yyscanner,"keywordtype");
1056 yyextra->code->codify(yytext);
1057 endFontClass(yyscanner);
1059 yyextra->name+=yytext;
1061 <Body,TemplDecl,ObjCMethod>{TYPEKWSL}/{B}* {
1062 if (yyextra->lang!=SrcLangExt_Slice)
1068 startFontClass(yyscanner,"keywordtype");
1069 yyextra->code->codify(yytext);
1070 endFontClass(yyscanner);
1072 yyextra->name+=yytext;
1075 <Body>"generic"/{B}*"<"[^\n\/\-\.\{\">]*">"{B}* {
1076 startFontClass(yyscanner,"keyword");
1077 yyextra->code->codify(yytext);
1078 endFontClass(yyscanner);
1079 yyextra->sharpCount=0;
1082 <Body>"template"/{B}*"<"[^\n\/\-\.\{\">]*">"{B}* { // template<...>
1083 startFontClass(yyscanner,"keyword");
1084 yyextra->code->codify(yytext);
1085 endFontClass(yyscanner);
1086 yyextra->sharpCount=0;
1089 <TemplDecl>"class"|"typename" {
1090 startFontClass(yyscanner,"keyword");
1091 codifyLines(yyscanner,yytext);
1092 endFontClass(yyscanner);
1095 yyextra->code->codify(yytext);
1096 yyextra->sharpCount++;
1099 yyextra->code->codify(yytext);
1100 yyextra->sharpCount--;
1101 if (yyextra->sharpCount<=0)
1107 startFontClass(yyscanner,"keyword");
1108 codifyLines(yyscanner,yytext);
1109 endFontClass(yyscanner);
1110 BEGIN( yyextra->lastTemplCastContext );
1112 <TemplCast>{ID}("::"{ID})* {
1113 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
1115 <TemplCast>("const"|"volatile"){B}* {
1116 startFontClass(yyscanner,"keyword");
1117 codifyLines(yyscanner,yytext);
1118 endFontClass(yyscanner);
1121 codifyLines(yyscanner,yytext);
1123 <Body,MemberCall2,FuncCall>{CASTKW}{B}*"<" { // static_cast<T>(
1124 startFontClass(yyscanner,"keyword");
1125 codifyLines(yyscanner,yytext);
1126 endFontClass(yyscanner);
1127 yyextra->lastTemplCastContext = YY_START;
1130 <Body>"$this->"{SCOPENAME}/{BN}*[;,)\]] { // PHP member variable
1132 generatePHPVariableLink(yyscanner,*yyextra->code,yytext);
1133 yyextra->name+=yytext+7;
1135 <Body,TemplCast>{SCOPENAME}{B}*"<"[^\n\/\-\.\{\">\(]*">"{ENDIDopt}/{B}* { // A<T> *pt;
1136 if (isCastKeyword(yytext) && YY_START==Body)
1141 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
1142 yyextra->name+=yytext;
1144 <Body>{SCOPENAME}/{BN}*[:;,)\]] { // "int var;" or "var, var2" or "debug(f) macro" , or int var : 5;
1145 if (startsWithKeyword(yytext,"typedef")) REJECT;
1147 // changed this to generateFunctionLink, see bug 624514
1148 generateFunctionLink(yyscanner,*yyextra->code,yytext);
1149 yyextra->name+=yytext;
1151 <Body>{SCOPENAME}/{B}* { // p->func()
1152 if (startsWithKeyword(yytext,"typedef")) REJECT;
1154 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
1155 yyextra->name+=yytext;
1157 <Body>"("{B}*("*"{B}*)+{SCOPENAME}+{B}*")"/{B}* { // (*p)->func() but not "if (p) ..."
1158 yyextra->code->codify(yytext);
1159 uint s=0;while (s<(uint)yyleng && !isId(yytext[s])) s++;
1160 uint e=(uint)yyleng-1;while (e>1 && !isId(yytext[e])) e--;
1161 QCString varname = ((QCString)yytext).mid(s,e-s+1);
1163 yyextra->name=varname;
1165 <Body>{SCOPETNAME}{B}*"<"[^\n\/\-\.\{\">]*">"/{BN}*"(" |
1166 <Body>{SCOPETNAME}/{BN}*"(" { // a() or c::a() or t<A,B>::a() or A\B\foo()
1167 if (isCastKeyword(yytext))
1172 generateFunctionLink(yyscanner,*yyextra->code,yytext);
1173 yyextra->bracketCount=0;
1174 yyextra->args.resize(0);
1175 yyextra->name+=yytext;
1178 <FuncCall,Body,MemberCall,MemberCall2,SkipInits,InlineInit>{RAWBEGIN} {
1179 QCString text(yytext);
1180 uint i=(uint)text.find('R');
1181 yyextra->code->codify(text.left(i+1));
1182 startFontClass(yyscanner,"stringliteral");
1183 yyextra->code->codify(QCString(yytext+i+1));
1184 yyextra->lastStringContext=YY_START;
1185 yyextra->inForEachExpression = FALSE;
1186 yyextra->delimiter = yytext+i+2;
1187 yyextra->delimiter=yyextra->delimiter.left(yyextra->delimiter.length()-1);
1190 <FuncCall,Body,MemberCall,MemberCall2,SkipInits,InlineInit>\" {
1191 startFontClass(yyscanner,"stringliteral");
1192 yyextra->code->codify(yytext);
1193 yyextra->lastStringContext=YY_START;
1194 yyextra->inForEachExpression = FALSE;
1195 BEGIN( SkipString );
1197 <FuncCall,Body,MemberCall,MemberCall2,SkipInits,InlineInit>{NUMBER} { //Note similar code in commentcnv.l
1198 if (yyextra->lang!=SrcLangExt_Cpp) REJECT;
1199 yyextra->code->codify(yytext);
1201 <FuncCall,Body,MemberCall,MemberCall2,SkipInits,InlineInit>\' {
1202 startFontClass(yyscanner,"stringliteral");
1203 yyextra->code->codify(yytext);
1204 yyextra->lastStringContext=YY_START;
1205 yyextra->inForEachExpression = FALSE;
1206 BEGIN( SkipStringS );
1208 <SkipString>[^\"\\\r\n]* {
1209 yyextra->code->codify(yytext);
1211 <SkipStringS>[^\'\\\r\n]* {
1212 yyextra->code->codify(yytext);
1214 <SkipString,SkipStringS>{CPPC}|{CCS} {
1215 yyextra->code->codify(yytext);
1218 yyextra->code->codify(yytext);
1219 endFontClass(yyscanner);
1220 BEGIN( yyextra->lastStringContext );
1223 yyextra->code->codify(yytext);
1224 endFontClass(yyscanner);
1225 BEGIN( yyextra->lastStringContext );
1227 <SkipString,SkipStringS>\\. {
1228 yyextra->code->codify(yytext);
1230 <RawString>{RAWEND} {
1231 yyextra->code->codify(yytext);
1232 QCString delimiter(yytext+1);
1233 delimiter=delimiter.left(delimiter.length()-1);
1234 if (delimiter==yyextra->delimiter)
1236 BEGIN( yyextra->lastStringContext );
1239 <RawString>[^)\n]+ { yyextra->code->codify(yytext); }
1240 <RawString>. { yyextra->code->codify(yytext); }
1241 <RawString>\n { codifyLines(yyscanner,yytext); }
1242 <SkipVerbString>[^"\n]+ {
1243 yyextra->code->codify(yytext);
1245 <SkipVerbString>\"\" { // escaped quote
1246 yyextra->code->codify(yytext);
1248 <SkipVerbString>\" { // end of string
1249 yyextra->code->codify(yytext);
1250 endFontClass(yyscanner);
1251 BEGIN( yyextra->lastVerbStringContext );
1254 yyextra->code->codify(yytext);
1256 <SkipVerbString>\n {
1257 codifyLines(yyscanner,yytext);
1260 yyextra->code->codify(yytext);
1261 yyextra->name.resize(0);yyextra->type.resize(0);
1264 if (yyextra->insideTemplate)
1266 yyextra->sharpCount++;
1268 yyextra->code->codify(yytext);
1271 if (yyextra->insideTemplate)
1273 if (--yyextra->sharpCount<=0)
1275 yyextra->insideTemplate=FALSE;
1278 yyextra->code->codify(yytext);
1280 <Body,MemberCall,MemberCall2,FuncCall>"'"((\\0[Xx0-9]+)|(\\.)|(.))"'" {
1281 startFontClass(yyscanner,"charliteral");
1282 yyextra->code->codify(yytext);
1283 endFontClass(yyscanner);
1286 if (yytext[0]=='-') // -> could be overloaded
1288 updateCallContextForSmartPointer(yyscanner);
1290 yyextra->code->codify(yytext);
1291 yyextra->memCallContext = YY_START;
1292 BEGIN( MemberCall );
1294 <MemberCall>{SCOPETNAME}/{BN}*"(" {
1295 if (yyextra->theCallContext.getScope().globalDef())
1297 if (!generateClassMemberLink(yyscanner,*yyextra->code,yyextra->theCallContext.getScope().globalDef(),yytext))
1299 codifyLines(yyscanner,yytext);
1300 addToSearchIndex(yyscanner,yytext);
1302 yyextra->name.resize(0);
1306 codifyLines(yyscanner,yytext);
1307 addToSearchIndex(yyscanner,yytext);
1308 yyextra->name.resize(0);
1310 yyextra->type.resize(0);
1311 if (yyextra->memCallContext==Body)
1317 BEGIN(yyextra->memCallContext);
1320 <MemberCall>{SCOPENAME}/{B}* {
1321 if (yyextra->theCallContext.getScope().globalDef())
1323 DBG_CTX((stderr,"yyextra->theCallContext.getClass()=%p\n",(void*)yyextra->theCallContext.getScope().globalDef()));
1324 if (!generateClassMemberLink(yyscanner,*yyextra->code,yyextra->theCallContext.getScope().globalDef(),yytext))
1326 codifyLines(yyscanner,yytext);
1327 addToSearchIndex(yyscanner,yytext);
1329 yyextra->name.resize(0);
1333 DBG_CTX((stderr,"no class context!\n"));
1334 codifyLines(yyscanner,yytext);
1335 addToSearchIndex(yyscanner,yytext);
1336 yyextra->name.resize(0);
1338 yyextra->type.resize(0);
1339 BEGIN(yyextra->memCallContext);
1342 if (yyextra->insideObjC && *yytext=='[')
1344 DBG_CTX((stderr,"Found start of ObjC call!\n"));
1345 // start of a method call
1346 yyextra->contextMap.clear();
1347 yyextra->nameMap.clear();
1348 yyextra->objectMap.clear();
1349 yyextra->wordMap.clear();
1350 yyextra->commentMap.clear();
1351 yyextra->currentCtxId = 0;
1352 yyextra->currentNameId = 0;
1353 yyextra->currentObjId = 0;
1354 yyextra->currentCtx = 0;
1355 yyextra->braceCount = 0;
1361 yyextra->code->codify(yytext);
1362 yyextra->saveName = yyextra->name;
1363 yyextra->saveType = yyextra->type;
1364 if (*yytext!='[' && !yyextra->type.isEmpty())
1366 //printf("yyextra->scopeStack.bottom()=%p\n",yyextra->scopeStack.bottom());
1367 //if (yyextra->scopeStack.top()!=CLASSBLOCK) // commented out for bug731363
1369 //printf("AddVariable: '%s' '%s' context=%d\n",
1370 // qPrint(yyextra->type),qPrint(yyextra->name),yyextra->theVarContext.count());
1371 addVariable(yyscanner,yyextra->type,yyextra->name);
1373 yyextra->name.resize(0);
1375 if (*yytext==';' || *yytext=='=')
1377 yyextra->type.resize(0);
1378 yyextra->name.resize(0);
1380 else if (*yytext=='[')
1382 yyextra->theCallContext.pushScope(yyextra->name, yyextra->type);
1384 yyextra->args.resize(0);
1385 yyextra->parmType.resize(0);
1386 yyextra->parmName.resize(0);
1389 <ObjCCall,ObjCMName>"["|"{" {
1390 saveObjCContext(yyscanner);
1391 yyextra->currentCtx->format+=*yytext;
1393 DBG_CTX((stderr,"open\n"));
1395 <ObjCCall,ObjCMName>"]"|"}" {
1396 yyextra->currentCtx->format+=*yytext;
1397 restoreObjCContext(yyscanner);
1399 if (yyextra->currentCtx==0)
1402 ObjCCallCtx *ctx = 0;
1403 auto it = yyextra->contextMap.find(0);
1404 if (it!=yyextra->contextMap.end())
1406 ctx = it->second.get();
1408 writeObjCMethodCall(yyscanner,ctx);
1411 DBG_CTX((stderr,"close\n"));
1413 <ObjCCall,ObjCMName>{CPPC}.* {
1414 yyextra->currentCtx->format+=escapeComment(yyscanner,yytext);
1416 <ObjCCall,ObjCMName>{CCS} {
1417 yyextra->lastObjCCallContext = YY_START;
1418 yyextra->currentCtx->comment.str(yytext);
1419 BEGIN(ObjCCallComment);
1421 <ObjCCallComment>{CCE} {
1422 yyextra->currentCtx->comment << yytext;
1423 std::string commentStr = yyextra->currentCtx->comment.str();
1424 yyextra->currentCtx->format+=escapeComment(yyscanner,commentStr.c_str());
1425 BEGIN(yyextra->lastObjCCallContext);
1427 <ObjCCallComment>[^*\n]+ { yyextra->currentCtx->comment << yytext; }
1428 <ObjCCallComment>{CPPC}|{CCS} { yyextra->currentCtx->comment << yytext; }
1429 <ObjCCallComment>\n { yyextra->currentCtx->comment << *yytext; }
1430 <ObjCCallComment>. { yyextra->currentCtx->comment << *yytext; }
1432 yyextra->currentCtx->format+=escapeObject(yyscanner,yytext);
1433 if (yyextra->braceCount==0)
1435 yyextra->currentCtx->objectTypeOrName=yytext;
1436 DBG_CTX((stderr,"new type=%s\n",qPrint(yyextra->currentCtx->objectTypeOrName)));
1440 <ObjCMName>{ID}/{BN}*"]" {
1441 if (yyextra->braceCount==0 &&
1442 yyextra->currentCtx->methodName.isEmpty())
1444 yyextra->currentCtx->methodName=yytext;
1445 yyextra->currentCtx->format+=escapeName(yyscanner,yytext);
1449 yyextra->currentCtx->format+=escapeWord(yyscanner,yytext);
1452 <ObjCMName>{ID}/{BN}*":" {
1453 if (yyextra->braceCount==0)
1455 yyextra->currentCtx->methodName+=yytext;
1456 yyextra->currentCtx->methodName+=":";
1458 yyextra->currentCtx->format+=escapeName(yyscanner,yytext);
1460 <ObjCSkipStr>[^\n\"$\\]* { yyextra->currentCtx->format+=yytext; }
1461 <ObjCSkipStr>\\. { yyextra->currentCtx->format+=yytext; }
1462 <ObjCSkipStr>"\"" { yyextra->currentCtx->format+=yytext;
1463 BEGIN(yyextra->lastStringContext);
1465 <ObjCCall,ObjCMName>{CHARLIT} { yyextra->currentCtx->format+=yytext; }
1466 <ObjCCall,ObjCMName>"@"?"\"" { yyextra->currentCtx->format+=yytext;
1467 yyextra->lastStringContext=YY_START;
1470 <ObjCCall,ObjCMName,ObjCSkipStr>"$" { yyextra->currentCtx->format+="$$"; }
1471 <ObjCCall,ObjCMName>"(" { yyextra->currentCtx->format+=*yytext; yyextra->braceCount++; }
1472 <ObjCCall,ObjCMName>")" { yyextra->currentCtx->format+=*yytext; yyextra->braceCount--; }
1473 <ObjCSkipStr>"@"/"\"" { // needed to prevent matching the global rule (for C#)
1474 yyextra->currentCtx->format+=yytext;
1476 <ObjCCall,ObjCMName,ObjCSkipStr>{ID} { yyextra->currentCtx->format+=escapeWord(yyscanner,yytext); }
1477 <ObjCCall,ObjCMName,ObjCSkipStr>. { yyextra->currentCtx->format+=*yytext; }
1478 <ObjCCall,ObjCMName,ObjCSkipStr>\n { yyextra->currentCtx->format+=*yytext; }
1481 yyextra->theCallContext.popScope(yyextra->name, yyextra->type);
1482 yyextra->code->codify(yytext);
1483 // TODO: nested arrays like: a[b[0]->func()]->func()
1484 yyextra->name = yyextra->saveName;
1485 yyextra->type = yyextra->saveType;
1488 yyextra->code->codify(yytext);
1490 <Body>[0-9]+[xX][0-9A-Fa-f]+ {
1491 yyextra->code->codify(yytext);
1493 <MemberCall2,FuncCall>{KEYWORD}/([^a-z_A-Z0-9]) {
1494 //addParmType(yyscanner);
1495 //yyextra->parmName=yytext;
1496 if (skipLanguageSpecificKeyword(yyscanner,yytext)) REJECT;
1497 startFontClass(yyscanner,"keyword");
1498 yyextra->code->codify(yytext);
1499 endFontClass(yyscanner);
1501 <MemberCall2,FuncCall,OldStyleArgs,TemplCast>{TYPEKW}/([^a-z_A-Z0-9]) {
1502 addParmType(yyscanner);
1503 yyextra->parmName=yytext;
1504 startFontClass(yyscanner,"keywordtype");
1505 yyextra->code->codify(yytext);
1506 endFontClass(yyscanner);
1508 <MemberCall2,FuncCall,OldStyleArgs,TemplCast>{TYPEKWSL}/([^a-z_A-Z0-9]) {
1509 if (yyextra->lang!=SrcLangExt_Slice)
1515 addParmType(yyscanner);
1516 yyextra->parmName=yytext;
1517 startFontClass(yyscanner,"keywordtype");
1518 yyextra->code->codify(yytext);
1519 endFontClass(yyscanner);
1522 <MemberCall2,FuncCall>{FLOWKW}/([^a-z_A-Z0-9]) {
1523 addParmType(yyscanner);
1524 yyextra->parmName=yytext;
1525 startFontClass(yyscanner,"keywordflow");
1526 yyextra->code->codify(yytext);
1527 endFontClass(yyscanner);
1529 <MemberCall2,FuncCall>{FLOWCONDITION}/([^a-z_A-Z0-9]) {
1530 incrementFlowKeyWordCount(yyscanner);
1531 addParmType(yyscanner);
1532 yyextra->parmName=yytext;
1533 startFontClass(yyscanner,"keywordflow");
1534 yyextra->code->codify(yytext);
1535 endFontClass(yyscanner);
1537 <MemberCall2,FuncCall>{ID}(({B}*"<"[^\n\[\](){}<>]*">")?({B}*"::"{B}*{ID})?)* {
1538 if (isCastKeyword(yytext))
1542 addParmType(yyscanner);
1543 yyextra->parmName=yytext;
1544 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext,!yyextra->insideBody);
1546 <FuncCall>";" { // probably a cast, not a function call
1547 yyextra->code->codify(yytext);
1548 yyextra->inForEachExpression = FALSE;
1551 <MemberCall2,FuncCall>, {
1552 yyextra->code->codify(yytext);
1553 addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
1554 yyextra->parmType.resize(0);yyextra->parmName.resize(0);
1556 <MemberCall2,FuncCall>"{" {
1557 if (yyextra->bracketCount>0)
1559 yyextra->code->codify(yytext);
1560 yyextra->skipInlineInitContext=YY_START;
1561 yyextra->curlyCount=0;
1569 <InlineInit>"{" { yyextra->curlyCount++;
1570 yyextra->code->codify(yytext);
1573 yyextra->code->codify(yytext);
1574 if (--yyextra->curlyCount<=0)
1576 BEGIN(yyextra->skipInlineInitContext);
1580 codifyLines(yyscanner,yytext);
1583 yyextra->code->codify(yytext);
1585 <MemberCall2,FuncCall>"(" {
1586 yyextra->parmType.resize(0);yyextra->parmName.resize(0);
1587 yyextra->code->codify(yytext);
1588 yyextra->bracketCount++;
1589 yyextra->theCallContext.pushScope(yyextra->name, yyextra->type);
1590 if (YY_START==FuncCall && !yyextra->insideBody)
1592 yyextra->theVarContext.pushScope();
1595 <MemberCall2,FuncCall>{OPERATOR} { // operator
1596 if (qstrcmp(yytext,"*") &&
1597 qstrcmp(yytext,"&") &&
1598 qstrcmp(yytext,"^") &&
1599 qstrcmp(yytext,"%")) // typically a pointer or reference
1601 // not a * or &, or C++/CLI's ^ or %
1602 yyextra->parmType.resize(0);yyextra->parmName.resize(0);
1604 yyextra->code->codify(yytext);
1606 <MemberCall,MemberCall2,FuncCall>("*"{B}*)?")" {
1607 if (yytext[0]==')') // no a pointer cast
1609 DBG_CTX((stderr,"addVariable(%s,%s)\n",qPrint(yyextra->parmType),qPrint(yyextra->parmName)));
1610 if (yyextra->parmType.isEmpty())
1612 yyextra->parmType=yyextra->parmName;
1613 yyextra->parmName.resize(0);
1615 addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
1619 yyextra->parmType = yyextra->parmName;
1620 yyextra->parmName.resize(0);
1621 addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
1623 yyextra->theCallContext.popScope(yyextra->name, yyextra->type);
1624 yyextra->inForEachExpression = FALSE;
1625 //yyextra->theCallContext.setClass(0); // commented out, otherwise a()->b() does not work for b().
1626 yyextra->code->codify(yytext);
1627 if (--yyextra->bracketCount<=0)
1629 if (yyextra->name.isEmpty())
1639 <CallEnd>[ \t\n]* { codifyLines(yyscanner,yytext); }
1641 <MemberCall2,FuncCall>")"[ \t\n]*[;:] {
1644 codifyLines(yyscanner,yytext);
1645 yyextra->bracketCount=0;
1646 if (*yytext==';') yyextra->searchingForBody=FALSE;
1647 if (!yyextra->type.isEmpty())
1649 DBG_CTX((stderr,"add variable yyextra->type=%s yyextra->name=%s)\n",qPrint(yyextra->type),qPrint(yyextra->name)));
1650 addVariable(yyscanner,yyextra->type,yyextra->name);
1652 yyextra->parmType.resize(0);yyextra->parmName.resize(0);
1653 yyextra->theCallContext.setScope(ScopedTypeVariant());
1654 if (*yytext==';' || yyextra->insideBody)
1656 if (!yyextra->insideBody)
1658 yyextra->theVarContext.popScope();
1660 yyextra->name.resize(0);yyextra->type.resize(0);
1665 yyextra->bracketCount=0;
1669 <CallEnd>{ENDQopt}/{BN}*(";"|"="|"throw"{BN}*"(") {
1670 startFontClass(yyscanner,"keyword");
1671 codifyLines(yyscanner,yytext);
1672 endFontClass(yyscanner);
1674 <CallEnd,OldStyleArgs>("const"|"volatile"|"sealed"|"override")*({BN}+("const"|"volatile"|"sealed"|"override"))*{BN}*"{" {
1675 if (yyextra->insideBody)
1677 yyextra->theVarContext.pushScope();
1679 addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
1680 //yyextra->theCallContext.popScope(yyextra->name, yyextra->type);
1681 yyextra->parmType.resize(0);yyextra->parmName.resize(0);
1682 int index = yyextra->name.findRev("::");
1683 DBG_CTX((stderr,"yyextra->name=%s\n",qPrint(yyextra->name)));
1686 QCString scope = yyextra->name.left((uint)index);
1687 if (!yyextra->classScope.isEmpty()) scope.prepend((yyextra->classScope+"::"));
1688 const ClassDef *cd=yyextra->symbolResolver.resolveClass(Doxygen::globalScope,scope);
1691 setClassScope(yyscanner,cd->name());
1692 yyextra->scopeStack.push(SCOPEBLOCK);
1693 DBG_CTX((stderr,"** scope stack push SCOPEBLOCK\n"));
1697 //setClassScope(yyscanner,yyextra->realScope);
1698 yyextra->scopeStack.push(INNERBLOCK);
1699 DBG_CTX((stderr,"** scope stack push INNERBLOCK\n"));
1704 DBG_CTX((stderr,"** scope stack push INNERBLOCK\n"));
1705 yyextra->scopeStack.push(INNERBLOCK);
1707 yytext[yyleng-1]='\0';
1708 QCString cv(yytext);
1709 if (!cv.stripWhiteSpace().isEmpty())
1711 startFontClass(yyscanner,"keyword");
1712 codifyLines(yyscanner,yytext);
1713 endFontClass(yyscanner);
1715 else // just whitespace
1717 codifyLines(yyscanner,yytext);
1719 yyextra->code->codify("{");
1720 if (yyextra->searchingForBody)
1722 yyextra->searchingForBody=FALSE;
1723 yyextra->insideBody=TRUE;
1725 if (yyextra->insideBody) yyextra->bodyCurlyCount++;
1726 yyextra->type.resize(0); yyextra->name.resize(0);
1729 <CallEnd>"try" { // function-try-block
1730 startFontClass(yyscanner,"keyword");
1731 yyextra->code->codify(yytext);
1732 endFontClass(yyscanner);
1733 yyextra->inFunctionTryBlock=TRUE;
1735 <CallEnd>"requires" { // function-try-block
1736 startFontClass(yyscanner,"keyword");
1737 yyextra->code->codify(yytext);
1738 endFontClass(yyscanner);
1741 if (yyextra->insideBody || !yyextra->parmType.isEmpty())
1745 // could be K&R style definition
1746 addParmType(yyscanner);
1747 yyextra->parmName=yytext;
1748 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext,!yyextra->insideBody);
1749 BEGIN(OldStyleArgs);
1751 <OldStyleArgs>{ID} {
1752 addParmType(yyscanner);
1753 yyextra->parmName=yytext;
1754 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext,!yyextra->insideBody);
1756 <OldStyleArgs>[,;] {
1757 yyextra->code->codify(yytext);
1758 addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
1759 if (*yytext==';') yyextra->parmType.resize(0);
1760 yyextra->parmName.resize(0);
1762 <CallEnd,OldStyleArgs>"#" {
1763 startFontClass(yyscanner,"preprocessor");
1764 yyextra->lastSkipCppContext = Body;
1765 yyextra->code->codify(yytext);
1770 if (!yyextra->insideBody)
1772 yyextra->theVarContext.popScope();
1774 yyextra->name.resize(0);yyextra->args.resize(0);
1775 yyextra->parmType.resize(0);yyextra->parmName.resize(0);
1779 yyextra->code->codify(yytext);
1780 yyextra->type.resize(0); yyextra->name.resize(0);
1784 yyextra->code->codify(yytext);
1785 if (yyextra->searchingForBody)
1787 yyextra->searchingForBody=FALSE;
1788 yyextra->insideBody=TRUE;
1790 if (yyextra->insideBody) yyextra->bodyCurlyCount++;
1791 if (yyextra->name.find("::")!=-1)
1793 DBG_CTX((stderr,"** scope stack push SCOPEBLOCK\n"));
1794 yyextra->scopeStack.push(SCOPEBLOCK);
1795 setClassScope(yyscanner,yyextra->realScope);
1799 DBG_CTX((stderr,"** scope stack push INNERBLOCK\n"));
1800 yyextra->scopeStack.push(INNERBLOCK);
1802 yyextra->type.resize(0); yyextra->name.resize(0);
1805 <SkipInits>{ID}{B}*"{" {
1806 QCString text(yytext);
1807 int bracketPos = text.find('{');
1808 int spacePos = text.find(' ');
1809 int len = spacePos==-1 ? bracketPos : spacePos;
1810 generateClassOrGlobalLink(yyscanner,*yyextra->code,text.left(len));
1811 yyextra->code->codify(QCString(yytext+len));
1814 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
1816 <FuncCall>{ID}/"(" {
1817 generateFunctionLink(yyscanner,*yyextra->code,yytext);
1819 <FuncCall>{ID}/("."|"->") {
1820 yyextra->name=yytext;
1821 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
1822 BEGIN( MemberCall2 );
1824 <FuncCall,MemberCall2>("("{B}*("*"{B}*)+{ID}+{B}*")"{B}*)/("."|"->") {
1825 yyextra->code->codify(yytext);
1826 uint s=0;while (!isId(yytext[s])) s++;
1827 uint e=(uint)yyleng-1;while (e>1 && !isId(yytext[e])) e--;
1828 yyextra->name=((QCString)yytext).mid(s,e-s+1);
1829 BEGIN( MemberCall2 );
1831 <MemberCall2>{ID}/([ \t\n]*"(") {
1832 if (!yyextra->args.isEmpty())
1833 generateMemberLink(yyscanner,*yyextra->code,yyextra->args,yytext);
1835 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
1836 yyextra->args.resize(0);
1839 <MemberCall2>{ID}/([ \t\n]*("."|"->")) {
1840 //yyextra->code->codify(yytext);
1841 yyextra->name=yytext;
1842 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
1843 BEGIN( MemberCall2 );
1845 <MemberCall2>"->"|"." {
1846 if (yytext[0]=='-') // -> could be overloaded
1848 updateCallContextForSmartPointer(yyscanner);
1850 yyextra->code->codify(yytext);
1851 yyextra->memCallContext = YY_START;
1852 BEGIN( MemberCall );
1854 <SkipComment>{CCS}("!"?){CCE} {
1855 yyextra->code->codify(yytext);
1856 endFontClass(yyscanner);
1857 BEGIN( yyextra->lastCContext ) ;
1859 <SkipComment>{CPPC}|{CCS} {
1860 yyextra->code->codify(yytext);
1862 <SkipComment>[^*\/\n]+ {
1863 yyextra->code->codify(yytext);
1865 <SkipComment>[ \t]*{CCE} {
1866 yyextra->code->codify(yytext);
1867 endFontClass(yyscanner);
1868 if (yyextra->lastCContext==SkipCPP)
1870 startFontClass(yyscanner,"preprocessor");
1872 BEGIN( yyextra->lastCContext ) ;
1874 <SkipCxxComment>[^\r\n]*"\\"[\r]?\n { // line continuation
1875 codifyLines(yyscanner,yytext);
1877 <SkipCxxComment>[^\r\n]+ {
1878 yyextra->code->codify(yytext);
1881 <SkipCxxComment>\n {
1883 endFontClass(yyscanner);
1884 BEGIN( yyextra->lastCContext ) ;
1887 yyextra->code->codify(yytext);
1889 <RemoveSpecialCComment>{CCE}{B}*\n({B}*\n)*({B}*(({CPPC}"@"[{}])|({CCS}"@"[{}]{CCE})){B}*\n)?{B}*{CCS}[*!]/{NCOMM} {
1890 yyextra->yyLineNr+=QCString(yytext).contains('\n');
1892 <RemoveSpecialCComment>{CCE}{B}*\n({B}*\n)*({B}*(({CPPC}"@"[{}])|({CCS}"@"[{}]{CCE})){B}*\n)? {
1893 if (yyextra->lastSpecialCContext==SkipCxxComment)
1894 { // force end of C++ comment here
1895 yyextra->yyLineNr+=QCString(yytext).contains('\n');
1896 nextCodeLine(yyscanner);
1897 endFontClass(yyscanner);
1898 BEGIN( yyextra->lastCContext ) ;
1902 yyextra->yyLineNr+=QCString(yytext).contains('\n');
1903 if (yytext[yyleng-1]=='\n')
1905 yyextra->yyLineNr--;
1910 nextCodeLine(yyscanner);
1912 BEGIN(yyextra->lastSpecialCContext);
1915 <RemoveSpecialCComment>{CCE} {
1916 BEGIN(yyextra->lastSpecialCContext);
1918 <RemoveSpecialCComment>[^*\n]+
1919 <RemoveSpecialCComment>{CPPC}|{CCS}
1920 <RemoveSpecialCComment>\n { yyextra->yyLineNr++; }
1921 <RemoveSpecialCComment>.
1922 <MemberCall>[^a-z_A-Z0-9(\n] {
1923 yyextra->code->codify(yytext);
1924 yyextra->type.resize(0);
1925 yyextra->name.resize(0);
1926 BEGIN(yyextra->memCallContext);
1928 <*>\n({B}*{CPPC}[!/][^\n]*\n)+ { // remove special one-line comment
1929 if (YY_START==SkipCPP) REJECT;
1930 if (Config_getBool(STRIP_CODE_COMMENTS))
1932 yyextra->yyLineNr+=QCString(yytext).contains('\n');
1933 nextCodeLine(yyscanner);
1937 startFontClass(yyscanner,"comment");
1938 codifyLines(yyscanner,yytext);
1939 endFontClass(yyscanner);
1941 if (YY_START==SkipCxxComment)
1943 endFontClass(yyscanner);
1944 BEGIN( yyextra->lastCContext ) ;
1948 endFontClass(yyscanner);
1949 BEGIN( yyextra->lastSkipCppContext ) ;
1952 <*>\n{B}*{CPPC}"@"[{}].*\n { // remove one-line group marker
1953 if (Config_getBool(STRIP_CODE_COMMENTS))
1955 yyextra->yyLineNr+=2;
1956 nextCodeLine(yyscanner);
1960 startFontClass(yyscanner,"comment");
1961 codifyLines(yyscanner,yytext);
1962 endFontClass(yyscanner);
1964 if (YY_START==SkipCxxComment)
1966 endFontClass(yyscanner);
1967 BEGIN( yyextra->lastCContext ) ;
1970 <*>\n{B}*{CCS}"@"[{}] { // remove one-line group marker
1971 if (Config_getBool(STRIP_CODE_COMMENTS))
1973 if (YY_START != RemoveSpecialCComment) yyextra->lastSpecialCContext = YY_START;
1974 yyextra->yyLineNr++;
1975 BEGIN(RemoveSpecialCComment);
1979 // check is to prevent getting stuck in skipping C++ comments
1980 if (YY_START != SkipComment && YY_START != SkipCxxComment)
1982 yyextra->lastCContext = YY_START ;
1984 startFontClass(yyscanner,"comment");
1985 codifyLines(yyscanner,yytext);
1989 <*>^{B}*{CPPC}"@"[{}].*\n { // remove one-line group marker
1990 if (Config_getBool(STRIP_CODE_COMMENTS))
1992 yyextra->yyLineNr++;
1993 nextCodeLine(yyscanner);
1997 startFontClass(yyscanner,"comment");
1998 codifyLines(yyscanner,yytext);
1999 endFontClass(yyscanner);
2002 <*>^{B}*{CCS}"@"[{}] { // remove multi-line group marker
2003 if (Config_getBool(STRIP_CODE_COMMENTS))
2005 if (YY_START != RemoveSpecialCComment) yyextra->lastSpecialCContext = YY_START;
2006 BEGIN(RemoveSpecialCComment);
2010 // check is to prevent getting stuck in skipping C++ comments
2011 if (YY_START != SkipComment && YY_START != SkipCxxComment)
2013 yyextra->lastCContext = YY_START ;
2015 startFontClass(yyscanner,"comment");
2016 yyextra->code->codify(yytext);
2020 <*>^{B}*{CPPC}[!/][^\n]* { // remove special one-line comment
2021 if (!Config_getBool(STRIP_CODE_COMMENTS))
2023 startFontClass(yyscanner,"comment");
2024 codifyLines(yyscanner,yytext);
2025 endFontClass(yyscanner);
2028 <*>{CPPC}[!/][^\n]* { // strip special one-line comment
2029 if (YY_START==SkipComment || YY_START==SkipString) REJECT;
2030 if (!Config_getBool(STRIP_CODE_COMMENTS))
2032 startFontClass(yyscanner,"comment");
2033 codifyLines(yyscanner,yytext);
2034 endFontClass(yyscanner);
2037 <*>\n{B}*{CCS}[!*]/{NCOMM} {
2038 if (Config_getBool(STRIP_CODE_COMMENTS))
2040 if (YY_START != RemoveSpecialCComment) yyextra->lastSpecialCContext = YY_START;
2041 yyextra->yyLineNr++;
2042 BEGIN(RemoveSpecialCComment);
2046 // check is to prevent getting stuck in skipping C++ comments
2047 if (YY_START != SkipComment && YY_START != SkipCxxComment)
2049 yyextra->lastCContext = YY_START ;
2051 startFontClass(yyscanner,"comment");
2052 codifyLines(yyscanner,yytext);
2056 <*>^{B}*{CCS}"*"[*]+/[^/] { // special C "banner" comment block at a new line
2057 if (Config_getBool(JAVADOC_BANNER) && Config_getBool(STRIP_CODE_COMMENTS))
2059 if (YY_START != RemoveSpecialCComment) yyextra->lastSpecialCContext = YY_START;
2060 BEGIN(RemoveSpecialCComment);
2064 // check is to prevent getting stuck in skipping C++ comments
2065 if (YY_START != SkipComment && YY_START != SkipCxxComment)
2067 yyextra->lastCContext = YY_START ;
2069 startFontClass(yyscanner,"comment");
2070 yyextra->code->codify(yytext);
2074 <*>^{B}*{CCS}[!*]/{NCOMM} { // special C comment block at a new line
2075 if (Config_getBool(STRIP_CODE_COMMENTS))
2077 if (YY_START != RemoveSpecialCComment) yyextra->lastSpecialCContext = YY_START;
2078 BEGIN(RemoveSpecialCComment);
2082 // check is to prevent getting stuck in skipping C++ comments
2083 if (YY_START != SkipComment && YY_START != SkipCxxComment)
2085 yyextra->lastCContext = YY_START ;
2087 startFontClass(yyscanner,"comment");
2088 yyextra->code->codify(yytext);
2092 <*>{CCS}[!*]/{NCOMM} { // special C comment block half way a line
2093 if (YY_START==SkipString) REJECT;
2094 if (Config_getBool(STRIP_CODE_COMMENTS))
2096 if (YY_START != RemoveSpecialCComment) yyextra->lastSpecialCContext = YY_START;
2097 BEGIN(RemoveSpecialCComment);
2101 // check is to prevent getting stuck in skipping C++ comments
2102 if (YY_START != SkipComment && YY_START != SkipCxxComment)
2104 yyextra->lastCContext = YY_START ;
2106 startFontClass(yyscanner,"comment");
2107 yyextra->code->codify(yytext);
2111 <*>{CCS}("!"?){CCE} {
2112 if (YY_START==SkipString) REJECT;
2113 if (!Config_getBool(STRIP_CODE_COMMENTS))
2115 startFontClass(yyscanner,"comment");
2116 yyextra->code->codify(yytext);
2117 endFontClass(yyscanner);
2120 <SkipComment>[^\*\n]+ {
2121 yyextra->code->codify(yytext);
2124 startFontClass(yyscanner,"comment");
2125 yyextra->code->codify(yytext);
2126 // check is to prevent getting stuck in skipping C++ comments
2127 if (YY_START != SkipComment && YY_START != SkipCxxComment)
2129 yyextra->lastCContext = YY_START ;
2131 BEGIN( SkipComment ) ;
2133 <*>@\" { // C# verbatim string
2134 startFontClass(yyscanner,"stringliteral");
2135 yyextra->code->codify(yytext);
2136 yyextra->lastVerbStringContext=YY_START;
2137 BEGIN(SkipVerbString);
2140 startFontClass(yyscanner,"comment");
2141 yyextra->code->codify(yytext);
2142 yyextra->lastCContext = YY_START ;
2143 BEGIN( SkipCxxComment ) ;
2146 yyextra->code->codify(yytext);
2147 yyextra->theCallContext.pushScope(yyextra->name, yyextra->type);
2150 yyextra->code->codify(yytext);
2151 yyextra->theCallContext.popScope(yyextra->name, yyextra->type);
2155 codifyLines(yyscanner,yytext);
2157 <*>[\x80-\xFF]* { // keep utf8 characters together...
2158 yyextra->yyColNr+=yyleng;
2159 yyextra->code->codify(yytext);
2163 yyextra->code->codify(yytext);
2166 <*>([ \t\n]*"\n"){2,} { // combine multiple blank lines
2167 //QCString sepLine=yytext;
2168 //yyextra->code->codify("\n\n");
2169 //yyextra->yyLineNr+=sepLine.contains('\n');
2170 //char sepLine[3]="\n\n";
2171 codifyLines(yyscanner,yytext);
2177 /*@ ----------------------------------------------------------------------------
2180 static bool startsWithKeyword(const QCString &str,const QCString &kw)
2182 if (str.length()<kw.length()) return false; // string too short to match
2183 return str==kw || // exact match
2184 (str.startsWith(kw) && !isId(str.at(kw.length()))); // match that is not a substring
2187 static void addVariable(yyscan_t yyscanner,QCString type,QCString name)
2189 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2190 DBG_CTX((stderr,"VariableContext::addVariable(%s,%s)\n",qPrint(type),qPrint(name)));
2191 QCString ltype = type.simplifyWhiteSpace();
2192 QCString lname = name.simplifyWhiteSpace();
2193 if (ltype.left(7)=="struct ")
2195 ltype = ltype.right(ltype.length()-7);
2197 else if (ltype.left(6)=="union ")
2199 ltype = ltype.right(ltype.length()-6);
2201 if (ltype.isEmpty() || lname.isEmpty()) return;
2202 DBG_CTX((stderr,"** addVariable trying: type='%s' name='%s' currentDefinition=%s\n",
2203 qPrint(ltype),qPrint(lname),yyextra->currentDefinition?qPrint(yyextra->currentDefinition->name()):"<none>"));
2204 auto it = yyextra->codeClassMap.find(ltype.str());
2205 if (it!=yyextra->codeClassMap.end()) // look for class definitions inside the code block
2207 DBG_CTX((stderr,"** addVariable type='%s' name='%s'\n",qPrint(ltype),qPrint(lname)));
2208 yyextra->theVarContext.addVariable(lname,std::move(it->second)); // add it to a list
2212 const ClassDef *varDef = yyextra->symbolResolver.resolveClass(yyextra->currentDefinition,ltype);
2216 DBG_CTX((stderr,"** addVariable type='%s' name='%s'\n",qPrint(ltype),qPrint(lname)));
2217 yyextra->theVarContext.addVariable(lname,ScopedTypeVariant(varDef)); // add it to a list
2219 else if ((i=ltype.find('<'))!=-1)
2221 // probably a template class
2222 QCString typeName(ltype.left(i));
2223 addVariable(yyscanner,typeName,name);
2227 if (!yyextra->theVarContext.atGlobalScope()) // for local variables add a dummy entry so the name
2228 // is hidden to avoid false links to global variables with the same name
2229 // TODO: make this work for namespaces as well!
2231 DBG_CTX((stderr,"** addVariable: dummy context for '%s'\n",qPrint(lname)));
2232 yyextra->theVarContext.addVariable(lname,ScopedTypeVariant());
2236 DBG_CTX((stderr,"** addVariable: not adding variable!\n"));
2242 //-------------------------------------------------------------------
2244 /*! add class/namespace name s to the scope */
2245 static void pushScope(yyscan_t yyscanner,const QCString &s)
2247 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2248 yyextra->classScopeLengthStack.push(int(yyextra->classScope.length()));
2249 if (yyextra->classScope.isEmpty() || leftScopeMatch(s,yyextra->classScope))
2251 yyextra->classScope = s;
2255 yyextra->classScope += "::";
2256 yyextra->classScope += s;
2258 DBG_CTX((stderr,"pushScope(%s) result: '%s'\n",qPrint(s),qPrint(yyextra->classScope)));
2262 /*! remove the top class/namespace name from the scope */
2263 static void popScope(yyscan_t yyscanner)
2265 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2266 if (!yyextra->classScopeLengthStack.empty())
2268 int length = yyextra->classScopeLengthStack.top();
2269 yyextra->classScopeLengthStack.pop();
2270 yyextra->classScope.truncate(length);
2274 //err("Too many end of scopes found!\n");
2276 DBG_CTX((stderr,"popScope() result: '%s'\n",qPrint(yyextra->classScope)));
2279 static void setCurrentDoc(yyscan_t yyscanner,const QCString &anchor)
2281 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2282 if (Doxygen::searchIndex)
2284 std::lock_guard<std::mutex> lock(g_searchIndexMutex);
2285 if (yyextra->searchCtx)
2287 yyextra->code->setCurrentDoc(yyextra->searchCtx,yyextra->searchCtx->anchor(),FALSE);
2291 yyextra->code->setCurrentDoc(yyextra->sourceFileDef,anchor,TRUE);
2296 static void addToSearchIndex(yyscan_t yyscanner,const QCString &text)
2298 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2299 if (Doxygen::searchIndex)
2301 std::lock_guard<std::mutex> lock(g_searchIndexMutex);
2302 yyextra->code->addWord(text,FALSE);
2306 static void addToSearchIndex(yyscan_t yyscanner,const char *text)
2308 addToSearchIndex(yyscanner,QCString(text));
2312 static void setClassScope(yyscan_t yyscanner,const QCString &name)
2314 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2315 DBG_CTX((stderr,"setClassScope(%s)\n",qPrint(name)));
2317 n=n.simplifyWhiteSpace();
2318 int ts=n.find('<'); // start of template
2319 int te=n.findRev('>'); // end of template
2320 DBG_CTX((stderr,"ts=%d te=%d\n",ts,te));
2321 if (ts!=-1 && te!=-1 && te>ts)
2323 // remove template from scope
2324 n=n.left(ts)+n.right(n.length()-te-1);
2326 while (!yyextra->classScopeLengthStack.empty())
2328 popScope(yyscanner);
2330 yyextra->classScope.resize(0);
2332 while ((i=n.find("::"))!=-1)
2334 pushScope(yyscanner,n.left(i));
2337 pushScope(yyscanner,n);
2338 DBG_CTX((stderr,"--->New class scope '%s'\n",qPrint(yyextra->classScope)));
2341 /*! start a new line of code, inserting a line number if yyextra->sourceFileDef
2342 * is TRUE. If a definition starts at the current line, then the line
2343 * number is linked to the documentation of that definition.
2345 static void startCodeLine(yyscan_t yyscanner)
2347 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2348 //if (yyextra->currentFontClass) { yyextra->code->endFontClass(yyscanner); }
2349 if (yyextra->sourceFileDef && yyextra->lineNumbers)
2351 //QCString lineNumber,lineAnchor;
2352 //lineNumber.sprintf("%05d",yyextra->yyLineNr);
2353 //lineAnchor.sprintf("l%05d",yyextra->yyLineNr);
2355 const Definition *d = yyextra->sourceFileDef->getSourceDefinition(yyextra->yyLineNr);
2356 DBG_CTX((stderr,"%s:startCodeLine(%d)=%p\n",qPrint(yyextra->sourceFileDef->name()),yyextra->yyLineNr,(void*)d));
2357 if (!yyextra->includeCodeFragment && d)
2359 yyextra->currentDefinition = d;
2360 yyextra->currentMemberDef = yyextra->sourceFileDef->getSourceMember(yyextra->yyLineNr);
2361 yyextra->insideBody = FALSE;
2362 yyextra->searchingForBody = TRUE;
2363 yyextra->realScope = d->name();
2364 //yyextra->classScope = "";
2365 yyextra->type.resize(0);
2366 yyextra->name.resize(0);
2367 yyextra->args.resize(0);
2368 yyextra->parmType.resize(0);
2369 yyextra->parmName.resize(0);
2370 DBG_CTX((stderr,"Real scope: '%s'\n",qPrint(yyextra->realScope)));
2371 yyextra->bodyCurlyCount = 0;
2372 QCString lineAnchor;
2373 lineAnchor.sprintf("l%05d",yyextra->yyLineNr);
2374 if (yyextra->currentMemberDef)
2376 yyextra->code->writeLineNumber(yyextra->currentMemberDef->getReference(),
2377 yyextra->currentMemberDef->getOutputFileBase(),
2378 yyextra->currentMemberDef->anchor(),
2379 yyextra->yyLineNr,!yyextra->includeCodeFragment);
2380 setCurrentDoc(yyscanner,lineAnchor);
2382 else if (d->isLinkableInProject())
2384 yyextra->code->writeLineNumber(d->getReference(),
2385 d->getOutputFileBase(),
2386 QCString(),yyextra->yyLineNr,!yyextra->includeCodeFragment);
2387 setCurrentDoc(yyscanner,lineAnchor);
2392 yyextra->code->writeLineNumber(QCString(),QCString(),QCString(),yyextra->yyLineNr,
2393 !yyextra->includeCodeFragment);
2396 DBG_CTX((stderr,"startCodeLine(%d)\n",yyextra->yyLineNr));
2397 yyextra->code->startCodeLine(yyextra->sourceFileDef && yyextra->lineNumbers);
2398 if (yyextra->currentFontClass)
2400 yyextra->code->startFontClass(QCString(yyextra->currentFontClass));
2406 static void endCodeLine(yyscan_t yyscanner)
2408 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2409 DBG_CTX((stderr,"endCodeLine(%d)\n",yyextra->yyLineNr));
2410 endFontClass(yyscanner);
2411 yyextra->code->endCodeLine();
2414 static void nextCodeLine(yyscan_t yyscanner)
2416 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2417 const char * fc = yyextra->currentFontClass;
2418 endCodeLine(yyscanner);
2419 if (yyextra->yyLineNr<yyextra->inputLines)
2421 yyextra->currentFontClass = fc;
2422 startCodeLine(yyscanner);
2426 /*! write a code fragment 'text' that may span multiple lines, inserting
2427 * line numbers for each line.
2429 static void codifyLines(yyscan_t yyscanner,const QCString &text)
2431 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2432 DBG_CTX((stderr,"codifyLines(%d,\"%s\")\n",yyextra->yyLineNr,qPrint(text)));
2433 if (text.isEmpty()) return;
2434 const char *p=text.data(),*sp=p;
2440 while ((c=*p++) && c!='\n') { yyextra->yyColNr++; }
2443 yyextra->yyLineNr++;
2445 int l = (int)(p-sp-1);
2446 char *tmp = (char*)malloc(l+1);
2449 yyextra->code->codify(QCString(tmp));
2451 nextCodeLine(yyscanner);
2455 yyextra->code->codify(QCString(sp));
2461 static void codifyLines(yyscan_t yyscanner,const char *text)
2463 codifyLines(yyscanner,QCString(text));
2466 static void incrementFlowKeyWordCount(yyscan_t yyscanner)
2468 std::lock_guard<std::mutex> lock(g_countFlowKeywordsMutex);
2469 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2470 if (yyextra->currentMemberDef && yyextra->currentMemberDef->isFunction())
2472 MemberDefMutable *md = toMemberDefMutable(yyextra->currentMemberDef);
2475 md->incrementFlowKeyWordCount();
2480 /*! writes a link to a fragment \a text that may span multiple lines, inserting
2481 * line numbers for each line. If \a text contains newlines, the link will be
2482 * split into multiple links with the same destination, one for each line.
2484 static void writeMultiLineCodeLink(yyscan_t yyscanner,CodeOutputInterface &ol,
2485 const Definition *d,
2486 const QCString &text)
2488 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2489 bool sourceTooltips = Config_getBool(SOURCE_TOOLTIPS);
2490 yyextra->tooltipManager.addTooltip(ol,d);
2491 QCString ref = d->getReference();
2492 QCString file = d->getOutputFileBase();
2493 QCString anchor = d->anchor();
2495 if (!sourceTooltips) // fall back to simple "title" tooltips
2497 tooltip = d->briefDescriptionAsTooltip();
2500 const char *p=text.data();
2505 while ((c=*p++) && c!='\n') { }
2508 yyextra->yyLineNr++;
2509 DBG_CTX((stderr,"writeCodeLink(%s,%s,%s,%s)\n",qPrint(ref),qPrint(file),qPrint(anchor),qPrint(QCString(sp,p-sp-1))));
2510 ol.writeCodeLink(d->codeSymbolType(),ref,file,anchor,QCString(sp,p-sp-1),tooltip);
2511 nextCodeLine(yyscanner);
2515 DBG_CTX((stderr,"writeCodeLink(%s,%s,%s,%s)\n",qPrint(ref),qPrint(file),qPrint(anchor),sp));
2516 ol.writeCodeLink(d->codeSymbolType(),ref,file,anchor,QCString(sp),tooltip);
2522 static void addType(yyscan_t yyscanner)
2524 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2525 if (yyextra->name=="const") { yyextra->name.resize(0); return; }
2526 if (!yyextra->type.isEmpty()) yyextra->type += ' ' ;
2527 yyextra->type += yyextra->name ;
2528 yyextra->name.resize(0) ;
2529 if (!yyextra->type.isEmpty()) yyextra->type += ' ' ;
2530 yyextra->type += yyextra->args ;
2531 yyextra->args.resize(0) ;
2534 static void addParmType(yyscan_t yyscanner)
2536 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2537 if (yyextra->parmName=="const") { yyextra->parmName.resize(0); return; }
2538 if (!yyextra->parmType.isEmpty()) yyextra->parmType += ' ' ;
2539 yyextra->parmType += yyextra->parmName ;
2540 yyextra->parmName.resize(0) ;
2543 // TODO: make this have a scope only effect, at least not modifying the FileDef object.
2544 static void addUsingDirective(yyscan_t yyscanner,const char *name)
2546 std::lock_guard<std::mutex> lock(g_usingDirectiveMutex);
2547 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2548 if (yyextra->sourceFileDef && name)
2550 const NamespaceDef *nd = Doxygen::namespaceLinkedMap->find(name);
2553 const_cast<FileDef*>(yyextra->sourceFileDef)->addUsingDirective(nd);
2558 static void setParameterList(yyscan_t yyscanner,const MemberDef *md)
2560 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2561 yyextra->classScope = md->getClassDef() ? md->getClassDef()->name() : QCString();
2562 for (const Argument &a : md->argumentList())
2564 yyextra->parmName = a.name;
2565 yyextra->parmType = a.type;
2566 int i = yyextra->parmType.find('*');
2567 if (i!=-1) yyextra->parmType = yyextra->parmType.left(i);
2568 i = yyextra->parmType.find('&');
2569 if (i!=-1) yyextra->parmType = yyextra->parmType.left(i);
2570 yyextra->parmType.stripPrefix("const ");
2571 yyextra->parmType=yyextra->parmType.stripWhiteSpace();
2572 addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
2576 static const ClassDef *stripClassName(yyscan_t yyscanner,const QCString &s,const Definition *d)
2578 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2583 while (extractClassNameFromType(type,pos,className,templSpec)!=-1)
2585 QCString clName=className+templSpec;
2586 const ClassDef *cd=0;
2587 if (!yyextra->classScope.isEmpty())
2589 cd=yyextra->symbolResolver.resolveClass(d,yyextra->classScope+"::"+clName);
2593 cd=yyextra->symbolResolver.resolveClass(d,clName);
2595 DBG_CTX((stderr,"stripClass trying '%s' = %p\n",qPrint(clName),(void*)cd));
2605 static const MemberDef *setCallContextForVar(yyscan_t yyscanner,const QCString &name)
2607 if (name.isEmpty()) return 0;
2608 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2609 DBG_CTX((stderr,"setCallContextForVar(%s) yyextra->classScope=%s\n",qPrint(name),qPrint(yyextra->classScope)));
2611 int scopeEnd = name.findRev("::");
2612 if (scopeEnd!=-1) // name with explicit scope
2614 QCString scope = name.left(scopeEnd);
2615 QCString locName = name.right(name.length()-scopeEnd-2);
2616 DBG_CTX((stderr,"explicit scope: name=%s scope=%s\n",qPrint(locName),qPrint(scope)));
2617 const ClassDef *mcd = getClass(scope);
2618 if (mcd && !locName.isEmpty())
2620 const MemberDef *md=mcd->getMemberByName(locName);
2623 DBG_CTX((stderr,"name=%s scope=%s\n",qPrint(locName),qPrint(scope)));
2624 yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,md->typeString(),md->getOuterScope())));
2628 else // check namespace as well
2630 const NamespaceDef *mnd = getResolvedNamespace(scope);
2631 if (mnd && !locName.isEmpty())
2633 const MemberDef *md=mnd->getMemberByName(locName);
2636 DBG_CTX((stderr,"name=%s scope=%s\n",qPrint(locName),qPrint(scope)));
2637 yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,md->typeString(),md->getOuterScope())));
2644 const MemberName *mn;
2645 const ScopedTypeVariant *mcv = yyextra->theVarContext.findVariable(name);
2648 DBG_CTX((stderr,"local variable?\n"));
2649 if (mcv->type()!=ScopedTypeVariant::Dummy) // locally found variable
2651 DBG_CTX((stderr,"local var '%s' mcd=%s\n",qPrint(name),qPrint(mcv->name())));
2652 yyextra->theCallContext.setScope(*mcv);
2657 DBG_CTX((stderr,"class member? scope=%s\n",qPrint(yyextra->classScope)));
2658 // look for a class member
2659 const ClassDef *mcd = getClass(yyextra->classScope);
2662 DBG_CTX((stderr,"Inside class %s\n",qPrint(mcd->name())));
2663 const MemberDef *md=mcd->getMemberByName(name);
2666 DBG_CTX((stderr,"Found member %s\n",qPrint(md->name())));
2667 if (yyextra->scopeStack.empty() || yyextra->scopeStack.top()!=CLASSBLOCK)
2669 DBG_CTX((stderr,"class member '%s' mcd=%s\n",qPrint(name),qPrint(mcd->name())));
2670 yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,md->typeString(),md->getOuterScope())));
2677 // look for a global member
2678 if ((mn=Doxygen::functionNameLinkedMap->find(name)))
2680 DBG_CTX((stderr,"global var '%s'\n",qPrint(name)));
2681 if (mn->size()==1) // global defined only once
2683 const std::unique_ptr<MemberDef> &md=mn->front();
2684 if (!md->isStatic() || md->getBodyDef()==yyextra->sourceFileDef)
2686 yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,md->typeString(),md->getOuterScope())));
2691 else if (mn->size()>1) // global defined more than once
2693 for (const auto &md : *mn)
2695 //printf("mn=%p md=%p md->getBodyDef()=%p yyextra->sourceFileDef=%p\n",
2697 // md->getBodyDef(),yyextra->sourceFileDef);
2699 // in case there are multiple members we could link to, we
2700 // only link to members if defined in the same file or
2701 // defined as external.
2702 if (!md->isStatic() || md->getBodyDef()==yyextra->sourceFileDef)
2704 yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,md->typeString(),md->getOuterScope())));
2705 DBG_CTX((stderr,"returning member %s in source file %s\n",qPrint(md->name()),qPrint(yyextra->sourceFileDef->name())));
2715 static void updateCallContextForSmartPointer(yyscan_t yyscanner)
2717 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2718 const Definition *d = yyextra->theCallContext.getScope().globalDef();
2719 //printf("updateCallContextForSmartPointer() cd=%s\n",cd ? qPrint(d->name()) : "<none>");
2720 const MemberDef *md;
2721 if (d && d->definitionType()==Definition::TypeClass && (md=(toClassDef(d))->isSmartPointer()))
2723 const ClassDef *ncd = stripClassName(yyscanner,md->typeString(),md->getOuterScope());
2726 yyextra->theCallContext.setScope(ScopedTypeVariant(ncd));
2727 //printf("Found smart pointer call %s->%s!\n",qPrint(cd->name()),qPrint(ncd->name()));
2732 static bool getLinkInScope(yyscan_t yyscanner,
2733 const QCString &c, // scope
2734 const QCString &m, // member
2735 const QCString &memberText, // exact text
2736 CodeOutputInterface &ol,
2737 const QCString &text,
2741 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2742 const MemberDef *md = 0;
2743 const ClassDef *cd = 0;
2744 const FileDef *fd = 0;
2745 const NamespaceDef *nd = 0;
2746 const GroupDef *gd = 0;
2747 DBG_CTX((stderr,"getLinkInScope: trying '%s'::'%s' varOnly=%d\n",qPrint(c),qPrint(m),varOnly));
2748 if (getDefs(c,m,"()",md,cd,fd,nd,gd,FALSE,yyextra->sourceFileDef,FALSE) &&
2749 (!varOnly || md->isVariable()))
2751 if (md->isLinkable())
2753 DBG_CTX((stderr,"found it %s!\n",qPrint(md->qualifiedName())));
2754 if (yyextra->exampleBlock)
2756 std::lock_guard<std::mutex> lock(g_addExampleMutex);
2758 anchor.sprintf("a%d",yyextra->anchorCount);
2759 DBG_CTX((stderr,"addExampleFile(%s,%s,%s)\n",qPrint(anchor),qPrint(yyextra->exampleName),
2760 qPrint(yyextra->exampleFile)));
2761 MemberDefMutable *mdm = toMemberDefMutable(md);
2762 if (mdm && mdm->addExample(anchor,yyextra->exampleName,yyextra->exampleFile))
2764 ol.writeCodeAnchor(anchor);
2765 yyextra->anchorCount++;
2769 const Definition *d = md->getOuterScope()==Doxygen::globalScope ?
2770 md->resolveAlias()->getFileDef() : md->getOuterScope();
2771 if (md->resolveAlias()->getGroupDef()) d = md->resolveAlias()->getGroupDef();
2772 if (d && d->isLinkable())
2774 yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,md->typeString(),md->getOuterScope())));
2775 DBG_CTX((stderr,"yyextra->currentDefinition=%p yyextra->currentMemberDef=%p yyextra->insideBody=%d\n",
2776 (void*)yyextra->currentDefinition,(void*)yyextra->currentMemberDef,yyextra->insideBody));
2778 if (yyextra->currentDefinition && yyextra->currentMemberDef &&
2779 yyextra->insideBody && yyextra->collectXRefs)
2781 std::lock_guard<std::mutex> lock(g_docCrossReferenceMutex);
2782 addDocCrossReference(toMemberDefMutable(yyextra->currentMemberDef),toMemberDefMutable(md));
2784 DBG_CTX((stderr,"d->getReference()='%s' d->getOutputBase()='%s' name='%s' member name='%s'\n",qPrint(d->getReference()),qPrint(d->getOutputFileBase()),qPrint(d->name()),qPrint(md->name())));
2786 writeMultiLineCodeLink(yyscanner,ol,md, !text.isEmpty() ? text : memberText);
2787 addToSearchIndex(yyscanner,!text.isEmpty() ? text : memberText);
2791 else // found member, but it is not linkable, so make sure content inside is not assigned
2792 // to the previous member, see bug762760
2794 DBG_CTX((stderr,"unlinkable member %s\n",qPrint(md->name())));
2795 yyextra->currentMemberDef = 0;
2801 static bool getLink(yyscan_t yyscanner,
2802 const QCString &className,
2803 const QCString &memberName,
2804 CodeOutputInterface &ol,
2805 const QCString &text,
2808 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2809 DBG_CTX((stderr,"getLink(%s,%s) yyextra->curClassName=%s\n",
2810 qPrint(className),qPrint(memberName),qPrint(yyextra->curClassName)));
2811 QCString m=removeRedundantWhiteSpace(memberName);
2812 QCString c=className;
2813 if (!getLinkInScope(yyscanner,c,m,memberName,ol,text,varOnly))
2815 if (!yyextra->curClassName.isEmpty())
2817 if (!c.isEmpty()) c.prepend("::");
2818 c.prepend(yyextra->curClassName);
2819 return getLinkInScope(yyscanner,c,m,memberName,ol,text,varOnly);
2826 static void generateClassOrGlobalLink(yyscan_t yyscanner,
2827 CodeOutputInterface &ol,
2828 const QCString &clName,
2832 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2834 QCString className=clName;
2835 if (!className.isEmpty() && className[0]=='~') // correct for matching negated values i.s.o. destructors.
2837 className=className.mid(1);
2839 if (className.isEmpty())
2841 yyextra->code->codify("~");
2844 if (yyextra->insideProtocolList) // for Obj-C
2848 if (yyextra->lang==SrcLangExt_PHP)
2850 className = substitute(className,"\\","::"); // for PHP namespaces
2852 else if (yyextra->lang==SrcLangExt_CSharp || yyextra->lang==SrcLangExt_Java)
2854 className = substitute(className,".","::"); // for PHP namespaces
2856 const ScopedTypeVariant *lcd=0;
2857 const ClassDef *cd=0;
2858 const MemberDef *md=0;
2861 DBG_CTX((stderr,"generateClassOrGlobalLink(className=%s)\n",qPrint(className)));
2862 if (!yyextra->isPrefixedWithThis || (lcd=yyextra->theVarContext.findVariable(className))==0) // not a local variable
2864 const Definition *d = yyextra->currentDefinition;
2865 DBG_CTX((stderr,"d=%s yyextra->sourceFileDef=%s\n",d?qPrint(d->name()):"<none>",yyextra->sourceFileDef?qPrint(yyextra->sourceFileDef->name()):"<none>"));
2866 cd = yyextra->symbolResolver.resolveClass(d,className);
2867 md = yyextra->symbolResolver.getTypedef();
2868 DBG_CTX((stderr,"non-local variable name=%s cd=%s md=%s!\n",
2869 qPrint(className),cd?qPrint(cd->name()):"<none>",
2870 md?qPrint(md->name()):"<none>"));
2871 i=className.find('<');
2872 QCString bareName = className;
2873 if (i!=-1) bareName = bareName.left(i);
2874 if (cd==0 && md==0 && i!=-1)
2876 DBG_CTX((stderr,"bareName=%s\n",qPrint(bareName)));
2877 if (bareName!=className)
2879 cd = yyextra->symbolResolver.resolveClass(d,bareName); // try unspecialized version
2880 md = yyextra->symbolResolver.getTypedef();
2883 const NamespaceDef *nd = getResolvedNamespace(className);
2884 if (nd && nd->isLinkable())
2886 yyextra->theCallContext.setScope(ScopedTypeVariant(nd));
2887 addToSearchIndex(yyscanner,className);
2888 writeMultiLineCodeLink(yyscanner,*yyextra->code,nd,clName);
2891 const ConceptDef *conceptDef = getResolvedConcept(d,bareName);
2892 if (conceptDef && conceptDef->isLinkable())
2894 yyextra->theCallContext.setScope(ScopedTypeVariant(conceptDef));
2895 addToSearchIndex(yyscanner,className);
2896 writeMultiLineCodeLink(yyscanner,*yyextra->code,conceptDef,clName);
2899 DBG_CTX((stderr,"md=%s\n",md?qPrint(md->name()):"<none>"));
2900 DBG_CTX((stderr,"is found as a type cd=%s nd=%s\n",
2901 cd?qPrint(cd->name()):"<null>",
2902 nd?qPrint(nd->name()):"<null>"));
2903 if (cd==0 && md==0) // also see if it is variable or enum or enum value
2905 if (getLink(yyscanner,yyextra->classScope,clName,ol,clName,varOnly))
2913 DBG_CTX((stderr,"local variable!\n"));
2914 if (lcd->type()!=ScopedTypeVariant::Dummy)
2916 DBG_CTX((stderr,"non-dummy context lcd=%s!\n",qPrint(lcd->name())));
2917 yyextra->theCallContext.setScope(*lcd);
2919 // to following is needed for links to a global variable, but is
2920 // no good for a link to a local variable that is also a global symbol.
2922 //if (getLink(yyscanner,yyextra->classScope,clName,ol,clName))
2928 DBG_CTX((stderr,"is a local variable cd=%p!\n",(void*)cd));
2930 yyextra->isPrefixedWithThis = FALSE; // discard the "this" prefix for the next calls
2932 if (cd && cd->isLinkable()) // is it a linkable class
2934 DBG_CTX((stderr,"is linkable class %s\n",qPrint(clName)));
2935 if (yyextra->exampleBlock)
2937 std::lock_guard<std::mutex> lock(g_addExampleMutex);
2939 anchor.sprintf("_a%d",yyextra->anchorCount);
2940 DBG_CTX((stderr,"addExampleClass(%s,%s,%s)\n",qPrint(anchor),qPrint(yyextra->exampleName),
2941 qPrint(yyextra->exampleFile)));
2942 ClassDefMutable *cdm = toClassDefMutable(const_cast<ClassDef*>(cd));
2943 if (cdm && cdm->addExample(anchor,yyextra->exampleName,yyextra->exampleFile))
2945 ol.writeCodeAnchor(anchor);
2946 yyextra->anchorCount++;
2949 writeMultiLineCodeLink(yyscanner,ol,cd,clName);
2950 addToSearchIndex(yyscanner,className);
2951 yyextra->theCallContext.setScope(ScopedTypeVariant(cd));
2954 const Definition *d = md->getOuterScope()==Doxygen::globalScope ?
2955 md->getFileDef() : md->getOuterScope();
2956 if (md->getGroupDef()) d = md->getGroupDef();
2957 if (d && d->isLinkable() && md->isLinkable() &&
2958 yyextra->currentMemberDef && yyextra->collectXRefs)
2960 std::lock_guard<std::mutex> lock(g_docCrossReferenceMutex);
2961 addDocCrossReference(toMemberDefMutable(yyextra->currentMemberDef),toMemberDefMutable(md));
2965 else // not a class, maybe a global member
2967 DBG_CTX((stderr,"class %s not linkable! cd=%p md=%p typeOnly=%d\n",qPrint(clName),(void*)cd,(void*)md,typeOnly));
2968 if (!isLocal && (md!=0 || (cd==0 && !typeOnly))) // not a class, see if it is a global enum/variable/typedef.
2970 if (md==0) // not found as a typedef
2972 md = setCallContextForVar(yyscanner,clName);
2973 DBG_CTX((stderr,"setCallContextForVar(%s) md=%p yyextra->currentDefinition=%p\n",qPrint(clName),(void*)md,(void*)yyextra->currentDefinition));
2974 if (md && yyextra->currentDefinition)
2976 DBG_CTX((stderr,"%s accessible from %s? %d md->getOuterScope=%s\n",
2977 qPrint(md->name()),qPrint(yyextra->currentDefinition->name()),
2978 yyextra->symbolResolver.isAccessibleFrom(yyextra->currentDefinition,md),
2979 qPrint(md->getOuterScope()->name())));
2982 if (md && yyextra->currentDefinition &&
2983 yyextra->symbolResolver.isAccessibleFrom(yyextra->currentDefinition,md)==-1)
2985 md=0; // variable not accessible
2988 if (md && (!varOnly || md->isVariable()))
2990 DBG_CTX((stderr,"is a global md=%p yyextra->currentDefinition=%s linkable=%d\n",(void*)md,yyextra->currentDefinition?qPrint(yyextra->currentDefinition->name()):"<none>",md->isLinkable()));
2991 if (md->isLinkable())
2993 writeMultiLineCodeLink(yyscanner,ol,md,clName);
2994 addToSearchIndex(yyscanner,clName);
2995 if (yyextra->currentMemberDef && yyextra->collectXRefs)
2997 std::lock_guard<std::mutex> lock(g_docCrossReferenceMutex);
2998 addDocCrossReference(toMemberDefMutable(yyextra->currentMemberDef),toMemberDefMutable(md));
3005 // nothing found, just write out the word
3006 DBG_CTX((stderr,"not found!\n"));
3007 codifyLines(yyscanner,clName);
3008 addToSearchIndex(yyscanner,clName);
3012 static void generateClassOrGlobalLink(yyscan_t yyscanner,CodeOutputInterface &ol,const char *clName,
3013 bool typeOnly,bool varOnly)
3015 generateClassOrGlobalLink(yyscanner,ol,QCString(clName),typeOnly,varOnly);
3018 static bool generateClassMemberLink(yyscan_t yyscanner,
3019 CodeOutputInterface &ol,
3020 const MemberDef *xmd,
3021 const QCString &memName)
3023 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3024 // extract class definition of the return type in order to resolve
3025 // a->b()->c() like call chains
3027 DBG_CTX((stderr,"type='%s' args='%s' class=%s\n",
3028 qPrint(xmd->typeString()),qPrint(xmd->argsString()),
3029 qPrint(xmd->getClassDef()->name())));
3031 if (yyextra->exampleBlock)
3033 std::lock_guard<std::mutex> lock(g_addExampleMutex);
3035 anchor.sprintf("a%d",yyextra->anchorCount);
3036 DBG_CTX((stderr,"addExampleFile(%s,%s,%s)\n",qPrint(anchor),qPrint(yyextra->exampleName),
3037 qPrint(yyextra->exampleFile)));
3038 MemberDefMutable *mdm = toMemberDefMutable(xmd);
3039 if (mdm && mdm->addExample(anchor,yyextra->exampleName,yyextra->exampleFile))
3041 ol.writeCodeAnchor(anchor);
3042 yyextra->anchorCount++;
3046 const ClassDef *typeClass = stripClassName(yyscanner,removeAnonymousScopes(xmd->typeString()),xmd->getOuterScope());
3047 DBG_CTX((stderr,"%s -> typeName=%p\n",qPrint(xmd->typeString()),(void*)typeClass));
3048 yyextra->theCallContext.setScope(ScopedTypeVariant(typeClass));
3050 const Definition *xd = xmd->getOuterScope()==Doxygen::globalScope ?
3051 xmd->getFileDef() : xmd->getOuterScope();
3052 if (xmd->getGroupDef()) xd = xmd->getGroupDef();
3053 if (xd && xd->isLinkable())
3056 DBG_CTX((stderr,"yyextra->currentDefinition=%p yyextra->currentMemberDef=%p xmd=%p yyextra->insideBody=%d\n",
3057 (void*)yyextra->currentDefinition,(void*)yyextra->currentMemberDef,(void*)xmd,yyextra->insideBody));
3059 if (xmd->templateMaster()) xmd = xmd->templateMaster();
3061 if (xmd->isLinkable())
3063 // add usage reference
3064 if (yyextra->currentDefinition && yyextra->currentMemberDef &&
3065 yyextra->insideBody && yyextra->collectXRefs)
3067 std::lock_guard<std::mutex> lock(g_docCrossReferenceMutex);
3068 addDocCrossReference(toMemberDefMutable(yyextra->currentMemberDef),toMemberDefMutable(xmd));
3071 // write the actual link
3072 writeMultiLineCodeLink(yyscanner,ol,xmd,memName);
3073 addToSearchIndex(yyscanner,memName);
3081 static bool generateClassMemberLink(yyscan_t yyscanner,
3082 CodeOutputInterface &ol,
3083 const Definition *def,
3084 const QCString &memName)
3086 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3087 if (def && def->definitionType()==Definition::TypeClass)
3089 const ClassDef *cd = toClassDef(def);
3090 const MemberDef *xmd = cd->getMemberByName(memName);
3091 DBG_CTX((stderr,"generateClassMemberLink(class=%s,member=%s)=%p\n",qPrint(def->name()),qPrint(memName),(void*)xmd));
3094 return generateClassMemberLink(yyscanner,ol,xmd,memName);
3098 const Definition *innerDef = cd->findInnerCompound(memName);
3101 yyextra->theCallContext.setScope(ScopedTypeVariant(innerDef));
3102 addToSearchIndex(yyscanner,memName);
3103 writeMultiLineCodeLink(yyscanner,*yyextra->code,innerDef,memName);
3108 else if (def && def->definitionType()==Definition::TypeNamespace)
3110 const NamespaceDef *nd = toNamespaceDef(def);
3111 DBG_CTX((stderr,"Looking for %s inside namespace %s\n",qPrint(memName),qPrint(nd->name())));
3112 const Definition *innerDef = nd->findInnerCompound(memName);
3115 yyextra->theCallContext.setScope(ScopedTypeVariant(innerDef));
3116 addToSearchIndex(yyscanner,memName);
3117 writeMultiLineCodeLink(yyscanner,*yyextra->code,innerDef,memName);
3124 static void generateMemberLink(yyscan_t yyscanner,
3125 CodeOutputInterface &ol,
3126 const QCString &varName,
3127 const QCString &memName)
3129 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3130 DBG_CTX((stderr,"generateMemberLink(object=%s,mem=%s) classScope=%s\n",
3131 qPrint(varName),qPrint(memName),qPrint(yyextra->classScope)));
3133 if (varName.isEmpty()) return;
3135 // look for the variable in the current context
3136 const ScopedTypeVariant *stv = yyextra->theVarContext.findVariable(varName);
3139 if (stv->type()!=ScopedTypeVariant::Dummy)
3141 DBG_CTX((stderr,"Class found!\n"));
3142 if (getLink(yyscanner,stv->name(),memName,ol))
3144 DBG_CTX((stderr,"Found result!\n"));
3147 if (stv->localDef() && !stv->localDef()->baseClasses().empty())
3149 for (const auto &bcName : stv->localDef()->baseClasses())
3151 if (getLink(yyscanner,bcName,memName,ol))
3153 DBG_CTX((stderr,"Found result!\n"));
3160 else // variable not in current context, maybe it is in a parent context
3162 const ClassDef *vcd = yyextra->symbolResolver.resolveClass(yyextra->currentDefinition,yyextra->classScope);
3163 if (vcd && vcd->isLinkable())
3165 DBG_CTX((stderr,"Found class %s for variable '%s'\n",qPrint(yyextra->classScope),qPrint(varName)));
3166 MemberName *vmn=Doxygen::memberNameLinkedMap->find(varName);
3170 QCString vn=varName;
3171 if ((vi=vn.findRev("::"))!=-1 || (vi=vn.findRev('.'))!=-1) // explicit scope A::b(), probably static member
3173 const ClassDef *jcd = getClass(vn.left(vi));
3174 vn=vn.right(vn.length()-vi-2);
3175 vmn=Doxygen::memberNameLinkedMap->find(vn);
3176 //printf("Trying name '%s' scope=%s\n",qPrint(vn),qPrint(scope));
3179 for (const auto &vmd : *vmn)
3181 if (vmd->getClassDef()==jcd)
3183 DBG_CTX((stderr,"Found variable type=%s\n",qPrint(vmd->typeString())));
3184 const ClassDef *mcd=stripClassName(yyscanner,vmd->typeString(),vmd->getOuterScope());
3185 if (mcd && mcd->isLinkable())
3187 if (generateClassMemberLink(yyscanner,ol,mcd,memName)) return;
3196 DBG_CTX((stderr,"There is a variable with name '%s'\n",qPrint(varName)));
3197 for (const auto &vmd : *vmn)
3199 if (vmd->getClassDef()==vcd)
3201 DBG_CTX((stderr,"Found variable type=%s\n",qPrint(vmd->typeString())));
3202 const ClassDef *mcd=stripClassName(yyscanner,vmd->typeString(),vmd->getOuterScope());
3203 if (mcd && mcd->isLinkable())
3205 if (generateClassMemberLink(yyscanner,ol,mcd,memName)) return;
3212 // nothing found -> write result as is
3213 codifyLines(yyscanner,memName);
3214 addToSearchIndex(yyscanner,memName);
3218 static void generatePHPVariableLink(yyscan_t yyscanner,CodeOutputInterface &ol,const char *varName)
3220 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3221 QCString name(varName+7); // strip $this->
3223 DBG_CTX((stderr,"generatePHPVariableLink(%s) name=%s scope=%s\n",varName,qPrint(name),qPrint(yyextra->classScope)));
3224 if (!getLink(yyscanner,yyextra->classScope,name,ol,QCString(varName)))
3226 codifyLines(yyscanner,varName);
3230 static void generateFunctionLink(yyscan_t yyscanner,CodeOutputInterface &ol,const QCString &funcName)
3232 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3233 //CodeClassDef *ccd=0;
3234 QCString locScope=yyextra->classScope;
3235 QCString locFunc=removeRedundantWhiteSpace(funcName);
3236 if (yyextra->lang==SrcLangExt_PHP && locFunc.startsWith("self::")) locFunc=locFunc.mid(4);
3238 QCString funcWithScope=locFunc;
3239 QCString funcWithFullScope=locFunc;
3240 QCString fullScope=locScope;
3241 DBG_CTX((stdout,"*** locScope=%s locFunc=%s\n",qPrint(locScope),qPrint(locFunc)));
3243 int i=locFunc.findRev("::");
3244 if (yyextra->currentMemberDef && yyextra->currentMemberDef->resolveAlias()->getClassDef() &&
3245 funcName==yyextra->currentMemberDef->localName() &&
3246 yyextra->currentMemberDef->getDefLine()==yyextra->yyLineNr &&
3247 generateClassMemberLink(yyscanner,ol,yyextra->currentMemberDef,funcName)
3250 // special case where funcName is the name of a method that is also
3251 // defined on this line. In this case we can directly link to
3252 // yyextra->currentMemberDef, which is not only faster, but
3253 // in case of overloaded methods, this will make sure that we link to
3254 // the correct method, and thereby get the correct reimplemented relations.
3255 // See also bug 549022.
3258 if (i==-1) i=locFunc.findRev("."),len=1;
3259 if (i==-1) i=locFunc.findRev("\\"),len=1; // for PHP
3262 funcScope=locFunc.left(i);
3263 locFunc=locFunc.right(locFunc.length()-i-len).stripWhiteSpace();
3264 int ts=locScope.find('<'); // start of template
3265 int te=locScope.findRev('>'); // end of template
3266 DBG_CTX((stderr,"ts=%d te=%d\n",ts,te));
3267 if (ts!=-1 && te!=-1 && te>ts)
3269 // remove template from scope
3270 locScope=locScope.left(ts)+locScope.right(locScope.length()-te-1);
3272 ts=funcScope.find('<'); // start of template
3273 te=funcScope.findRev('>'); // end of template
3274 DBG_CTX((stderr,"ts=%d te=%d\n",ts,te));
3275 if (ts!=-1 && te!=-1 && te>ts)
3277 // remove template from scope
3278 funcScope=funcScope.left(ts)+funcScope.right(funcScope.length()-te-1);
3280 if (!funcScope.isEmpty())
3282 funcWithScope = funcScope+"::"+locFunc;
3283 if (!locScope.isEmpty())
3285 fullScope=locScope+"::"+funcScope;
3288 if (!locScope.isEmpty())
3290 funcWithFullScope = locScope+"::"+funcWithScope;
3294 if (!fullScope.isEmpty())
3296 auto it = yyextra->codeClassMap.find(fullScope.str());
3297 if (it!=yyextra->codeClassMap.end())
3299 ScopedTypeVariant ccd = it->second;
3300 if (ccd.localDef() && !ccd.localDef()->baseClasses().empty())
3302 for (const auto &bcName : ccd.localDef()->baseClasses())
3304 if (getLink(yyscanner,bcName,locFunc,ol,funcName))
3313 if (!locScope.isEmpty() && fullScope!=locScope)
3315 auto it = yyextra->codeClassMap.find(locScope.str());
3316 if (it!=yyextra->codeClassMap.end())
3318 ScopedTypeVariant ccd = it->second;
3319 if (ccd.localDef() && !ccd.localDef()->baseClasses().empty())
3321 for (const auto &bcName : ccd.localDef()->baseClasses())
3323 if (getLink(yyscanner,bcName,funcWithScope,ol,funcName))
3331 if (!getLink(yyscanner,locScope,funcWithScope,ol,funcName))
3333 generateClassOrGlobalLink(yyscanner,ol,funcName);
3339 static void generateFunctionLink(yyscan_t yyscanner,CodeOutputInterface &ol,const char *funcName)
3341 generateFunctionLink(yyscanner,ol,QCString(funcName));
3344 /*! counts the number of lines in the input */
3345 static int countLines(yyscan_t yyscanner)
3347 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3348 const char *p=yyextra->inputString;
3354 if (c=='\n') count++;
3356 if (p>yyextra->inputString && *(p-1)!='\n')
3357 { // last line does not end with a \n, so we add an extra
3358 // line and explicitly terminate the line after parsing.
3360 yyextra->needsTermination=TRUE;
3365 static void endFontClass(yyscan_t yyscanner)
3367 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3368 if (yyextra->currentFontClass)
3370 yyextra->code->endFontClass();
3371 yyextra->currentFontClass=0;
3375 static void startFontClass(yyscan_t yyscanner,const char *s)
3377 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3378 endFontClass(yyscanner);
3379 yyextra->code->startFontClass(QCString(s));
3380 yyextra->currentFontClass=s;
3383 //----------------------------------------------------------------------------
3385 // recursively writes a linkified Objective-C method call
3386 static void writeObjCMethodCall(yyscan_t yyscanner,ObjCCallCtx *ctx)
3389 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3391 if (!ctx->methodName.isEmpty())
3393 DBG_CTX((stderr,"writeObjCMethodCall(%s) obj=%s method=%s\n",
3394 qPrint(ctx->format),qPrint(ctx->objectTypeOrName),qPrint(ctx->methodName)));
3395 if (!ctx->objectTypeOrName.isEmpty() && ctx->objectTypeOrName.at(0)!='$')
3397 DBG_CTX((stderr,"Looking for object=%s method=%s\n",qPrint(ctx->objectTypeOrName),
3398 qPrint(ctx->methodName)));
3399 const ScopedTypeVariant *stv = yyextra->theVarContext.findVariable(ctx->objectTypeOrName);
3400 if (stv==0) // not a local variable
3402 if (ctx->objectTypeOrName=="self")
3404 if (yyextra->currentDefinition &&
3405 yyextra->currentDefinition->definitionType()==Definition::TypeClass)
3407 ctx->objectType = toClassDef(yyextra->currentDefinition);
3412 ctx->objectType = yyextra->symbolResolver.resolveClass(yyextra->currentDefinition,ctx->objectTypeOrName);
3413 ctx->method = yyextra->symbolResolver.getTypedef();
3415 DBG_CTX((stderr," object is class? %p\n",(void*)ctx->objectType));
3416 if (ctx->objectType) // found class
3418 ctx->method = ctx->objectType->getMemberByName(ctx->methodName);
3419 DBG_CTX((stderr," yes->method=%s\n",ctx->method?qPrint(ctx->method->name()):"<none>"));
3421 else if (ctx->method==0) // search for class variable with the same name
3423 DBG_CTX((stderr," no\n"));
3424 DBG_CTX((stderr,"yyextra->currentDefinition=%p\n",(void*)yyextra->currentDefinition));
3425 if (yyextra->currentDefinition &&
3426 yyextra->currentDefinition->definitionType()==Definition::TypeClass)
3428 ctx->objectVar = (toClassDef(yyextra->currentDefinition))->getMemberByName(ctx->objectTypeOrName);
3429 DBG_CTX((stderr," ctx->objectVar=%p\n",(void*)ctx->objectVar));
3432 ctx->objectType = stripClassName(yyscanner,ctx->objectVar->typeString(),yyextra->currentDefinition);
3433 DBG_CTX((stderr," ctx->objectType=%p\n",(void*)ctx->objectType));
3434 if (ctx->objectType && !ctx->methodName.isEmpty())
3436 ctx->method = ctx->objectType->getMemberByName(ctx->methodName);
3437 DBG_CTX((stderr," ctx->method=%p\n",(void*)ctx->method));
3443 else // local variable
3445 DBG_CTX((stderr," object is local variable\n"));
3446 if (stv->globalDef() && !ctx->methodName.isEmpty())
3448 const ClassDef *cd = toClassDef(stv->globalDef());
3451 ctx->method = cd->getMemberByName(ctx->methodName);
3453 DBG_CTX((stderr," class=%p method=%p\n",(void*)cd,(void*)ctx->method));
3459 DBG_CTX((stderr,"["));
3460 if (!ctx->format.isEmpty())
3462 const char *p = ctx->format.data();
3463 while ((c=*p++)) // for each character in ctx->format
3468 if (nc=='$') // escaped $
3470 yyextra->code->codify("$");
3472 else // name fragment or reference to a nested call
3474 if (nc=='n') // name fragment
3478 while (nc!=0 && isdigit(nc)) { refIdStr+=nc; nc=*p++; }
3480 int refId=refIdStr.toInt();
3481 auto it = yyextra->nameMap.find(refId);
3482 if (it!=yyextra->nameMap.end())
3484 QCString name = it->second;
3485 if (ctx->method && ctx->method->isLinkable())
3487 writeMultiLineCodeLink(yyscanner,*yyextra->code,ctx->method,name);
3488 if (yyextra->currentMemberDef && yyextra->collectXRefs)
3490 std::lock_guard<std::mutex> lock(g_docCrossReferenceMutex);
3491 addDocCrossReference(toMemberDefMutable(yyextra->currentMemberDef),toMemberDefMutable(ctx->method));
3496 codifyLines(yyscanner,name);
3501 DBG_CTX((stderr,"Invalid name: id=%d\n",refId));
3504 else if (nc=='o') // reference to potential object name
3508 while (nc!=0 && isdigit(nc)) { refIdStr+=nc; nc=*p++; }
3510 int refId=refIdStr.toInt();
3511 auto it = yyextra->objectMap.find(refId);
3512 if (it!=yyextra->objectMap.end())
3514 QCString object = it->second;
3517 if (yyextra->currentDefinition &&
3518 yyextra->currentDefinition->definitionType()==Definition::TypeClass)
3520 ctx->objectType = toClassDef(yyextra->currentDefinition);
3521 if (ctx->objectType->categoryOf())
3523 ctx->objectType = ctx->objectType->categoryOf();
3525 if (ctx->objectType && !ctx->methodName.isEmpty())
3527 ctx->method = ctx->objectType->getMemberByName(ctx->methodName);
3530 startFontClass(yyscanner,"keyword");
3531 codifyLines(yyscanner,object);
3532 endFontClass(yyscanner);
3534 else if (object=="super")
3536 if (yyextra->currentDefinition &&
3537 yyextra->currentDefinition->definitionType()==Definition::TypeClass)
3539 const ClassDef *cd = toClassDef(yyextra->currentDefinition);
3540 if (cd->categoryOf())
3542 cd = cd->categoryOf();
3544 for (const auto &bclass : cd->baseClasses())
3546 if (bclass.classDef->compoundType()!=ClassDef::Protocol)
3548 ctx->objectType = bclass.classDef;
3549 if (ctx->objectType && !ctx->methodName.isEmpty())
3551 ctx->method = ctx->objectType->getMemberByName(ctx->methodName);
3556 startFontClass(yyscanner,"keyword");
3557 codifyLines(yyscanner,object);
3558 endFontClass(yyscanner);
3560 else if (ctx->objectVar && ctx->objectVar->isLinkable()) // object is class variable
3562 writeMultiLineCodeLink(yyscanner,*yyextra->code,ctx->objectVar,object);
3563 if (yyextra->currentMemberDef && yyextra->collectXRefs)
3565 std::lock_guard<std::mutex> lock(g_docCrossReferenceMutex);
3566 addDocCrossReference(toMemberDefMutable(yyextra->currentMemberDef),toMemberDefMutable(ctx->objectVar));
3569 else if (ctx->objectType &&
3570 ctx->objectType->isLinkable()
3571 ) // object is class name
3573 const ClassDef *cd = ctx->objectType;
3574 writeMultiLineCodeLink(yyscanner,*yyextra->code,cd,object);
3576 else // object still needs to be resolved
3578 const ClassDef *cd = yyextra->symbolResolver.resolveClass(yyextra->currentDefinition, object);
3579 if (cd && cd->isLinkable())
3581 if (ctx->objectType==0) ctx->objectType=cd;
3582 writeMultiLineCodeLink(yyscanner,*yyextra->code,cd,object);
3586 codifyLines(yyscanner,object);
3592 DBG_CTX((stderr,"Invalid object: id=%d\n",refId));
3595 else if (nc=='c') // reference to nested call
3599 while (nc!=0 && isdigit(nc)) { refIdStr+=nc; nc=*p++; }
3601 int refId=refIdStr.toInt();
3602 auto it = yyextra->contextMap.find(refId);
3603 if (it!=yyextra->contextMap.end()) // recurse into nested call
3605 ObjCCallCtx *ictx = it->second.get();
3606 writeObjCMethodCall(yyscanner,ictx);
3607 if (ictx->method) // link to nested call successfully
3609 // get the ClassDef representing the method's return type
3610 if (QCString(ictx->method->typeString())=="id")
3612 // see if the method name is unique, if so we link to it
3613 MemberName *mn=Doxygen::memberNameLinkedMap->find(ctx->methodName);
3614 //printf("mn->count=%d ictx->method=%s ctx->methodName=%s\n",
3615 // mn==0?-1:(int)mn->count(),
3616 // qPrint(ictx->method->name()),
3617 // qPrint(ctx->methodName));
3618 if (mn && mn->size()==1) // member name unique
3620 ctx->method = mn->front().get();
3625 ctx->objectType = stripClassName(yyscanner,ictx->method->typeString(),yyextra->currentDefinition);
3626 if (ctx->objectType && !ctx->methodName.isEmpty())
3628 ctx->method = ctx->objectType->getMemberByName(ctx->methodName);
3631 DBG_CTX((stderr," ***** method=%s -> object=%p\n",qPrint(ictx->method->name()),(void*)ctx->objectType));
3636 DBG_CTX((stderr,"Invalid context: id=%d\n",refId));
3639 else if (nc=='w') // some word
3643 while (nc!=0 && isdigit(nc)) { refIdStr+=nc; nc=*p++; }
3645 int refId=refIdStr.toInt();
3646 auto it = yyextra->wordMap.find(refId);
3647 if (it!=yyextra->wordMap.end())
3649 QCString word = it->second;
3650 codifyLines(yyscanner,word);
3653 else if (nc=='d') // comment block
3657 while (nc!=0 && isdigit(nc)) { refIdStr+=nc; nc=*p++; }
3659 int refId=refIdStr.toInt();
3660 auto it = yyextra->commentMap.find(refId);
3661 if (it!=yyextra->commentMap.end())
3663 QCString comment = it->second;
3664 startFontClass(yyscanner,"comment");
3665 codifyLines(yyscanner,comment);
3666 endFontClass(yyscanner);
3669 else // illegal marker
3671 ASSERT("invalid escape sequence"==0);
3675 else // normal non-marker character
3679 codifyLines(yyscanner,s);
3683 DBG_CTX((stderr,"%s %s]\n",qPrint(ctx->objectTypeOrName),qPrint(ctx->methodName)));
3684 DBG_CTX((stderr,"}=(type='%s',name='%s')",
3685 qPrint(ctx->objectTypeOrName),
3686 qPrint(ctx->methodName)));
3689 // Replaces an Objective-C method name fragment s by a marker of the form
3690 // $n12, the number (12) can later be used as a key for obtaining the name
3691 // fragment, from yyextra->nameMap
3692 static QCString escapeName(yyscan_t yyscanner,const char *s)
3694 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3696 result.sprintf("$n%d",yyextra->currentNameId);
3697 yyextra->nameMap.emplace(std::make_pair(yyextra->currentNameId,s));
3698 yyextra->currentNameId++;
3702 static QCString escapeObject(yyscan_t yyscanner,const char *s)
3704 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3706 result.sprintf("$o%d",yyextra->currentObjId);
3707 yyextra->objectMap.emplace(std::make_pair(yyextra->currentObjId,s));
3708 yyextra->currentObjId++;
3712 static QCString escapeWord(yyscan_t yyscanner,const char *s)
3714 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3716 result.sprintf("$w%d",yyextra->currentWordId);
3717 yyextra->wordMap.emplace(std::make_pair(yyextra->currentWordId,s));
3718 yyextra->currentWordId++;
3722 static QCString escapeComment(yyscan_t yyscanner,const char *s)
3724 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3726 result.sprintf("$d%d",yyextra->currentCommentId);
3727 yyextra->commentMap.emplace(std::make_pair(yyextra->currentCommentId,s));
3728 yyextra->currentCommentId++;
3732 static bool skipLanguageSpecificKeyword(yyscan_t yyscanner,const char *keyword)
3734 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3735 static std::unordered_set<std::string> non_cpp_keywords = {
3736 "__assume", "__super", "abstract", "function",
3737 "gcnew", "gcroot", "generic", "get",
3738 "internal", "null", "pin_ptr", "raise",
3739 "remove", "self", "set", "transient"};
3740 return yyextra->lang==SrcLangExt_Cpp && (non_cpp_keywords.find(keyword) != non_cpp_keywords.end());
3743 static bool isCastKeyword(const char *keyword)
3745 QCString s(keyword);
3747 if (i==-1) return FALSE;
3748 QCString kw = s.left(i).stripWhiteSpace();
3749 return kw=="const_cast" || kw=="static_cast" || kw=="dynamic_cast" || kw=="reinterpret_cast";
3752 static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size)
3754 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3755 yy_size_t inputPosition = yyextra->inputPosition;
3756 const char *s = yyextra->inputString + inputPosition;
3758 while( c < max_size && *s )
3763 yyextra->inputPosition += c;
3768 static void saveObjCContext(yyscan_t yyscanner)
3770 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3771 if (yyextra->currentCtx)
3773 yyextra->currentCtx->format+=QCString().sprintf("$c%d",yyextra->currentCtxId);
3774 if (yyextra->braceCount==0 && YY_START==ObjCCall)
3776 yyextra->currentCtx->objectTypeOrName=yyextra->currentCtx->format.mid(1);
3777 DBG_CTX((stderr,"new type=%s\n",qPrint(yyextra->currentCtx->objectTypeOrName)));
3779 yyextra->contextStack.push(yyextra->currentCtx);
3783 DBG_CTX((stderr,"Trying to save NULL context!\n"));
3785 auto newCtx = std::make_unique<ObjCCallCtx>();
3786 newCtx->id = yyextra->currentCtxId;
3787 newCtx->lexState = YY_START;
3788 newCtx->braceCount = yyextra->braceCount;
3789 newCtx->objectType = 0;
3790 newCtx->objectVar = 0;
3792 DBG_CTX((stderr,"save state=%d\n",YY_START));
3793 yyextra->currentCtx = newCtx.get();
3794 yyextra->contextMap.emplace(std::make_pair(yyextra->currentCtxId,std::move(newCtx)));
3795 yyextra->braceCount = 0;
3796 yyextra->currentCtxId++;
3799 static void restoreObjCContext(yyscan_t yyscanner)
3801 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3802 DBG_CTX((stderr,"restore state=%d->%d\n",YY_START,yyextra->currentCtx->lexState));
3803 BEGIN(yyextra->currentCtx->lexState);
3804 yyextra->braceCount = yyextra->currentCtx->braceCount;
3805 if (!yyextra->contextStack.empty())
3807 yyextra->currentCtx = yyextra->contextStack.top();
3808 yyextra->contextStack.pop();
3812 yyextra->currentCtx = 0;
3813 DBG_CTX((stderr,"Trying to pop context while yyextra->contextStack is empty!\n"));
3817 struct CCodeParser::Private
3823 CCodeParser::CCodeParser() : p(std::make_unique<CCodeParser::Private>())
3825 codeYYlex_init_extra(&p->state,&p->yyscanner);
3827 codeYYset_debug(1,p->yyscanner);
3829 resetCodeParserState();
3832 CCodeParser::~CCodeParser()
3834 codeYYlex_destroy(p->yyscanner);
3837 void CCodeParser::resetCodeParserState()
3839 struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
3840 DBG_CTX((stderr,"***CodeParser::reset()\n"));
3841 yyextra->theVarContext.clear();
3842 while (!yyextra->classScopeLengthStack.empty()) yyextra->classScopeLengthStack.pop();
3843 yyextra->codeClassMap.clear();
3844 yyextra->curClassBases.clear();
3845 yyextra->anchorCount = 0;
3848 void CCodeParser::setStartCodeLine(const bool inp)
3850 struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
3851 yyextra->beginCodeLine = inp;
3854 void CCodeParser::parseCode(CodeOutputInterface &od,const QCString &className,const QCString &s,
3855 SrcLangExt lang,bool exBlock, const QCString &exName,const FileDef *fd,
3856 int startLine,int endLine,bool inlineFragment,
3857 const MemberDef *memberDef,bool showLineNumbers,const Definition *searchCtx,
3860 yyscan_t yyscanner = p->yyscanner;
3861 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3862 DBG_CTX((stderr,"***parseCode() exBlock=%d exName=%s fd=%p className=%s searchCtx=%s\n",
3863 exBlock,qPrint(exName),(void*)fd,qPrint(className),searchCtx?qPrint(searchCtx->name()):"<none>"));
3865 if (s.isEmpty()) return;
3867 printlex(yy_flex_debug, TRUE, __FILE__, fd ? qPrint(fd->fileName()): NULL);
3869 yyextra->code = &od;
3870 yyextra->inputString = s.data();
3871 yyextra->inputPosition = 0;
3872 codeYYrestart(0,yyscanner);
3873 yyextra->currentFontClass = 0;
3874 yyextra->needsTermination = FALSE;
3875 yyextra->searchCtx = searchCtx;
3876 yyextra->collectXRefs = collectXRefs;
3877 yyextra->inFunctionTryBlock = FALSE;
3878 yyextra->symbolResolver.setFileScope(fd);
3881 yyextra->yyLineNr = startLine;
3883 yyextra->yyLineNr = 1;
3886 yyextra->inputLines = endLine+1;
3888 yyextra->inputLines = yyextra->yyLineNr + countLines(yyscanner) - 1;
3890 yyextra->curlyCount = 0;
3891 yyextra->bodyCurlyCount = 0;
3892 yyextra->bracketCount = 0;
3893 yyextra->sharpCount = 0;
3894 yyextra->insideTemplate = FALSE;
3895 yyextra->theCallContext.clear();
3896 while (!yyextra->scopeStack.empty()) yyextra->scopeStack.pop();
3897 yyextra->classScope = className;
3898 DBG_CTX((stderr,"parseCCode %s\n",qPrint(className)));
3899 yyextra->exampleBlock = exBlock;
3900 yyextra->exampleName = exName;
3901 yyextra->sourceFileDef = fd;
3902 yyextra->lineNumbers = fd!=0 && showLineNumbers;
3903 bool cleanupSourceDef = FALSE;
3906 // create a dummy filedef for the example
3907 yyextra->sourceFileDef = createFileDef(QCString(),(!exName.isEmpty()?exName:"generated"));
3908 cleanupSourceDef = TRUE;
3910 yyextra->lang = lang;
3911 yyextra->insideObjC = lang==SrcLangExt_ObjC;
3912 if (yyextra->sourceFileDef)
3914 setCurrentDoc(yyscanner,"l00001");
3916 yyextra->currentDefinition = getResolvedNamespace(className);
3917 yyextra->currentMemberDef = 0;
3918 yyextra->searchingForBody = exBlock;
3919 yyextra->insideBody = FALSE;
3920 yyextra->bracketCount = 0;
3921 if (!yyextra->exampleName.isEmpty())
3923 yyextra->exampleFile = convertNameToFile(yyextra->exampleName+"-example",FALSE,TRUE);
3924 DBG_CTX((stderr,"yyextra->exampleFile=%s\n",qPrint(yyextra->exampleFile)));
3926 yyextra->includeCodeFragment = inlineFragment;
3927 DBG_CTX((stderr,"** exBlock=%d exName=%s include=%d\n",exBlock,qPrint(exName),inlineFragment));
3928 if (yyextra->beginCodeLine) startCodeLine(yyscanner);
3929 yyextra->type.resize(0);
3930 yyextra->name.resize(0);
3931 yyextra->args.resize(0);
3932 yyextra->parmName.resize(0);
3933 yyextra->parmType.resize(0);
3934 if (memberDef) setParameterList(yyscanner,memberDef);
3936 codeYYlex(yyscanner);
3937 yyextra->lexInit=TRUE;
3938 if (yyextra->needsTermination)
3940 endFontClass(yyscanner);
3941 DBG_CTX((stderr,"endCodeLine(%d)\n",yyextra->yyLineNr));
3942 yyextra->code->endCodeLine();
3944 if (cleanupSourceDef)
3946 // delete the temporary file definition used for this example
3947 delete yyextra->sourceFileDef;
3948 yyextra->sourceFileDef=0;
3950 // write the tooltips
3951 yyextra->tooltipManager.writeTooltips(od);
3953 printlex(yy_flex_debug, FALSE, __FILE__, fd ? qPrint(fd->fileName()): NULL);
3957 #if USE_STATE2STRING