6 #include <clang-c/Index.h>
24 static uint g_currentLine=0;
25 static bool g_searchForBody=FALSE;
26 static bool g_insideBody=FALSE;
27 static uint g_bracketCount=0;
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;
65 static QCString
detab(
const QCString &s)
69 int size = s.length();
70 const char *data = s.data();
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
145 QStrList resultIncludes;
146 QStrListIterator it2(files);
147 for (it2.toFirst();it2.current();++it2)
149 if (incFound.find(it2.current()))
151 resultIncludes.append(it2.current());
155 files=resultIncludes;
160 static bool clangAssistedParsing =
Config_getBool(CLANG_ASSISTED_PARSING);
163 if (!clangAssistedParsing)
return;
165 p->fileName = fileName;
166 p->index = clang_createIndex(0, 0);
169 char **argv = (
char**)malloc(
sizeof(
char*)*(4+
Doxygen::inputPaths.count()+includePath.count()+clangOptions.count()));
173 for (di.toFirst();di.current();++di,++argc)
175 QCString inc = QCString(
"-I")+di.currentKey();
176 argv[argc]=strdup(inc.data());
180 for (uint i=0;i<includePath.count();i++)
182 QCString inc = QCString(
"-I")+includePath.at(i);
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)
201 QCString fn = fileName;
202 if (
p->detectedLang==ClangParser::Private::Detected_Cpp &&
203 (fn.right(4).lower()==
".cpp" || fn.right(4).lower()==
".cxx" ||
204 fn.right(3).lower()==
".cc" || fn.right(2).lower()==
".c"))
206 p->detectedLang = ClangParser::Private::Detected_Cpp;
208 else if (fn.right(3).lower()==
".mm")
210 p->detectedLang = ClangParser::Private::Detected_ObjCpp;
212 else if (fn.right(2).lower()==
".m")
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++");
232 argv[argc++]=strdup(fileName);
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];
241 p->ufs[0].Filename = strdup(fileName);
242 p->ufs[0].Contents =
p->sources[0].data();
243 p->ufs[0].Length =
p->sources[0].length();
244 QStrListIterator it(filesInTranslationUnit);
246 for (it.toFirst();it.current() && i<numUnsavedFiles;++it,i++)
248 p->fileMapping.insert(it.current(),
new uint(i));
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);
283 QFileInfo fi(fileName);
284 CXFile f = clang_getFile(
p->tu, fileName);
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);
315 QFileInfo fi(fileName);
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)
477 static bool init=TRUE;
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);
578 uint &line,uint &column,
const char *fontClass=0)
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);
614 FileDef *fd,uint &line,uint &column,
622 QCString anchor = d->
anchor();
629 char *p=(
char *)text;
634 while ((c=*p++) && c!=
'\n') { column++; }
643 writeLineNumber(ol,fd,line);
655 uint &line,uint &column,
const char *text)
657 QCString incName = text;
658 incName = incName.mid(1,incName.length()-2);
660 if (!incName.isEmpty())
668 for (fni.toFirst();!found && (ifd=fni.current());++fni)
678 ol.
writeCodeLink(ifd->getReference(),ifd->getOutputFileBase(),0,text,ifd->briefDescriptionAsTooltip());
682 codifyLines(ol,ifd,text,line,column,
"preprocessor");
687 uint &line,uint &column,
const char *text)
694 for (mni.toFirst();(md=mni.current());++mni)
698 writeMultiLineCodeLink(ol,fd,line,column,md,text);
703 codifyLines(ol,fd,text,line,column);
708 uint &line,uint &column,
const char *text,
int tokenIndex)
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))
744 writeMultiLineCodeLink(ol,fd,line,column,d,text);
748 codifyLines(ol,fd,text,line,column);
750 clang_disposeString(usr);
753 static void detectFunctionBody(
const char *s)
758 if (g_searchForBody && (qstrcmp(s,
":")==0 || qstrcmp(s,
"{")==0))
760 g_searchForBody=FALSE;
763 else if (g_searchForBody && qstrcmp(s,
";")==0)
765 g_searchForBody=FALSE;
768 if (g_insideBody && qstrcmp(s,
"{")==0)
772 if (g_insideBody && qstrcmp(s,
"}")==0)
775 if (g_bracketCount<=0)
787 g_currentDefinition=0;
788 g_currentMemberDef=0;
790 g_searchForBody=FALSE;
794 unsigned int line=1,column=1;
795 QCString lineNumber,lineAnchor;
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);
803 if (l > line) column = 1;
809 writeLineNumber(ol,fd,line);
811 while (column<c) { ol.
codify(
" "); column++; }
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)
826 codifyLines(ol,fd,s,line,column,
827 cursorKind==CXCursor_PreprocessingDirective ?
"preprocessor" :
831 case CXToken_Literal:
832 if (cursorKind==CXCursor_InclusionDirective)
836 else if (s[0]==
'"' || s[0]==
'\'')
838 codifyLines(ol,fd,s,line,column,
"stringliteral");
842 codifyLines(ol,fd,s,line,column);
845 case CXToken_Comment:
846 codifyLines(ol,fd,s,line,column,
"comment");
849 if (tokenKind==CXToken_Punctuation)
851 detectFunctionBody(s);
856 case CXCursor_PreprocessingDirective:
857 codifyLines(ol,fd,s,line,column,
"preprocessor");
859 case CXCursor_MacroDefinition:
860 codifyLines(ol,fd,s,line,column,
"preprocessor");
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)
886 codifyLines(ol,fd,s,line,column);
891 clang_disposeString(tokenString);
908 #else // use stubbed functionality in case libclang support is disabled.