Doxygen
Loading...
Searching...
No Matches
code.l
Go to the documentation of this file.
1/******************************************************************************
2 *
3 * Copyright (C) 1997-2020 by Dimitri van Heesch.
4 *
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.
10 *
11 * Documents produced by Doxygen are derivative works derived from the
12 * input used in their production; they are not affected by this license.
13 *
14 */
15%option never-interactive
16%option prefix="codeYY"
17%option reentrant
18%option extra-type="struct codeYY_state *"
19%top{
20#include <stdint.h>
21// forward declare yyscan_t to improve type safety
22#define YY_TYPEDEF_YY_SCANNER_T
23struct yyguts_t;
24typedef yyguts_t *yyscan_t;
yyguts_t * yyscan_t
Definition code.l:24
25}
26
27%{
28
29/*
30 * includes
31 */
32
33#include <utility>
34#include <memory>
35#include <algorithm>
36#include <unordered_map>
37#include <unordered_set>
38#include <stack>
39#include <vector>
40#include <string>
41#include <mutex>
42#include <sstream>
43#include <cstdint>
44
45#include <stdio.h>
46#include <assert.h>
47#include <ctype.h>
48
49#include "code.h"
50#include "entry.h"
51#include "doxygen.h"
52#include "message.h"
53#include "outputlist.h"
54#include "util.h"
55#include "membername.h"
56#include "searchindex.h"
57#include "arguments.h"
58#include "config.h"
59#include "groupdef.h"
60#include "classlist.h"
61#include "filedef.h"
62#include "filename.h"
63#include "namespacedef.h"
64#include "tooltip.h"
65#include "scopedtypevariant.h"
66#include "symbolresolver.h"
67#include "dir.h"
68#include "debug.h"
69#include "moduledef.h"
70
71// Toggle for some debugging info
72//#define DBG_CTX(x) fprintf x
73#define DBG_CTX(x) do { } while(0)
74
75#define YY_NO_UNISTD_H 1
76
77#define CLASSBLOCK 1
78#define SCOPEBLOCK 2
79#define INNERBLOCK 3
80
81// context for an Objective-C method call
95
97{
98 OutputCodeList * code = nullptr;
99
100 std::unordered_map< std::string, ScopedTypeVariant > codeClassMap;
103
106
107 const char * inputString = nullptr; //!< the code fragment as text
108 yy_size_t inputPosition = 0; //!< read offset during parsing
111 int inputLines = 0; //!< number of line in the code fragment
112 int yyLineNr = 0; //!< current line number
114 bool skipCodify = FALSE; //!< for CSharp files scoped namespace {
115
119
126 std::stack<int> scopeStack; //!< 1 if bracket starts a scope,
127 // 2 for internal blocks
128 int anchorCount = 0;
129 std::unique_ptr<FileDef> exampleFileDef;
130 const FileDef * sourceFileDef = nullptr;
132 const Definition * currentDefinition = nullptr;
133 const MemberDef * currentMemberDef = nullptr;
135 const char * currentFontClass = nullptr;
142
144 int curlyCount = 0;
145 int sharpCount = 0;
148
158
159 SrcLangExt lang = SrcLangExt::Unknown;
163
165
166 std::vector<int> scopeNameLengthStack;
167
169 const Definition *searchCtx = nullptr;
171
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;
185
186 using UsingContext = std::map<std::string,const NamespaceDef*>;
187
193 std::vector<const Definition *> foldStack;
194};
195
196static bool isCastKeyword(const char *s);
197
198//-------------------------------------------------------------------
199[[maybe_unused]] static const char *stateToString(int state);
200
201static void saveObjCContext(yyscan_t yyscanner);
202static void restoreObjCContext(yyscan_t yyscanner);
203static void pushScope(yyscan_t yyscanner,const QCString &s);
204static void popScope(yyscan_t yyscanner);
205static void setCurrentDoc(yyscan_t yyscanner,const QCString &anchor);
206static void addToSearchIndex(yyscan_t yyscanner,const QCString &text);
207static void addToSearchIndex(yyscan_t yyscanner,const char *text);
208static void setClassScope(yyscan_t yyscanner,const QCString &name);
209static void startCodeLine(yyscan_t yyscanner);
210static void endCodeLine(yyscan_t yyscanner);
211static void nextCodeLine(yyscan_t yyscanner);
212static void startFontClass(yyscan_t yyscanner,const char *s,bool specialComment=false);
213static void endFontClass(yyscan_t yyscanner,bool specialComment=false);
214static void codifyLines(yyscan_t yyscanner,const QCString &text);
215static void codifyLines(yyscan_t yyscanner,const char *text);
216static void incrementFlowKeyWordCount(yyscan_t yyscanner);
217static void writeMultiLineCodeLink(yyscan_t yyscanner,OutputCodeList &ol,
218 const Definition *d,
219 const QCString &text);
220static void addType(yyscan_t yyscanner);
221static void addParmType(yyscan_t yyscanner);
222static void addUsingDirective(yyscan_t yyscanner,const QCString &name);
223static void setParameterList(yyscan_t yyscanner,const MemberDef *md);
224static const ClassDef *stripClassName(yyscan_t yyscanner,const QCString &s,const Definition *d);
225static const MemberDef *setCallContextForVar(yyscan_t yyscanner,const QCString &name);
226static void updateCallContextForSmartPointer(yyscan_t yyscanner);
227static bool getLinkInScope(yyscan_t yyscanner,const QCString &c, // scope
228 const QCString &m, // member
229 const QCString &memberText, // exact text
230 OutputCodeList &ol,
231 const QCString &text,
232 bool varOnly=FALSE
233 );
234static bool getLink(yyscan_t yyscanner,const QCString &className,
235 const QCString &memberName,
236 OutputCodeList &ol,
237 const QCString &text=QCString(),
238 bool varOnly=FALSE);
239static void generateClassOrGlobalLink(yyscan_t yyscanner,OutputCodeList &ol,const QCString &clName,
240 bool typeOnly=FALSE,bool varOnly=FALSE);
241static void generateClassOrGlobalLink(yyscan_t yyscanner,OutputCodeList &ol,const char *clName,
242 bool typeOnly=FALSE,bool varOnly=FALSE);
243static bool generateClassMemberLink(yyscan_t yyscanner,OutputCodeList &ol,const MemberDef *xmd,const QCString &memName);
244static bool generateClassMemberLink(yyscan_t yyscanner,OutputCodeList &ol,const Definition *def,const QCString &memName);
245static void generateMemberLink(yyscan_t yyscanner,OutputCodeList &ol,const QCString &varName,
246 const QCString &memName);
247static void generatePHPVariableLink(yyscan_t yyscanner,OutputCodeList &ol,const char *varName);
248static void generateFunctionLink(yyscan_t yyscanner,OutputCodeList &ol,const QCString &funcName);
249static void generateFunctionLink(yyscan_t yyscanner,OutputCodeList &ol,const char *funcName);
250static int countLines(yyscan_t yyscanner);
251static void writeObjCMethodCall(yyscan_t yyscanner,ObjCCallCtx *ctx);
252static QCString escapeName(yyscan_t yyscanner,const char *s);
253static QCString escapeObject(yyscan_t yyscanner,const char *s);
254static QCString escapeWord(yyscan_t yyscanner,const char *s);
255static QCString escapeComment(yyscan_t yyscanner,const char *s);
256static bool skipLanguageSpecificKeyword(yyscan_t yyscanner,const char *kw);
257static int yyread(yyscan_t yyscanner,char *buf,int max_size);
258static void addVariable(yyscan_t yyscanner,QCString type,QCString name);
259static bool startsWithKeyword(const QCString &str,const QCString &kw);
260static void endCodeFold(yyscan_t yyscanner);
261
262/* -----------------------------------------------------------------
263 */
264#undef YY_INPUT
265#define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size);
266
267// otherwise the filename would be the name of the converted file (*.cpp instead of *.l)
268static inline const char *getLexerFILE() {return __FILE__;}
269#include "doxygen_lex.h"
270
Represents the call context.
A abstract class representing of a compound symbol.
Definition classdef.h:104
The common base class of all entity definitions found in the sources.
Definition definition.h:76
A model of a file symbol.
Definition filedef.h:99
A model of a class/file/namespace member symbol.
Definition memberdef.h:48
Class representing a list of different code generators.
Definition outputlist.h:164
This is an alternative implementation of QCString.
Definition qcstring.h:101
Text streaming class that buffers data.
Definition textstream.h:36
Class that manages the tooltips for a source file.
Definition tooltip.h:26
static bool isCastKeyword(const char *s)
Definition code.l:3983
static void pushScope(yyscan_t yyscanner, const QCString &s)
Definition code.l:2249
static void writeMultiLineCodeLink(yyscan_t yyscanner, OutputCodeList &ol, const Definition *d, const QCString &text)
Definition code.l:2568
static QCString escapeName(yyscan_t yyscanner, const char *s)
Definition code.l:3902
static void endCodeLine(yyscan_t yyscanner)
Definition code.l:2490
static bool skipLanguageSpecificKeyword(yyscan_t yyscanner, const char *kw)
Definition code.l:3942
static QCString escapeWord(yyscan_t yyscanner, const char *s)
Definition code.l:3922
static void generateClassOrGlobalLink(yyscan_t yyscanner, OutputCodeList &ol, const QCString &clName, bool typeOnly=FALSE, bool varOnly=FALSE)
Definition code.l:2925
static void restoreObjCContext(yyscan_t yyscanner)
Definition code.l:4039
static void nextCodeLine(yyscan_t yyscanner)
Definition code.l:2499
static void popScope(yyscan_t yyscanner)
Definition code.l:2267
static void startCodeLine(yyscan_t yyscanner)
Definition code.l:2421
static void codifyLines(yyscan_t yyscanner, const QCString &text)
Definition code.l:2517
static void incrementFlowKeyWordCount(yyscan_t yyscanner)
Definition code.l:2550
static bool startsWithKeyword(const QCString &str, const QCString &kw)
Definition code.l:2177
static int yyread(yyscan_t yyscanner, char *buf, int max_size)
Definition code.l:3992
static int countLines(yyscan_t yyscanner)
Definition code.l:3483
static void addToSearchIndex(yyscan_t yyscanner, const QCString &text)
Definition code.l:2299
static const char * stateToString(int state)
static void addParmType(yyscan_t yyscanner)
Definition code.l:2618
static bool getLinkInScope(yyscan_t yyscanner, const QCString &c, const QCString &m, const QCString &memberText, OutputCodeList &ol, const QCString &text, bool varOnly=FALSE)
Definition code.l:2816
static const ClassDef * stripClassName(yyscan_t yyscanner, const QCString &s, const Definition *d)
Definition code.l:2658
static void updateCallContextForSmartPointer(yyscan_t yyscanner)
Definition code.l:2799
static QCString escapeObject(yyscan_t yyscanner, const char *s)
Definition code.l:3912
static void generateMemberLink(yyscan_t yyscanner, OutputCodeList &ol, const QCString &varName, const QCString &memName)
Definition code.l:3262
static void addUsingDirective(yyscan_t yyscanner, const QCString &name)
Definition code.l:2627
static bool getLink(yyscan_t yyscanner, const QCString &className, const QCString &memberName, OutputCodeList &ol, const QCString &text=QCString(), bool varOnly=FALSE)
Definition code.l:2900
static void startFontClass(yyscan_t yyscanner, const char *s, bool specialComment=false)
Definition code.l:3516
static const MemberDef * setCallContextForVar(yyscan_t yyscanner, const QCString &name)
Definition code.l:2689
static void endFontClass(yyscan_t yyscanner, bool specialComment=false)
Definition code.l:3501
static QCString escapeComment(yyscan_t yyscanner, const char *s)
Definition code.l:3932
static void generateFunctionLink(yyscan_t yyscanner, OutputCodeList &ol, const QCString &funcName)
Definition code.l:3368
static void addVariable(yyscan_t yyscanner, QCString type, QCString name)
Definition code.l:2184
static const char * getLexerFILE()
Definition code.l:268
static void setClassScope(yyscan_t yyscanner, const QCString &name)
Definition code.l:2313
static bool generateClassMemberLink(yyscan_t yyscanner, OutputCodeList &ol, const MemberDef *xmd, const QCString &memName)
Definition code.l:3157
static void setCurrentDoc(yyscan_t yyscanner, const QCString &anchor)
Definition code.l:2283
static void setParameterList(yyscan_t yyscanner, const MemberDef *md)
Definition code.l:2641
static void addType(yyscan_t yyscanner)
Definition code.l:2606
static void saveObjCContext(yyscan_t yyscanner)
Definition code.l:4008
static void writeObjCMethodCall(yyscan_t yyscanner, ObjCCallCtx *ctx)
Definition code.l:3532
static void endCodeFold(yyscan_t yyscanner)
Definition code.l:2342
static void generatePHPVariableLink(yyscan_t yyscanner, OutputCodeList &ol, const char *varName)
Definition code.l:3356
std::vector< std::string > StringVector
Definition containers.h:33
QCString s
Definition htmlgen.cpp:154
#define FALSE
Definition qcstring.h:34
Web server based search engine.
const MemberDef * method
Definition code.l:90
int braceCount
Definition code.l:93
int lexState
Definition code.l:92
QCString objectTypeOrName
Definition code.l:86
TextStream comment
Definition code.l:87
const MemberDef * objectVar
Definition code.l:89
QCString methodName
Definition code.l:85
const ClassDef * objectType
Definition code.l:88
QCString format
Definition code.l:91
int memCallContext
Definition code.l:155
StringVector curClassBases
Definition code.l:102
bool lineNumbers
Definition code.l:131
int bodyCurlyCount
Definition code.l:138
CallContext theCallContext
Definition code.l:190
std::unordered_map< int, QCString > commentMap
Definition code.l:183
int lastCContext
Definition code.l:156
bool includeCodeFragment
Definition code.l:134
bool insideTemplate
Definition code.l:120
const Definition * currentDefinition
Definition code.l:132
std::unique_ptr< FileDef > exampleFileDef
Definition code.l:129
int lastSpecialCContext
Definition code.l:150
std::unordered_map< int, QCString > wordMap
Definition code.l:182
bool inFunctionTryBlock
Definition code.l:146
int braceCount
Definition code.l:184
bool collectXRefs
Definition code.l:170
QCString saveType
Definition code.l:140
QCString delimiter
Definition code.l:141
QCString fileName
Definition code.l:109
const char * currentFontClass
Definition code.l:135
bool insideBody
Definition code.l:137
std::stack< int > scopeStack
1 if bracket starts a scope,
Definition code.l:126
const FileDef * sourceFileDef
Definition code.l:130
std::unordered_map< int, QCString > objectMap
Definition code.l:181
ObjCCallCtx * currentCtx
Definition code.l:172
bool exampleBlock
Definition code.l:116
std::unordered_map< int, std::unique_ptr< ObjCCallCtx > > contextMap
Definition code.l:179
bool inForEachExpression
Definition code.l:147
QCString curClassName
Definition code.l:101
VariableContext theVarContext
Definition code.l:188
QCString type
Definition code.l:121
bool lexInit
Definition code.l:164
int bracketCount
Definition code.l:143
QCString parmName
Definition code.l:105
int anchorCount
Definition code.l:128
int lastSkipCppContext
Definition code.l:152
int curlyCount
Definition code.l:144
TooltipManager tooltipManager
Definition code.l:192
std::vector< int > scopeNameLengthStack
Definition code.l:166
int currentCommentId
Definition code.l:177
QCString name
Definition code.l:122
int sharpCount
Definition code.l:145
QCString exampleName
Definition code.l:117
std::map< std::string, const NamespaceDef * > UsingContext
Definition code.l:186
bool insideCodeLine
Definition code.l:113
const char * inputString
the code fragment as text
Definition code.l:107
const Definition * searchCtx
Definition code.l:169
QCString parmType
Definition code.l:104
QCString absFileName
Definition code.l:110
int isPrefixedWithThis
Definition code.l:168
bool searchingForBody
Definition code.l:136
QCString realScope
Definition code.l:125
int lastTemplCastContext
Definition code.l:149
SrcLangExt lang
Definition code.l:159
SymbolResolver symbolResolver
Definition code.l:191
int currentObjId
Definition code.l:175
int currentWordId
Definition code.l:176
int lastObjCCallContext
Definition code.l:154
QCString args
Definition code.l:123
yy_size_t inputPosition
read offset during parsing
Definition code.l:108
bool insideObjC
Definition code.l:160
bool insideSpecialComment
Definition code.l:162
int lastStringContext
Definition code.l:151
QCString scopeName
Definition code.l:124
int yyLineNr
current line number
Definition code.l:112
int currentCtxId
Definition code.l:173
std::vector< const Definition * > foldStack
Definition code.l:193
bool insideProtocolList
Definition code.l:161
OutputCodeList * code
Definition code.l:98
int lastVerbStringContext
Definition code.l:153
int inputLines
number of line in the code fragment
Definition code.l:111
const MemberDef * currentMemberDef
Definition code.l:133
std::unordered_map< std::string, ScopedTypeVariant > codeClassMap
Definition code.l:100
QCString exampleFile
Definition code.l:118
UsingContext theUsingContext
Definition code.l:189
std::unordered_map< int, QCString > nameMap
Definition code.l:180
bool skipCodify
for CSharp files scoped namespace {
Definition code.l:114
int currentNameId
Definition code.l:174
std::stack< ObjCCallCtx * > contextStack
Definition code.l:178
int skipInlineInitContext
Definition code.l:157
QCString saveName
Definition code.l:139
SrcLangExt
Definition types.h:207
A bunch of utility functions.
271%}
272
273B [ \t]
274Bopt {B}*
275BN [ \t\n\r]
276ID [$a-z_A-Z\x80-\xFF][$a-z_A-Z0-9\x80-\xFF]*
277SEP ("::"|"\\")
278SCOPENAME ("::"{BN}*)?({ID}{BN}*{SEP}{BN}*)*("~"{BN}*)?{ID}
279TEMPLIST "<"[^\"\}\{\‍(\‍)\/\n>]*">"
280SCOPETNAME (((({ID}{TEMPLIST}?){BN}*)?{SEP}{BN}*)*)((~{BN}*)?{ID})
281SCOPEPREFIX ({ID}{TEMPLIST}?{BN}*{SEP}{BN}*)+
282KEYWORD_OBJC ("@public"|"@private"|"@protected"|"@class"|"@implementation"|"@interface"|"@end"|"@selector"|"@protocol"|"@optional"|"@required"|"@throw"|"@synthesize"|"@property")
283 /* please also pay attention to skipLanguageSpecificKeyword when changing the list of keywords. */
284KEYWORD ("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"|"sealed"|"final"|"import"|"synchronized"|"transient"|"alignas"|"alignof"|"concept"|"requires"|"decltype"|{KEYWORD_OBJC}|"constexpr"|"consteval"|"constinit"|"co_await"|"co_return"|"co_yield"|"static_assert"|"_Static_assert"|"noexcept"|"thread_local"|"enum"{B}+("class"|"struct"))
285FLOWKW ("break"|"catch"|"continue"|"default"|"do"|"else"|"finally"|"return"|"switch"|"throw"|"throws"|"@catch"|"@finally")
286FLOWCONDITION ("case"|"for"|"foreach"|"for each"|"goto"|"if"|"try"|"while"|"@try")
287TYPEKW ("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")
288TYPEKWSL ("LocalObject"|"Object"|"Value")
289CASTKW ("const_cast"|"dynamic_cast"|"reinterpret_cast"|"static_cast")
290CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^' \\\n]{1,4}"'"))
291ARITHOP "+"|"-"|"/"|"*"|"%"|"--"|"++"
292ASSIGNOP "="|"*="|"/="|"%="|"+="|"-="|"<<="|">>="|"&="|"^="|"|="
293LOGICOP "=="|"!="|">"|"<"|">="|"<="|"&&"|"||"|"!"|"<=>"
294BITOP "&"|"|"|"^"|"<<"|">>"|"~"
295OPERATOR {ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP}
296RAWBEGIN (u|U|L|u8)?R\"[^ \t\‍(\‍)\\]{0,16}"("
297RAWEND ")"[^ \t\‍(\‍)\\]{0,16}\"
298MODULE_ID ({ID}".")*{ID}
299
300 /* no comment start / end signs inside square brackets */
301NCOMM [^/\*]
302 //- start: NUMBER -------------------------------------------------------------------------
303 // Note same defines in commentcnv.l: keep in sync
304DECIMAL_INTEGER [1-9][0-9']*[0-9]?[uU]?[lL]?[lL]?
305HEXADECIMAL_INTEGER "0"[xX][0-9a-zA-Z']+[0-9a-zA-Z]?
306OCTAL_INTEGER "0"[0-7][0-7']+[0-7]?
307BINARY_INTEGER "0"[bB][01][01']*[01]?
308INTEGER_NUMBER {DECIMAL_INTEGER}|{HEXADECIMAL_INTEGER}|{OCTAL_INTEGER}|{BINARY_INTEGER}
309
310FP_SUF [fFlL]
311
312DIGIT_SEQ [0-9][0-9']*[0-9]?
313FRAC_CONST {DIGIT_SEQ}"."|{DIGIT_SEQ}?"."{DIGIT_SEQ}
314FP_EXP [eE][+-]?{DIGIT_SEQ}
315DEC_FP1 {FRAC_CONST}{FP_EXP}?{FP_SUF}?
316DEC_FP2 {DIGIT_SEQ}{FP_EXP}{FP_SUF}
317
318HEX_DIGIT_SEQ [0-9a-fA-F][0-9a-fA-F']*[0-9a-fA-F]?
319HEX_FRAC_CONST {HEX_DIGIT_SEQ}"."|{HEX_DIGIT_SEQ}?"."{HEX_DIGIT_SEQ}
320BIN_EXP [pP][+-]?{DIGIT_SEQ}
321HEX_FP1 "0"[xX]{HEX_FRAC_CONST}{BIN_EXP}{FP_SUF}?
322HEX_FP2 "0"[xX]{HEX_DIGIT_SEQ}{BIN_EXP}{FP_SUF}?
323
324FLOAT_DECIMAL {DEC_FP1}|{DEC_FP2}
325FLOAT_HEXADECIMAL {HEX_FP1}|{HEX_FP2}
326FLOAT_NUMBER {FLOAT_DECIMAL}|{FLOAT_HEXADECIMAL}
327NUMBER {INTEGER_NUMBER}|{FLOAT_NUMBER}
328 //- end: NUMBER ---------------------------------------------------------------------------
329
330 // C start comment
331CCS "/\*"
332 // C end comment
333CCE "*\/"
334 // Cpp comment
335CPPC "/\/"
336
337 // ENDIDopt
338ENDIDopt ("::"{ID})*
339 // Optional end qualifiers
340ENDQopt ("const"|"volatile"|"sealed"|"override")({BN}+("const"|"volatile"|"sealed"|"override"))*
341
342%option noyywrap
343
344%x SkipString
345%x SkipStringS
346%x SkipVerbString
347%x SkipCPP
348%x SkipComment
349%x SkipCxxComment
350%x Body
351%x BodyVar
352%x FuncCall
353%x MemberCall
354%x MemberCall2
355%x SkipInits
356%x ClassName
357%x AlignAs
358%x AlignAsEnd
359%x PackageName
360%x ClassVar
361%x CppCliTypeModifierFollowup
362%x Bases
363%x SkipSharp
364%x ReadInclude
365%x TemplDecl
366%x TemplCast
367%x CallEnd
368%x ObjCMethod
369%x ObjCParams
370%x ObjCParamType
371%x ObjCCall
372%x ObjCMName
373%x ObjCSkipStr
374%x ObjCCallComment
375%x OldStyleArgs
376%x ConceptName
377%x UsingName
378%x RawString
379%x InlineInit
380%x ModuleName
381%x ModuleImport
382
384
385<*>\x0d
386<Body>^([ \t]*"#"[ \t]*("include"|"import")[ \t]*)("<"|"\"") {
387 startFontClass(yyscanner,"preprocessor");
388 yyextra->code->codify(yytext);
389 BEGIN( ReadInclude );
390 }
391<Body>("@interface"|"@implementation"|"@protocol")[ \t\n]+ {
392 yyextra->insideObjC=TRUE;
393 startFontClass(yyscanner,"keyword");
394 codifyLines(yyscanner,yytext);
395 endFontClass(yyscanner);
396 if (!yyextra->insideTemplate)
397 BEGIN( ClassName );
398 }
#define TRUE
Definition qcstring.h:37
399<Body>(("public"|"private"){B}+)?("ref"|"value"|"interface"|"enum"){B}+("class"|"struct") {
400 if (yyextra->insideTemplate) REJECT;
401 startFontClass(yyscanner,"keyword");
402 codifyLines(yyscanner,yytext);
403 endFontClass(yyscanner);
404 BEGIN( ClassName );
405 }
406<Body>"property"|"event"/{BN}* {
407 if (yyextra->insideTemplate) REJECT;
408 startFontClass(yyscanner,"keyword");
409 codifyLines(yyscanner,yytext);
410 endFontClass(yyscanner);
411 }
412<Body>("partial"{B}+)?("class"|"struct"|"union"|"namespace"|"interface"){B}+ {
413 startFontClass(yyscanner,"keyword");
414 codifyLines(yyscanner,yytext);
415 endFontClass(yyscanner);
416 if (!yyextra->insideTemplate)
417 BEGIN( ClassName );
418 }
419<Body>("package")[ \t\n]+ {
420 startFontClass(yyscanner,"keyword");
421 codifyLines(yyscanner,yytext);
422 endFontClass(yyscanner);
423 BEGIN( PackageName );
424 }
425<ClassVar>\n {
426 if (!yyextra->insideObjC) REJECT;
427 codifyLines(yyscanner,yytext);
428 BEGIN(Body);
429 }
430<Body,ClassVar,Bases>"-"|"+" {
431 if (!yyextra->insideObjC || yyextra->insideBody)
432 {
433 yyextra->code->codify(yytext);
434 }
435 else // Start of Objective-C method
436 {
437 DBG_CTX((stderr,"Start of Objective-C method!\n"));
438 yyextra->code->codify(yytext);
439 BEGIN(ObjCMethod);
440 }
441 }
#define DBG_CTX(x)
Definition code.l:73
442<ObjCMethod>":" {
443 yyextra->code->codify(yytext);
444 BEGIN(ObjCParams);
445 }
446<ObjCParams>"(" {
447 yyextra->code->codify(yytext);
448 BEGIN(ObjCParamType);
449 }
450<ObjCParams,ObjCMethod>";"|"{" {
451 yyextra->code->codify(yytext);
452 if (*yytext=='{')
453 {
454 if (yyextra->searchingForBody)
455 {
456 yyextra->searchingForBody=FALSE;
457 yyextra->insideBody=TRUE;
458 }
459 if (yyextra->insideBody) yyextra->bodyCurlyCount++;
460 if (!yyextra->curClassName.isEmpty()) // valid class name
461 {
462 pushScope(yyscanner,yyextra->curClassName);
463 DBG_CTX((stderr,"** scope stack push SCOPEBLOCK\n"));
464 yyextra->scopeStack.push(SCOPEBLOCK);
465 }
466 }
467 yyextra->type.clear();
468 yyextra->name.clear();
469 BEGIN(Body);
470 }
#define SCOPEBLOCK
Definition code.l:78
471<ObjCParams>{ID}{B}*":" {
472 yyextra->code->codify(yytext);
473 }
474<ObjCParamType>{TYPEKW} {
475 startFontClass(yyscanner,"keywordtype");
476 yyextra->code->codify(yytext);
477 endFontClass(yyscanner);
478 yyextra->parmType=yytext;
479 }
480<ObjCParamType>{ID} {
481 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
482 yyextra->parmType=yytext;
483 }
484<ObjCParamType>")" {
485 yyextra->code->codify(yytext);
486 BEGIN(ObjCParams);
487 }
488<ObjCParams>{ID} {
489 yyextra->code->codify(yytext);
490 yyextra->parmName=yytext;
491 addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
492 yyextra->parmType.clear();yyextra->parmName.clear();
493 }
494<ObjCMethod,ObjCParams,ObjCParamType>{ID} {
495 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
496 }
497<ObjCMethod,ObjCParams,ObjCParamType>. {
498 yyextra->code->codify(yytext);
499 }
500<ObjCMethod,ObjCParams,ObjCParamType>\n {
501 codifyLines(yyscanner,yytext);
502 }
503<ReadInclude>[^\n\">]+/(">"|"\"") {
504 //FileInfo *f;
505 bool found = false;
506 bool ambig = false;
507 QCString absIncFileName = determineAbsoluteIncludeName(yyextra->absFileName,yytext);
508 const FileDef *fd=findFileDef(Doxygen::inputNameLinkedMap,absIncFileName,ambig);
509 //printf("looking for include %s -> %s fd=%p\n",yytext,qPrint(absPath),fd);
510 if (fd && fd->isLinkable())
511 {
512 if (ambig) // multiple input files match the name
513 {
514 DBG_CTX((stderr,"===== yes %s is ambiguous\n",yytext));
515 QCString name(Dir::cleanDirPath(yytext));
516 if (!name.isEmpty() && yyextra->sourceFileDef)
517 {
518 const FileName *fn = Doxygen::inputNameLinkedMap->find(name);
519 if (fn)
520 {
521 // see if this source file actually includes the file
522 auto it = std::find_if(fn->begin(),
523 fn->end(),
524 [&sfd=yyextra->sourceFileDef]
525 (const auto &lfd)
526 { return sfd->isIncluded(lfd->absFilePath()); });
527 found = it!=fn->end();
528 }
529 }
530 }
531 else // not ambiguous
532 {
533 found = TRUE;
534 }
535 }
536 DBG_CTX((stderr," include file %s found=%d\n",fd ? qPrint(fd->absFilePath()) : "<none>",found));
537 if (found)
538 {
539 writeMultiLineCodeLink(yyscanner,*yyextra->code,fd,yytext);
540 }
541 else
542 {
543 yyextra->code->codify(yytext);
544 }
545 char c=(char)yyinput(yyscanner);
546 QCString text;
547 text+=c;
548 yyextra->code->codify(text);
549 endFontClass(yyscanner);
550 BEGIN( Body );
551 }
virtual bool isLinkable() const =0
static std::string cleanDirPath(const std::string &path)
Definition dir.cpp:357
static FileNameLinkedMap * inputNameLinkedMap
Definition doxygen.h:105
virtual QCString absFilePath() const =0
Class representing all files with a certain base name.
Definition filename.h:30
const char * qPrint(const char *s)
Definition qcstring.h:672
QCString determineAbsoluteIncludeName(const QCString &curFile, const QCString &incFileName)
Definition util.cpp:4116
FileDef * findFileDef(const FileNameLinkedMap *fnMap, const QCString &n, bool &ambig)
Definition util.cpp:3417
552<Body,Bases>^[ \t]*"#" {
553 startFontClass(yyscanner,"preprocessor");
554 yyextra->lastSkipCppContext = YY_START;
555 yyextra->code->codify(yytext);
556 BEGIN( SkipCPP ) ;
557 }
558<SkipCPP>\" {
559 yyextra->code->codify(yytext);
560 yyextra->lastStringContext=YY_START;
561 BEGIN( SkipString ) ;
562 }
563<SkipCPP>. {
564 yyextra->code->codify(yytext);
565 }
566<SkipCPP>[^\n\/\\\"]+ {
567 yyextra->code->codify(yytext);
568 }
569<SkipCPP>\\[\r]?\n {
570 codifyLines(yyscanner,yytext);
571 }
572<SkipCPP>{CPPC}/[^/!] {
573 REJECT;
574 }
575<Body,FuncCall,MemberCall,MemberCall2>"}" {
576 yyextra->theVarContext.popScope();
577 yyextra->theCallContext.popScope(yyextra->name, yyextra->type, yyextra->bracketCount);
578 yyextra->type.clear();
579 yyextra->name.clear();
580
581 if (!yyextra->scopeStack.empty())
582 {
583 int scope = yyextra->scopeStack.top();
584 yyextra->scopeStack.pop();
585 DBG_CTX((stderr,"** scope stack pop SCOPEBLOCK=%d\n",scope==SCOPEBLOCK));
586 if (scope==SCOPEBLOCK || scope==CLASSBLOCK)
587 {
588 popScope(yyscanner);
589 }
590 }
591
592 yyextra->code->codify(yytext);
593
594 DBG_CTX((stderr,"yyextra->bodyCurlyCount=%d\n",yyextra->bodyCurlyCount));
595 if (--yyextra->bodyCurlyCount<=0)
596 {
597 yyextra->insideBody=FALSE;
598 yyextra->currentMemberDef=nullptr;
599 if (yyextra->currentDefinition)
600 yyextra->currentDefinition=yyextra->currentDefinition->getOuterScope();
601 }
602 BEGIN(Body);
603 }
#define CLASSBLOCK
Definition code.l:77
604<Body,ClassVar>"@end" {
605 DBG_CTX((stderr,"End of objc scope fd=%s\n",qPrint(yyextra->sourceFileDef->name())));
606 if (yyextra->sourceFileDef)
607 {
608 const FileDef *fd=yyextra->sourceFileDef;
609 yyextra->insideObjC = fd->name().lower().endsWith(".m") ||
610 fd->name().lower().endsWith(".mm");
611 DBG_CTX((stderr,"insideObjC=%d\n",yyextra->insideObjC));
612 }
613 else
614 {
615 yyextra->insideObjC = FALSE;
616 }
617 if (yyextra->insideBody)
618 {
619 yyextra->theVarContext.popScope();
620
621 if (!yyextra->scopeStack.empty())
622 {
623 int scope = yyextra->scopeStack.top();
624 yyextra->scopeStack.pop();
625 DBG_CTX((stderr,"** scope stack pop SCOPEBLOCK=%d\n",scope==SCOPEBLOCK));
626 if (scope==SCOPEBLOCK || scope==CLASSBLOCK)
627 {
628 popScope(yyscanner);
629 }
630 }
631 yyextra->insideBody=FALSE;
632 }
633
634 startFontClass(yyscanner,"keyword");
635 yyextra->code->codify(yytext);
636 endFontClass(yyscanner);
637
638 yyextra->currentMemberDef=nullptr;
639 if (yyextra->currentDefinition)
640 yyextra->currentDefinition=yyextra->currentDefinition->getOuterScope();
641 BEGIN(Body);
642 }
virtual const QCString & name() const =0
QCString lower() const
Definition qcstring.h:234
bool endsWith(const char *s) const
Definition qcstring.h:509
643<ClassName,ClassVar>";" {
644 if (yyextra->lang==SrcLangExt::CSharp)
645 {
646 yyextra->code->codify(yytext);
647 yyextra->skipCodify = true;
648 unput('{');
649 }
650 else
651 {
652 yyextra->code->codify(yytext);
653 yyextra->searchingForBody=FALSE;
654 BEGIN( Body );
655 }
656 }
657<ClassName,ClassVar>[*&^%]+ {
658 yyextra->type=yyextra->curClassName;
659 yyextra->name.clear();
660 yyextra->code->codify(yytext);
661 BEGIN( Body ); // variable of type struct *
662 }
663<ClassName>"__declspec"{B}*"("{B}*{ID}{B}*")" {
664 startFontClass(yyscanner,"keyword");
665 yyextra->code->codify(yytext);
666 endFontClass(yyscanner);
667 }
668<ClassName>{ID}("."{ID})* |
669<ClassName>{ID}("::"{ID})* {
670 if (yyextra->lang==SrcLangExt::CSharp)
671 yyextra->curClassName=substitute(yytext,".","::");
672 else
673 yyextra->curClassName=yytext;
674 addType(yyscanner);
675 if (yyextra->curClassName=="alignas")
676 {
677 startFontClass(yyscanner,"keyword");
678 yyextra->code->codify(yytext);
679 endFontClass(yyscanner);
680 BEGIN( AlignAs );
681 }
682 else
683 {
684 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
685 BEGIN( ClassVar );
686 }
687 }
QCString substitute(const QCString &s, const QCString &src, const QCString &dst)
substitute all occurrences of src in s by dst
Definition qcstring.cpp:477
688<AlignAs>"(" {
689 yyextra->bracketCount=1;
690 yyextra->code->codify(yytext);
691 BEGIN( AlignAsEnd );
692 }
693<AlignAs>\n { yyextra->yyLineNr++;
694 codifyLines(yyscanner,yytext);
695 }
696<AlignAs>. { yyextra->code->codify(yytext); }
697<AlignAsEnd>"(" { yyextra->code->codify(yytext);
698 yyextra->bracketCount++;
699 }
700<AlignAsEnd>")" {
701 yyextra->code->codify(yytext);
702 if (--yyextra->bracketCount<=0)
703 {
704 BEGIN(ClassName);
705 }
706 }
707<AlignAsEnd>\n { yyextra->yyLineNr++;
708 codifyLines(yyscanner,yytext);
709 }
710<AlignAsEnd>. { yyextra->code->codify(yytext); }
711<ClassName>{ID}("\\"{ID})* { // PHP namespace
712 yyextra->curClassName=substitute(yytext,"\\","::");
713 yyextra->scopeStack.push(CLASSBLOCK);
714 pushScope(yyscanner,yyextra->curClassName);
715 addType(yyscanner);
716 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
717 BEGIN( ClassVar );
718 }
719<ClassName>{ID}{B}*"("{ID}")" { // Obj-C category
720 yyextra->curClassName=removeRedundantWhiteSpace(yytext);
721 yyextra->scopeStack.push(CLASSBLOCK);
722 pushScope(yyscanner,yyextra->curClassName);
723 addType(yyscanner);
724 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
725 BEGIN( ClassVar );
726 }
QCString removeRedundantWhiteSpace(const QCString &s)
Definition util.cpp:579
727<PackageName>{ID}("."{ID})* {
728 yyextra->curClassName=substitute(yytext,".","::");
729 DBG_CTX((stderr,"found package: %s\n",qPrint(yyextra->curClassName)));
730 addType(yyscanner);
731 codifyLines(yyscanner,yytext);
732 }
733<ClassVar>"=" {
734 unput(*yytext);
735 BEGIN( Body );
736 }
737<ClassVar>("extends"|"implements") { // Java, Slice
738 startFontClass(yyscanner,"keyword");
739 codifyLines(yyscanner,yytext);
740 endFontClass(yyscanner);
741 yyextra->curClassBases.clear();
742 BEGIN( Bases );
743 }
744<ClassVar>("sealed"|"abstract")/{BN}*(":"|"{") {
745 DBG_CTX((stderr,"***** C++/CLI modifier %s on yyextra->curClassName=%s\n",yytext,qPrint(yyextra->curClassName)));
746 startFontClass(yyscanner,"keyword");
747 codifyLines(yyscanner,yytext);
748 endFontClass(yyscanner);
749 BEGIN( CppCliTypeModifierFollowup );
750 }
751<ClassVar>{ID} {
752 yyextra->type = yyextra->curClassName;
753 yyextra->name = yytext;
754 if (yyextra->insideBody)
755 {
756 addVariable(yyscanner,yyextra->type,yyextra->name);
757 }
758 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
759 }
760<ClassName,ClassVar,CppCliTypeModifierFollowup>{B}*":"{B}* {
761 codifyLines(yyscanner,yytext);
762 yyextra->curClassBases.clear();
763 BEGIN( Bases );
764 }
765<PackageName>[ \t]*";" |
766<Bases>^{Bopt}/"@"{ID} | // Objective-C interface
767<Bases,ClassName,ClassVar,CppCliTypeModifierFollowup>{B}*"{"{B}* {
768 yyextra->theVarContext.pushScope();
769 if (!yyextra->skipCodify) yyextra->code->codify(yytext);
770 yyextra->skipCodify = false;
771 if (YY_START==ClassVar && yyextra->curClassName.isEmpty())
772 {
773 yyextra->curClassName = yyextra->name;
774 }
775 if (yyextra->searchingForBody)
776 {
777 yyextra->searchingForBody=FALSE;
778 yyextra->insideBody=TRUE;
779 }
780 if (yyextra->insideBody) yyextra->bodyCurlyCount++;
781 if (!yyextra->curClassName.isEmpty()) // valid class name
782 {
783 DBG_CTX((stderr,"** scope stack push CLASSBLOCK\n"));
784 yyextra->scopeStack.push(CLASSBLOCK);
785 pushScope(yyscanner,yyextra->curClassName);
786 DBG_CTX((stderr,"***** yyextra->curClassName=%s\n",qPrint(yyextra->curClassName)));
787 if (yyextra->symbolResolver.resolveClass(yyextra->currentDefinition,yyextra->curClassName,true)==nullptr)
788 {
789 DBG_CTX((stderr,"Adding new class %s\n",qPrint(yyextra->curClassName)));
790 ScopedTypeVariant var(yyextra->curClassName);
791 // insert base classes.
792 for (const auto &s : yyextra->curClassBases)
793 {
794 const ClassDef *bcd=nullptr;
795 auto it = yyextra->codeClassMap.find(s);
796 if (it!=yyextra->codeClassMap.end())
797 {
798 bcd = toClassDef(it->second.globalDef());
799 }
800 if (bcd==nullptr) bcd=yyextra->symbolResolver.resolveClass(yyextra->currentDefinition,QCString(s),true);
801 if (bcd && bcd->name()!=yyextra->curClassName)
802 {
803 var.localDef()->insertBaseClass(bcd->name());
804 }
805 }
806 yyextra->codeClassMap.emplace(yyextra->curClassName.str(),std::move(var));
807 }
808 //printf("yyextra->codeClassList.count()=%d\n",yyextra->codeClassList.count());
809 }
810 else // not a class name -> assume inner block
811 {
812 DBG_CTX((stderr,"** scope stack push INNERBLOCK\n"));
813 yyextra->scopeStack.push(INNERBLOCK);
814 }
815 yyextra->curClassName.clear();
816 yyextra->curClassBases.clear();
817 BEGIN( Body );
818 }
ClassDef * toClassDef(Definition *d)
#define INNERBLOCK
Definition code.l:79
819<Bases>"virtual"|"public"|"protected"|"private"|"@public"|"@private"|"@protected" {
820 startFontClass(yyscanner,"keyword");
821 yyextra->code->codify(yytext);
822 endFontClass(yyscanner);
823 }
824<Bases>{SEP}?({ID}{SEP})*{ID} {
825 DBG_CTX((stderr,"%s:addBase(%s)\n",qPrint(yyextra->curClassName),yytext));
826 yyextra->curClassBases.emplace_back(yytext);
827 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
828 }
829<Bases>"<" {
830 yyextra->code->codify(yytext);
831 if (!yyextra->insideObjC)
832 {
833 yyextra->sharpCount=1;
834 BEGIN ( SkipSharp );
835 }
836 else
837 {
838 yyextra->insideProtocolList=TRUE;
839 }
840 }
841<Bases>">" {
842 yyextra->code->codify(yytext);
843 yyextra->insideProtocolList=FALSE;
844 }
845<SkipSharp>"<" {
846 yyextra->code->codify(yytext);
847 ++yyextra->sharpCount;
848 }
849<SkipSharp>">" {
850 yyextra->code->codify(yytext);
851 if (--yyextra->sharpCount<=0)
852 BEGIN ( Bases );
853 }
854<SkipSharp>"\"" {
855 yyextra->code->codify(yytext);
856 yyextra->lastStringContext=YY_START;
857 BEGIN(SkipString);
858 }
859<SkipSharp>"\'" {
860 yyextra->code->codify(yytext);
861 yyextra->lastStringContext=YY_START;
862 BEGIN(SkipStringS);
863 }
864<Bases>"(" {
865 yyextra->code->codify(yytext);
866 yyextra->sharpCount=1;
867 BEGIN ( SkipSharp );
868 }
869<SkipSharp>"(" {
870 yyextra->code->codify(yytext);
871 ++yyextra->sharpCount;
872 }
873<SkipSharp>")" {
874 yyextra->code->codify(yytext);
875 if (--yyextra->sharpCount<=0)
876 BEGIN ( Bases );
877 }
878
879
880<Bases>"," {
881 yyextra->code->codify(yytext);
882 }
883
884
885<Body>{SCOPEPREFIX}?"operator"{B}*"()"{Bopt}/"(" {
886 addType(yyscanner);
887 generateFunctionLink(yyscanner,*yyextra->code,yytext);
888 yyextra->bracketCount=0;
889 yyextra->args.clear();
890 yyextra->name+=yytext;
891 BEGIN( FuncCall );
892 }
893<Body>{SCOPEPREFIX}?"operator"/"(" {
894 addType(yyscanner);
895 generateFunctionLink(yyscanner,*yyextra->code,yytext);
896 yyextra->bracketCount=0;
897 yyextra->args.clear();
898 yyextra->name+=yytext;
899 BEGIN( FuncCall );
900 }
901<Body>{SCOPEPREFIX}?"operator"[^a-z_A-Z0-9\‍(\n]+/"(" {
902 addType(yyscanner);
903 generateFunctionLink(yyscanner,*yyextra->code,yytext);
904 yyextra->bracketCount=0;
905 yyextra->args.clear();
906 yyextra->name+=yytext;
907 BEGIN( FuncCall );
908 }
909<Body,TemplDecl>("template"|"generic")/([^a-zA-Z0-9]) {
910 startFontClass(yyscanner,"keyword");
911 codifyLines(yyscanner,yytext);
912 endFontClass(yyscanner);
913 yyextra->insideTemplate=TRUE;
914 yyextra->sharpCount=0;
915 }
916<Body>"concept"{BN}+ {
917 startFontClass(yyscanner,"keyword");
918 codifyLines(yyscanner,yytext);
919 endFontClass(yyscanner);
920 BEGIN(ConceptName);
921 }
922<Body>"using"{BN}+"namespace"{BN}+ {
923 startFontClass(yyscanner,"keyword");
924 codifyLines(yyscanner,yytext);
925 endFontClass(yyscanner);
926 BEGIN(UsingName);
927 }
928<Body>"using"{BN}+ {
929 startFontClass(yyscanner,"keyword");
930 codifyLines(yyscanner,yytext);
931 endFontClass(yyscanner);
932 BEGIN(UsingName);
933 }
934<Body>"module"/{B}*[:;]? { // 'module X' or 'module : private' or 'module;'
935 if (yyextra->lang!=SrcLangExt::Cpp) REJECT;
936 if (!yyextra->type.isEmpty() || !yyextra->name.isEmpty()) REJECT;
937 startFontClass(yyscanner,"keyword");
938 codifyLines(yyscanner,yytext);
939 endFontClass(yyscanner);
940 BEGIN(ModuleName);
941 }
942<Body>"import"/{B}*[<":]? {
943 if (yyextra->lang!=SrcLangExt::Cpp) REJECT;
944 startFontClass(yyscanner,"keyword");
945 codifyLines(yyscanner,yytext);
946 endFontClass(yyscanner);
947 BEGIN(ModuleImport);
948 }
949<ConceptName>{ID}("::"{ID})* {
950 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
951 }
952<ConceptName>"=" { codifyLines(yyscanner,yytext); BEGIN(Body); }
953<UsingName>{ID}(("::"|"."){ID})* {
954 addUsingDirective(yyscanner,substitute(yytext,".","::"));
955 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
956 BEGIN(Body);
957 }
958<UsingName>\n { codifyLines(yyscanner,yytext); BEGIN(Body); }
959<UsingName>. { codifyLines(yyscanner,yytext); BEGIN(Body); }
960<Body,FuncCall>"$"?"this"("->"|".") { yyextra->code->codify(yytext); // this-> for C++, this. for C#
961 yyextra->isPrefixedWithThis = TRUE;
962 }
963<Body>{KEYWORD}/([^a-z_A-Z0-9]) {
964 if (yyextra->lang==SrcLangExt::Java && qstrcmp("internal",yytext) ==0) REJECT;
965 if (skipLanguageSpecificKeyword(yyscanner,yytext)) REJECT;
966 QCString text=yytext;
967 startFontClass(yyscanner,"keyword");
968 codifyLines(yyscanner,yytext);
969 if (text=="typedef" || text.find("enum ")!=-1) // typedef or strong enum
970 {
971 addType(yyscanner);
972 yyextra->name+=yytext;
973 }
974 endFontClass(yyscanner);
975 }
int find(char c, int index=0, bool cs=TRUE) const
Definition qcstring.cpp:43
int qstrcmp(const char *str1, const char *str2)
Definition qcstring.h:69
976<Body>{KEYWORD}/{B}* {
977 if (skipLanguageSpecificKeyword(yyscanner,yytext)) REJECT;
978 startFontClass(yyscanner,"keyword");
979 codifyLines(yyscanner,yytext);
980 endFontClass(yyscanner);
981 }
982<Body>{KEYWORD}/{BN}*"(" {
983 if (skipLanguageSpecificKeyword(yyscanner,yytext)) REJECT;
984 startFontClass(yyscanner,"keyword");
985 codifyLines(yyscanner,yytext);
986 endFontClass(yyscanner);
987 yyextra->name.clear();yyextra->type.clear();
988 }
989<FuncCall>"in"/{BN}* {
990 if (!yyextra->inForEachExpression) REJECT;
991 startFontClass(yyscanner,"keywordflow");
992 codifyLines(yyscanner,yytext);
993 endFontClass(yyscanner);
994 // insert the variable in the parent scope, see bug 546158
995 yyextra->theVarContext.popScope();
996 addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
997 yyextra->theVarContext.pushScope();
998 yyextra->name.clear();yyextra->type.clear();
999 }
1000<Body>{FLOWKW}/{BN}*"(" {
1001 startFontClass(yyscanner,"keywordflow");
1002 codifyLines(yyscanner,yytext);
1003 endFontClass(yyscanner);
1004 yyextra->name.clear();yyextra->type.clear();
1005 yyextra->inForEachExpression = (qstrcmp(yytext,"for each")==0 || qstrcmp(yytext, "foreach")==0);
1006 BEGIN(FuncCall);
1007 }
1008<Body>{FLOWCONDITION}/{BN}*"(" {
1009 incrementFlowKeyWordCount(yyscanner);
1010 startFontClass(yyscanner,"keywordflow");
1011 codifyLines(yyscanner,yytext);
1012 endFontClass(yyscanner);
1013 yyextra->name.clear();yyextra->type.clear();
1014 yyextra->inForEachExpression = (strcmp(yytext,"for each")==0 || strcmp(yytext, "foreach")==0);
1015 BEGIN(FuncCall);
1016 }
1017<Body>{FLOWKW}/([^a-z_A-Z0-9]) {
1018 startFontClass(yyscanner,"keywordflow");
1019 codifyLines(yyscanner,yytext);
1020 endFontClass(yyscanner);
1021 if (yyextra->inFunctionTryBlock && (qstrcmp(yytext,"catch")==0 || qstrcmp(yytext,"finally")==0))
1022 {
1023 yyextra->inFunctionTryBlock=FALSE;
1024 }
1025 }
1026<Body>{FLOWCONDITION}/([^a-z_A-Z0-9]) {
1027 incrementFlowKeyWordCount(yyscanner);
1028 startFontClass(yyscanner,"keywordflow");
1029 codifyLines(yyscanner,yytext);
1030 endFontClass(yyscanner);
1031 if (yyextra->inFunctionTryBlock && (strcmp(yytext,"catch")==0 || strcmp(yytext,"finally")==0))
1032 {
1033 yyextra->inFunctionTryBlock=FALSE;
1034 }
1035 }
1036<Body>{FLOWKW}/{B}* {
1037 startFontClass(yyscanner,"keywordflow");
1038 codifyLines(yyscanner,yytext);
1039 endFontClass(yyscanner);
1040 }
1041<Body>{FLOWCONDITION}/{B}* {
1042 incrementFlowKeyWordCount(yyscanner);
1043 startFontClass(yyscanner,"keywordflow");
1044 codifyLines(yyscanner,yytext);
1045 endFontClass(yyscanner);
1046 }
1047<Body>"*"{B}*")" { // end of cast?
1048 yyextra->code->codify(yytext);
1049 yyextra->theCallContext.popScope(yyextra->name, yyextra->type, yyextra->bracketCount);
1050 yyextra->bracketCount--;
1051 yyextra->parmType = yyextra->name;
1052 BEGIN(FuncCall);
1053 }
1054<Body>"\\‍)"|"\\‍(" {
1055 yyextra->code->codify(yytext);
1056 }
1057<Body>[\\|\‍)\+\-\/\%\~\!] {
1058 yyextra->code->codify(yytext);
1059 yyextra->name.clear();yyextra->type.clear();
1060 if (*yytext==')')
1061 {
1062 yyextra->theCallContext.popScope(yyextra->name, yyextra->type, yyextra->bracketCount);
1063 yyextra->bracketCount--;
1064 if (yyextra->bracketCount<=0)
1065 {
1066 BEGIN(FuncCall);
1067 }
1068 }
1069 }
1070<Body,TemplDecl,ObjCMethod>{TYPEKW}/{B}* {
1071 startFontClass(yyscanner,"keywordtype");
1072 yyextra->code->codify(yytext);
1073 endFontClass(yyscanner);
1074 addType(yyscanner);
1075 yyextra->name+=yytext;
1076 }
1077<Body,TemplDecl,ObjCMethod>{TYPEKWSL}/{B}* {
1078 if (yyextra->lang!=SrcLangExt::Slice)
1079 {
1080 REJECT;
1081 }
1082 else
1083 {
1084 startFontClass(yyscanner,"keywordtype");
1085 yyextra->code->codify(yytext);
1086 endFontClass(yyscanner);
1087 addType(yyscanner);
1088 yyextra->name+=yytext;
1089 }
1090 }
1091<Body>"generic"/{B}*"<"[^\n\/\-\.\{\">]*">"{B}* {
1092 startFontClass(yyscanner,"keyword");
1093 yyextra->code->codify(yytext);
1094 endFontClass(yyscanner);
1095 yyextra->sharpCount=0;
1096 BEGIN(TemplDecl);
1097 }
1098<Body>"template"/{B}*"<"[^\n\/\-\.\{\">]*">"{B}* { // template<...>
1099 startFontClass(yyscanner,"keyword");
1100 yyextra->code->codify(yytext);
1101 endFontClass(yyscanner);
1102 yyextra->sharpCount=0;
1103 BEGIN(TemplDecl);
1104 }
1105<TemplDecl>"class"|"typename" {
1106 startFontClass(yyscanner,"keyword");
1107 codifyLines(yyscanner,yytext);
1108 endFontClass(yyscanner);
1109 }
1110<TemplDecl>"<" {
1111 yyextra->code->codify(yytext);
1112 yyextra->sharpCount++;
1113 }
1114<TemplDecl>">" {
1115 yyextra->code->codify(yytext);
1116 yyextra->sharpCount--;
1117 if (yyextra->sharpCount<=0)
1118 {
1119 BEGIN(Body);
1120 }
1121 }
1122<TemplCast>">" {
1123 startFontClass(yyscanner,"keyword");
1124 codifyLines(yyscanner,yytext);
1125 endFontClass(yyscanner);
1126 BEGIN( yyextra->lastTemplCastContext );
1127 }
1128<TemplCast>{ID}("::"{ID})* {
1129 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
1130 }
1131<TemplCast>("const"|"volatile"){B}* {
1132 startFontClass(yyscanner,"keyword");
1133 codifyLines(yyscanner,yytext);
1134 endFontClass(yyscanner);
1135 }
1136<TemplCast>[*^]* {
1137 codifyLines(yyscanner,yytext);
1138 }
1139<Body,MemberCall2,FuncCall>{CASTKW}{B}*"<" { // static_cast<T>(
1140 startFontClass(yyscanner,"keyword");
1141 codifyLines(yyscanner,yytext);
1142 endFontClass(yyscanner);
1143 yyextra->lastTemplCastContext = YY_START;
1144 BEGIN(TemplCast);
1145 }
1146<Body>"$this->"{SCOPENAME}/{BN}*[;,)\]] { // PHP member variable
1147 addType(yyscanner);
1148 generatePHPVariableLink(yyscanner,*yyextra->code,yytext);
1149 yyextra->name+=yytext+7;
1150 }
1151<Body,TemplCast>{SCOPENAME}{B}*"<"[^\n\/\-\.\{\">\‍(']*">"{ENDIDopt}/{B}* { // A<T> *pt;
1152 if (isCastKeyword(yytext) && YY_START==Body)
1153 {
1154 REJECT;
1155 }
1156 addType(yyscanner);
1157 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
1158 yyextra->name+=yytext;
1159 }
1160<ModuleName,ModuleImport>{MODULE_ID}({BN}*":"{BN}*{MODULE_ID})? {
1161 QCString name = yytext;
1162 int i = name.find(':');
1163 QCString partition;
1164 if (i!=-1)
1165 {
1166 partition = name.mid(i+1).stripWhiteSpace();
1167 name = name.left(i).stripWhiteSpace();
1168 }
1170 if (mod)
1171 {
1172 writeMultiLineCodeLink(yyscanner,*yyextra->code,mod,yytext);
1173 }
1174 else
1175 {
1176 codifyLines(yyscanner,yytext);
1177 }
1178 }
static ModuleManager & instance()
ModuleDef * getPrimaryInterface(const QCString &moduleName) const
QCString mid(size_t index, size_t len=static_cast< size_t >(-1)) const
Definition qcstring.h:226
QCString stripWhiteSpace() const
returns a copy of this string with leading and trailing whitespace removed
Definition qcstring.h:245
QCString left(size_t len) const
Definition qcstring.h:214
size_t i
Definition htmlgen.cpp:161
1179<ModuleName>":"{BN}+"private" {
1180 QCString text=yytext;
1181 int i=text.find('p');
1182 codifyLines(yyscanner,text.left(i));
1183 startFontClass(yyscanner,"keyword");
1184 codifyLines(yyscanner,text.mid(i));
1185 endFontClass(yyscanner);
1186 }
1187<ModuleName>";" { yyextra->code->codify(yytext); BEGIN(Body); }
1188<ModuleName>. { yyextra->code->codify(yytext); }
1189<ModuleName>\n { codifyLines(yyscanner,yytext); }
1190<ModuleImport>["<] { yyextra->code->codify(yytext); BEGIN(ReadInclude); }
1191<ModuleImport>";" { yyextra->code->codify(yytext); BEGIN(Body); }
1192<ModuleImport>. { yyextra->code->codify(yytext); }
1193<ModuleImport>\n { codifyLines(yyscanner,yytext); }
1194
1195<Body>{SCOPENAME}/{BN}*[:;,)\]] { // "int var;" or "var, var2" or "debug(f) macro" , or int var : 5;
1196 if (startsWithKeyword(yytext,"typedef") || startsWithKeyword(yytext,"using"))
1197 {
1198 REJECT;
1199 }
1200 addType(yyscanner);
1201 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
1202 yyextra->name+=yytext;
1203 }
1204<Body>{ID}("."{ID})+/{BN}+ { // CSharp/Java scope
1205 if (yyextra->lang==SrcLangExt::CSharp || yyextra->lang==SrcLangExt::Java)
1206 {
1207 addType(yyscanner);
1208 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
1209 yyextra->name+=yytext;
1210 }
1211 else
1212 {
1213 REJECT;
1214 }
1215 }
1216<Body>"export"/{B}* {
1217 if (yyextra->lang!=SrcLangExt::Cpp) REJECT;
1218 startFontClass(yyscanner,"keyword");
1219 codifyLines(yyscanner,yytext);
1220 endFontClass(yyscanner);
1221 }
1222<Body>{SCOPENAME}/{B}* { // p->func()
1223 if (startsWithKeyword(yytext,"typedef") || startsWithKeyword(yytext,"using"))
1224 {
1225 REJECT;
1226 }
1227 addType(yyscanner);
1228 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
1229 yyextra->name+=yytext;
1230 }
1231<Body>"("{B}*("*"{B}*)+{SCOPENAME}+{B}*")"/{B}* { // (*p)->func() but not "if (p) ..."
1232 yyextra->code->codify(yytext);
1233 uint32_t s=0;while (s<(uint32_t)yyleng && !isId(yytext[s])) s++;
1234 uint32_t e=(uint32_t)yyleng-1;while (e>1 && !isId(yytext[e])) e--;
1235 QCString varname = ((QCString)yytext).mid(s,e-s+1);
1236 addType(yyscanner);
1237 yyextra->name=std::move(varname);
1238 }
bool isId(int c)
Definition util.h:208
1239<Body>{SCOPETNAME}{B}*"<"[^\n\/\-\.\{\">]*">"/{BN}*"(" |
1240<Body>{SCOPETNAME}/{BN}*"(" { // a() or c::a() or t<A,B>::a() or A\B\foo()
1241 if (isCastKeyword(yytext))
1242 {
1243 REJECT;
1244 }
1245 addType(yyscanner);
1246 generateFunctionLink(yyscanner,*yyextra->code,yytext);
1247 yyextra->bracketCount=0;
1248 yyextra->args.clear();
1249 yyextra->name+=yytext;
1250 BEGIN( FuncCall );
1251 }
1252<FuncCall,Body,MemberCall,MemberCall2,SkipInits,InlineInit>{RAWBEGIN} {
1253 QCString text(yytext);
1254 uint32_t i=(uint32_t)text.find('R');
1255 yyextra->code->codify(text.left(i+1));
1256 startFontClass(yyscanner,"stringliteral");
1257 yyextra->code->codify(QCString(yytext+i+1));
1258 yyextra->lastStringContext=YY_START;
1259 yyextra->inForEachExpression = FALSE;
1260 yyextra->delimiter = extractBeginRawStringDelimiter(yytext);
1261 BEGIN( RawString );
1262 }
QCString extractBeginRawStringDelimiter(const char *rawStart)
Definition util.cpp:7451
1263<FuncCall,Body,MemberCall,MemberCall2,SkipInits,InlineInit,ClassVar,OldStyleArgs>\" {
1264 startFontClass(yyscanner,"stringliteral");
1265 yyextra->code->codify(yytext);
1266 yyextra->lastStringContext=YY_START;
1267 yyextra->inForEachExpression = FALSE;
1268 BEGIN( SkipString );
1269 }
1270<FuncCall,Body,MemberCall,MemberCall2,SkipInits,InlineInit>{NUMBER} { //Note similar code in commentcnv.l
1271 if (yyextra->lang!=SrcLangExt::Cpp) REJECT;
1272 yyextra->code->codify(yytext);
1273 }
1274<FuncCall,Body,MemberCall,MemberCall2,SkipInits,InlineInit>\' {
1275 startFontClass(yyscanner,"stringliteral");
1276 yyextra->code->codify(yytext);
1277 yyextra->lastStringContext=YY_START;
1278 yyextra->inForEachExpression = FALSE;
1279 BEGIN( SkipStringS );
1280 }
1281<SkipString>[^\"\\\r\n]{1,100} {
1282 yyextra->code->codify(yytext);
1283 }
1284<SkipStringS>[^\'\\\r\n]{1,100} {
1285 yyextra->code->codify(yytext);
1286 }
1287<SkipString,SkipStringS>{CPPC}|{CCS} {
1288 yyextra->code->codify(yytext);
1289 }
1290<SkipString>@?\" {
1291 yyextra->code->codify(yytext);
1292 if (yyextra->lastStringContext!=SkipCPP)
1293 {
1294 endFontClass(yyscanner);
1295 }
1296 BEGIN( yyextra->lastStringContext );
1297 }
1298<SkipStringS>\' {
1299 yyextra->code->codify(yytext);
1300 endFontClass(yyscanner);
1301 BEGIN( yyextra->lastStringContext );
1302 }
1303<SkipString,SkipStringS>\\. {
1304 yyextra->code->codify(yytext);
1305 }
1306<RawString>{RAWEND} {
1307 yyextra->code->codify(yytext);
1308 if (extractEndRawStringDelimiter(yytext)==yyextra->delimiter)
1309 {
1310 BEGIN( yyextra->lastStringContext );
1311 }
1312 }
QCString extractEndRawStringDelimiter(const char *rawEnd)
Definition util.cpp:7459
1313<RawString>[^)\n]+ { yyextra->code->codify(yytext); }
1314<RawString>. { yyextra->code->codify(yytext); }
1315<RawString>\n { codifyLines(yyscanner,yytext); }
1316<SkipVerbString>[^"\n]+ {
1317 yyextra->code->codify(yytext);
1318 }
1319<SkipVerbString>\"\" { // escaped quote
1320 yyextra->code->codify(yytext);
1321 }
1322<SkipVerbString>\" { // end of string
1323 yyextra->code->codify(yytext);
1324 endFontClass(yyscanner);
1325 BEGIN( yyextra->lastVerbStringContext );
1326 }
1327<SkipVerbString>. {
1328 yyextra->code->codify(yytext);
1329 }
1330<SkipVerbString>\n {
1331 codifyLines(yyscanner,yytext);
1332 }
1333<Body>":" {
1334 yyextra->code->codify(yytext);
1335 yyextra->name.clear();yyextra->type.clear();
1336 }
1337<Body>"<" {
1338 if (yyextra->insideTemplate)
1339 {
1340 yyextra->sharpCount++;
1341 }
1342 yyextra->code->codify(yytext);
1343 }
1344<Body>">" {
1345 if (yyextra->insideTemplate)
1346 {
1347 if (--yyextra->sharpCount<=0)
1348 {
1349 yyextra->insideTemplate=FALSE;
1350 }
1351 }
1352 yyextra->code->codify(yytext);
1353 }
1354<Body,MemberCall,MemberCall2,FuncCall,OldStyleArgs>"'"((\\0[Xx0-9]+)|(\\.)|(.))"'" {
1355 startFontClass(yyscanner,"charliteral");
1356 yyextra->code->codify(yytext);
1357 endFontClass(yyscanner);
1358 }
1359<Body>"."|"->" {
1360 if (yytext[0]=='-') // -> could be overloaded
1361 {
1363 }
1364 yyextra->code->codify(yytext);
1365 yyextra->memCallContext = YY_START;
1366 BEGIN( MemberCall );
1367 }
1368<MemberCall>{SCOPETNAME}/{BN}*"(" {
1369 if (yyextra->theCallContext.getScope().globalDef())
1370 {
1371 if (!generateClassMemberLink(yyscanner,*yyextra->code,yyextra->theCallContext.getScope().globalDef(),yytext))
1372 {
1373 codifyLines(yyscanner,yytext);
1374 addToSearchIndex(yyscanner,yytext);
1375 }
1376 yyextra->name.clear();
1377 }
1378 else
1379 {
1380 codifyLines(yyscanner,yytext);
1381 addToSearchIndex(yyscanner,yytext);
1382 yyextra->name.clear();
1383 }
1384 yyextra->type.clear();
1385 if (yyextra->memCallContext==Body)
1386 {
1387 BEGIN(FuncCall);
1388 }
1389 else
1390 {
1391 BEGIN(yyextra->memCallContext);
1392 }
1393 }
1394<MemberCall>{SCOPENAME}/{B}* {
1395 if (yyextra->theCallContext.getScope().globalDef())
1396 {
1397 DBG_CTX((stderr,"yyextra->theCallContext.getClass()=%p\n",(void*)yyextra->theCallContext.getScope().globalDef()));
1398 if (!generateClassMemberLink(yyscanner,*yyextra->code,yyextra->theCallContext.getScope().globalDef(),yytext))
1399 {
1400 codifyLines(yyscanner,yytext);
1401 addToSearchIndex(yyscanner,yytext);
1402 }
1403 yyextra->name.clear();
1404 }
1405 else
1406 {
1407 DBG_CTX((stderr,"no class context!\n"));
1408 codifyLines(yyscanner,yytext);
1409 addToSearchIndex(yyscanner,yytext);
1410 yyextra->name.clear();
1411 }
1412 yyextra->type.clear();
1413 BEGIN(yyextra->memCallContext);
1414 }
1415<Body>[,=;\[{] {
1416 if (yyextra->insideObjC && *yytext=='[')
1417 {
1418 DBG_CTX((stderr,"Found start of ObjC call!\n"));
1419 // start of a method call
1420 yyextra->contextMap.clear();
1421 yyextra->nameMap.clear();
1422 yyextra->objectMap.clear();
1423 yyextra->wordMap.clear();
1424 yyextra->commentMap.clear();
1425 yyextra->currentCtxId = 0;
1426 yyextra->currentNameId = 0;
1427 yyextra->currentObjId = 0;
1428 yyextra->currentCtx = nullptr;
1429 yyextra->braceCount = 0;
1430 unput('[');
1431 BEGIN(ObjCCall);
1432 }
1433 else
1434 {
1435 if (*yytext!='{') yyextra->code->codify(yytext);
1436 yyextra->saveName = yyextra->name;
1437 yyextra->saveType = yyextra->type;
1438 if (*yytext!='[' && !yyextra->type.isEmpty())
1439 {
1440 //printf("yyextra->scopeStack.bottom()=%p\n",yyextra->scopeStack.bottom());
1441 //if (yyextra->scopeStack.top()!=CLASSBLOCK) // commented out for bug731363
1442 {
1443 //printf("AddVariable: '%s' '%s' context=%d\n",
1444 // qPrint(yyextra->type),qPrint(yyextra->name),yyextra->theVarContext.count());
1445 addVariable(yyscanner,yyextra->type,yyextra->name);
1446 }
1447 yyextra->name.clear();
1448 }
1449 if (*yytext==';' || *yytext=='=' || *yytext=='{')
1450 {
1451 yyextra->type.clear();
1452 yyextra->name.clear();
1453 }
1454 else if (*yytext=='[')
1455 {
1456 yyextra->theCallContext.pushScope(yyextra->name, yyextra->type, yyextra->bracketCount);
1457 }
1458 yyextra->args.clear();
1459 yyextra->parmType.clear();
1460 yyextra->parmName.clear();
1461 if (*yytext=='{')
1462 {
1463 BEGIN( BodyVar );
1464 unput('{');
1465 }
1466 }
1467 }
1468<Body,FuncCall,BodyVar>"{" {
1469 yyextra->theVarContext.pushScope();
1470 yyextra->theCallContext.pushScope(yyextra->name, yyextra->type, yyextra->bracketCount);
1471 yyextra->bracketCount = 0;
1472
1473 DBG_CTX((stderr,"** type='%s' name='%s'\n",qPrint(yyextra->type),qPrint(yyextra->name)));
1474 if (yyextra->type.find("enum ")!=-1)
1475 { // for strong enums we need to start a scope
1476 DBG_CTX((stderr,"** scope stack push SCOPEBLOCK\n"));
1477 pushScope(yyscanner,yyextra->name);
1478 yyextra->scopeStack.push(SCOPEBLOCK);
1479 }
1480 else
1481 {
1482 DBG_CTX((stderr,"** scope stack push INNERBLOCK\n"));
1483 yyextra->scopeStack.push(INNERBLOCK);
1484 }
1485
1486 if (yyextra->searchingForBody)
1487 {
1488 yyextra->searchingForBody=FALSE;
1489 yyextra->insideBody=TRUE;
1490 }
1491 yyextra->code->codify(yytext);
1492 if (yyextra->insideBody)
1493 {
1494 yyextra->bodyCurlyCount++;
1495 }
1496 yyextra->type.clear();
1497 yyextra->name.clear();
1498 BEGIN( Body );
1499 }
1500<ObjCCall,ObjCMName>"["|"{" {
1501 saveObjCContext(yyscanner);
1502 yyextra->currentCtx->format+=*yytext;
1503 BEGIN(ObjCCall);
1504 DBG_CTX((stderr,"open\n"));
1505 }
1506<ObjCCall,ObjCMName>"]"|"}" {
1507 yyextra->currentCtx->format+=*yytext;
1508 restoreObjCContext(yyscanner);
1509 BEGIN(ObjCMName);
1510 if (yyextra->currentCtx==nullptr)
1511 {
1512 // end of call
1513 ObjCCallCtx *ctx = nullptr;
1514 auto it = yyextra->contextMap.find(0);
1515 if (it!=yyextra->contextMap.end())
1516 {
1517 ctx = it->second.get();
1518 }
1519 writeObjCMethodCall(yyscanner,ctx);
1520 BEGIN(Body);
1521 }
1522 DBG_CTX((stderr,"close\n"));
1523 }
1524<ObjCCall,ObjCMName>{CPPC}.* {
1525 yyextra->currentCtx->format+=escapeComment(yyscanner,yytext);
1526 }
1527<ObjCCall,ObjCMName>{CCS} {
1528 yyextra->lastObjCCallContext = YY_START;
1529 yyextra->currentCtx->comment.str(yytext);
1530 BEGIN(ObjCCallComment);
1531 }
1532<ObjCCallComment>{CCE} {
1533 yyextra->currentCtx->comment << yytext;
1534 std::string commentStr = yyextra->currentCtx->comment.str();
1535 yyextra->currentCtx->format+=escapeComment(yyscanner,commentStr.c_str());
1536 BEGIN(yyextra->lastObjCCallContext);
1537 }
1538<ObjCCallComment>[^*\n]+ { yyextra->currentCtx->comment << yytext; }
1539<ObjCCallComment>{CPPC}|{CCS} { yyextra->currentCtx->comment << yytext; }
1540<ObjCCallComment>\n { yyextra->currentCtx->comment << *yytext; }
1541<ObjCCallComment>. { yyextra->currentCtx->comment << *yytext; }
1542<ObjCCall>{ID}({B}*"."{B}*{ID})* {
1543 yyextra->currentCtx->format+=escapeObject(yyscanner,QCString(yytext).data());
1544 if (yyextra->braceCount==0)
1545 {
1546 yyextra->currentCtx->objectTypeOrName=yytext;
1547 DBG_CTX((stderr,"new type=%s\n",qPrint(yyextra->currentCtx->objectTypeOrName)));
1548 BEGIN(ObjCMName);
1549 }
1550 }
const char * data
Definition htmlgen.cpp:158
1551<ObjCMName>{ID}/{BN}*"]" {
1552 if (yyextra->braceCount==0 &&
1553 yyextra->currentCtx->methodName.isEmpty())
1554 {
1555 yyextra->currentCtx->methodName=yytext;
1556 yyextra->currentCtx->format+=escapeName(yyscanner,yytext);
1557 }
1558 else
1559 {
1560 yyextra->currentCtx->format+=escapeWord(yyscanner,yytext);
1561 }
1562 }
1563<ObjCMName>{ID}/{BN}*":" {
1564 if (yyextra->braceCount==0)
1565 {
1566 yyextra->currentCtx->methodName+=yytext;
1567 yyextra->currentCtx->methodName+=":";
1568 }
1569 yyextra->currentCtx->format+=escapeName(yyscanner,yytext);
1570 }
1571<ObjCSkipStr>[^\n\"$\\]* { yyextra->currentCtx->format+=yytext; }
1572<ObjCSkipStr>\\. { yyextra->currentCtx->format+=yytext; }
1573<ObjCSkipStr>"\"" { yyextra->currentCtx->format+=yytext;
1574 BEGIN(yyextra->lastStringContext);
1575 }
1576<ObjCCall,ObjCMName>{CHARLIT} { yyextra->currentCtx->format+=yytext; }
1577<ObjCCall,ObjCMName>"@"?"\"" { yyextra->currentCtx->format+=yytext;
1578 yyextra->lastStringContext=YY_START;
1579 BEGIN(ObjCSkipStr);
1580 }
1581<ObjCCall,ObjCMName,ObjCSkipStr>"$" { yyextra->currentCtx->format+="$$"; }
1582<ObjCCall,ObjCMName>"(" { yyextra->currentCtx->format+=*yytext; yyextra->braceCount++; }
1583<ObjCCall,ObjCMName>")" { yyextra->currentCtx->format+=*yytext; yyextra->braceCount--; }
1584<ObjCSkipStr>"@"/"\"" { // needed to prevent matching the global rule (for C#)
1585 yyextra->currentCtx->format+=yytext;
1586 }
1587<ObjCCall,ObjCMName,ObjCSkipStr>{ID} { yyextra->currentCtx->format+=escapeWord(yyscanner,yytext); }
1588<ObjCCall,ObjCMName,ObjCSkipStr>. { yyextra->currentCtx->format+=*yytext; }
1589<ObjCCall,ObjCMName,ObjCSkipStr>\n { yyextra->currentCtx->format+=*yytext; }
1590
1591<Body>"]" {
1592 yyextra->theCallContext.popScope(yyextra->name, yyextra->type, yyextra->bracketCount);
1593 yyextra->code->codify(yytext);
1594 // TODO: nested arrays like: a[b[0]->func()]->func()
1595 yyextra->name = yyextra->saveName;
1596 yyextra->type = yyextra->saveType;
1597 }
1598<Body>[0-9]+ {
1599 yyextra->code->codify(yytext);
1600 }
1601<Body>[0-9]+[xX][0-9A-Fa-f]+ {
1602 yyextra->code->codify(yytext);
1603 }
1604<MemberCall2,FuncCall>{KEYWORD}/([^a-z_A-Z0-9]) {
1605 //addParmType(yyscanner);
1606 //yyextra->parmName=yytext;
1607 if (skipLanguageSpecificKeyword(yyscanner,yytext)) REJECT;
1608 startFontClass(yyscanner,"keyword");
1609 yyextra->code->codify(yytext);
1610 endFontClass(yyscanner);
1611 }
1612<MemberCall2,FuncCall,OldStyleArgs,TemplCast>{TYPEKW}/([^a-z_A-Z0-9]) {
1613 addParmType(yyscanner);
1614 yyextra->parmName=yytext;
1615 startFontClass(yyscanner,"keywordtype");
1616 yyextra->code->codify(yytext);
1617 endFontClass(yyscanner);
1618 }
1619<MemberCall2,FuncCall,OldStyleArgs,TemplCast>{TYPEKWSL}/([^a-z_A-Z0-9]) {
1620 if (yyextra->lang!=SrcLangExt::Slice)
1621 {
1622 REJECT;
1623 }
1624 else
1625 {
1626 addParmType(yyscanner);
1627 yyextra->parmName=yytext;
1628 startFontClass(yyscanner,"keywordtype");
1629 yyextra->code->codify(yytext);
1630 endFontClass(yyscanner);
1631 }
1632 }
1633<MemberCall2,FuncCall>{FLOWKW}/([^a-z_A-Z0-9]) {
1634 addParmType(yyscanner);
1635 yyextra->parmName=yytext;
1636 startFontClass(yyscanner,"keywordflow");
1637 yyextra->code->codify(yytext);
1638 endFontClass(yyscanner);
1639 }
1640<MemberCall2,FuncCall>{FLOWCONDITION}/([^a-z_A-Z0-9]) {
1641 incrementFlowKeyWordCount(yyscanner);
1642 addParmType(yyscanner);
1643 yyextra->parmName=yytext;
1644 startFontClass(yyscanner,"keywordflow");
1645 yyextra->code->codify(yytext);
1646 endFontClass(yyscanner);
1647 }
1648<MemberCall2,FuncCall>("::")?{ID}(({B}*"<"[^\n\[\](){}<>']*">")?({B}*"::"{B}*{ID})?)* {
1649 if (isCastKeyword(yytext))
1650 {
1651 REJECT;
1652 }
1653 addParmType(yyscanner);
1654 yyextra->parmName=yytext;
1655 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext,!yyextra->insideBody);
1656 }
1657<FuncCall>";" { // probably a cast, not a function call
1658 yyextra->code->codify(yytext);
1659 yyextra->inForEachExpression = FALSE;
1660 BEGIN( Body );
1661 }
1662<MemberCall2,FuncCall>, {
1663 yyextra->code->codify(yytext);
1664 addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
1665 yyextra->parmType.clear();yyextra->parmName.clear();
1666 }
1667<MemberCall2,FuncCall>"{" {
1668 if (yyextra->bracketCount>0)
1669 {
1670 yyextra->code->codify(yytext);
1671 yyextra->skipInlineInitContext=YY_START;
1672 yyextra->curlyCount=0;
1673 BEGIN(InlineInit);
1674 }
1675 else
1676 {
1677 REJECT;
1678 }
1679 }
1680<InlineInit>"{" { yyextra->curlyCount++;
1681 yyextra->code->codify(yytext);
1682 }
1683<InlineInit>"}" {
1684 yyextra->code->codify(yytext);
1685 if (--yyextra->curlyCount<=0)
1686 {
1687 BEGIN(yyextra->skipInlineInitContext);
1688 }
1689 }
1690<InlineInit>\n {
1691 codifyLines(yyscanner,yytext);
1692 }
1693<InlineInit>. {
1694 yyextra->code->codify(yytext);
1695 }
1696<MemberCall2,FuncCall>"(" {
1697 yyextra->parmType.clear();yyextra->parmName.clear();
1698 yyextra->code->codify(yytext);
1699 yyextra->bracketCount++;
1700 yyextra->theCallContext.pushScope(yyextra->name, yyextra->type, yyextra->bracketCount);
1701 if (YY_START==FuncCall && !yyextra->insideBody)
1702 {
1703 yyextra->theVarContext.pushScope();
1704 }
1705 }
1706<MemberCall2,FuncCall>{OPERATOR} { // operator
1707 if (qstrcmp(yytext,"*") &&
1708 qstrcmp(yytext,"&") &&
1709 qstrcmp(yytext,"^") &&
1710 qstrcmp(yytext,"%")) // typically a pointer or reference
1711 {
1712 // not a * or &, or C++/CLI's ^ or %
1713 yyextra->parmType.clear();yyextra->parmName.clear();
1714 }
1715 yyextra->code->codify(yytext);
1716 }
1717<MemberCall,MemberCall2,FuncCall>("*"{B}*)?")" {
1718 if (yytext[0]==')') // no a pointer cast
1719 {
1720 DBG_CTX((stderr,"addVariable(%s,%s)\n",qPrint(yyextra->parmType),qPrint(yyextra->parmName)));
1721 if (yyextra->parmType.isEmpty())
1722 {
1723 yyextra->parmType=yyextra->parmName;
1724 yyextra->parmName.clear();
1725 }
1726 addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
1727 }
1728 else
1729 {
1730 yyextra->parmType = yyextra->parmName;
1731 yyextra->parmName.clear();
1732 addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
1733 }
1734 yyextra->theCallContext.popScope(yyextra->name, yyextra->type, yyextra->bracketCount);
1735 yyextra->inForEachExpression = FALSE;
1736 //yyextra->theCallContext.setClass(0); // commented out, otherwise a()->b() does not work for b().
1737 yyextra->code->codify(yytext);
1738 if (--yyextra->bracketCount<=0)
1739 {
1740 if (yyextra->name.isEmpty())
1741 {
1742 BEGIN( Body );
1743 }
1744 else
1745 {
1746 BEGIN( CallEnd );
1747 }
1748 }
1749 }
1750<MemberCall,MemberCall2,FuncCall>[;:] { // recover from unexpected end of call
1751 //if (yytext[0]==';' || yyextra->bracketCount<=0)
1752 if (yyextra->bracketCount<=0)
1753 {
1754 unput(*yytext);
1755 BEGIN(CallEnd);
1756 }
1757 else
1758 {
1759 yyextra->code->codify(yytext);
1760 }
1761 }
1762<CallEnd>[ \t\n]* { codifyLines(yyscanner,yytext); }
1763<CallEnd>[;:] {
1764 codifyLines(yyscanner,yytext);
1765 yyextra->bracketCount=0;
1766 if (*yytext==';') yyextra->searchingForBody=FALSE;
1767 if (!yyextra->type.isEmpty())
1768 {
1769 DBG_CTX((stderr,"add variable yyextra->type=%s yyextra->name=%s)\n",qPrint(yyextra->type),qPrint(yyextra->name)));
1770 addVariable(yyscanner,yyextra->type,yyextra->name);
1771 }
1772 yyextra->parmType.clear();yyextra->parmName.clear();
1773 yyextra->theCallContext.setScope(ScopedTypeVariant());
1774 if (*yytext==';' || yyextra->insideBody)
1775 {
1776 if (!yyextra->insideBody)
1777 {
1778 yyextra->theVarContext.popScope();
1779 }
1780 yyextra->name.clear();yyextra->type.clear();
1781 BEGIN( Body );
1782 }
1783 else
1784 {
1785 yyextra->bracketCount=0;
1786 BEGIN( SkipInits );
1787 }
1788 }
1789<CallEnd>{ENDQopt}/{BN}*(";"|"="|"throw"{BN}*"(") {
1790 startFontClass(yyscanner,"keyword");
1791 codifyLines(yyscanner,yytext);
1792 endFontClass(yyscanner);
1793 }
1794<CallEnd,OldStyleArgs>("const"|"volatile"|"sealed"|"override")*({BN}+("const"|"volatile"|"sealed"|"override"))*{BN}*"{" {
1795 if (yyextra->insideBody)
1796 {
1797 yyextra->theVarContext.pushScope();
1798 }
1799 addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
1800 //yyextra->theCallContext.popScope(yyextra->name, yyextra->type);
1801 yyextra->parmType.clear();yyextra->parmName.clear();
1802 int index = yyextra->name.findRev("::");
1803 DBG_CTX((stderr,"yyextra->name=%s\n",qPrint(yyextra->name)));
1804 if (index!=-1)
1805 {
1806 QCString scope = yyextra->name.left((uint32_t)index);
1807 if (!yyextra->scopeName.isEmpty()) scope.prepend((yyextra->scopeName+"::"));
1808 const ClassDef *cd=yyextra->symbolResolver.resolveClass(Doxygen::globalScope,scope,true);
1809 if (cd)
1810 {
1811 setClassScope(yyscanner,cd->name());
1812 yyextra->scopeStack.push(SCOPEBLOCK);
1813 DBG_CTX((stderr,"** scope stack push SCOPEBLOCK\n"));
1814 }
1815 else
1816 {
1817 //setClassScope(yyscanner,yyextra->realScope);
1818 yyextra->scopeStack.push(INNERBLOCK);
1819 DBG_CTX((stderr,"** scope stack push INNERBLOCK\n"));
1820 }
1821 }
1822 else
1823 {
1824 DBG_CTX((stderr,"** scope stack push INNERBLOCK\n"));
1825 yyextra->scopeStack.push(INNERBLOCK);
1826 }
1827 yytext[yyleng-1]='\0';
1828 QCString cv(yytext);
1829 if (!cv.stripWhiteSpace().isEmpty())
1830 {
1831 startFontClass(yyscanner,"keyword");
1832 codifyLines(yyscanner,yytext);
1833 endFontClass(yyscanner);
1834 }
1835 else // just whitespace
1836 {
1837 codifyLines(yyscanner,yytext);
1838 }
1839 yyextra->code->codify("{");
1840 if (yyextra->searchingForBody)
1841 {
1842 yyextra->searchingForBody=FALSE;
1843 yyextra->insideBody=TRUE;
1844 }
1845 if (yyextra->insideBody) yyextra->bodyCurlyCount++;
1846 yyextra->type.clear(); yyextra->name.clear();
1847 BEGIN( Body );
1848 }
static NamespaceDefMutable * globalScope
Definition doxygen.h:121
QCString & prepend(const char *s)
Definition qcstring.h:407
1849<CallEnd>"try" { // function-try-block
1850 startFontClass(yyscanner,"keyword");
1851 yyextra->code->codify(yytext);
1852 endFontClass(yyscanner);
1853 yyextra->inFunctionTryBlock=TRUE;
1854 }
1855<CallEnd>"requires" { // function-try-block
1856 startFontClass(yyscanner,"keyword");
1857 yyextra->code->codify(yytext);
1858 endFontClass(yyscanner);
1859 }
1860<CallEnd>{ID} {
1861 if (yyextra->insideBody || !yyextra->parmType.isEmpty())
1862 {
1863 REJECT;
1864 }
1865 // could be K&R style definition
1866 addParmType(yyscanner);
1867 yyextra->parmName=yytext;
1868 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext,!yyextra->insideBody);
1869 BEGIN(OldStyleArgs);
1870 }
1871<OldStyleArgs>{ID} {
1872 addParmType(yyscanner);
1873 yyextra->parmName=yytext;
1874 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext,!yyextra->insideBody);
1875 }
1876<OldStyleArgs>[,;] {
1877 yyextra->code->codify(yytext);
1878 addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
1879 if (*yytext==';') yyextra->parmType.clear();
1880 yyextra->parmName.clear();
1881 }
1882<CallEnd,OldStyleArgs>"#" {
1883 startFontClass(yyscanner,"preprocessor");
1884 yyextra->lastSkipCppContext = Body;
1885 yyextra->code->codify(yytext);
1886 BEGIN( SkipCPP );
1887 }
1888<CallEnd>. {
1889 unput(*yytext);
1890 if (!yyextra->insideBody)
1891 {
1892 yyextra->theVarContext.popScope();
1893 }
1894 yyextra->name.clear();yyextra->args.clear();
1895 yyextra->parmType.clear();yyextra->parmName.clear();
1896 BEGIN( Body );
1897 }
1898<SkipInits>";" {
1899 yyextra->code->codify(yytext);
1900 yyextra->type.clear(); yyextra->name.clear();
1901 BEGIN( Body );
1902 }
1903<SkipInits>"{" {
1904 yyextra->code->codify(yytext);
1905 if (yyextra->searchingForBody)
1906 {
1907 yyextra->searchingForBody=FALSE;
1908 yyextra->insideBody=TRUE;
1909 }
1910 if (yyextra->insideBody) yyextra->bodyCurlyCount++;
1911 if (yyextra->name.find("::")!=-1)
1912 {
1913 DBG_CTX((stderr,"** scope stack push SCOPEBLOCK\n"));
1914 yyextra->scopeStack.push(SCOPEBLOCK);
1915 setClassScope(yyscanner,yyextra->realScope);
1916 }
1917 else
1918 {
1919 DBG_CTX((stderr,"** scope stack push INNERBLOCK\n"));
1920 yyextra->scopeStack.push(INNERBLOCK);
1921 }
1922 yyextra->type.clear(); yyextra->name.clear();
1923 BEGIN( Body );
1924 }
1925<SkipInits>{ID}{B}*"{" {
1926 QCString text(yytext);
1927 int bracketPos = text.find('{');
1928 int spacePos = text.find(' ');
1929 int len = spacePos==-1 ? bracketPos : spacePos;
1930 generateClassOrGlobalLink(yyscanner,*yyextra->code,text.left(len));
1931 yyextra->code->codify(QCString(yytext+len));
1932 }
1933<SkipInits>{ID} {
1934 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
1935 }
1936<FuncCall>{ID}/"(" {
1937 generateFunctionLink(yyscanner,*yyextra->code,yytext);
1938 }
1939<FuncCall>{ID}/("."|"->") {
1940 yyextra->name=yytext;
1941 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
1942 BEGIN( MemberCall2 );
1943 }
1944<FuncCall,MemberCall2>("("{B}*("*"{B}*)+{ID}+{B}*")"{B}*)/("."|"->") {
1945 yyextra->code->codify(yytext);
1946 uint32_t s=0;while (!isId(yytext[s])) s++;
1947 uint32_t e=(uint32_t)yyleng-1;while (e>1 && !isId(yytext[e])) e--;
1948 yyextra->name=((QCString)yytext).mid(s,e-s+1);
1949 BEGIN( MemberCall2 );
1950 }
1951<MemberCall2>{ID}/([ \t\n]*"(") {
1952 if (!yyextra->args.isEmpty())
1953 generateMemberLink(yyscanner,*yyextra->code,yyextra->args,yytext);
1954 else
1955 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
1956 yyextra->args.clear();
1957 BEGIN( FuncCall );
1958 }
1959<MemberCall2>{ID}/([ \t\n]*("."|"->")) {
1960 //yyextra->code->codify(yytext);
1961 yyextra->name=yytext;
1962 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
1963 BEGIN( MemberCall2 );
1964 }
1965<MemberCall2>"->"|"." {
1966 if (yytext[0]=='-') // -> could be overloaded
1967 {
1969 }
1970 yyextra->code->codify(yytext);
1971 yyextra->memCallContext = YY_START;
1972 BEGIN( MemberCall );
1973 }
1974<SkipComment>{CCS}("!"?){CCE} {
1975 yyextra->code->codify(yytext);
1976 endFontClass(yyscanner,true);
1977 BEGIN( yyextra->lastCContext ) ;
1978 }
1979<SkipComment>{CPPC}|{CCS} {
1980 yyextra->code->codify(yytext);
1981 }
1982<SkipComment>[^*\/\n]+ {
1983 yyextra->code->codify(yytext);
1984 }
1985<SkipComment>[ \t]*{CCE} {
1986 yyextra->code->codify(yytext);
1987 endFontClass(yyscanner,true);
1988 if (yyextra->lastCContext==SkipCPP)
1989 {
1990 startFontClass(yyscanner,"preprocessor");
1991 }
1992 BEGIN( yyextra->lastCContext ) ;
1993 }
1994<SkipCxxComment>[^\r\n]*"\\"[\r]?\n { // line continuation
1995 codifyLines(yyscanner,yytext);
1996 }
1997<SkipCxxComment>[^\r\n]+ {
1998 yyextra->code->codify(yytext);
1999 }
2000<SkipCxxComment>\r
2001<SkipCxxComment>\n {
2002 unput('\n');
2003 endFontClass(yyscanner);
2004 BEGIN( yyextra->lastCContext ) ;
2005 }
2006<SkipCxxComment>. {
2007 yyextra->code->codify(yytext);
2008 }
2009<MemberCall>[^a-z_A-Z0-9(\n] {
2010 yyextra->code->codify(yytext);
2011 yyextra->type.clear();
2012 yyextra->name.clear();
2013 BEGIN(yyextra->memCallContext);
2014 }
2015<*>\n({B}*{CPPC}[!/][^\n]*\n)+ { // remove special one-line comment
2016 if (YY_START==SkipCPP) REJECT;
2017 startFontClass(yyscanner,"comment",true);
2018 codifyLines(yyscanner,QCString(yytext).left(yyleng-1));
2019 endFontClass(yyscanner,true);
2020 codifyLines(yyscanner,"\n");
2021 if (YY_START==SkipCxxComment)
2022 {
2023 BEGIN( yyextra->lastCContext ) ;
2024 }
2025 }
2026<SkipCPP>\n/(.|\n) {
2027 endFontClass(yyscanner);
2028 BEGIN( yyextra->lastSkipCppContext ) ;
2029 unput('\n');
2030 }
2031<*>\n{B}*{CPPC}"@"[{}].*\n { // remove one-line group marker
2032 startFontClass(yyscanner,"comment",true);
2033 codifyLines(yyscanner,QCString(yytext).left(yyleng-1));
2034 endFontClass(yyscanner,true);
2035 codifyLines(yyscanner,"\n");
2036 if (YY_START==SkipCxxComment)
2037 {
2038 BEGIN( yyextra->lastCContext ) ;
2039 }
2040 }
2041<*>\n{B}*{CCS}"@"[{}] { // remove one-line group marker
2042 // check is to prevent getting stuck in skipping C++ comments
2043 if (YY_START != SkipComment && YY_START != SkipCxxComment)
2044 {
2045 yyextra->lastCContext = YY_START ;
2046 }
2047 startFontClass(yyscanner,"comment",true);
2048 codifyLines(yyscanner,yytext);
2049 BEGIN(SkipComment);
2050 }
2051<*>^{B}*{CPPC}"@"[{}].*\n { // remove one-line group marker
2052 startFontClass(yyscanner,"comment",true);
2053 codifyLines(yyscanner,QCString(yytext).left(yyleng-1));
2054 endFontClass(yyscanner,true);
2055 codifyLines(yyscanner,"\n");
2056 }
2057<*>^{B}*{CCS}"@"[{}] { // remove multi-line group marker
2058 // check is to prevent getting stuck in skipping C++ comments
2059 if (YY_START != SkipComment && YY_START != SkipCxxComment)
2060 {
2061 yyextra->lastCContext = YY_START ;
2062 }
2063 startFontClass(yyscanner,"comment",true);
2064 yyextra->code->codify(yytext);
2065 BEGIN(SkipComment);
2066 }
2067<*>^{B}*{CPPC}[!/][^\n]* { // remove special one-line comment
2068 startFontClass(yyscanner,"comment",true);
2069 codifyLines(yyscanner,yytext);
2070 endFontClass(yyscanner,true);
2071 }
2072<*>{CPPC}[!/][^\n]* { // strip special one-line comment
2073 if (YY_START==SkipComment || YY_START==SkipString) REJECT;
2074 startFontClass(yyscanner,"comment",true);
2075 codifyLines(yyscanner,yytext);
2076 endFontClass(yyscanner,true);
2077 }
2078<*>\n{B}*{CCS}[!*]/{NCOMM} {
2079 // check is to prevent getting stuck in skipping C++ comments
2080 if (YY_START != SkipComment && YY_START != SkipCxxComment)
2081 {
2082 yyextra->lastCContext = YY_START ;
2083 }
2084 startFontClass(yyscanner,"comment",true);
2085 codifyLines(yyscanner,yytext);
2086 BEGIN(SkipComment);
2087 }
2088<*>^{B}*{CCS}"*"[*]+/[^/] {
2089 // check is to prevent getting stuck in skipping C++ comments
2090 if (YY_START != SkipComment && YY_START != SkipCxxComment)
2091 {
2092 yyextra->lastCContext = YY_START ;
2093 }
2094 // special C "banner" comment block at a new line
2095 startFontClass(yyscanner,"comment",Config_getBool(JAVADOC_BANNER));
2096 yyextra->code->codify(yytext);
2097 BEGIN(SkipComment);
2098 }
#define Config_getBool(name)
Definition config.h:33
2099<*>^{B}*{CCS}[!*]/{NCOMM} { // special C comment block at a new line
2100 // check is to prevent getting stuck in skipping C++ comments
2101 if (YY_START != SkipComment && YY_START != SkipCxxComment)
2102 {
2103 yyextra->lastCContext = YY_START ;
2104 }
2105 startFontClass(yyscanner,"comment",true);
2106 yyextra->code->codify(yytext);
2107 BEGIN(SkipComment);
2108 }
2109<*>{CCS}[!*]/{NCOMM} { // special C comment block half way a line
2110 if (YY_START==SkipString) REJECT;
2111 // check is to prevent getting stuck in skipping C++ comments
2112 if (YY_START != SkipComment && YY_START != SkipCxxComment)
2113 {
2114 yyextra->lastCContext = YY_START ;
2115 }
2116 startFontClass(yyscanner,"comment",true);
2117 yyextra->code->codify(yytext);
2118 BEGIN(SkipComment);
2119 }
2120<*>{CCS}("!"?){CCE} {
2121 if (YY_START==SkipString) REJECT;
2122 bool specialComment = QCString(yytext).find('!')!=-1;
2123 startFontClass(yyscanner,"comment",specialComment);
2124 yyextra->code->codify(yytext);
2125 endFontClass(yyscanner,specialComment);
2126 }
2127<SkipComment>[^\*\n]+ {
2128 yyextra->code->codify(yytext);
2129 }
2130<*>{CCS} {
2131 startFontClass(yyscanner,"comment");
2132 yyextra->code->codify(yytext);
2133 // check is to prevent getting stuck in skipping C++ comments
2134 if (YY_START != SkipComment && YY_START != SkipCxxComment)
2135 {
2136 yyextra->lastCContext = YY_START ;
2137 }
2138 BEGIN( SkipComment ) ;
2139 }
2140<*>[$]?@\" { // C# (interpolated) verbatim string
2141 startFontClass(yyscanner,"stringliteral");
2142 yyextra->code->codify(yytext);
2143 yyextra->lastVerbStringContext=YY_START;
2144 BEGIN(SkipVerbString);
2145 }
2146<*>{CPPC} {
2147 startFontClass(yyscanner,"comment");
2148 yyextra->code->codify(yytext);
2149 yyextra->lastCContext = YY_START ;
2150 BEGIN( SkipCxxComment ) ;
2151 }
2152<*>"("|"[" {
2153 if (yytext[0]=='(') yyextra->bracketCount++;
2154 yyextra->code->codify(yytext);
2155 yyextra->theCallContext.pushScope(yyextra->name, yyextra->type, yyextra->bracketCount);
2156 }
2157<*>")"|"]" {
2158 if (yytext[0]==')') yyextra->bracketCount--;
2159 yyextra->code->codify(yytext);
2160 yyextra->theCallContext.popScope(yyextra->name, yyextra->type, yyextra->bracketCount);
2161 }
2162<*>\n {
2163 codifyLines(yyscanner,yytext);
2164 }
2165<*>[\x80-\xFF]* { // keep utf8 characters together...
2166 yyextra->code->codify(yytext);
2167 }
2168<*>. {
2169 yyextra->code->codify(yytext);
2170 }
2171
2172%%
2173
2174/*@ ----------------------------------------------------------------------------
2175 */
2176
2177static bool startsWithKeyword(const QCString &str,const QCString &kw)
2178{
2179 if (str.length()<kw.length()) return false; // string too short to match
2180 return str==kw || // exact match
2181 (str.startsWith(kw) && !isId(str.at(kw.length()))); // match that is not a substring
2182}
2183
2184static void addVariable(yyscan_t yyscanner,QCString type,QCString name)
2185{
2186 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2187 DBG_CTX((stderr,"VariableContext::addVariable(%s,%s)\n",qPrint(type),qPrint(name)));
2188 QCString ltype = type.simplifyWhiteSpace();
2189 QCString lname = name.simplifyWhiteSpace();
2190 ltype.stripPrefix("struct ");
2191 ltype.stripPrefix("union ");
2192 if (ltype.isEmpty() || lname.isEmpty()) return;
2193 ltype = substitute(ltype,".","::");
2194 DBG_CTX((stderr,"** addVariable trying: type='%s' name='%s' currentDefinition=%s\n",
2195 qPrint(ltype),qPrint(lname),yyextra->currentDefinition?qPrint(yyextra->currentDefinition->name()):"<none>"));
2196 auto it = yyextra->codeClassMap.find(ltype.str());
2197 if (it!=yyextra->codeClassMap.end()) // look for class definitions inside the code block
2198 {
2199 DBG_CTX((stderr,"** addVariable type='%s' name='%s'\n",qPrint(ltype),qPrint(lname)));
2200 yyextra->theVarContext.addVariable(lname,std::move(it->second)); // add it to a list
2201 }
2202 else
2203 {
2204 auto findVariableType = [&yyscanner,&yyg,&ltype,&lname,&name](const Definition *d) -> const ClassDef *
2205 {
2206 const ClassDef *varDef = yyextra->symbolResolver.resolveClass(d,ltype,true);
2207 int i=0;
2208 if (varDef)
2209 {
2210 DBG_CTX((stderr,"** addVariable type='%s' name='%s'\n",qPrint(ltype),qPrint(lname)));
2211 yyextra->theVarContext.addVariable(lname,ScopedTypeVariant(varDef)); // add it to a list
2212 }
2213 else if ((i=ltype.find('<'))!=-1)
2214 {
2215 // probably a template class
2216 addVariable(yyscanner,ltype.left(i),name);
2217 }
2218 return varDef;
2219 };
2220 const ClassDef *varDef = findVariableType(yyextra->currentDefinition);
2221 if (varDef==nullptr) // also check via using directive
2222 {
2223 for (const auto &[usingName,namespaceDef] : yyextra->theUsingContext)
2224 {
2225 varDef = findVariableType(namespaceDef);
2226 if (varDef) break;
2227 }
2228 }
2229 if (varDef==nullptr)
2230 {
2231 if (!yyextra->theVarContext.atGlobalScope()) // for local variables add a dummy entry so the name
2232 // is hidden to avoid false links to global variables with the same name
2233 // TODO: make this work for namespaces as well!
2234 {
2235 DBG_CTX((stderr,"** addVariable: dummy context for '%s'\n",qPrint(lname)));
2236 yyextra->theVarContext.addVariable(lname,ScopedTypeVariant());
2237 }
2238 else
2239 {
2240 DBG_CTX((stderr,"** addVariable: not adding variable!\n"));
2241 }
2242 }
2243 }
2244}
2245
2246//-------------------------------------------------------------------
2247
2248/*! add class/namespace name s to the scope */
2249static void pushScope(yyscan_t yyscanner,const QCString &s)
2250{
2251 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2252 yyextra->scopeNameLengthStack.push_back(int(yyextra->scopeName.length()));
2253 if (yyextra->scopeName.isEmpty() || leftScopeMatch(s,yyextra->scopeName))
2254 {
2255 yyextra->scopeName = s;
2256 }
2257 else
2258 {
2259 yyextra->scopeName += "::";
2260 yyextra->scopeName += s;
2261 }
2262 DBG_CTX((stderr,"pushScope(%s) result: '%s'\n",qPrint(s),qPrint(yyextra->scopeName)));
2263}
2264
2265
2266/*! remove the top class/namespace name from the scope */
2267static void popScope(yyscan_t yyscanner)
2268{
2269 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2270 if (!yyextra->scopeNameLengthStack.empty())
2271 {
2272 int length = yyextra->scopeNameLengthStack.back();
2273 yyextra->scopeNameLengthStack.pop_back();
2274 yyextra->scopeName.resize(length);
2275 }
2276 else
2277 {
2278 //err("Too many end of scopes found!\n");
2279 }
2280 DBG_CTX((stderr,"popScope() result: '%s'\n",qPrint(yyextra->scopeName)));
2281}
2282
2283static void setCurrentDoc(yyscan_t yyscanner,const QCString &anchor)
2284{
2285 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2286 if (Doxygen::searchIndex.enabled())
2287 {
2288 if (yyextra->searchCtx)
2289 {
2290 Doxygen::searchIndex.setCurrentDoc(yyextra->searchCtx,yyextra->searchCtx->anchor(),FALSE);
2291 }
2292 else
2293 {
2294 Doxygen::searchIndex.setCurrentDoc(yyextra->sourceFileDef,anchor,TRUE);
2295 }
2296 }
2297}
2298
2299static void addToSearchIndex(yyscan_t /*yyscanner*/,const QCString &text)
2300{
2301 if (Doxygen::searchIndex.enabled())
2302 {
2303 Doxygen::searchIndex.addWord(text,FALSE);
2304 }
2305}
2306
2307static void addToSearchIndex(yyscan_t yyscanner,const char *text)
2308{
2309 addToSearchIndex(yyscanner,QCString(text));
2310}
2311
2312
2313static void setClassScope(yyscan_t yyscanner,const QCString &name)
2314{
2315 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2316 DBG_CTX((stderr,"setClassScope(%s)\n",qPrint(name)));
2317 QCString n=name;
2318 n=n.simplifyWhiteSpace();
2319 int ts=n.find('<'); // start of template
2320 int te=n.findRev('>'); // end of template
2321 DBG_CTX((stderr,"ts=%d te=%d\n",ts,te));
2322 if (ts!=-1 && te!=-1 && te>ts)
2323 {
2324 // remove template from scope
2325 n=n.left(ts)+n.right(n.length()-te-1);
2326 }
2327 while (!yyextra->scopeNameLengthStack.empty())
2328 {
2329 popScope(yyscanner);
2330 }
2331 yyextra->scopeName.clear();
2332 int i;
2333 while ((i=n.find("::"))!=-1)
2334 {
2335 pushScope(yyscanner,n.left(i));
2336 n = n.mid(i+2);
2337 }
2338 pushScope(yyscanner,n);
2339 DBG_CTX((stderr,"--->New class scope '%s'\n",qPrint(yyextra->scopeName)));
2340}
2341
2342static void endCodeFold(yyscan_t yyscanner)
2343{
2344 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2345 while (!yyextra->foldStack.empty())
2346 {
2347 const Definition *dd = yyextra->foldStack.back();
2348 if (dd->getEndBodyLine()+1==yyextra->yyLineNr) // +1 to close the section after the end of the body
2349 {
2350 yyextra->code->endFold();
2351 //fprintf(stderr,"%d: end codeFolding for %s [%d..%d]\n",yyextra->yyLineNr,qPrint(dd->name()),dd->getStartDefLine(),dd->getEndBodyLine());
2352 yyextra->foldStack.pop_back();
2353 }
2354 else
2355 {
2356 //fprintf(stderr,"no end of block dd=%s end=%d\n",qPrint(dd->qualifiedName()),dd->getEndBodyLine());
2357 break;
2358 }
2359 }
2360}
2361
2362
2363static void codeFolding(yyscan_t yyscanner,const Definition *d)
2364{
2365 if (Config_getBool(HTML_CODE_FOLDING))
2366 {
2367 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2368 //fprintf(stderr,"codeFolding at %d\n",yyextra->yyLineNr);
2369 //if (d)
2370 // fprintf(stderr,"%d: codeFolding: candidate=%s [%d..%d]\n",yyextra->yyLineNr,qPrint(d->qualifiedName()),d->getStartDefLine(),d->getEndBodyLine());
2371 endCodeFold(yyscanner);
2372 if (d)
2373 {
2374 int startLine = d->getStartDefLine();
2375 int endLine = d->getEndBodyLine();
2376 if (endLine!=-1 && startLine!=endLine &&
2377 // since the end of a section is closed after the last line, we need to avoid starting a
2378 // new section if the previous section ends at the same line, i.e. something like
2379 // struct X {
2380 // ...
2381 // }; struct S { <- start of S and end of X at the same line
2382 // ...
2383 // };
2384 (yyextra->foldStack.empty() || yyextra->foldStack.back()->getEndBodyLine()!=startLine))
2385 {
2386 //printf("%d: start codeFolding for %s [%d..%d]\n",yyextra->yyLineNr,qPrint(d->name()),d->getStartDefLine(),d->getEndBodyLine());
2388 {
2389 const MemberDef *md = toMemberDef(d);
2390 if (md && md->isDefine())
2391 {
2392 yyextra->code->startFold(yyextra->yyLineNr,"",""); // #define X ...
2393 }
2394 else if (md && md->isCallable())
2395 {
2396 yyextra->code->startFold(yyextra->yyLineNr,"{","}"); // func() { ... }
2397 }
2398 else
2399 {
2400 yyextra->code->startFold(yyextra->yyLineNr,"{","};"); // enum X { ... }
2401 }
2402 }
2404 {
2405 yyextra->code->startFold(yyextra->yyLineNr,"{","};"); // class X { ... };
2406 }
2407 else
2408 {
2409 yyextra->code->startFold(yyextra->yyLineNr,"{","}"); // namespace X {...}
2410 }
2411 yyextra->foldStack.push_back(d);
2412 }
2413 }
2414 }
2415}
2416
2417/*! start a new line of code, inserting a line number if yyextra->sourceFileDef
2418 * is TRUE. If a definition starts at the current line, then the line
2419 * number is linked to the documentation of that definition.
2420 */
2421static void startCodeLine(yyscan_t yyscanner)
2422{
2423 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2424 //if (yyextra->currentFontClass) { yyextra->code->endFontClass(yyscanner); }
2425 if (yyextra->sourceFileDef && yyextra->lineNumbers)
2426 {
2427 //QCString lineNumber,lineAnchor;
2428 //lineNumber.sprintf("%05d",yyextra->yyLineNr);
2429 //lineAnchor.sprintf("l%05d",yyextra->yyLineNr);
2430
2431 const Definition *d = yyextra->sourceFileDef->getSourceDefinition(yyextra->yyLineNr);
2432 //printf("%s:startCodeLine(%d)=%p\n",qPrint(yyextra->sourceFileDef->name()),yyextra->yyLineNr,(void*)d);
2433 DBG_CTX((stderr,"%s:startCodeLine(%d)=%p\n",qPrint(yyextra->sourceFileDef->name()),yyextra->yyLineNr,(void*)d));
2434 if (!yyextra->includeCodeFragment && d)
2435 {
2436 yyextra->currentDefinition = d;
2437 yyextra->currentMemberDef = yyextra->sourceFileDef->getSourceMember(yyextra->yyLineNr);
2438 yyextra->insideBody = FALSE;
2439 yyextra->searchingForBody = TRUE;
2440 yyextra->realScope = d!=Doxygen::globalScope ? d->name() : "";
2441 yyextra->type.clear();
2442 yyextra->name.clear();
2443 yyextra->args.clear();
2444 yyextra->parmType.clear();
2445 yyextra->parmName.clear();
2446 DBG_CTX((stderr,"Real scope: '%s'\n",qPrint(yyextra->realScope)));
2447 yyextra->bodyCurlyCount = 0;
2448 QCString lineAnchor;
2449 lineAnchor.sprintf("l%05d",yyextra->yyLineNr);
2450 if (yyextra->currentMemberDef)
2451 {
2452 codeFolding(yyscanner,yyextra->currentMemberDef);
2453 yyextra->code->writeLineNumber(yyextra->currentMemberDef->getReference(),
2454 yyextra->currentMemberDef->getOutputFileBase(),
2455 yyextra->currentMemberDef->anchor(),
2456 yyextra->yyLineNr,!yyextra->includeCodeFragment);
2457 setCurrentDoc(yyscanner,lineAnchor);
2458 }
2459 else if (d->isLinkableInProject())
2460 {
2461 codeFolding(yyscanner,d);
2462 yyextra->code->writeLineNumber(d->getReference(),
2463 d->getOutputFileBase(),
2464 QCString(),yyextra->yyLineNr,!yyextra->includeCodeFragment);
2465 setCurrentDoc(yyscanner,lineAnchor);
2466 }
2467 else
2468 {
2469 codeFolding(yyscanner,nullptr);
2470 }
2471 }
2472 else
2473 {
2474 codeFolding(yyscanner,nullptr);
2475 yyextra->code->writeLineNumber(QCString(),QCString(),QCString(),yyextra->yyLineNr,
2476 !yyextra->includeCodeFragment);
2477 }
2478 }
2479 DBG_CTX((stderr,"startCodeLine(%d)\n",yyextra->yyLineNr));
2480 yyextra->code->startCodeLine(yyextra->yyLineNr);
2481 yyextra->insideCodeLine = true;
2482 if (yyextra->currentFontClass)
2483 {
2484 yyextra->code->startFontClass(QCString(yyextra->currentFontClass));
2485 }
2486}
2487
2488
2489
2490static void endCodeLine(yyscan_t yyscanner)
2491{
2492 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2493 DBG_CTX((stderr,"endCodeLine(%d)\n",yyextra->yyLineNr));
2494 endFontClass(yyscanner);
2495 yyextra->code->endCodeLine();
2496 yyextra->insideCodeLine = false;
2497}
2498
2499static void nextCodeLine(yyscan_t yyscanner)
2500{
2501 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2502 const char * fc = yyextra->currentFontClass;
2503 if (yyextra->insideCodeLine)
2504 {
2505 endCodeLine(yyscanner);
2506 }
2507 if (yyextra->yyLineNr<yyextra->inputLines)
2508 {
2509 yyextra->currentFontClass = fc;
2510 startCodeLine(yyscanner);
2511 }
2512}
2513
2514/*! write a code fragment 'text' that may span multiple lines, inserting
2515 * line numbers for each line.
2516 */
2517static void codifyLines(yyscan_t yyscanner,const QCString &text)
2518{
2519 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2520 DBG_CTX((stderr,"codifyLines(%d,\"%s\")\n",yyextra->yyLineNr,qPrint(text)));
2521 if (text.isEmpty()) return;
2522 const char *p=text.data(),*sp=p;
2523 char c;
2524 bool done=FALSE;
2525 while (!done)
2526 {
2527 sp=p;
2528 while ((c=*p++) && c!='\n');
2529 if (c=='\n')
2530 {
2531 yyextra->yyLineNr++;
2532 size_t l = static_cast<size_t>(p-sp-1);
2533 std::string tmp(sp,l);
2534 yyextra->code->codify(tmp.c_str());
2535 nextCodeLine(yyscanner);
2536 }
2537 else
2538 {
2539 yyextra->code->codify(QCString(sp));
2540 done=TRUE;
2541 }
2542 }
2543}
2544
2545static void codifyLines(yyscan_t yyscanner,const char *text)
2546{
2547 codifyLines(yyscanner,QCString(text));
2548}
2549
2551{
2552 std::lock_guard<std::mutex> lock(Doxygen::countFlowKeywordsMutex);
2553 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2554 if (yyextra->currentMemberDef && yyextra->currentMemberDef->isFunction())
2555 {
2556 MemberDefMutable *md = toMemberDefMutable(const_cast<MemberDef*>(yyextra->currentMemberDef));
2557 if (md)
2558 {
2560 }
2561 }
2562}
2563
2564/*! writes a link to a fragment \a text that may span multiple lines, inserting
2565 * line numbers for each line. If \a text contains newlines, the link will be
2566 * split into multiple links with the same destination, one for each line.
2567 */
2569 const Definition *d,
2570 const QCString &text)
2571{
2572 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2573 bool sourceTooltips = Config_getBool(SOURCE_TOOLTIPS);
2574 yyextra->tooltipManager.addTooltip(d);
2575 QCString ref = d->getReference();
2576 QCString file = d->getOutputFileBase();
2577 QCString anchor = d->anchor();
2578 QCString tooltip;
2579 if (!sourceTooltips) // fall back to simple "title" tooltips
2580 {
2581 tooltip = d->briefDescriptionAsTooltip();
2582 }
2583 bool done=FALSE;
2584 const char *p=text.data();
2585 while (!done)
2586 {
2587 const char *sp=p;
2588 char c = 0;
2589 while ((c=*p++) && c!='\n') { }
2590 if (c=='\n')
2591 {
2592 yyextra->yyLineNr++;
2593 DBG_CTX((stderr,"writeCodeLink(%s,%s,%s,%s)\n",qPrint(ref),qPrint(file),qPrint(anchor),qPrint(QCString(sp,p-sp-1))));
2594 ol.writeCodeLink(d->codeSymbolType(),ref,file,anchor,QCString(sp,p-sp-1),tooltip);
2595 nextCodeLine(yyscanner);
2596 }
2597 else
2598 {
2599 DBG_CTX((stderr,"writeCodeLink(%s,%s,%s,%s)\n",qPrint(ref),qPrint(file),qPrint(anchor),sp));
2600 ol.writeCodeLink(d->codeSymbolType(),ref,file,anchor,QCString(sp),tooltip);
2601 done=TRUE;
2602 }
2603 }
2604}
2605
2606static void addType(yyscan_t yyscanner)
2607{
2608 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2609 if (yyextra->name=="const") { yyextra->name.clear(); return; }
2610 if (!yyextra->type.isEmpty()) yyextra->type += ' ' ;
2611 yyextra->type += yyextra->name ;
2612 yyextra->name.clear() ;
2613 if (!yyextra->type.isEmpty()) yyextra->type += ' ' ;
2614 yyextra->type += yyextra->args ;
2615 yyextra->args.clear() ;
2616}
2617
2618static void addParmType(yyscan_t yyscanner)
2619{
2620 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2621 if (yyextra->parmName=="const") { yyextra->parmName.clear(); return; }
2622 if (!yyextra->parmType.isEmpty()) yyextra->parmType += ' ' ;
2623 yyextra->parmType += yyextra->parmName ;
2624 yyextra->parmName.clear() ;
2625}
2626
2627static void addUsingDirective(yyscan_t yyscanner,const QCString &name)
2628{
2629 //printf("AddUsingDirective(%s)\n",qPrint(name));
2630 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2631 if (yyextra->sourceFileDef && !name.isEmpty())
2632 {
2633 const NamespaceDef *nd = Doxygen::namespaceLinkedMap->find(name);
2634 if (nd)
2635 {
2636 yyextra->theUsingContext.emplace(name.str(),nd);
2637 }
2638 }
2639}
2640
2641static void setParameterList(yyscan_t yyscanner,const MemberDef *md)
2642{
2643 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2644 for (const Argument &a : md->argumentList())
2645 {
2646 yyextra->parmName = a.name;
2647 yyextra->parmType = a.type;
2648 int i = yyextra->parmType.find('*');
2649 if (i!=-1) yyextra->parmType = yyextra->parmType.left(i);
2650 i = yyextra->parmType.find('&');
2651 if (i!=-1) yyextra->parmType = yyextra->parmType.left(i);
2652 yyextra->parmType.stripPrefix("const ");
2653 yyextra->parmType=yyextra->parmType.stripWhiteSpace();
2654 addVariable(yyscanner,yyextra->parmType,yyextra->parmName);
2655 }
2656}
2657
2658static const ClassDef *stripClassName(yyscan_t yyscanner,const QCString &s,const Definition *d)
2659{
2660 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2661 DBG_CTX((stderr,"stripClassName(scope=%s,type=%s) scopeName=%s\n",
2662 qPrint(d?d->name():""),qPrint(s),qPrint(yyextra->scopeName)));
2663 int pos=0;
2664 QCString type = s;
2665 QCString className;
2666 QCString templSpec;
2667 while (extractClassNameFromType(type,pos,className,templSpec)!=-1)
2668 {
2669 QCString clName=className+templSpec;
2670 const ClassDef *cd=nullptr;
2671 if (!yyextra->scopeName.isEmpty())
2672 {
2673 cd=yyextra->symbolResolver.resolveClass(d,yyextra->scopeName+"::"+clName,true);
2674 }
2675 if (cd==nullptr)
2676 {
2677 cd=yyextra->symbolResolver.resolveClass(d,clName,true);
2678 }
2679 DBG_CTX((stderr,"stripClass trying '%s' = %p\n",qPrint(clName),(void*)cd));
2680 if (cd)
2681 {
2682 return cd;
2683 }
2684 }
2685
2686 return nullptr;
2687}
2688
2689static const MemberDef *setCallContextForVar(yyscan_t yyscanner,const QCString &name)
2690{
2691 if (name.isEmpty()) return nullptr;
2692 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2693 DBG_CTX((stderr,"setCallContextForVar(%s) yyextra->scopeName=%s\n",qPrint(name),qPrint(yyextra->scopeName)));
2694
2695 int scopeEnd = name.findRev("::");
2696 if (scopeEnd!=-1) // name with explicit scope
2697 {
2698 QCString scope = name.left(scopeEnd);
2699 QCString locName = name.right(name.length()-scopeEnd-2);
2700 DBG_CTX((stderr,"explicit scope: name=%s scope=%s\n",qPrint(locName),qPrint(scope)));
2701 const ClassDef *mcd = getClass(scope);
2702 if (mcd && !locName.isEmpty())
2703 {
2704 const MemberDef *md=mcd->getMemberByName(locName);
2705 if (md)
2706 {
2707 DBG_CTX((stderr,"name=%s scope=%s\n",qPrint(locName),qPrint(scope)));
2708 yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,md->typeString(),md->getOuterScope())));
2709 return md;
2710 }
2711 }
2712 else // check namespace as well
2713 {
2714 const NamespaceDef *mnd = getResolvedNamespace(scope);
2715 if (mnd && !locName.isEmpty())
2716 {
2717 const MemberDef *md=mnd->getMemberByName(locName);
2718 if (md)
2719 {
2720 DBG_CTX((stderr,"name=%s scope=%s\n",qPrint(locName),qPrint(scope)));
2721 yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,md->typeString(),md->getOuterScope())));
2722 return md;
2723 }
2724 }
2725 }
2726 }
2727
2728 const ScopedTypeVariant *mcv = yyextra->theVarContext.findVariable(name);
2729 if (mcv)
2730 {
2731 DBG_CTX((stderr,"local variable?\n"));
2732 if (!mcv->isDummy()) // locally found variable
2733 {
2734 DBG_CTX((stderr,"local var '%s' mcd=%s\n",qPrint(name),qPrint(mcv->name())));
2735 yyextra->theCallContext.setScope(*mcv);
2736 }
2737 }
2738 else
2739 {
2740 DBG_CTX((stderr,"class member? scope=%s\n",qPrint(yyextra->scopeName)));
2741 // look for a class member
2742 const ClassDef *mcd = getClass(yyextra->scopeName);
2743 if (mcd)
2744 {
2745 DBG_CTX((stderr,"Inside class %s\n",qPrint(mcd->name())));
2746 const MemberDef *md=mcd->getMemberByName(name);
2747 if (md)
2748 {
2749 DBG_CTX((stderr,"Found member %s\n",qPrint(md->name())));
2750 if (yyextra->scopeStack.empty() || yyextra->scopeStack.top()!=CLASSBLOCK)
2751 {
2752 DBG_CTX((stderr,"class member '%s' mcd=%s\n",qPrint(name),qPrint(mcd->name())));
2753 yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,md->typeString(),md->getOuterScope())));
2754 }
2755 return md;
2756 }
2757 }
2758 }
2759
2760 // look for a global member
2761 const MemberName *mn = Doxygen::functionNameLinkedMap->find(name);
2762 if (mn)
2763 {
2764 DBG_CTX((stderr,"global var '%s'\n",qPrint(name)));
2765 if (mn->size()==1) // global defined only once
2766 {
2767 const std::unique_ptr<MemberDef> &md=mn->front();
2768 if (!md->isStatic() || md->getBodyDef()==yyextra->sourceFileDef)
2769 {
2770 yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,md->typeString(),md->getOuterScope())));
2771 return md.get();
2772 }
2773 return nullptr;
2774 }
2775 else if (mn->size()>1) // global defined more than once
2776 {
2777 for (const auto &md : *mn)
2778 {
2779 //printf("mn=%p md=%p md->getBodyDef()=%p yyextra->sourceFileDef=%p\n",
2780 // mn,md,
2781 // md->getBodyDef(),yyextra->sourceFileDef);
2782
2783 // in case there are multiple members we could link to, we
2784 // only link to members if defined in the same file or
2785 // defined as external.
2786 if (!md->isStatic() || md->getBodyDef()==yyextra->sourceFileDef)
2787 {
2788 yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,md->typeString(),md->getOuterScope())));
2789 DBG_CTX((stderr,"returning member %s in source file %s\n",qPrint(md->name()),qPrint(yyextra->sourceFileDef->name())));
2790 return md.get();
2791 }
2792 }
2793 return nullptr;
2794 }
2795 }
2796 return nullptr;
2797}
2798
2800{
2801 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2802 const Definition *d = yyextra->theCallContext.getScope().globalDef();
2803 //printf("updateCallContextForSmartPointer() cd=%s\n",cd ? qPrint(d->name()) : "<none>");
2804 const MemberDef *md = nullptr;
2805 if (d && d->definitionType()==Definition::TypeClass && (md=(toClassDef(d))->isSmartPointer()))
2806 {
2807 const ClassDef *ncd = stripClassName(yyscanner,md->typeString(),md->getOuterScope());
2808 if (ncd)
2809 {
2810 yyextra->theCallContext.setScope(ScopedTypeVariant(ncd));
2811 //printf("Found smart pointer call %s->%s!\n",qPrint(cd->name()),qPrint(ncd->name()));
2812 }
2813 }
2814}
2815
2816static bool getLinkInScope(yyscan_t yyscanner,
2817 const QCString &c, // scope
2818 const QCString &m, // member
2819 const QCString &memberText, // exact text
2820 OutputCodeList &ol,
2821 const QCString &text,
2822 bool varOnly
2823 )
2824{
2825 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2826 DBG_CTX((stderr,"getLinkInScope: trying '%s'::'%s' varOnly=%d\n",qPrint(c),qPrint(m),varOnly));
2827 GetDefInput input(c,m,"()");
2828 input.currentFile = yyextra->sourceFileDef;
2829 input.insideCode = true;
2830 GetDefResult result = getDefs(input);
2831 DBG_CTX((stderr,"scopeNameLengthStack.size()=%zu\n",yyextra->scopeNameLengthStack.size()));
2832 if (!result.found && !yyextra->scopeNameLengthStack.empty() && c==yyextra->scopeName)
2833 {
2834 QCString localName = yyextra->scopeName.mid(yyextra->scopeNameLengthStack[0]+2); // try also without leading scope
2835 auto it = yyextra->codeClassMap.find(localName.str());
2836 if (it!=yyextra->codeClassMap.end())
2837 {
2838 ScopedTypeVariant ccd = it->second;
2839 if (ccd.localDef() && !ccd.localDef()->baseClasses().empty())
2840 {
2841 for (const auto &bcName : ccd.localDef()->baseClasses())
2842 {
2843 DBG_CTX((stderr,"trying lookup via base class %s\n",qPrint(bcName)));
2844 input.scopeName = bcName;
2845 result = getDefs(input);
2846 if (result.found) break;
2847 }
2848 }
2849 }
2850 }
2851 if (result.found && result.md && (!varOnly || result.md->isVariable()))
2852 {
2853 if (result.md->isLinkable())
2854 {
2855 DBG_CTX((stderr,"found it %s!\n",qPrint(result.md->qualifiedName())));
2856 if (yyextra->exampleBlock)
2857 {
2858 std::lock_guard<std::mutex> lock(Doxygen::addExampleMutex);
2859 QCString anchor;
2860 anchor.sprintf("a%d",yyextra->anchorCount);
2861 DBG_CTX((stderr,"addExampleFile(%s,%s,%s)\n",qPrint(anchor),qPrint(yyextra->exampleName),
2862 qPrint(yyextra->exampleFile)));
2863 MemberDefMutable *mdm = toMemberDefMutable(const_cast<MemberDef*>(result.md));
2864 if (mdm && mdm->addExample(anchor,yyextra->exampleName,yyextra->exampleFile))
2865 {
2866 ol.writeCodeAnchor(anchor);
2867 yyextra->anchorCount++;
2868 }
2869 }
2870
2871 const Definition *d = result.md->getOuterScope()==Doxygen::globalScope ?
2872 result.md->resolveAlias()->getFileDef() : result.md->getOuterScope();
2873 if (result.md->resolveAlias()->getGroupDef()) d = result.md->resolveAlias()->getGroupDef();
2874 if (d && d->isLinkable())
2875 {
2876 const ClassDef *ncd = stripClassName(yyscanner,result.md->typeString(),result.md->getOuterScope());
2877 if (ncd)
2878 {
2879 yyextra->theCallContext.setScope(ScopedTypeVariant(ncd));
2880 }
2881 DBG_CTX((stderr,"yyextra->currentDefinition=%p yyextra->currentMemberDef=%p yyextra->insideBody=%d\n",
2882 (void*)yyextra->currentDefinition,(void*)yyextra->currentMemberDef,yyextra->insideBody));
2883
2884 if (yyextra->currentDefinition && yyextra->currentMemberDef &&
2885 yyextra->insideBody && yyextra->collectXRefs)
2886 {
2887 addDocCrossReference(yyextra->currentMemberDef,result.md);
2888 }
2889 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(result.md->name())));
2890
2891 writeMultiLineCodeLink(yyscanner,ol,result.md, !text.isEmpty() ? text : memberText);
2892 addToSearchIndex(yyscanner,!text.isEmpty() ? text : memberText);
2893 return TRUE;
2894 }
2895 }
2896 }
2897 return FALSE;
2898}
2899
2900static bool getLink(yyscan_t yyscanner,
2901 const QCString &className,
2902 const QCString &memberName,
2903 OutputCodeList &ol,
2904 const QCString &text,
2905 bool varOnly)
2906{
2907 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2908 DBG_CTX((stderr,"getLink(%s,%s) yyextra->curClassName=%s\n",
2909 qPrint(className),qPrint(memberName),qPrint(yyextra->curClassName)));
2910 QCString m=removeRedundantWhiteSpace(memberName);
2911 QCString c=className;
2912 if (!getLinkInScope(yyscanner,c,m,memberName,ol,text,varOnly))
2913 {
2914 if (!yyextra->curClassName.isEmpty())
2915 {
2916 if (!c.isEmpty()) c.prepend("::");
2917 c.prepend(yyextra->curClassName);
2918 return getLinkInScope(yyscanner,c,m,memberName,ol,text,varOnly);
2919 }
2920 return FALSE;
2921 }
2922 return TRUE;
2923}
2924
2926 OutputCodeList &ol,
2927 const QCString &scName,
2928 bool typeOnly,
2929 bool varOnly)
2930{
2931 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
2932 QCString scopeName=scName;
2933 if (!scopeName.isEmpty() && scopeName[0]=='~') // correct for matching negated values i.s.o. destructors.
2934 {
2935 scopeName=scopeName.mid(1);
2936 }
2937 if (scopeName.isEmpty())
2938 {
2939 yyextra->code->codify("~");
2940 return;
2941 }
2942 if (yyextra->insideProtocolList) // for Obj-C
2943 {
2944 scopeName+="-p";
2945 }
2946 if (yyextra->lang==SrcLangExt::PHP)
2947 {
2948 scopeName = substitute(scopeName,"\\","::"); // for PHP namespaces
2949 }
2950 else if (yyextra->lang==SrcLangExt::CSharp || yyextra->lang==SrcLangExt::Java)
2951 {
2952 scopeName = substitute(scopeName,".","::"); // for C#/Java namespaces
2953 }
2954 if (yyextra->currentDefinition==nullptr && !yyextra->scopeName.isEmpty())
2955 {
2956 scopeName = yyextra->scopeName+"::"+scopeName;
2957 }
2958 const ScopedTypeVariant *lcd=nullptr;
2959 const Definition *sym=nullptr;
2960 bool isLocal=FALSE;
2961
2962 DBG_CTX((stderr,"generateClassOrGlobalLink(name=%s) yyextra->scopeName=%s scopeName=%s\n",qPrint(scName),qPrint(yyextra->scopeName),qPrint(scopeName)));
2963 if (!yyextra->isPrefixedWithThis || (lcd=yyextra->theVarContext.findVariable(scopeName))==nullptr) // not a local variable
2964 {
2965 int i=scopeName.find('<');
2966 QCString bareName = scopeName;
2967 if (i!=-1) bareName = bareName.left(i);
2968
2969 auto checkForSymbol = [&yyg,&bareName,&scopeName](const Definition *parent,
2970 const Definition *&sym_)
2971 {
2972 sym_ = yyextra->symbolResolver.resolveSymbol(parent,scopeName,QCString(),false,true);
2973 DBG_CTX((stderr,"non-local variable name=%s sym=%s!\n",
2974 qPrint(scopeName),sym_?qPrint(sym_->name()):"<none>"));
2975 if (sym_==nullptr && !bareName.isEmpty())
2976 {
2977 DBG_CTX((stderr,"bareName=%s\n",qPrint(bareName)));
2978 if (bareName!=scopeName)
2979 {
2980 sym_ = yyextra->symbolResolver.resolveSymbol(parent,bareName,QCString(),false,true); // try unspecialized version
2981 }
2982 }
2983 };
2984 const Definition *d = yyextra->currentDefinition;
2985 DBG_CTX((stderr,"d=%s yyextra->sourceFileDef=%s\n",d?qPrint(d->name()):"<none>",yyextra->sourceFileDef?qPrint(yyextra->sourceFileDef->name()):"<none>"));
2986 checkForSymbol(d,sym);
2987 if (sym==nullptr && d && d->definitionType()==Definition::TypeClass)
2988 {
2989 const FileDef *fd = toClassDef(d)->getFileDef();
2990 if (fd)
2991 {
2992 // also check for using directive in the file that defines this class
2993 for (const auto &nd : fd->getUsedNamespaces())
2994 {
2995 checkForSymbol(nd,sym);
2996 if (sym) break;
2997 }
2998 }
2999 }
3000 if (sym==nullptr)
3001 {
3002 // also check via using directive
3003 for (const auto &[usingName,namespaceDef] : yyextra->theUsingContext)
3004 {
3005 checkForSymbol(namespaceDef,sym);
3006 if (sym) break;
3007 }
3008 }
3009
3010 const NamespaceDef *nd = getResolvedNamespace(scopeName);
3011 if (nd && nd->isLinkable())
3012 {
3013 yyextra->theCallContext.setScope(ScopedTypeVariant(nd));
3014 addToSearchIndex(yyscanner,scopeName);
3015 writeMultiLineCodeLink(yyscanner,*yyextra->code,nd,scName);
3016 return;
3017 }
3018 const ConceptDef *conceptDef = getResolvedConcept(d,bareName);
3019 if (conceptDef && conceptDef->isLinkable())
3020 {
3021 yyextra->theCallContext.setScope(ScopedTypeVariant(conceptDef));
3022 addToSearchIndex(yyscanner,scopeName);
3023 writeMultiLineCodeLink(yyscanner,*yyextra->code,conceptDef,scName);
3024 return;
3025 }
3026 DBG_CTX((stderr,"sym=%s\n",sym?qPrint(sym->name()):"<none>"));
3027 DBG_CTX((stderr,"is found as a type sym=%s nd=%s\n",
3028 sym?qPrint(sym->name()):"<null>",
3029 nd?qPrint(nd->name()):"<null>"));
3030 if (sym==nullptr) // also see if it is variable or enum or enum value
3031 {
3032 if (getLink(yyscanner,yyextra->scopeName,scName,ol,scName,varOnly))
3033 {
3034 return;
3035 }
3036 }
3037 }
3038 else
3039 {
3040 DBG_CTX((stderr,"local variable!\n"));
3041 if (!lcd->isDummy())
3042 {
3043 DBG_CTX((stderr,"non-dummy context lcd=%s!\n",qPrint(lcd->name())));
3044 yyextra->theCallContext.setScope(*lcd);
3045
3046 // to following is needed for links to a global variable, but is
3047 // no good for a link to a local variable that is also a global symbol.
3048
3049 //if (getLink(yyscanner,yyextra->scopeName,scName,ol,scName))
3050 //{
3051 //return;
3052 //}
3053 }
3054 isLocal=TRUE;
3055 DBG_CTX((stderr,"is a local variable sym=%p!\n",(void*)sym));
3056 }
3057 yyextra->isPrefixedWithThis = FALSE; // discard the "this" prefix for the next calls
3058
3059 if (sym && sym->isLinkable()) // is it a linkable class
3060 {
3061 DBG_CTX((stderr,"is linkable class %s\n",qPrint(scName)));
3062 if (yyextra->exampleBlock)
3063 {
3064 std::lock_guard<std::mutex> lock(Doxygen::addExampleMutex);
3065 QCString anchor;
3066 anchor.sprintf("_a%d",yyextra->anchorCount);
3067 DBG_CTX((stderr,"addExampleClass(%s,%s,%s)\n",qPrint(anchor),qPrint(yyextra->exampleName),
3068 qPrint(yyextra->exampleFile)));
3070 {
3071 ClassDefMutable *cdm = toClassDefMutable(const_cast<Definition*>(sym));
3072 if (cdm && cdm->addExample(anchor,yyextra->exampleName,yyextra->exampleFile))
3073 {
3074 ol.writeCodeAnchor(anchor);
3075 yyextra->anchorCount++;
3076 }
3077 }
3078 else if (sym->definitionType()==Definition::TypeMember)
3079 {
3080 MemberDefMutable *mdm = toMemberDefMutable(const_cast<Definition*>(sym));
3081 if (mdm && mdm->addExample(anchor,yyextra->exampleName,yyextra->exampleFile))
3082 {
3083 ol.writeCodeAnchor(anchor);
3084 yyextra->anchorCount++;
3085 }
3086 }
3087 }
3088 writeMultiLineCodeLink(yyscanner,ol,sym,scName);
3089 addToSearchIndex(yyscanner,scopeName);
3090 yyextra->theCallContext.setScope(ScopedTypeVariant(sym));
3091 if (sym && sym->definitionType()==Definition::TypeMember)
3092 {
3093 const MemberDef *md = toMemberDef(sym);
3094 const Definition *d = sym->getOuterScope()==Doxygen::globalScope ?
3095 md->getFileDef() : md->getOuterScope();
3096 if (md->getGroupDef()) d = md->getGroupDef();
3097 if (d && d->isLinkable() && md->isLinkable() &&
3098 yyextra->currentMemberDef && yyextra->collectXRefs)
3099 {
3100 addDocCrossReference(yyextra->currentMemberDef,md);
3101 }
3102 }
3103 }
3104 else // not a class, maybe a global member
3105 {
3106 const MemberDef *md = sym && sym->definitionType()==Definition::TypeMember ? toMemberDef(sym) : nullptr;
3107 DBG_CTX((stderr,"class %s not linkable! cd=%p typeOnly=%d\n",qPrint(scName),(void*)sym,typeOnly));
3108 if (!isLocal && (md || (!sym && !typeOnly))) // not a class, see if it is a global enum/variable/typedef.
3109 {
3110 if (md==nullptr) // not found as a typedef
3111 {
3112 md = setCallContextForVar(yyscanner,scName);
3113 DBG_CTX((stderr,"setCallContextForVar(%s) md=%p yyextra->currentDefinition=%s\n",qPrint(scName),(void*)md,yyextra->currentDefinition ? qPrint(yyextra->currentDefinition->name()) : "<none>"));
3114 if (md && yyextra->currentDefinition)
3115 {
3116 DBG_CTX((stderr,"%s accessible from %s? %d md->getOuterScope=%s\n",
3117 qPrint(md->name()),qPrint(yyextra->currentDefinition->name()),
3118 yyextra->symbolResolver.isAccessibleFrom(yyextra->currentDefinition,md),
3119 qPrint(md->getOuterScope()->name())));
3120 }
3121
3122 if (md && yyextra->currentDefinition &&
3123 yyextra->symbolResolver.isAccessibleFrom(yyextra->currentDefinition,md)==-1)
3124 {
3125 md=nullptr; // variable not accessible
3126 }
3127 }
3128 if (md && (!varOnly || md->isVariable()))
3129 {
3130 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()));
3131 if (md->isLinkable())
3132 {
3133 writeMultiLineCodeLink(yyscanner,ol,md,scName);
3134 addToSearchIndex(yyscanner,scName);
3135 if (yyextra->currentMemberDef && yyextra->collectXRefs)
3136 {
3137 addDocCrossReference(yyextra->currentMemberDef,md);
3138 }
3139 return;
3140 }
3141 }
3142 }
3143
3144 // nothing found, just write out the word
3145 DBG_CTX((stderr,"not found!\n"));
3146 codifyLines(yyscanner,scName);
3147 addToSearchIndex(yyscanner,scName);
3148 }
3149}
3150
3151static void generateClassOrGlobalLink(yyscan_t yyscanner,OutputCodeList &ol,const char *clName,
3152 bool typeOnly,bool varOnly)
3153{
3154 generateClassOrGlobalLink(yyscanner,ol,QCString(clName),typeOnly,varOnly);
3155}
3156
3157static bool generateClassMemberLink(yyscan_t yyscanner,
3158 OutputCodeList &ol,
3159 const MemberDef *xmd,
3160 const QCString &memName)
3161{
3162 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3163 // extract class definition of the return type in order to resolve
3164 // a->b()->c() like call chains
3165
3166 DBG_CTX((stderr,"type='%s' args='%s' class=%s\n",
3167 qPrint(xmd->typeString()),qPrint(xmd->argsString()),
3168 qPrint(xmd->getClassDef()->name())));
3169
3170 if (yyextra->exampleBlock)
3171 {
3172 std::lock_guard<std::mutex> lock(Doxygen::addExampleMutex);
3173 QCString anchor;
3174 anchor.sprintf("a%d",yyextra->anchorCount);
3175 DBG_CTX((stderr,"addExampleFile(%s,%s,%s)\n",qPrint(anchor),qPrint(yyextra->exampleName),
3176 qPrint(yyextra->exampleFile)));
3177 MemberDefMutable *mdm = toMemberDefMutable(const_cast<MemberDef*>(xmd));
3178 if (mdm && mdm->addExample(anchor,yyextra->exampleName,yyextra->exampleFile))
3179 {
3180 ol.writeCodeAnchor(anchor);
3181 yyextra->anchorCount++;
3182 }
3183 }
3184
3185 const ClassDef *typeClass = stripClassName(yyscanner,removeAnonymousScopes(xmd->typeString()),xmd->getOuterScope());
3186 DBG_CTX((stderr,"%s -> typeName=%p\n",qPrint(xmd->typeString()),(void*)typeClass));
3187 yyextra->theCallContext.setScope(ScopedTypeVariant(typeClass));
3188
3189 const Definition *xd = xmd->getOuterScope()==Doxygen::globalScope ?
3190 xmd->getFileDef() : xmd->getOuterScope();
3191 if (xmd->getGroupDef()) xd = xmd->getGroupDef();
3192 if (xd && xd->isLinkable())
3193 {
3194
3195 DBG_CTX((stderr,"yyextra->currentDefinition=%p yyextra->currentMemberDef=%p xmd=%p yyextra->insideBody=%d\n",
3196 (void*)yyextra->currentDefinition,(void*)yyextra->currentMemberDef,(void*)xmd,yyextra->insideBody));
3197
3198 if (xmd->templateMaster()) xmd = xmd->templateMaster();
3199
3200 if (xmd->isLinkable())
3201 {
3202 // add usage reference
3203 if (yyextra->currentDefinition && yyextra->currentMemberDef &&
3204 yyextra->insideBody && yyextra->collectXRefs)
3205 {
3206 addDocCrossReference(yyextra->currentMemberDef,xmd);
3207 }
3208
3209 // write the actual link
3210 writeMultiLineCodeLink(yyscanner,ol,xmd,memName);
3211 addToSearchIndex(yyscanner,memName);
3212 return TRUE;
3213 }
3214 }
3215
3216 return FALSE;
3217}
3218
3219static bool generateClassMemberLink(yyscan_t yyscanner,
3220 OutputCodeList &ol,
3221 const Definition *def,
3222 const QCString &memName)
3223{
3224 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3225 if (def && def->definitionType()==Definition::TypeClass)
3226 {
3227 const ClassDef *cd = toClassDef(def);
3228 const MemberDef *xmd = cd->getMemberByName(memName);
3229 DBG_CTX((stderr,"generateClassMemberLink(class=%s,member=%s)=%p\n",qPrint(def->name()),qPrint(memName),(void*)xmd));
3230 if (xmd)
3231 {
3232 return generateClassMemberLink(yyscanner,ol,xmd,memName);
3233 }
3234 else
3235 {
3236 const Definition *innerDef = cd->findInnerCompound(memName);
3237 if (innerDef)
3238 {
3239 yyextra->theCallContext.setScope(ScopedTypeVariant(innerDef));
3240 addToSearchIndex(yyscanner,memName);
3241 writeMultiLineCodeLink(yyscanner,*yyextra->code,innerDef,memName);
3242 return TRUE;
3243 }
3244 }
3245 }
3246 else if (def && def->definitionType()==Definition::TypeNamespace)
3247 {
3248 const NamespaceDef *nd = toNamespaceDef(def);
3249 DBG_CTX((stderr,"Looking for %s inside namespace %s\n",qPrint(memName),qPrint(nd->name())));
3250 const Definition *innerDef = nd->findInnerCompound(memName);
3251 if (innerDef)
3252 {
3253 yyextra->theCallContext.setScope(ScopedTypeVariant(innerDef));
3254 addToSearchIndex(yyscanner,memName);
3255 writeMultiLineCodeLink(yyscanner,*yyextra->code,innerDef,memName);
3256 return TRUE;
3257 }
3258 }
3259 return FALSE;
3260}
3261
3262static void generateMemberLink(yyscan_t yyscanner,
3263 OutputCodeList &ol,
3264 const QCString &varName,
3265 const QCString &memName)
3266{
3267 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3268 DBG_CTX((stderr,"generateMemberLink(object=%s,mem=%s) classScope=%s\n",
3269 qPrint(varName),qPrint(memName),qPrint(yyextra->scopeName)));
3270
3271 if (varName.isEmpty()) return;
3272
3273 // look for the variable in the current context
3274 const ScopedTypeVariant *stv = yyextra->theVarContext.findVariable(varName);
3275 if (stv)
3276 {
3277 if (!stv->isDummy())
3278 {
3279 DBG_CTX((stderr,"Class found!\n"));
3280 if (getLink(yyscanner,stv->name(),memName,ol))
3281 {
3282 DBG_CTX((stderr,"Found result!\n"));
3283 return;
3284 }
3285 if (stv->localDef() && !stv->localDef()->baseClasses().empty())
3286 {
3287 for (const auto &bcName : stv->localDef()->baseClasses())
3288 {
3289 if (getLink(yyscanner,bcName,memName,ol))
3290 {
3291 DBG_CTX((stderr,"Found result!\n"));
3292 return;
3293 }
3294 }
3295 }
3296 }
3297 }
3298 else // variable not in current context, maybe it is in a parent context
3299 {
3300 const ClassDef *vcd = yyextra->symbolResolver.resolveClass(yyextra->currentDefinition,yyextra->scopeName,true);
3301 if (vcd && vcd->isLinkable())
3302 {
3303 DBG_CTX((stderr,"Found class %s for variable '%s'\n",qPrint(yyextra->scopeName),qPrint(varName)));
3304 MemberName *vmn=Doxygen::memberNameLinkedMap->find(varName);
3305 if (vmn==nullptr)
3306 {
3307 int vi = 0;
3308 QCString vn=varName;
3309 if ((vi=vn.findRev("::"))!=-1 || (vi=vn.findRev('.'))!=-1) // explicit scope A::b(), probably static member
3310 {
3311 const ClassDef *jcd = getClass(vn.left(vi));
3312 vn=vn.right(vn.length()-vi-2);
3313 vmn=Doxygen::memberNameLinkedMap->find(vn);
3314 //printf("Trying name '%s' scope=%s\n",qPrint(vn),qPrint(scope));
3315 if (vmn)
3316 {
3317 for (const auto &vmd : *vmn)
3318 {
3319 if (vmd->getClassDef()==jcd)
3320 {
3321 DBG_CTX((stderr,"Found variable type=%s\n",qPrint(vmd->typeString())));
3322 const ClassDef *mcd=stripClassName(yyscanner,vmd->typeString(),vmd->getOuterScope());
3323 if (mcd && mcd->isLinkable())
3324 {
3325 if (generateClassMemberLink(yyscanner,ol,mcd,memName)) return;
3326 }
3327 }
3328 }
3329 }
3330 }
3331 }
3332 if (vmn)
3333 {
3334 DBG_CTX((stderr,"There is a variable with name '%s'\n",qPrint(varName)));
3335 for (const auto &vmd : *vmn)
3336 {
3337 if (vmd->getClassDef()==vcd)
3338 {
3339 DBG_CTX((stderr,"Found variable type=%s\n",qPrint(vmd->typeString())));
3340 const ClassDef *mcd=stripClassName(yyscanner,vmd->typeString(),vmd->getOuterScope());
3341 if (mcd && mcd->isLinkable())
3342 {
3343 if (generateClassMemberLink(yyscanner,ol,mcd,memName)) return;
3344 }
3345 }
3346 }
3347 }
3348 }
3349 }
3350 // nothing found -> write result as is
3351 codifyLines(yyscanner,memName);
3352 addToSearchIndex(yyscanner,memName);
3353 return;
3354}
3355
3356static void generatePHPVariableLink(yyscan_t yyscanner,OutputCodeList &ol,const char *varName)
3357{
3358 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3359 QCString name(varName+7); // strip $this->
3360 name.prepend("$");
3361 DBG_CTX((stderr,"generatePHPVariableLink(%s) name=%s scope=%s\n",varName,qPrint(name),qPrint(yyextra->scopeName)));
3362 if (!getLink(yyscanner,yyextra->scopeName,name,ol,QCString(varName)))
3363 {
3364 codifyLines(yyscanner,varName);
3365 }
3366}
3367
3368static void generateFunctionLink(yyscan_t yyscanner,OutputCodeList &ol,const QCString &funcName)
3369{
3370 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3371 //CodeClassDef *ccd=nullptr;
3372 QCString locScope=yyextra->scopeName;
3373 QCString locFunc=removeRedundantWhiteSpace(funcName);
3374 if (yyextra->lang==SrcLangExt::PHP && locFunc.startsWith("self::")) locFunc=locFunc.mid(4);
3375 QCString funcScope;
3376 QCString funcWithScope=locFunc;
3377 QCString funcWithFullScope=locFunc;
3378 QCString fullScope=locScope;
3379 DBG_CTX((stderr,"*** locScope=%s locFunc=%s\n",qPrint(locScope),qPrint(locFunc)));
3380 int len=2;
3381 int i=locFunc.findRev("::");
3382 if (yyextra->currentMemberDef && yyextra->currentMemberDef->resolveAlias()->getClassDef() &&
3383 funcName==yyextra->currentMemberDef->localName() &&
3384 yyextra->currentMemberDef->getDefLine()==yyextra->yyLineNr &&
3385 generateClassMemberLink(yyscanner,ol,yyextra->currentMemberDef,funcName)
3386 )
3387 {
3388 // special case where funcName is the name of a method that is also
3389 // defined on this line. In this case we can directly link to
3390 // yyextra->currentMemberDef, which is not only faster, but
3391 // in case of overloaded methods, this will make sure that we link to
3392 // the correct method, and thereby get the correct reimplemented relations.
3393 // See also bug 549022.
3394 goto exit;
3395 }
3396 if (i==-1) i=locFunc.findRev("."),len=1;
3397 if (i==-1) i=locFunc.findRev("\\"),len=1; // for PHP
3398 if (i>0)
3399 {
3400 funcScope=locFunc.left(i);
3401 locFunc=locFunc.right(locFunc.length()-i-len).stripWhiteSpace();
3402 int ts=locScope.find('<'); // start of template
3403 int te=locScope.findRev('>'); // end of template
3404 DBG_CTX((stderr,"ts=%d te=%d\n",ts,te));
3405 if (ts!=-1 && te!=-1 && te>ts)
3406 {
3407 // remove template from scope
3408 locScope=locScope.left(ts)+locScope.right(locScope.length()-te-1);
3409 }
3410 ts=funcScope.find('<'); // start of template
3411 te=funcScope.findRev('>'); // end of template
3412 DBG_CTX((stderr,"ts=%d te=%d\n",ts,te));
3413 if (ts!=-1 && te!=-1 && te>ts)
3414 {
3415 // remove template from scope
3416 funcScope=funcScope.left(ts)+funcScope.right(funcScope.length()-te-1);
3417 }
3418 if (!funcScope.isEmpty())
3419 {
3420 funcWithScope = funcScope+"::"+locFunc;
3421 if (!locScope.isEmpty())
3422 {
3423 fullScope=locScope+"::"+funcScope;
3424 }
3425 }
3426 if (!locScope.isEmpty())
3427 {
3428 funcWithFullScope = locScope+"::"+funcWithScope;
3429 }
3430 }
3431
3432 if (!fullScope.isEmpty())
3433 {
3434 auto it = yyextra->codeClassMap.find(fullScope.str());
3435 if (it!=yyextra->codeClassMap.end())
3436 {
3437 ScopedTypeVariant ccd = it->second;
3438 if (ccd.localDef() && !ccd.localDef()->baseClasses().empty())
3439 {
3440 for (const auto &bcName : ccd.localDef()->baseClasses())
3441 {
3442 if (getLink(yyscanner,bcName,locFunc,ol,funcName))
3443 {
3444 goto exit;
3445 }
3446 }
3447 }
3448 }
3449 }
3450
3451 if (!locScope.isEmpty() && fullScope!=locScope)
3452 {
3453 auto it = yyextra->codeClassMap.find(locScope.str());
3454 if (it!=yyextra->codeClassMap.end())
3455 {
3456 ScopedTypeVariant ccd = it->second;
3457 if (ccd.localDef() && !ccd.localDef()->baseClasses().empty())
3458 {
3459 for (const auto &bcName : ccd.localDef()->baseClasses())
3460 {
3461 if (getLink(yyscanner,bcName,funcWithScope,ol,funcName))
3462 {
3463 goto exit;
3464 }
3465 }
3466 }
3467 }
3468 }
3469 if (!getLink(yyscanner,locScope,funcWithScope,ol,funcName))
3470 {
3471 generateClassOrGlobalLink(yyscanner,ol,funcName);
3472 }
3473exit:
3474 return;
3475}
3476
3477static void generateFunctionLink(yyscan_t yyscanner,OutputCodeList &ol,const char *funcName)
3478{
3479 generateFunctionLink(yyscanner,ol,QCString(funcName));
3480}
3481
3482/*! counts the number of lines in the input */
3483static int countLines(yyscan_t yyscanner)
3484{
3485 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3486 const char *p=yyextra->inputString;
3487 char c = 0;
3488 int count=1;
3489 while ((c=*p))
3490 {
3491 p++ ;
3492 if (c=='\n') count++;
3493 }
3494 if (p>yyextra->inputString && *(p-1)!='\n')
3495 { // last line does not end with a \n, so we add an extra
3496 count++;
3497 }
3498 return count;
3499}
3500
3501static void endFontClass(yyscan_t yyscanner,bool specialComment)
3502{
3503 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3504 if (yyextra->currentFontClass)
3505 {
3506 yyextra->code->endFontClass();
3507 yyextra->currentFontClass=nullptr;
3508 }
3509 if (specialComment && yyextra->insideSpecialComment)
3510 {
3511 yyextra->code->endSpecialComment();
3512 yyextra->insideSpecialComment = false;
3513 }
3514}
3515
3516static void startFontClass(yyscan_t yyscanner,const char *s,bool specialComment)
3517{
3518 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3519 endFontClass(yyscanner);
3520 if (specialComment)
3521 {
3522 yyextra->code->startSpecialComment();
3523 yyextra->insideSpecialComment = true;
3524 }
3525 yyextra->code->startFontClass(QCString(s));
3526 yyextra->currentFontClass=s;
3527}
3528
3529//----------------------------------------------------------------------------
3530
3531// recursively writes a linkified Objective-C method call
3532static void writeObjCMethodCall(yyscan_t yyscanner,ObjCCallCtx *ctx)
3533{
3534 if (ctx==nullptr) return;
3535 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3536 char c = 0;
3537 if (!ctx->methodName.isEmpty())
3538 {
3539 DBG_CTX((stderr,"writeObjCMethodCall(%s) obj=%s method=%s\n",
3541 if (!ctx->objectTypeOrName.isEmpty() && ctx->objectTypeOrName.at(0)!='$')
3542 {
3543 DBG_CTX((stderr,"Looking for object=%s method=%s\n",qPrint(ctx->objectTypeOrName),
3544 qPrint(ctx->methodName)));
3545 const ScopedTypeVariant *stv = yyextra->theVarContext.findVariable(ctx->objectTypeOrName);
3546 if (stv!=nullptr) // local variable
3547 {
3548 DBG_CTX((stderr," object is local variable\n"));
3549 if (stv->globalDef() && !ctx->methodName.isEmpty())
3550 {
3551 const ClassDef *cd = toClassDef(stv->globalDef());
3552 if (cd)
3553 {
3554 ctx->method = cd->getMemberByName(ctx->methodName);
3555 }
3556 DBG_CTX((stderr," class=%p method=%p\n",(void*)cd,(void*)ctx->method));
3557 }
3558 }
3559 }
3560 }
3561
3562 DBG_CTX((stderr,"["));
3563 if (!ctx->format.isEmpty())
3564 {
3565 const char *p = ctx->format.data();
3566 bool skip = false;
3567 char skipChar = ' ';
3568 while ((c=*p++)) // for each character in ctx->format
3569 {
3570 if (skip)
3571 {
3572 char s[2];
3573 s[0]=c;s[1]=0;
3574 codifyLines(yyscanner,s);
3575 if (c==skipChar)
3576 {
3577 skip = false;
3578 skipChar = ' ';
3579 }
3580 else if (c=='\\')
3581 {
3582 c = *p++;
3583 s[0]=c;
3584 codifyLines(yyscanner,s);
3585 }
3586 }
3587 else if (c=='$')
3588 {
3589 char nc=*p++;
3590 if (nc=='$') // escaped $
3591 {
3592 yyextra->code->codify("$");
3593 }
3594 else // name fragment or reference to a nested call
3595 {
3596 if (nc=='n') // name fragment
3597 {
3598 nc=*p++;
3599 QCString refIdStr;
3600 while (nc!=0 && isdigit(nc)) { refIdStr+=nc; nc=*p++; }
3601 p--;
3602 int refId=refIdStr.toInt();
3603 auto it = yyextra->nameMap.find(refId);
3604 if (it!=yyextra->nameMap.end())
3605 {
3606 QCString name = it->second;
3607 if (ctx->method && ctx->method->isLinkable())
3608 {
3609 writeMultiLineCodeLink(yyscanner,*yyextra->code,ctx->method,name);
3610 if (yyextra->currentMemberDef && yyextra->collectXRefs)
3611 {
3612 addDocCrossReference(yyextra->currentMemberDef,ctx->method);
3613 }
3614 }
3615 else
3616 {
3617 codifyLines(yyscanner,name);
3618 }
3619 }
3620 else
3621 {
3622 DBG_CTX((stderr,"Invalid name: id=%d\n",refId));
3623 }
3624 }
3625 else if (nc=='o') // reference to potential object name, e.g. 'self', or 'self.var1' or 'self.var1.var2'
3626 {
3627 nc=*p++;
3628 QCString refIdStr;
3629 while (nc!=0 && isdigit(nc)) { refIdStr+=nc; nc=*p++; }
3630 p--;
3631 int refId=refIdStr.toInt();
3632 auto it = yyextra->objectMap.find(refId);
3633 if (it!=yyextra->objectMap.end())
3634 {
3635 QCString object = it->second;
3636 if (object=="self")
3637 {
3638 if (yyextra->currentDefinition &&
3639 yyextra->currentDefinition->definitionType()==Definition::TypeClass)
3640 {
3641 ctx->objectType = toClassDef(yyextra->currentDefinition);
3642 if (ctx->objectType->categoryOf())
3643 {
3644 ctx->objectType = ctx->objectType->categoryOf();
3645 }
3646 if (ctx->objectType && !ctx->methodName.isEmpty())
3647 {
3648 ctx->method = ctx->objectType->getMemberByName(ctx->methodName);
3649 }
3650 }
3651 startFontClass(yyscanner,"keyword");
3652 codifyLines(yyscanner,object);
3653 endFontClass(yyscanner);
3654 }
3655 else if (object=="super")
3656 {
3657 if (yyextra->currentDefinition &&
3658 yyextra->currentDefinition->definitionType()==Definition::TypeClass)
3659 {
3660 const ClassDef *cd = toClassDef(yyextra->currentDefinition);
3661 if (cd->categoryOf())
3662 {
3663 cd = cd->categoryOf();
3664 }
3665 for (const auto &bclass : cd->baseClasses())
3666 {
3667 if (bclass.classDef->compoundType()!=ClassDef::Protocol)
3668 {
3669 ctx->objectType = bclass.classDef;
3670 if (ctx->objectType && !ctx->methodName.isEmpty())
3671 {
3672 ctx->method = ctx->objectType->getMemberByName(ctx->methodName);
3673 }
3674 }
3675 }
3676 }
3677 startFontClass(yyscanner,"keyword");
3678 codifyLines(yyscanner,object);
3679 endFontClass(yyscanner);
3680 }
3681 else if (ctx->objectVar && ctx->objectVar->isLinkable()) // object is class variable
3682 {
3683 writeMultiLineCodeLink(yyscanner,*yyextra->code,ctx->objectVar,object);
3684 if (yyextra->currentMemberDef && yyextra->collectXRefs)
3685 {
3686 addDocCrossReference(yyextra->currentMemberDef,ctx->objectVar);
3687 }
3688 }
3689 else if (ctx->objectType && ctx->objectType->isLinkable()) // object is class name
3690 {
3691 const ClassDef *cd = ctx->objectType;
3692 writeMultiLineCodeLink(yyscanner,*yyextra->code,cd,object);
3693 }
3694 else // object still needs to be resolved
3695 {
3696 int pp=0;
3697 int dotPos=object.find('.',pp);
3698 int len = static_cast<int>(object.length());
3699 if (dotPos==-1) dotPos=len;
3700 const Definition *scope = yyextra->currentDefinition;
3701 //printf("initial scope=%s\n",scope?qPrint(scope->name()):"none");
3702 for (;;)
3703 {
3704 QCString fragment = object.mid(pp,dotPos-pp);
3705 QCString fragmentStripped = fragment.stripWhiteSpace();
3706 //printf("fragment=%s\n",qPrint(fragment));
3707 if (fragmentStripped=="self")
3708 {
3709 if (scope && scope->definitionType()==Definition::TypeClass)
3710 {
3711 scope = ctx->objectType = toClassDef(scope);
3712 }
3713 //printf("self scope=%s\n",scope?qPrint(scope->name()):"none");
3714 startFontClass(yyscanner,"keyword");
3715 codifyLines(yyscanner,fragment);
3716 endFontClass(yyscanner);
3717 }
3718 else
3719 {
3720 const Definition *symbol = yyextra->symbolResolver.resolveSymbol(scope,fragmentStripped,QCString(),false,true);
3721 //printf("scope=%s name=%s -> symbol=%s\n",scope?qPrint(scope->name()):"none",qPrint(fragment),
3722 // symbol?qPrint(symbol->name()):"none");
3723 if (symbol && symbol->definitionType()==Definition::TypeClass)
3724 {
3725 scope = ctx->objectType = toClassDef(symbol);
3726 ctx->method = yyextra->symbolResolver.getTypedef();
3727 }
3728 else if (symbol && symbol->definitionType()==Definition::TypeMember)
3729 {
3730 scope = ctx->objectType = stripClassName(yyscanner,toMemberDef(symbol)->typeString(),scope);
3731 }
3732 if (scope && scope!=Doxygen::globalScope)
3733 {
3734 writeMultiLineCodeLink(yyscanner,*yyextra->code,scope,fragment);
3735 }
3736 else
3737 {
3738 codifyLines(yyscanner,fragment);
3739 }
3740 //printf("new scope=%s\n",scope?qPrint(scope->name()):"none");
3741 }
3742 if (dotPos==len)
3743 {
3744 break;
3745 }
3746 else // find next fragment
3747 {
3748 codifyLines(yyscanner,".");
3749 pp=dotPos+1;
3750 dotPos=object.find('.',pp);
3751 if (dotPos==-1) dotPos=len;
3752 }
3753 }
3754 DBG_CTX((stderr," object is class? %p\n",(void*)ctx->objectType));
3755 if (ctx->objectType) // found class
3756 {
3757 ctx->method = ctx->objectType->getMemberByName(ctx->methodName);
3758 DBG_CTX((stderr," yes->method=%s\n",ctx->method?qPrint(ctx->method->name()):"<none>"));
3759 }
3760 else if (ctx->method==nullptr) // search for class variable with the same name
3761 {
3762 DBG_CTX((stderr," no\n"));
3763 DBG_CTX((stderr,"yyextra->currentDefinition=%p\n",(void*)yyextra->currentDefinition));
3764 if (yyextra->currentDefinition &&
3765 yyextra->currentDefinition->definitionType()==Definition::TypeClass)
3766 {
3767 ctx->objectVar = (toClassDef(yyextra->currentDefinition))->getMemberByName(ctx->objectTypeOrName);
3768 DBG_CTX((stderr," ctx->objectVar=%p\n",(void*)ctx->objectVar));
3769 if (ctx->objectVar)
3770 {
3771 ctx->objectType = stripClassName(yyscanner,ctx->objectVar->typeString(),yyextra->currentDefinition);
3772 DBG_CTX((stderr," ctx->objectType=%p\n",(void*)ctx->objectType));
3773 if (ctx->objectType && !ctx->methodName.isEmpty())
3774 {
3775 ctx->method = ctx->objectType->getMemberByName(ctx->methodName);
3776 DBG_CTX((stderr," ctx->method=%p\n",(void*)ctx->method));
3777 }
3778 }
3779 }
3780 }
3781 }
3782 }
3783 else
3784 {
3785 DBG_CTX((stderr,"Invalid object: id=%d\n",refId));
3786 }
3787 }
3788 else if (nc=='c') // reference to nested call
3789 {
3790 nc=*p++;
3791 QCString refIdStr;
3792 while (nc!=0 && isdigit(nc)) { refIdStr+=nc; nc=*p++; }
3793 p--;
3794 int refId=refIdStr.toInt();
3795 auto it = yyextra->contextMap.find(refId);
3796 if (it!=yyextra->contextMap.end()) // recurse into nested call
3797 {
3798 ObjCCallCtx *ictx = it->second.get();
3799 writeObjCMethodCall(yyscanner,ictx);
3800 if (ictx->method) // link to nested call successfully
3801 {
3802 // get the ClassDef representing the method's return type
3803 if (QCString(ictx->method->typeString())=="id")
3804 {
3805 // see if the method name is unique, if so we link to it
3807 //printf("mn->count=%d ictx->method=%s ctx->methodName=%s\n",
3808 // mn==0?-1:(int)mn->count(),
3809 // qPrint(ictx->method->name()),
3810 // qPrint(ctx->methodName));
3811 if (mn && mn->size()==1) // member name unique
3812 {
3813 ctx->method = mn->front().get();
3814 }
3815 }
3816 else
3817 {
3818 ctx->objectType = stripClassName(yyscanner,ictx->method->typeString(),yyextra->currentDefinition);
3819 if (ctx->objectType && !ctx->methodName.isEmpty())
3820 {
3821 ctx->method = ctx->objectType->getMemberByName(ctx->methodName);
3822 }
3823 }
3824 DBG_CTX((stderr," ***** method=%s -> object=%p\n",qPrint(ictx->method->name()),(void*)ctx->objectType));
3825 }
3826 }
3827 else
3828 {
3829 DBG_CTX((stderr,"Invalid context: id=%d\n",refId));
3830 }
3831 }
3832 else if (nc=='w') // some word
3833 {
3834 nc=*p++;
3835 QCString refIdStr;
3836 while (nc!=0 && isdigit(nc)) { refIdStr+=nc; nc=*p++; }
3837 p--;
3838 int refId=refIdStr.toInt();
3839 auto it = yyextra->wordMap.find(refId);
3840 if (it!=yyextra->wordMap.end())
3841 {
3842 QCString word = it->second;
3843 bool isKeyword = word=="self";
3844 if (isKeyword)
3845 {
3846 startFontClass(yyscanner,"keyword");
3847 }
3848 codifyLines(yyscanner,word);
3849 if (isKeyword)
3850 {
3851 endFontClass(yyscanner);
3852 }
3853 }
3854 }
3855 else if (nc=='d') // comment block
3856 {
3857 nc=*p++;
3858 QCString refIdStr;
3859 while (nc!=0 && isdigit(nc)) { refIdStr+=nc; nc=*p++; }
3860 p--;
3861 int refId=refIdStr.toInt();
3862 auto it = yyextra->commentMap.find(refId);
3863 if (it!=yyextra->commentMap.end())
3864 {
3865 QCString comment = it->second;
3866 startFontClass(yyscanner,"comment");
3867 codifyLines(yyscanner,comment);
3868 endFontClass(yyscanner);
3869 }
3870 }
3871 else // illegal marker
3872 {
3873 ASSERT(0); // "invalid escape sequence"
3874 }
3875 }
3876 }
3877 else if (c=='\'' || c == '"')
3878 {
3879 char s[2];
3880 s[0]=c;s[1]=0;
3881 codifyLines(yyscanner,s);
3882 skip = true;
3883 skipChar = c;
3884 }
3885 else // normal non-marker character
3886 {
3887 char s[2];
3888 s[0]=c;s[1]=0;
3889 codifyLines(yyscanner,s);
3890 }
3891 }
3892 }
3893 DBG_CTX((stderr,"%s %s]\n",qPrint(ctx->objectTypeOrName),qPrint(ctx->methodName)));
3894 DBG_CTX((stderr,"}=(type='%s',name='%s')",
3896 qPrint(ctx->methodName)));
3897}
3898
3899// Replaces an Objective-C method name fragment s by a marker of the form
3900// $n12, the number (12) can later be used as a key for obtaining the name
3901// fragment, from yyextra->nameMap
3902static QCString escapeName(yyscan_t yyscanner,const char *s)
3903{
3904 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3905 QCString result;
3906 result.sprintf("$n%d",yyextra->currentNameId);
3907 yyextra->nameMap.emplace(yyextra->currentNameId,s);
3908 yyextra->currentNameId++;
3909 return result;
3910}
3911
3912static QCString escapeObject(yyscan_t yyscanner,const char *s)
3913{
3914 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3915 QCString result;
3916 result.sprintf("$o%d",yyextra->currentObjId);
3917 yyextra->objectMap.emplace(yyextra->currentObjId,s);
3918 yyextra->currentObjId++;
3919 return result;
3920}
3921
3922static QCString escapeWord(yyscan_t yyscanner,const char *s)
3923{
3924 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3925 QCString result;
3926 result.sprintf("$w%d",yyextra->currentWordId);
3927 yyextra->wordMap.emplace(yyextra->currentWordId,s);
3928 yyextra->currentWordId++;
3929 return result;
3930}
3931
3932static QCString escapeComment(yyscan_t yyscanner,const char *s)
3933{
3934 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3935 QCString result;
3936 result.sprintf("$d%d",yyextra->currentCommentId);
3937 yyextra->commentMap.emplace(yyextra->currentCommentId,s);
3938 yyextra->currentCommentId++;
3939 return result;
3940}
3941
3942static bool skipLanguageSpecificKeyword(yyscan_t yyscanner,const char *keyword)
3943{
3944 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3945 static const std::unordered_set<std::string> non_cpp_keywords = {
3946 "__assume", "__super", "abstract", "function",
3947 "gcnew", "gcroot", "generic", "get",
3948 "internal", "null", "pin_ptr", "raise",
3949 "remove", "self", "set", "transient",
3950 "sealed"
3951 };
3952 static const std::unordered_set<std::string> non_java_keywords = {
3953 "alignas", "alignof", "and", "and_eq", "asm",
3954 "atomic_cancel", "atomic_commit", "atomic_noexcept", "auto", "bitand",
3955 "bitor", "bool", "char8_t", "char16_t", "char32_t",
3956 "compl", "concept", "consteval", "constexpr", "constinit",
3957 "const_cast", "co_await", "co_return", "co_yield", "decltype",
3958 "delete", "dynamic_cast", "explicit", "export", "extern",
3959 "friend", "inline", "mutable", "namespace", "noexcept",
3960 "not", "not_eq", "nullptr", "operator", "or",
3961 "or_eq", "reflexpr", "register", "reinterpret_cast", "requires",
3962 "signed", "sizeof", "static_assert", "_Static_assert", "static_cast", "struct",
3963 "template", "thread_local", "typedef", "typeid", "typename",
3964 "union", "unsigned", "using", "virtual", "wchar_t",
3965 "xor", "xor_eq", "override", "sealed"
3966 };
3967 bool retval = false;
3968 switch (yyextra->lang)
3969 {
3970 case SrcLangExt::Cpp:
3971 retval = (non_cpp_keywords.find(keyword) != non_cpp_keywords.end());
3972 break;
3973 case SrcLangExt::Java:
3974 retval = (non_java_keywords.find(keyword) != non_java_keywords.end());
3975 break;
3976 default:
3977 retval = false;
3978 break;
3979 }
3980 return retval;
3981}
3982
3983static bool isCastKeyword(const char *keyword)
3984{
3985 QCString s(keyword);
3986 int i=s.find('<');
3987 if (i==-1) return FALSE;
3988 QCString kw = s.left(i).stripWhiteSpace();
3989 return kw=="const_cast" || kw=="static_cast" || kw=="dynamic_cast" || kw=="reinterpret_cast";
3990}
3991
3992static int yyread(yyscan_t yyscanner,char *buf,int max_size)
3993{
3994 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3995 yy_size_t inputPosition = yyextra->inputPosition;
3996 const char *s = yyextra->inputString + inputPosition;
3997 int c=0;
3998 while( c < max_size && *s )
3999 {
4000 *buf++ = *s++;
4001 c++;
4002 }
4003 yyextra->inputPosition += c;
4004 return c;
4005}
4006
4007
4008static void saveObjCContext(yyscan_t yyscanner)
4009{
4010 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
4011 if (yyextra->currentCtx)
4012 {
4013 yyextra->currentCtx->format+=QCString().sprintf("$c%d",yyextra->currentCtxId);
4014 if (yyextra->braceCount==0 && YY_START==ObjCCall)
4015 {
4016 yyextra->currentCtx->objectTypeOrName=yyextra->currentCtx->format.mid(1);
4017 DBG_CTX((stderr,"new type=%s\n",qPrint(yyextra->currentCtx->objectTypeOrName)));
4018 }
4019 yyextra->contextStack.push(yyextra->currentCtx);
4020 }
4021 else
4022 {
4023 DBG_CTX((stderr,"Trying to save NULL context!\n"));
4024 }
4025 auto newCtx = std::make_unique<ObjCCallCtx>();
4026 newCtx->id = yyextra->currentCtxId;
4027 newCtx->lexState = YY_START;
4028 newCtx->braceCount = yyextra->braceCount;
4029 newCtx->objectType = nullptr;
4030 newCtx->objectVar = nullptr;
4031 newCtx->method = nullptr;
4032 DBG_CTX((stderr,"save state=%d\n",YY_START));
4033 yyextra->currentCtx = newCtx.get();
4034 yyextra->contextMap.emplace(yyextra->currentCtxId,std::move(newCtx));
4035 yyextra->braceCount = 0;
4036 yyextra->currentCtxId++;
4037}
4038
4039static void restoreObjCContext(yyscan_t yyscanner)
4040{
4041 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
4042 DBG_CTX((stderr,"restore state=%d->%d\n",YY_START,yyextra->currentCtx->lexState));
4043 BEGIN(yyextra->currentCtx->lexState);
4044 yyextra->braceCount = yyextra->currentCtx->braceCount;
4045 if (!yyextra->contextStack.empty())
4046 {
4047 yyextra->currentCtx = yyextra->contextStack.top();
4048 yyextra->contextStack.pop();
4049 }
4050 else
4051 {
4052 yyextra->currentCtx = nullptr;
4053 DBG_CTX((stderr,"Trying to pop context while yyextra->contextStack is empty!\n"));
4054 }
4055}
4056
4062
4064{
4065 codeYYlex_init_extra(&p->state,&p->yyscanner);
4066#ifdef FLEX_DEBUG
4067 codeYYset_debug(Debug::isFlagSet(Debug::Lex_code)?1:0,p->yyscanner);
4068#endif
4070}
4071
4073{
4074 codeYYlex_destroy(p->yyscanner);
4075}
4076
4078{
4079 struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
4080 DBG_CTX((stderr,"***CodeParser::reset()\n"));
4081 yyextra->theVarContext.clear();
4082 while (!yyextra->scopeNameLengthStack.empty()) yyextra->scopeNameLengthStack.pop_back();
4083 yyextra->codeClassMap.clear();
4084 yyextra->curClassBases.clear();
4085 yyextra->anchorCount = 0;
4086 yyextra->insideCodeLine = false;
4087}
4088
4090{
4091 struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
4092 yyextra->insideCodeLine = inp;
4093}
4094
4096{
4097 struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
4098 return yyextra->insideCodeLine;
4099}
4100
4102 SrcLangExt lang,bool stripCodeComments,bool exBlock,const QCString &exName,const FileDef *fd,
4103 int startLine,int endLine,bool inlineFragment,
4104 const MemberDef *memberDef,bool showLineNumbers,const Definition *searchCtx,
4105 bool collectXRefs)
4106{
4107 yyscan_t yyscanner = p->yyscanner;
4108 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
4109 DBG_CTX((stderr,"***parseCode() exBlock=%d exName=%s fd=%p scopeName=%s searchCtx=%s\n",
4110 exBlock,qPrint(exName),(void*)fd,qPrint(scopeName),searchCtx?qPrint(searchCtx->name()):"<none>"));
4111
4112 if (s.isEmpty()) return;
4113
4114 DebugLex debugLex(Debug::Lex_code, __FILE__, fd ? qPrint(fd->fileName()): !exName.isEmpty() ? qPrint(exName) : nullptr);
4115
4116 od.stripCodeComments(stripCodeComments);
4117 yyextra->code = &od;
4118 yyextra->inputString = s.data();
4119 yyextra->fileName = fd ? fd->fileName():"";
4120 yyextra->absFileName = fd ? fd->absFilePath():"";
4121 yyextra->inputPosition = 0;
4122 codeYYrestart(nullptr,yyscanner);
4123 yyextra->currentFontClass = nullptr;
4124 yyextra->searchCtx = searchCtx;
4125 yyextra->collectXRefs = collectXRefs;
4126 yyextra->inFunctionTryBlock = FALSE;
4127 yyextra->symbolResolver.setFileScope(fd);
4128 yyextra->foldStack.clear();
4129 yyextra->insideSpecialComment = false;
4130
4131 if (startLine!=-1)
4132 yyextra->yyLineNr = startLine;
4133 else
4134 yyextra->yyLineNr = 1;
4135
4136 if (endLine!=-1)
4137 yyextra->inputLines = endLine+1;
4138 else
4139 yyextra->inputLines = yyextra->yyLineNr + countLines(yyscanner) - 1;
4140
4141 yyextra->curlyCount = 0;
4142 yyextra->bodyCurlyCount = 0;
4143 yyextra->bracketCount = 0;
4144 yyextra->sharpCount = 0;
4145 yyextra->insideTemplate = FALSE;
4146 yyextra->theCallContext.clear();
4147 while (!yyextra->scopeStack.empty()) yyextra->scopeStack.pop();
4148 yyextra->scopeName = scopeName;
4149 DBG_CTX((stderr,"parseCCode %s\n",qPrint(scopeName)));
4150 yyextra->exampleBlock = exBlock;
4151 yyextra->exampleName = exName;
4152 yyextra->sourceFileDef = fd;
4153 yyextra->lineNumbers = fd && showLineNumbers;
4154 if (fd==nullptr)
4155 {
4156 // create a dummy filedef for the example
4157 yyextra->exampleFileDef = createFileDef(QCString(),(!exName.isEmpty()?exName:"generated"));
4158 yyextra->sourceFileDef = yyextra->exampleFileDef.get();
4159 }
4160 yyextra->lang = lang;
4161 yyextra->insideObjC = lang==SrcLangExt::ObjC;
4162 if (yyextra->sourceFileDef)
4163 {
4164 setCurrentDoc(yyscanner,"l00001");
4165 }
4166 yyextra->currentDefinition = searchCtx ? searchCtx : getResolvedNamespace(scopeName);
4167 yyextra->currentMemberDef = nullptr;
4168 yyextra->searchingForBody = exBlock;
4169 yyextra->insideBody = FALSE;
4170 yyextra->bracketCount = 0;
4171 if (!yyextra->exampleName.isEmpty())
4172 {
4173 yyextra->exampleFile = convertNameToFile(yyextra->exampleName+"-example",FALSE,TRUE);
4174 DBG_CTX((stderr,"yyextra->exampleFile=%s\n",qPrint(yyextra->exampleFile)));
4175 }
4176 yyextra->includeCodeFragment = inlineFragment;
4177 DBG_CTX((stderr,"** exBlock=%d exName=%s include=%d\n",exBlock,qPrint(exName),inlineFragment));
4178 if (!yyextra->insideCodeLine)
4179 {
4180 startCodeLine(yyscanner);
4181 }
4182 yyextra->type.clear();
4183 yyextra->name.clear();
4184 yyextra->args.clear();
4185 yyextra->parmName.clear();
4186 yyextra->parmType.clear();
4187 if (memberDef) setParameterList(yyscanner,memberDef);
4188 BEGIN( Body );
4189 codeYYlex(yyscanner);
4190 yyextra->lexInit=TRUE;
4191 if (yyextra->insideCodeLine)
4192 {
4193 endCodeLine(yyscanner);
4194 }
4195 if (Config_getBool(HTML_CODE_FOLDING))
4196 {
4197 while (!yyextra->foldStack.empty())
4198 {
4199 yyextra->code->endFold();
4200 yyextra->foldStack.pop_back();
4201 }
4202 }
4203 if (yyextra->exampleFileDef)
4204 {
4205 // delete the temporary file definition used for this example
4206 yyextra->exampleFileDef.reset();
4207 yyextra->sourceFileDef=nullptr;
4208 }
4209 // write the tooltips
4210 yyextra->tooltipManager.writeTooltips(od);
4211}
4212
4213#include "code.l.h"
void parseCode(OutputCodeList &codeOutIntf, const QCString &scopeName, const QCString &input, SrcLangExt lang, bool stripCodeComments, bool isExampleBlock, const QCString &exampleName=QCString(), const FileDef *fileDef=nullptr, int startLine=-1, int endLine=-1, bool inlineFragment=FALSE, const MemberDef *memberDef=nullptr, bool showLineNumbers=TRUE, const Definition *searchCtx=nullptr, bool collectXRefs=TRUE) override
Parses a source file or fragment with the goal to produce highlighted and cross-referenced output.
Definition code.l:4101
void resetCodeParserState() override
Resets the state of the code parser.
Definition code.l:4077
CCodeParser()
Definition code.l:4063
void setInsideCodeLine(bool inp)
Definition code.l:4089
~CCodeParser() override
Definition code.l:4072
std::unique_ptr< Private > p
Definition code.h:56
bool insideCodeLine() const
Definition code.l:4095
virtual const BaseClassList & baseClasses() const =0
Returns the list of base classes from which this class directly inherits.
virtual const MemberDef * getMemberByName(const QCString &) const =0
Returns the member with the given name.
virtual ClassDef * categoryOf() const =0
Returns the class of which this is a category (Objective-C only)
virtual FileDef * getFileDef() const =0
Returns the namespace this compound is in, or 0 if it has a global scope.
virtual bool addExample(const QCString &anchor, const QCString &name, const QCString &file)=0
@ Lex_code
Definition debug.h:52
static bool isFlagSet(const DebugMask mask)
Definition debug.cpp:132
virtual int getEndBodyLine() const =0
virtual DefType definitionType() const =0
virtual QCString anchor() const =0
virtual QCString briefDescriptionAsTooltip() const =0
virtual bool isLinkableInProject() const =0
virtual const Definition * findInnerCompound(const QCString &name) const =0
virtual int getStartDefLine() const =0
virtual QCString getReference() const =0
virtual QCString qualifiedName() const =0
virtual CodeSymbolType codeSymbolType() const =0
virtual QCString getOutputFileBase() const =0
virtual Definition * getOuterScope() const =0
static NamespaceLinkedMap * namespaceLinkedMap
Definition doxygen.h:115
static MemberNameLinkedMap * functionNameLinkedMap
Definition doxygen.h:112
static std::mutex countFlowKeywordsMutex
Definition doxygen.h:141
static MemberNameLinkedMap * memberNameLinkedMap
Definition doxygen.h:111
static SearchIndexIntf searchIndex
Definition doxygen.h:124
static std::mutex addExampleMutex
Definition doxygen.h:142
virtual const LinkedRefMap< NamespaceDef > & getUsedNamespaces() const =0
virtual QCString fileName() const =0
std::vector< QCString > baseClasses() const
virtual QCString typeString() const =0
virtual const ClassDef * getClassDef() const =0
virtual GroupDef * getGroupDef()=0
virtual const FileDef * getFileDef() const =0
virtual const ArgumentList & argumentList() const =0
virtual MemberDef * resolveAlias()=0
virtual bool isDefine() const =0
virtual bool isVariable() const =0
virtual QCString argsString() const =0
virtual bool isCallable() const =0
virtual void incrementFlowKeyWordCount()=0
virtual bool addExample(const QCString &anchor, const QCString &name, const QCString &file)=0
Ptr & front()
Definition membername.h:51
size_t size() const
Definition membername.h:48
An abstract interface of a namespace symbol.
virtual const MemberDef * getMemberByName(const QCString &) const =0
void writeCodeLink(CodeSymbolType type, const QCString &ref, const QCString &file, const QCString &anchor, const QCString &name, const QCString &tooltip)
Definition outputlist.h:249
void writeCodeAnchor(const QCString &name)
Definition outputlist.h:275
void stripCodeComments(bool b)
Definition outputlist.h:237
int toInt(bool *ok=nullptr, int base=10) const
Definition qcstring.cpp:249
size_t length() const
Returns the length of the string, not counting the 0-terminator.
Definition qcstring.h:153
bool startsWith(const char *s) const
Definition qcstring.h:492
char & at(size_t i)
Returns a reference to the character at index i.
Definition qcstring.h:578
bool isEmpty() const
Returns TRUE iff the string is empty.
Definition qcstring.h:150
const std::string & str() const
Definition qcstring.h:537
QCString simplifyWhiteSpace() const
return a copy of this string with leading and trailing whitespace removed and multiple whitespace cha...
Definition qcstring.cpp:185
QCString right(size_t len) const
Definition qcstring.h:219
QCString & sprintf(const char *format,...)
Definition qcstring.cpp:29
int findRev(char c, int index=-1, bool cs=TRUE) const
Definition qcstring.cpp:91
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string.
Definition qcstring.h:159
bool stripPrefix(const QCString &prefix)
Definition qcstring.h:198
void clear()
Definition qcstring.h:169
const Definition * globalDef() const
QCString name() const
ClassDefMutable * toClassDefMutable(Definition *d)
ClassDef * getClass(const QCString &n)
static void codeFolding(yyscan_t yyscanner, const Definition *d)
Definition code.l:2363
ConceptDef * getResolvedConcept(const Definition *d, const QCString &name)
constexpr DocNodeVariant * parent(DocNodeVariant *n)
returns the parent node of a given node n or nullptr if the node has no parent.
Definition docnode.h:1330
std::unique_ptr< FileDef > createFileDef(const QCString &p, const QCString &n, const QCString &ref, const QCString &dn)
Definition filedef.cpp:268
void addDocCrossReference(const MemberDef *s, const MemberDef *d)
MemberDefMutable * toMemberDefMutable(Definition *d)
MemberDef * toMemberDef(Definition *d)
NamespaceDef * getResolvedNamespace(const QCString &name)
NamespaceDef * toNamespaceDef(Definition *d)
#define ASSERT(x)
Definition qcstring.h:39
This class contains the information about the argument of a function or template.
Definition arguments.h:27
codeYY_state state
Definition code.l:4060
yyscan_t yyscanner
Definition code.l:4059
const FileDef * currentFile
Definition util.h:117
QCString scopeName
Definition util.h:113
bool insideCode
Definition util.h:119
const MemberDef * md
Definition util.h:125
bool found
Definition util.h:124
int extractClassNameFromType(const QCString &type, int &pos, QCString &name, QCString &templSpec, SrcLangExt lang)
Definition util.cpp:4731
bool leftScopeMatch(const QCString &scope, const QCString &name)
Definition util.cpp:893
QCString removeAnonymousScopes(const QCString &str)
Definition util.cpp:173
QCString convertNameToFile(const QCString &name, bool allowDots, bool allowUnderscore)
Definition util.cpp:4020
GetDefResult getDefs(const GetDefInput &input)
Definition util.cpp:2823
const char * comment