7 #include <clang-c/Index.h>
8 #include "clang/Tooling/CompilationDatabase.h"
9 #include "clang/Tooling/Tooling.h"
41 static std::mutex g_docCrossReferenceMutex;
43 enum class DetectedLang { Cpp, ObjC, ObjCpp };
50 const char *data = s.
data();
53 const int maxIndent=1000000;
54 int minIndent=maxIndent;
62 int stop = tabSize - (col%tabSize);
65 while (stop--) out.
addChar(
' ');
79 for (
int j=0;j<bytes-1 && c!=0; j++)
86 if (col<minIndent) minIndent=col;
95 static const char * keywordToType(
const char *keyword)
98 "break",
"case",
"catch",
"continue",
"default",
"do",
99 "else",
"finally",
"for",
"foreach",
"for each",
"goto",
100 "if",
"return",
"switch",
"throw",
"throws",
"try",
101 "while",
"@try",
"@catch",
"@finally" });
103 "bool",
"char",
"double",
"float",
"int",
"long",
"object",
104 "short",
"signed",
"unsigned",
"void",
"wchar_t",
"size_t",
105 "boolean",
"id",
"SEL",
"string",
"nullptr" });
106 if (flowKeywords.find(keyword)!=flowKeywords.end())
return "keywordflow";
107 if (typeKeywords.find(keyword)!=typeKeywords.end())
return "keywordtype";
118 : parser(
p), fileDef(fd) {}
123 DetectedLang detectedLang = DetectedLang::Cpp;
125 std::vector<QCString> sources;
126 std::vector<CXUnsavedFile> ufs;
127 std::vector<CXCursor> cursors;
128 std::unordered_map<std::string,uint> fileMapping;
129 CXTranslationUnit tu = 0;
138 bool searchForBody=
FALSE;
139 bool insideBody=
FALSE;
144 : p(std::make_unique<
Private>(parser,fd))
151 return p->filesInSameTU;
157 QCString fileName =
p->fileDef->absFilePath();
158 p->fileDef->getAllIncludeFilesRecursively(
p->filesInSameTU);
161 bool clangAssistedParsing =
Config_getBool(CLANG_ASSISTED_PARSING);
162 bool clangIncludeInputPaths =
Config_getBool(CLANG_ADD_INC_PATHS);
166 if (!clangAssistedParsing)
return;
169 assert(
p->tokens==0);
170 assert(
p->numTokens==0);
171 p->index = clang_createIndex(0, 0);
175 size_t clang_option_len = 0;
176 std::vector<clang::tooling::CompileCommand> command;
177 if (
p->parser.database()!=
nullptr)
180 command =
p->parser.database()->getCompileCommands(fileName.
data());
181 if (!command.empty() )
184 clang_option_len = command[command.size()-1].CommandLine.size();
187 char **argv = (
char**)malloc(
sizeof(
char*)*
192 if (!command.empty() )
194 std::vector<std::string> options = command[command.size()-1].CommandLine;
196 for (
auto option = options.begin()+1; option != options.end(); option++)
198 argv[argc++] =
qstrdup(option->c_str());
201 for (
size_t i=0;i<clangOptions.size();i++)
203 argv[argc++]=
qstrdup(clangOptions[i].c_str());
211 if (clangIncludeInputPaths)
221 for (
size_t i=0;i<includePath.size();i++)
227 for (
size_t i=0;i<clangOptions.size();i++)
229 argv[argc++]=
qstrdup(clangOptions[i].c_str());
232 argv[argc++]=
qstrdup(
"-ferror-limit=0");
243 if (
p->detectedLang!=DetectedLang::Cpp &&
247 p->detectedLang = DetectedLang::Cpp;
251 p->detectedLang = DetectedLang::ObjCpp;
255 p->detectedLang = DetectedLang::ObjC;
258 switch (
p->detectedLang)
260 case DetectedLang::Cpp: argv[argc++]=
qstrdup(
"c++");
break;
261 case DetectedLang::ObjC: argv[argc++]=
qstrdup(
"objective-c");
break;
262 case DetectedLang::ObjCpp: argv[argc++]=
qstrdup(
"objective-c++");
break;
271 int numUnsavedFiles =
static_cast<int>(
p->filesInSameTU.size()+1);
272 p->numFiles = numUnsavedFiles;
273 p->sources.resize(numUnsavedFiles);
274 p->ufs.resize(numUnsavedFiles);
277 p->ufs[0].Contents =
p->sources[0].data();
278 p->ufs[0].Length =
p->sources[0].length();
279 p->fileMapping.insert({fileName.
data(),0});
281 for (
auto it =
p->filesInSameTU.begin();
282 it !=
p->filesInSameTU.end() && i<numUnsavedFiles;
285 p->fileMapping.insert({it->c_str(),
static_cast<uint>(i)});
287 p->ufs[i].Filename =
qstrdup(it->c_str());
288 p->ufs[i].Contents =
p->sources[i].data();
289 p->ufs[i].Length =
p->sources[i].length();
293 p->tu = clang_parseTranslationUnit(
p->index, 0,
294 argv, argc,
p->ufs.data(), numUnsavedFiles,
295 CXTranslationUnit_DetailedPreprocessingRecord);
307 int n=clang_getNumDiagnostics(
p->tu);
310 CXDiagnostic diag = clang_getDiagnostic(
p->tu, i);
311 CXString
string = clang_formatDiagnostic(diag,
312 clang_defaultDiagnosticDisplayOptions());
313 err(
"%s [clang]\n",clang_getCString(
string));
314 clang_disposeString(
string);
315 clang_disposeDiagnostic(diag);
320 err(
"clang: Failed to parse translation unit %s\n",
qPrint(fileName));
327 static bool clangAssistedParsing =
Config_getBool(CLANG_ASSISTED_PARSING);
328 if (!clangAssistedParsing)
return;
332 clang_disposeTokens(
p->tu,
p->tokens,
p->numTokens);
333 clang_disposeTranslationUnit(
p->tu);
334 clang_disposeIndex(
p->index);
335 p->fileMapping.clear();
339 for (
uint i=0;i<
p->numFiles;i++)
341 delete[]
p->ufs[i].Filename;
355 clang_disposeTokens(
p->tu,
p->tokens,
p->numTokens);
361 if (it!=
p->fileMapping.end() && it->second <
p->numFiles)
365 CXSourceLocation fileBegin = clang_getLocationForOffset(
p->tu, f, 0);
366 CXSourceLocation fileEnd = clang_getLocationForOffset(
p->tu, f,
p->ufs[i].Length);
367 CXSourceRange fileRange = clang_getRange(fileBegin, fileEnd);
369 clang_tokenize(
p->tu,fileRange,&
p->tokens,&
p->numTokens);
370 p->cursors.resize(
p->numTokens);
371 clang_annotateTokens(
p->tu,
p->tokens,
p->numTokens,
p->cursors.data());
385 if (symbol==0)
return result;
386 static bool clangAssistedParsing =
Config_getBool(CLANG_ASSISTED_PARSING);
387 if (!clangAssistedParsing)
return result;
389 auto getCurrentTokenLine = [=]() ->
uint
392 if (
p->numTokens==0)
return 1;
394 if (
p->curToken>=
p->numTokens)
p->curToken=
p->numTokens-1;
395 CXSourceLocation start = clang_getTokenLocation(
p->tu,
p->tokens[
p->curToken]);
396 clang_getSpellingLocation(start, 0, &l, &c, 0);
400 int sl = strlen(symbol);
401 uint l = getCurrentTokenLine();
402 while (l>=line &&
p->curToken>0)
407 l = getCurrentTokenLine();
412 l = getCurrentTokenLine();
416 while (l<=line && p->curToken<p->numTokens && !found)
418 CXString tokenString = clang_getTokenSpelling(
p->tu,
p->tokens[
p->curToken]);
423 const char *ts = clang_getCString(tokenString);
425 int startIndex =
p->curToken;
426 if (l==line && strncmp(ts,symbol,tl)==0)
433 if (
p->curToken>=
p->numTokens)
437 l = getCurrentTokenLine();
438 clang_disposeString(tokenString);
439 tokenString = clang_getTokenSpelling(
p->tu,
p->tokens[
p->curToken]);
440 ts = clang_getCString(tokenString);
441 tl = ts ? strlen(ts) : 0;
444 while (offset<sl && ((c=symbol[offset])==
' ' || c==
'\t' || c==
'\r' || c==
'\n'))
448 if (strncmp(ts,symbol+offset,tl)!=0)
458 CXCursor c =
p->cursors[
p->curToken];
459 CXString usr = clang_getCursorUSR(c);
461 result = clang_getCString(usr);
462 clang_disposeString(usr);
467 p->curToken = startIndex;
470 clang_disposeString(tokenString);
472 if (
p->curToken<
p->numTokens)
474 l = getCurrentTokenLine();
498 if (
p->currentMemberDef!=md)
500 p->searchForBody=
TRUE;
504 p->currentMemberDef=md;
508 line,writeLineAnchor);
512 p->currentMemberDef=0;
516 line,writeLineAnchor);
528 lineAnchor.
sprintf(
"l%05d",line);
536 uint &line,
uint &column,
const char *fontClass)
539 const char *
p=text,*sp=
p;
541 bool inlineCodeFragment =
false;
546 while ((c=*
p++) && c!=
'\n') { column++; }
550 int l = (int)(
p-sp-1);
552 char *tmp = (
char*)malloc(l+1);
578 p->tooltipManager.addTooltip(ol,d);
587 bool inlineCodeFragment =
false;
589 char *
p=(
char *)text;
594 while ((c=*
p++) && c!=
'\n') { column++; }
615 uint &line,
uint &column,
const char *text)
618 incName = incName.
mid(1,incName.
length()-2);
626 auto it = std::find_if(fn->begin(),
628 [&fd](
const auto &ifd)
629 { return fd->isIncluded(ifd->absFilePath()); });
630 bool found = it!=fn->end();
649 codifyLines(ol,ifd,text,line,column,
"preprocessor");
654 uint &line,
uint &column,
const char *text)
659 for (
const auto &md : *mn)
673 uint &line,
uint &column,
const char *text,
int tokenIndex)
675 CXCursor c =
p->cursors[tokenIndex];
676 CXCursor r = clang_getCursorReferenced(c);
677 if (!clang_equalCursors(r, c))
681 CXCursor t = clang_getSpecializedCursorTemplate(c);
682 if (!clang_Cursor_isNull(t) && !clang_equalCursors(t,c))
686 CXString usr = clang_getCursorUSR(c);
687 const char *usrStr = clang_getCString(usr);
710 (
p->currentMemberDef!=d ||
p->currentLine<line))
712 std::lock_guard<std::mutex> lock(g_docCrossReferenceMutex);
721 clang_disposeString(usr);
734 else if (
p->searchForBody &&
qstrcmp(s,
";")==0)
739 if (
p->insideBody &&
qstrcmp(s,
"{")==0)
743 if (
p->insideBody &&
qstrcmp(s,
"}")==0)
746 if (
p->bracketCount<=0)
757 p->currentMemberDef=0;
763 unsigned int line=1,column=1;
765 bool inlineCodeFragment =
false;
768 for (
unsigned int i=0;i<
p->numTokens;i++)
770 CXSourceLocation start = clang_getTokenLocation(
p->tu,
p->tokens[i]);
772 clang_getSpellingLocation(start, 0, &l, &c, 0);
773 if (l > line) column = 1;
781 while (column<c) { ol.
codify(
" "); column++; }
782 CXString tokenString = clang_getTokenSpelling(
p->tu,
p->tokens[i]);
783 char const *s = clang_getCString(tokenString);
784 CXCursorKind cursorKind = clang_getCursorKind(
p->cursors[i]);
785 CXTokenKind tokenKind = clang_getTokenKind(
p->tokens[i]);
789 case CXToken_Keyword:
790 if (strcmp(s,
"operator")==0)
797 cursorKind==CXCursor_PreprocessingDirective ?
"preprocessor" :
801 case CXToken_Literal:
802 if (cursorKind==CXCursor_InclusionDirective)
806 else if (s[0]==
'"' || s[0]==
'\'')
815 case CXToken_Comment:
819 if (tokenKind==CXToken_Punctuation)
826 case CXCursor_PreprocessingDirective:
829 case CXCursor_MacroDefinition:
832 case CXCursor_InclusionDirective:
835 case CXCursor_MacroExpansion:
839 if (tokenKind==CXToken_Identifier ||
840 (tokenKind==CXToken_Punctuation &&
841 (cursorKind==CXCursor_DeclRefExpr ||
842 cursorKind==CXCursor_MemberRefExpr ||
843 cursorKind==CXCursor_CallExpr ||
844 cursorKind==CXCursor_ObjCMessageExpr)
861 clang_disposeString(tokenString);
864 p->tooltipManager.writeTooltips(ol);
877 db = clang::tooling::CompilationDatabase::loadFromDirectory(clangCompileDatabase.
data(), error);
878 if (!clangCompileDatabase.
isEmpty() && clangCompileDatabase!=
"0" && db==
nullptr)
881 err(
"%s using clang compilation database path of: \"%s\"\n", error.c_str(),
882 clangCompileDatabase.
data());
886 std::unique_ptr<clang::tooling::CompilationDatabase> db;
905 return std::make_unique<ClangTUParser>(*
this,fd);
910 #else // use stubbed functionality in case libclang support is disabled.
922 return std::string();