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