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