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