6 #include <clang-c/Index.h> 24 static uint g_currentLine=0;
25 static bool g_searchForBody=
FALSE;
44 enum DetectedLang { Detected_Cpp, Detected_ObjC, Detected_ObjCpp };
45 Private() : tu(0), tokens(0), numTokens(0), cursors(0),
46 ufs(0), sources(0), numFiles(0), fileMapping(257),
47 detectedLang(Detected_Cpp)
48 { fileMapping.setAutoDelete(
TRUE); }
49 int getCurrentTokenLine();
61 QDict<uint> fileMapping;
62 DetectedLang detectedLang;
73 const int maxIndent=1000000;
74 int minIndent=maxIndent;
82 int stop = tabSize - (col%tabSize);
85 while (stop--) out.
addChar(
' ');
101 if (((
uchar)c&0xE0)==0xE0 && i<size)
105 if (((
uchar)c&0xF0)==0xF0 && i<size)
110 if (col<minIndent) minIndent=col;
120 static void inclusionVisitor(CXFile includedFile,
123 CXClientData clientData)
125 QDict<void> *fileDict = (QDict<void> *)clientData;
126 CXString incFileName = clang_getFileName(includedFile);
128 fileDict->insert(clang_getCString(incFileName),(
void*)0x8);
129 clang_disposeString(incFileName);
139 QDict<void> incFound(257);
140 clang_getInclusions(
p->tu,
142 (CXClientData)&incFound
149 if (incFound.find(it2.
current()))
155 files=resultIncludes;
160 static bool clangAssistedParsing =
Config_getBool(
"CLANG_ASSISTED_PARSING");
163 if (!clangAssistedParsing)
return;
166 p->index = clang_createIndex(0, 0);
173 for (di.toFirst();di.current();++di,++argc)
176 argv[argc]=strdup(inc.
data());
183 argv[argc++]=strdup(inc.
data());
186 for (
uint i=0;i<clangOptions.
count();i++)
188 argv[argc++]=strdup(clangOptions.
at(i));
191 argv[argc++]=strdup(
"-ferror-limit=0");
192 argv[argc++]=strdup(
"-x");
199 if (lang==
SrcLangExt_ObjC ||
p->detectedLang!=ClangParser::Private::Detected_Cpp)
202 if (
p->detectedLang==ClangParser::Private::Detected_Cpp &&
206 p->detectedLang = ClangParser::Private::Detected_Cpp;
210 p->detectedLang = ClangParser::Private::Detected_ObjCpp;
214 p->detectedLang = ClangParser::Private::Detected_ObjC;
217 switch(
p->detectedLang)
219 case ClangParser::Private::Detected_Cpp:
220 argv[argc++]=strdup(
"c++");
222 case ClangParser::Private::Detected_ObjC:
223 argv[argc++]=strdup(
"objective-c");
225 case ClangParser::Private::Detected_ObjCpp:
226 argv[argc++]=strdup(
"objective-c++");
233 static bool filterSourceFiles =
Config_getBool(
"FILTER_SOURCE_FILES");
236 uint numUnsavedFiles = filesInTranslationUnit.
count()+1;
237 p->numFiles = numUnsavedFiles;
238 p->sources =
new QCString[numUnsavedFiles];
239 p->ufs =
new CXUnsavedFile[numUnsavedFiles];
242 p->ufs[0].Contents =
p->sources[0].data();
243 p->ufs[0].Length =
p->sources[0].length();
250 p->ufs[i].Filename = strdup(it.
current());
251 p->ufs[i].Contents =
p->sources[i].data();
252 p->ufs[i].Length =
p->sources[i].length();
256 p->tu = clang_parseTranslationUnit(
p->index, 0,
257 argv, argc,
p->ufs, numUnsavedFiles,
258 CXTranslationUnit_DetailedPreprocessingRecord);
260 for (
int i=0;i<argc;++i)
272 for (
uint i=0,
n=clang_getNumDiagnostics(
p->tu); i!=
n; ++i)
274 CXDiagnostic diag = clang_getDiagnostic(
p->tu, i);
275 CXString
string = clang_formatDiagnostic(diag,
276 clang_defaultDiagnosticDisplayOptions());
277 err(
"%s [clang]\n",clang_getCString(
string));
278 clang_disposeString(
string);
279 clang_disposeDiagnostic(diag);
285 CXSourceLocation fileBegin = clang_getLocationForOffset(
p->tu, f, 0);
286 CXSourceLocation fileEnd = clang_getLocationForOffset(
p->tu, f,
p->ufs[0].Length);
287 CXSourceRange fileRange = clang_getRange(fileBegin, fileEnd);
290 clang_tokenize(
p->tu,fileRange,&
p->tokens,&
p->numTokens);
293 p->cursors=
new CXCursor[
p->numTokens];
294 clang_annotateTokens(
p->tu,
p->tokens,
p->numTokens,
p->cursors);
301 err(
"clang: Failed to parse translation unit %s\n",
fileName);
310 clang_disposeTokens(
p->tu,
p->tokens,
p->numTokens);
316 CXFile
f = clang_getFile(
p->tu, fileName);
317 uint *pIndex=
p->fileMapping.find(fileName);
318 if (pIndex && *pIndex<p->numFiles)
322 CXSourceLocation fileBegin = clang_getLocationForOffset(
p->tu, f, 0);
323 CXSourceLocation fileEnd = clang_getLocationForOffset(
p->tu, f,
p->ufs[i].Length);
324 CXSourceRange fileRange = clang_getRange(fileBegin, fileEnd);
326 clang_tokenize(
p->tu,fileRange,&
p->tokens,&
p->numTokens);
327 p->cursors=
new CXCursor[
p->numTokens];
328 clang_annotateTokens(
p->tu,
p->tokens,
p->numTokens,
p->cursors);
335 err(
"clang: Failed to find input file %s in mapping\n",fileName);
342 static bool clangAssistedParsing =
Config_getBool(
"CLANG_ASSISTED_PARSING");
343 if (!clangAssistedParsing)
return;
348 clang_disposeTokens(
p->tu,
p->tokens,
p->numTokens);
349 clang_disposeTranslationUnit(
p->tu);
350 clang_disposeIndex(
p->index);
351 p->fileMapping.clear();
356 for (
uint i=0;i<
p->numFiles;i++)
358 free((
void *)
p->ufs[i].Filename);
368 int ClangParser::Private::getCurrentTokenLine()
371 if (numTokens==0)
return 1;
373 if (curToken>=numTokens) curToken=numTokens-1;
374 CXSourceLocation
start = clang_getTokenLocation(tu,tokens[curToken]);
375 clang_getSpellingLocation(start, 0, &l, &c, 0);
383 if (symbol==0)
return result;
384 static bool clangAssistedParsing =
Config_getBool(
"CLANG_ASSISTED_PARSING");
385 if (!clangAssistedParsing)
return result;
387 int sl = strlen(symbol);
388 uint l =
p->getCurrentTokenLine();
389 while (l>=
line &&
p->curToken>0)
394 l =
p->getCurrentTokenLine();
399 l =
p->getCurrentTokenLine();
403 while (l<=line && p->curToken<p->numTokens && !found)
405 CXString tokenString = clang_getTokenSpelling(
p->tu,
p->tokens[
p->curToken]);
410 const char *ts = clang_getCString(tokenString);
412 int startIndex =
p->curToken;
413 if (l==
line && strncmp(ts,symbol,tl)==0)
420 if (
p->curToken>=
p->numTokens)
424 l =
p->getCurrentTokenLine();
425 clang_disposeString(tokenString);
426 tokenString = clang_getTokenSpelling(
p->tu,
p->tokens[
p->curToken]);
427 ts = clang_getCString(tokenString);
428 tl = ts ? strlen(ts) : 0;
431 while (offset<sl && ((c=symbol[offset])==
' ' || c==
'\t' || c==
'\r' || c==
'\n'))
435 if (strncmp(ts,symbol+offset,tl)!=0)
445 CXCursor
c =
p->cursors[
p->curToken];
446 CXString usr = clang_getCursorUSR(c);
448 result = clang_getCString(usr);
449 clang_disposeString(usr);
454 p->curToken = startIndex;
457 clang_disposeString(tokenString);
459 if (
p->curToken<
p->numTokens)
461 l =
p->getCurrentTokenLine();
475 static QCString keywordToType(
const char *keyword)
478 static QDict<void> flowKeywords(47);
479 static QDict<void> typeKeywords(47);
482 flowKeywords.insert(
"break",(
void*)0x8);
483 flowKeywords.insert(
"case",(
void*)0x8);
484 flowKeywords.insert(
"catch",(
void*)0x8);
485 flowKeywords.insert(
"continue",(
void*)0x8);
486 flowKeywords.insert(
"default",(
void*)0x8);
487 flowKeywords.insert(
"do",(
void*)0x8);
488 flowKeywords.insert(
"else",(
void*)0x8);
489 flowKeywords.insert(
"finally",(
void*)0x8);
490 flowKeywords.insert(
"for",(
void*)0x8);
491 flowKeywords.insert(
"foreach",(
void*)0x8);
492 flowKeywords.insert(
"for each",(
void*)0x8);
493 flowKeywords.insert(
"goto",(
void*)0x8);
494 flowKeywords.insert(
"if",(
void*)0x8);
495 flowKeywords.insert(
"return",(
void*)0x8);
496 flowKeywords.insert(
"switch",(
void*)0x8);
497 flowKeywords.insert(
"throw",(
void*)0x8);
498 flowKeywords.insert(
"throws",(
void*)0x8);
499 flowKeywords.insert(
"try",(
void*)0x8);
500 flowKeywords.insert(
"while",(
void*)0x8);
501 flowKeywords.insert(
"@try",(
void*)0x8);
502 flowKeywords.insert(
"@catch",(
void*)0x8);
503 flowKeywords.insert(
"@finally",(
void*)0x8);
505 typeKeywords.insert(
"bool",(
void*)0x8);
506 typeKeywords.insert(
"char",(
void*)0x8);
507 typeKeywords.insert(
"double",(
void*)0x8);
508 typeKeywords.insert(
"float",(
void*)0x8);
509 typeKeywords.insert(
"int",(
void*)0x8);
510 typeKeywords.insert(
"long",(
void*)0x8);
511 typeKeywords.insert(
"object",(
void*)0x8);
512 typeKeywords.insert(
"short",(
void*)0x8);
513 typeKeywords.insert(
"signed",(
void*)0x8);
514 typeKeywords.insert(
"unsigned",(
void*)0x8);
515 typeKeywords.insert(
"void",(
void*)0x8);
516 typeKeywords.insert(
"wchar_t",(
void*)0x8);
517 typeKeywords.insert(
"size_t",(
void*)0x8);
518 typeKeywords.insert(
"boolean",(
void*)0x8);
519 typeKeywords.insert(
"id",(
void*)0x8);
520 typeKeywords.insert(
"SEL",(
void*)0x8);
521 typeKeywords.insert(
"string",(
void*)0x8);
522 typeKeywords.insert(
"nullptr",(
void*)0x8);
525 if (flowKeywords[keyword])
return "keywordflow";
526 if (typeKeywords[keyword])
return "keywordtype";
535 g_currentDefinition=
d;
540 if (g_currentMemberDef!=md)
542 g_searchForBody=
TRUE;
546 g_currentMemberDef=
md;
554 g_currentMemberDef=0;
570 lineAnchor.
sprintf(
"l%05d",line);
581 const char *
p=text,*sp=
p;
587 while ((c=*p++) && c!=
'\n') {
column++; }
591 int l = (
int)(p-sp-1);
593 char *
tmp = (
char*)malloc(l+1);
601 writeLineNumber(ol,fd,
line);
629 char *
p=(
char *)text;
634 while ((c=*p++) && c!=
'\n') {
column++; }
643 writeLineNumber(ol,fd,
line);
658 incName = incName.
mid(1,incName.
length()-2);
710 CXCursor
c =
p->cursors[tokenIndex];
711 CXCursor
r = clang_getCursorReferenced(c);
712 if (!clang_equalCursors(r, c))
716 CXCursor
t = clang_getSpecializedCursorTemplate(c);
717 if (!clang_Cursor_isNull(t) && !clang_equalCursors(t,c))
721 CXString usr = clang_getCursorUSR(c);
722 const char *usrStr = clang_getCString(usr);
740 (g_currentMemberDef!=d || g_currentLine<
line))
750 clang_disposeString(usr);
753 static void detectFunctionBody(
const char *s)
760 g_searchForBody=
FALSE;
763 else if (g_searchForBody &&
qstrcmp(s,
";")==0)
765 g_searchForBody=
FALSE;
787 g_currentDefinition=0;
788 g_currentMemberDef=0;
790 g_searchForBody=
FALSE;
797 writeLineNumber(ol,fd,line);
798 for (
unsigned int i=0;i<
p->numTokens;i++)
800 CXSourceLocation
start = clang_getTokenLocation(
p->tu,
p->tokens[i]);
802 clang_getSpellingLocation(start, 0, &l, &c, 0);
809 writeLineNumber(ol,fd,line);
812 CXString tokenString = clang_getTokenSpelling(
p->tu,
p->tokens[i]);
813 char const *s = clang_getCString(tokenString);
814 CXCursorKind cursorKind = clang_getCursorKind(
p->cursors[i]);
815 CXTokenKind tokenKind = clang_getTokenKind(
p->tokens[i]);
819 case CXToken_Keyword:
820 if (
strcmp(s,
"operator")==0)
827 cursorKind==CXCursor_PreprocessingDirective ?
"preprocessor" :
831 case CXToken_Literal:
832 if (cursorKind==CXCursor_InclusionDirective)
836 else if (s[0]==
'"' || s[0]==
'\'')
845 case CXToken_Comment:
849 if (tokenKind==CXToken_Punctuation)
851 detectFunctionBody(s);
856 case CXCursor_PreprocessingDirective:
859 case CXCursor_MacroDefinition:
862 case CXCursor_InclusionDirective:
865 case CXCursor_MacroExpansion:
869 if (tokenKind==CXToken_Identifier ||
870 (tokenKind==CXToken_Punctuation &&
871 (cursorKind==CXCursor_DeclRefExpr ||
872 cursorKind==CXCursor_MemberRefExpr ||
873 cursorKind==CXCursor_CallExpr ||
874 cursorKind==CXCursor_ObjCMessageExpr)
891 clang_disposeString(tokenString);
908 #else // use stubbed functionality in case libclang support is disabled. static MemberNameSDict * functionNameSDict
QCString fileToString(const char *name, bool filter, bool isSourceCode)
virtual bool isLinkable() const =0
void switchToFile(const char *fileName)
virtual QCString getReference() const
QCString getReference() const
virtual void writeLineNumber(const char *ref, const char *file, const char *anchor, int lineNumber)=0
MemberDef * getSourceMember(int lineNr) const
static int g_bracketCount
void start(const char *fileName, QStrList &filesInTranslationUnit)
virtual void endFontClass()=0
void determineInputFilesInSameTu(QStrList &filesInTranslationUnit)
virtual void startFontClass(const char *clsName)=0
#define Config_getList(val)
static FileNameDict * inputNameDict
static void writeMultiLineCodeLink(CodeOutputInterface &ol, Definition *d, const char *text)
virtual QCString getOutputFileBase() const =0
virtual void setCurrentDoc(Definition *context, const char *anchor, bool isSourceFile)=0
static QDict< void > inputPaths
#define Config_getInt(val)
static void codifyLines(const char *text)
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
virtual DefType definitionType() const =0
static SearchIndexIntf * searchIndex
virtual void writeCodeLink(const char *ref, const char *file, const char *anchor, const char *name, const char *tooltip)=0
QCString right(uint len) const
QCString lookup(uint line, const char *symbol)
Definition * getSourceDefinition(int lineNr) const
void linkIdentifier(CodeOutputInterface &ol, FileDef *fd, uint &line, uint &column, const char *text, int tokenIndex)
static MemberDef * g_currentMemberDef
virtual void addWord(const char *word, bool hiPriority)=0
void append(const type *d)
A bunch of utility functions.
const char * data() const
#define Config_getBool(val)
static QCString detab(const QCString &s, int &refIndent)
void err(const char *fmt,...)
static QDict< Definition > * clangUsrMap
QCString mid(uint index, uint len=0xffffffff) const
QCString getOutputFileBase() const
QCString & sprintf(const char *format,...)
virtual void codify(const char *s)=0
void addDocCrossReference(MemberDef *src, MemberDef *dst)
SrcLangExt getLanguageFromFileName(const QCString fileName)
int strcmp(const String &s1, const String &s2)
virtual void startCodeLine(bool hasLineNumbers)=0
void line(double t, double *p, double &x, double &y, double &z)
std::vector< std::string > column
void writeSources(CodeOutputInterface &ol, FileDef *fd)
void linkInclude(CodeOutputInterface &ol, FileDef *fd, uint &line, uint &column, const char *text)
QCString getOutputFileBase() const
Wrapper for to let libclang assisted parsing.
QCString briefDescriptionAsTooltip() const
static ClangParser * s_instance
static ClangParser * instance()
virtual void endCodeLine()=0
The QFileInfo class provides system-independent file information.
Q_EXPORT int qstrcmp(const char *str1, const char *str2)
T * find(const char *key)
void linkMacro(CodeOutputInterface &ol, FileDef *fd, uint &line, uint &column, const char *text)
virtual QCString anchor() const =0
bool isIncluded(const QCString &name) const
static Definition * g_currentDefinition