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