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