19#include <QtCore/qdebug.h>
20#include <QtCore/qelapsedtimer.h>
21#include <QtCore/qfile.h>
22#include <QtCore/qscopedvaluerollback.h>
23#include <QtCore/qtemporarydir.h>
24#include <QtCore/qtextstream.h>
25#include <QtCore/qvarlengtharray.h>
27#include <clang-c/Index.h>
29#include <clang/AST/Decl.h>
30#include <clang/AST/DeclFriend.h>
31#include <clang/AST/DeclTemplate.h>
32#include <clang/AST/Expr.h>
33#include <clang/AST/Type.h>
34#include <clang/AST/TypeLoc.h>
35#include <clang/Basic/SourceLocation.h>
36#include <clang/Frontend/ASTUnit.h>
37#include <clang/Lex/Lexer.h>
38#include <llvm/Support/Casting.h>
40#include "clang/AST/QualTypeNames.h"
47struct CompilationIndex {
48 CXIndex index =
nullptr;
55 clang_disposeIndex(index);
60 CXTranslationUnit
tu =
nullptr;
71 clang_disposeTranslationUnit(
tu);
79static CXTranslationUnit_Flags
flags_ =
static_cast<CXTranslationUnit_Flags>(0);
83#ifndef QT_NO_DEBUG_STREAM
87 QDebugStateSaver saver(debug);
90 const size_t size = v.size();
91 debug <<
"std::vector<>[" << size <<
"](";
92 for (size_t i = 0; i < size; ++i) {
104 if (!lcQdocClang().isDebugEnabled())
107 static const auto displayOptions = CXDiagnosticDisplayOptions::CXDiagnostic_DisplaySourceLocation
108 | CXDiagnosticDisplayOptions::CXDiagnostic_DisplayColumn
109 | CXDiagnosticDisplayOptions::CXDiagnostic_DisplayOption;
111 for (
unsigned i = 0, numDiagnostics = clang_getNumDiagnostics(translationUnit); i < numDiagnostics; ++i) {
112 auto diagnostic = clang_getDiagnostic(translationUnit, i);
113 auto formattedDiagnostic = clang_formatDiagnostic(diagnostic, displayOptions);
114 qCDebug(lcQdocClang) << clang_getCString(formattedDiagnostic);
115 clang_disposeString(formattedDiagnostic);
116 clang_disposeDiagnostic(diagnostic);
121
122
123
124
125
126
127
128
129
130
131
132
134 assert(clang_isDeclaration(clang_getCursorKind(cursor)));
136 return static_cast<
const clang::Decl*>(cursor.data[0]);
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
171 declaration_context.getPrintingPolicy()
176
177
178
179
180
181
182
183
184
186 QString default_value = QString::fromStdString(clang::Lexer::getSourceText(
187 clang::CharSourceRange::getTokenRange(expression->getSourceRange()),
188 declaration_context.getSourceManager(),
189 declaration_context.getLangOpts()
192 if (default_value.startsWith(
"="))
193 default_value.remove(0, 1);
195 default_value = default_value.trimmed();
197 return default_value.toStdString();
201
202
203
204
205
206
207
208
210#if LIBCLANG_VERSION_MAJOR >= 19
211 return (parameter && parameter->hasDefaultArgument()) ?
212 get_fully_qualified_type_name(parameter->getDefaultArgument().getArgument().getAsType(), parameter->getASTContext()) :
215 return (parameter && parameter->hasDefaultArgument()) ?
216 get_fully_qualified_type_name(parameter->getDefaultArgument(), parameter->getASTContext()) :
223
224
225
226
227
228
229
230
232#if LIBCLANG_VERSION_MAJOR >= 19
233 return (parameter && parameter->hasDefaultArgument()) ?
234 get_expression_as_string(parameter->getDefaultArgument().getSourceExpression(), parameter->getASTContext()) :
"";
236 return (parameter && parameter->hasDefaultArgument()) ?
237 get_expression_as_string(parameter->getDefaultArgument(), parameter->getASTContext()) :
"";
243
244
245
246
247
248
249
250
252 std::string default_value{};
254 if (parameter && parameter->hasDefaultArgument()) {
255 const clang::TemplateName template_name = parameter->getDefaultArgument().getArgument().getAsTemplate();
257 llvm::raw_string_ostream ss{default_value};
258 template_name.print(ss, parameter->getASTContext().getPrintingPolicy(),
clang::TemplateName::Qualified::AsWritten);
261 return default_value;
265
266
267
268
269
270
271
272
273
274
276 if (!parameter || !parameter->hasDefaultArg() || parameter->hasUnparsedDefaultArg())
279 return get_expression_as_string(
280 parameter->hasUninstantiatedDefaultArg() ? parameter->getUninstantiatedDefaultArg() : parameter->getDefaultArg(),
281 parameter->getASTContext()
286
287
288
289
290
291
292
294 if (!declaration)
return "";
296 if (
auto type_template_parameter = llvm::dyn_cast<clang::TemplateTypeParmDecl>(declaration))
297 return get_default_value_initializer_as_string(type_template_parameter);
299 if (
auto non_type_template_parameter = llvm::dyn_cast<clang::NonTypeTemplateParmDecl>(declaration))
300 return get_default_value_initializer_as_string(non_type_template_parameter);
302 if (
auto template_template_parameter = llvm::dyn_cast<clang::TemplateTemplateParmDecl>(declaration)) {
303 return get_default_value_initializer_as_string(template_template_parameter);
306 if (
auto function_parameter = llvm::dyn_cast<clang::ParmVarDecl>(declaration)) {
307 return get_default_value_initializer_as_string(function_parameter);
314
315
316
317
321 CXCursorVisitor visitor = [](CXCursor c, CXCursor,
322 CXClientData client_data) -> CXChildVisitResult {
323 return (*
static_cast<T *>(client_data))(c);
325 return clang_visitChildren(cursor, visitor, &lambda);
329
330
333 QString ret = QString::fromUtf8(clang_getCString(string));
334 clang_disposeString(string);
339
340
341
343 assert(template_declaration);
347 auto template_parameters = template_declaration->getTemplateParameters();
348 for (
auto template_parameter : template_parameters->asArray()) {
349 auto kind{RelaxedTemplateParameter::Kind::TypeTemplateParameter};
352 if (
auto non_type_template_parameter = llvm::dyn_cast<clang::NonTypeTemplateParmDecl>(template_parameter)) {
353 kind = RelaxedTemplateParameter::Kind::NonTypeTemplateParameter;
354 type = get_fully_qualified_type_name(non_type_template_parameter->getType(), non_type_template_parameter->getASTContext());
386 if (QString::fromStdString(type).startsWith(
"typename ")) type.erase(0, std::string(
"typename ").size());
389 auto template_template_parameter = llvm::dyn_cast<clang::TemplateTemplateParmDecl>(template_parameter);
390 if (template_template_parameter) kind = RelaxedTemplateParameter::Kind::TemplateTemplateParameter;
392 template_declaration_ir.parameters.push_back({
394 template_parameter->isTemplateParameterPack(),
397 template_parameter->getNameAsString(),
398 get_default_value_initializer_as_string(template_parameter)
400 (template_template_parameter ?
401 std::optional<TemplateDeclarationStorage>(TemplateDeclarationStorage{
402 get_template_declaration(template_template_parameter).parameters
407 return template_declaration_ir;
411
412
415 unsigned int line, column;
417 clang_getPresumedLocation(location, &file, &line, &column);
425
426
431 return Access::Private;
432 case CX_CXXProtected:
433 return Access::Protected;
435 return Access::Public;
437 return Access::Public;
442
443
452 unsigned int offset1,
unsigned int offset2)
454 return QString::fromUtf8(cache.mid(offset1, offset2 - offset1));
457static QString
readFile(CXFile cxFile,
unsigned int offset1,
unsigned int offset2)
459 using FileCache = QList<FileCacheEntry>;
460 static FileCache cache;
462 CXString cxFileName = clang_getFileName(cxFile);
463 const QByteArray fileName = clang_getCString(cxFileName);
464 clang_disposeString(cxFileName);
466 for (
const auto &entry : std::as_const(cache)) {
467 if (fileName == entry.fileName)
468 return fromCache(entry.content, offset1, offset2);
471 QFile file(QString::fromUtf8(fileName));
472 if (file.open(QIODeviceBase::ReadOnly)) {
474 cache.prepend(entry);
475 while (cache.size() > 5)
477 return fromCache(entry.content, offset1, offset2);
484 auto start = clang_getRangeStart(range);
485 auto end = clang_getRangeEnd(range);
487 unsigned int offset1, offset2;
488 clang_getFileLocation(start, &file1,
nullptr,
nullptr, &offset1);
489 clang_getFileLocation(end, &file2,
nullptr,
nullptr, &offset2);
491 if (file1 != file2 || offset2 <= offset1)
494 return readFile(file1, offset1, offset2);
498
499
500
501
504 if (clang_getCursorKind(cursor) == CXCursor_ConversionFunction) {
508 auto conversion_declaration =
511 return QLatin1String(
"operator ") + QString::fromStdString(get_fully_qualified_type_name(
512 conversion_declaration->getConversionType(),
513 conversion_declaration->getASTContext()
517 QString name = fromCXString(clang_getCursorSpelling(cursor));
520 auto ltLoc = name.indexOf(
'<');
521 if (ltLoc > 0 && !name.startsWith(
"operator<"))
522 name = name.left(ltLoc);
527
528
529
533 auto kind = clang_getCursorKind(cur);
534 while (!clang_isInvalid(kind) && kind != CXCursor_TranslationUnit) {
536 case CXCursor_Namespace:
537 case CXCursor_StructDecl:
538 case CXCursor_ClassDecl:
539 case CXCursor_UnionDecl:
540 case CXCursor_ClassTemplate:
542 path.prepend(fromCXString(clang_getCursorSpelling(cur)));
544 case CXCursor_FunctionDecl:
545 case CXCursor_FunctionTemplate:
546 case CXCursor_CXXMethod:
547 case CXCursor_Constructor:
548 case CXCursor_Destructor:
549 case CXCursor_ConversionFunction:
550 path = functionName(cur);
555 cur = clang_getCursorSemanticParent(cur);
556 kind = clang_getCursorKind(cur);
562
563
564
567 auto kind = clang_getCursorKind(cur);
568 if (clang_isInvalid(kind))
570 if (kind == CXCursor_TranslationUnit)
578 auto parent =
static_cast<
Aggregate *>(p);
580 QString name = fromCXString(clang_getCursorSpelling(cur));
582 case CXCursor_Namespace:
584 case CXCursor_StructDecl:
585 case CXCursor_ClassDecl:
586 case CXCursor_UnionDecl:
587 case CXCursor_ClassTemplate:
589 case CXCursor_FunctionDecl:
590 case CXCursor_FunctionTemplate:
591 case CXCursor_CXXMethod:
592 case CXCursor_Constructor:
593 case CXCursor_Destructor:
594 case CXCursor_ConversionFunction: {
596 parent->findChildren(functionName(cur), candidates);
597 if (candidates.isEmpty())
600 CXType funcType = clang_getCursorType(cur);
601 auto numArg = clang_getNumArgTypes(funcType);
602 bool isVariadic = clang_isFunctionTypeVariadic(funcType);
603 QVarLengthArray<QString, 20> args;
606 if (kind == CXCursor_FunctionTemplate)
607 relaxed_template_declaration = get_template_declaration(
611 for (Node *candidate : std::as_const(candidates)) {
612 if (!candidate->isFunction(Node::CPP))
615 auto fn =
static_cast<FunctionNode *>(candidate);
617 if (!fn->templateDecl() && relaxed_template_declaration)
620 if (fn->templateDecl() && !relaxed_template_declaration)
623 if (fn->templateDecl() && relaxed_template_declaration &&
624 !are_template_declarations_substitutable(*fn->templateDecl(), *relaxed_template_declaration))
627 const Parameters ¶meters = fn->parameters();
629 if (parameters.count() != numArg + isVariadic)
632 if (fn->isConst() !=
bool(clang_CXXMethod_isConst(cur)))
635 if (isVariadic && parameters.last().type() != QLatin1String(
"..."))
638 if (fn->isRef() != (clang_Type_getCXXRefQualifier(funcType) == CXRefQualifier_LValue))
641 if (fn->isRefRef() != (clang_Type_getCXXRefQualifier(funcType) == CXRefQualifier_RValue))
644 auto function_declaration = get_cursor_declaration(cur)->getAsFunction();
646 bool different =
false;
647 for (
int i = 0; i < numArg; ++i) {
648 CXType argType = clang_getArgType(funcType, i);
650 if (args.size() <= i)
651 args.append(QString::fromStdString(get_fully_qualified_type_name(
652 function_declaration->getParamDecl(i)->getOriginalType(),
653 function_declaration->getASTContext()
656 QString recordedType = parameters.at(i).type();
657 QString typeSpelling = args.at(i);
659 different = recordedType != typeSpelling;
662 if (different && (argType.kind == CXType_Typedef || argType.kind == CXType_Elaborated)) {
663 QStringView canonicalType = parameters.at(i).canonicalType();
664 if (!canonicalType.isEmpty()) {
665 different = canonicalType !=
666 QString::fromStdString(get_fully_qualified_type_name(
667 function_declaration->getParamDecl(i)->getOriginalType().getCanonicalType(),
668 function_declaration->getASTContext()
683 case CXCursor_EnumDecl:
685 case CXCursor_FieldDecl:
686 case CXCursor_VarDecl:
688 case CXCursor_TypedefDecl:
697 CXCursor *overridden;
698 unsigned int numOverridden = 0;
699 clang_getOverriddenCursors(cursor, &overridden, &numOverridden);
700 for (uint i = 0; i < numOverridden; ++i) {
701 QString path = reconstructQualifiedPathForCursor(overridden[i]);
702 if (!path.isEmpty()) {
704 fn->setOverridesThis(path);
708 clang_disposeOverriddenCursors(overridden);
717 std::transform(allHeaders.cbegin(), allHeaders.cend(), std::inserter(allHeaders_, allHeaders_.begin()),
718 [](
const auto& header_file_path) {
return header_file_path.filename; });
725 auto ret = visitChildrenLambda(cursor, [&](CXCursor cur) {
726 auto loc = clang_getCursorLocation(cur);
727 if (clang_Location_isFromMainFile(loc))
728 return visitSource(cur, loc);
730 clang_getFileLocation(loc, &file,
nullptr,
nullptr,
nullptr);
731 bool isInteresting =
false;
732 auto it = isInterestingCache_.find(file);
733 if (it != isInterestingCache_.end()) {
736 QFileInfo fi(fromCXString(clang_getFileName(file)));
738 isInteresting = allHeaders_.find(fi.fileName()) != allHeaders_.end();
739 isInterestingCache_[file] = isInteresting;
742 return visitHeader(cur, loc);
745 return CXChildVisit_Continue;
747 return ret ? CXChildVisit_Break : CXChildVisit_Continue;
751
752
753
754 CXChildVisitResult
visitFnArg(CXCursor cursor,
Node **fnNode,
bool &ignoreSignature)
756 auto ret = visitChildrenLambda(cursor, [&](CXCursor cur) {
757 auto loc = clang_getCursorLocation(cur);
758 if (clang_Location_isFromMainFile(loc))
759 return visitFnSignature(cur, loc, fnNode, ignoreSignature);
760 return CXChildVisit_Continue;
762 return ret ? CXChildVisit_Break : CXChildVisit_Continue;
769
770
771
774 unsigned int line {}, column {};
775 friend bool operator<(
const SimpleLoc &a,
const SimpleLoc &b)
777 return a.line != b.line ? a.line < b.line : a.column < b.column;
781
782
783
784
785 QMap<SimpleLoc, CXCursor> declMap_;
789 std::set<QString> allHeaders_;
790 QHash<CXFile,
bool> isInterestingCache_;
793
794
795 bool ignoredSymbol(
const QString &symbolName)
797 if (symbolName == QLatin1String(
"QPrivateSignal"))
800 if (symbolName.startsWith(
"_qt_property_"))
803 if (symbolName.startsWith(
"<deduction guide"))
808 CXChildVisitResult visitSource(CXCursor cursor, CXSourceLocation loc);
809 CXChildVisitResult visitHeader(CXCursor cursor, CXSourceLocation loc);
810 CXChildVisitResult visitFnSignature(CXCursor cursor, CXSourceLocation loc,
Node **fnNode,
811 bool &ignoreSignature);
812 void processFunction(
FunctionNode *fn, CXCursor cursor);
813 bool parseProperty(
const QString &spelling,
const Location &loc);
814 void readParameterNamesAndAttributes(
FunctionNode *fn, CXCursor cursor);
815 Aggregate *getSemanticParent(CXCursor cursor);
819
820
821
822CXChildVisitResult
ClangVisitor::visitSource(CXCursor cursor, CXSourceLocation loc)
824 auto kind = clang_getCursorKind(cursor);
825 if (clang_isDeclaration(kind)) {
827 clang_getPresumedLocation(loc,
nullptr, &l.line, &l.column);
828 declMap_.insert(l, cursor);
829 return CXChildVisit_Recurse;
831 return CXChildVisit_Continue;
835
836
837
838
841 CXCursor sp = clang_getCursorSemanticParent(cursor);
842 CXCursor lp = clang_getCursorLexicalParent(cursor);
843 if (!clang_equalCursors(sp, lp) && clang_isDeclaration(clang_getCursorKind(sp))) {
852CXChildVisitResult
ClangVisitor::visitFnSignature(CXCursor cursor, CXSourceLocation,
Node **fnNode,
853 bool &ignoreSignature)
855 switch (clang_getCursorKind(cursor)) {
856 case CXCursor_Namespace:
857 return CXChildVisit_Recurse;
858 case CXCursor_FunctionDecl:
859 case CXCursor_FunctionTemplate:
860 case CXCursor_CXXMethod:
861 case CXCursor_Constructor:
862 case CXCursor_Destructor:
863 case CXCursor_ConversionFunction: {
864 ignoreSignature =
false;
865 if (ignoredSymbol(functionName(cursor))) {
867 ignoreSignature =
true;
873 readParameterNamesAndAttributes(fn, cursor);
877 if (
const auto function_declaration = declaration->getAsFunction()) {
878 auto declaredReturnType = function_declaration->getDeclaredReturnType();
879 if (llvm::dyn_cast_if_present<clang::AutoType>(declaredReturnType.getTypePtrOrNull()))
880 fn->setDeclaredReturnType(QString::fromStdString(declaredReturnType.getAsString()));
884 QString name = functionName(cursor);
885 if (ignoredSymbol(name))
886 return CXChildVisit_Continue;
887 Aggregate *semanticParent = getSemanticParent(cursor);
888 if (semanticParent && semanticParent
->isClass()) {
890 processFunction(candidate, cursor);
891 if (!candidate->isSpecialMemberFunction()) {
893 return CXChildVisit_Continue;
895 candidate->setDefault(
true);
905 return CXChildVisit_Continue;
908CXChildVisitResult
ClangVisitor::visitHeader(CXCursor cursor, CXSourceLocation loc)
910 auto kind = clang_getCursorKind(cursor);
913 case CXCursor_TypeAliasTemplateDecl:
914 case CXCursor_TypeAliasDecl: {
915 QString aliasDecl = getSpelling(clang_getCursorExtent(cursor)).simplified();
916 QStringList typeAlias = aliasDecl.split(QLatin1Char(
'='));
917 if (typeAlias.size() == 2) {
918 typeAlias[0] = typeAlias[0].trimmed();
919 const QLatin1String usingString(
"using ");
920 qsizetype usingPos = typeAlias[0].indexOf(usingString);
921 if (usingPos != -1) {
922 typeAlias[0].remove(0, usingPos + usingString.size());
923 typeAlias[0] = typeAlias[0].split(QLatin1Char(
' ')).first();
924 typeAlias[1] = typeAlias[1].trimmed();
925 auto *ta =
new TypeAliasNode(parent_, typeAlias[0], typeAlias[1]);
929 if (kind == CXCursor_TypeAliasTemplateDecl) {
931 ta->setTemplateDecl(get_template_declaration(template_decl));
935 return CXChildVisit_Continue;
937 case CXCursor_StructDecl:
938 case CXCursor_UnionDecl:
939 if (fromCXString(clang_getCursorSpelling(cursor)).isEmpty())
940 return CXChildVisit_Continue;
942 case CXCursor_ClassTemplate:
944 case CXCursor_ClassDecl: {
945 if (!clang_isCursorDefinition(cursor))
946 return CXChildVisit_Continue;
949 return CXChildVisit_Continue;
951 QString className = fromCXString(clang_getCursorSpelling(cursor));
953 Aggregate *semanticParent = getSemanticParent(cursor);
954 if (semanticParent && semanticParent->findNonfunctionChild(className, &
Node::isClassNode)) {
955 return CXChildVisit_Continue;
958 CXCursorKind actualKind = (kind == CXCursor_ClassTemplate) ?
959 clang_getTemplateCursorKind(cursor) : kind;
962 if (actualKind == CXCursor_StructDecl)
964 else if (actualKind == CXCursor_UnionDecl)
967 auto *classe =
new ClassNode(type, semanticParent, className);
971 if (kind == CXCursor_ClassTemplate) {
973 classe->setTemplateDecl(get_template_declaration(template_declaration));
976 QScopedValueRollback<Aggregate *> setParent(parent_, classe);
979 case CXCursor_CXXBaseSpecifier: {
981 return CXChildVisit_Continue;
983 auto type = clang_getCursorType(cursor);
984 auto baseCursor = clang_getTypeDeclaration(type);
986 auto classe =
static_cast<
ClassNode *>(parent_);
988 QString bcName = reconstructQualifiedPathForCursor(baseCursor);
989 classe->addUnresolvedBaseClass(access,
990 bcName.split(QLatin1String(
"::"), Qt::SkipEmptyParts));
991 return CXChildVisit_Continue;
993 auto baseClasse =
static_cast<
ClassNode *>(baseNode);
995 return CXChildVisit_Continue;
997 case CXCursor_Namespace: {
998 QString namespaceName = fromCXString(clang_getCursorDisplayName(cursor));
1008 QScopedValueRollback<Aggregate *> setParent(parent_, ns);
1011 case CXCursor_FunctionTemplate:
1013 case CXCursor_FunctionDecl:
1014 case CXCursor_CXXMethod:
1015 case CXCursor_Constructor:
1016 case CXCursor_Destructor:
1017 case CXCursor_ConversionFunction: {
1019 return CXChildVisit_Continue;
1020 QString name = functionName(cursor);
1021 if (ignoredSymbol(name))
1022 return CXChildVisit_Continue;
1025 return CXChildVisit_Continue;
1028 CXSourceRange range = clang_Cursor_getCommentRange(cursor);
1029 if (!clang_Range_isNull(range)) {
1030 QString comment = getSpelling(range);
1031 if (comment.startsWith(
"//!")) {
1032 qsizetype tag = comment.indexOf(QChar(
'['));
1034 qsizetype end = comment.indexOf(QChar(
']'), ++tag);
1036 fn->setTag(comment.mid(tag, end - tag));
1041 processFunction(fn, cursor);
1043 if (kind == CXCursor_FunctionTemplate) {
1045 fn->setTemplateDecl(get_template_declaration(template_declaration));
1048 return CXChildVisit_Continue;
1050#if CINDEX_VERSION
>= 36
1051 case CXCursor_FriendDecl: {
1055 case CXCursor_EnumDecl: {
1057 if (en && en->items().size())
1058 return CXChildVisit_Continue;
1060 QString enumTypeName = fromCXString(clang_getCursorSpelling(cursor));
1062 if (clang_Cursor_isAnonymous(cursor)) {
1063 enumTypeName =
"anonymous";
1071 en =
new EnumNode(parent_, enumTypeName, clang_EnumDecl_isScoped(cursor));
1077 visitChildrenLambda(cursor, [&](CXCursor cur) {
1078 if (clang_getCursorKind(cur) != CXCursor_EnumConstantDecl)
1079 return CXChildVisit_Continue;
1082 visitChildrenLambda(cur, [&](CXCursor cur) {
1083 if (clang_isExpression(clang_getCursorKind(cur))) {
1084 value = getSpelling(clang_getCursorExtent(cur));
1085 return CXChildVisit_Break;
1087 return CXChildVisit_Continue;
1089 if (value.isEmpty()) {
1090 QLatin1String hex(
"0x");
1091 if (!en->items().isEmpty() && en->items().last().value().startsWith(hex)) {
1092 value = hex + QString::number(clang_getEnumConstantDeclValue(cur), 16);
1094 value = QString::number(clang_getEnumConstantDeclValue(cur));
1098 en->addItem(EnumItem(fromCXString(clang_getCursorSpelling(cur)), value));
1099 return CXChildVisit_Continue;
1101 return CXChildVisit_Continue;
1103 case CXCursor_FieldDecl:
1104 case CXCursor_VarDecl: {
1106 return CXChildVisit_Continue;
1108 auto value_declaration =
1110 assert(value_declaration);
1113 auto var =
new VariableNode(parent_, fromCXString(clang_getCursorSpelling(cursor)));
1115 var->setAccess(access);
1117 var->setLeftType(QString::fromStdString(get_fully_qualified_type_name(
1118 value_declaration->getType(),
1119 value_declaration->getASTContext()
1121 var->setStatic(kind == CXCursor_VarDecl && parent_
->isClassNode());
1123 return CXChildVisit_Continue;
1125 case CXCursor_TypedefDecl: {
1127 return CXChildVisit_Continue;
1128 auto *td =
new TypedefNode(parent_, fromCXString(clang_getCursorSpelling(cursor)));
1132 visitChildrenLambda(cursor, [&](CXCursor cur) {
1133 if (clang_getCursorKind(cur) != CXCursor_TemplateRef
1134 || fromCXString(clang_getCursorSpelling(cur)) != QLatin1String(
"QFlags"))
1135 return CXChildVisit_Continue;
1137 visitChildrenLambda(cursor, [&](CXCursor cur) {
1138 if (clang_getCursorKind(cur) != CXCursor_TypeRef)
1139 return CXChildVisit_Continue;
1144 return CXChildVisit_Break;
1146 return CXChildVisit_Break;
1148 return CXChildVisit_Continue;
1154 parseProperty(getSpelling(clang_getCursorExtent(cursor)),
1155 fromCXSourceLocation(loc));
1157 return CXChildVisit_Continue;
1166 visitChildrenLambda(cursor, [&](CXCursor cur) {
1167 auto kind = clang_getCursorKind(cur);
1168 if (kind == CXCursor_AnnotateAttr) {
1169 QString annotation = fromCXString(clang_getCursorDisplayName(cur));
1170 if (annotation == QLatin1String(
"qt_slot")) {
1172 }
else if (annotation == QLatin1String(
"qt_signal")) {
1175 if (annotation == QLatin1String(
"qt_invokable"))
1177 }
else if (kind == CXCursor_CXXOverrideAttr) {
1179 }
else if (kind == CXCursor_ParmDecl) {
1181 return CXChildVisit_Break;
1183 if (QString name = fromCXString(clang_getCursorSpelling(cur)); !name.isEmpty())
1184 parameters
[i
].setName(name);
1187 Q_ASSERT(parameter_declaration);
1191 if (!default_value.empty())
1192 parameters[i].setDefaultValue(QString::fromStdString(default_value));
1196 return CXChildVisit_Continue;
1202 CXCursorKind kind = clang_getCursorKind(cursor);
1203 CXType funcType = clang_getCursorType(cursor);
1210 : clang_CXXMethod_isPureVirtual(cursor)
1227 const clang::FunctionDecl* function_declaration = declaration->getAsFunction();
1229 if (kind == CXCursor_Constructor
1231 || (kind == CXCursor_FunctionTemplate && fn->name() == parent_->name()))
1233 else if (kind == CXCursor_Destructor)
1236 fn->setReturnType(QString::fromStdString(get_fully_qualified_type_name(
1237 function_declaration->getReturnType(),
1238 function_declaration->getASTContext()
1241 const clang::CXXConstructorDecl* constructor_declaration = llvm::dyn_cast<
const clang::CXXConstructorDecl>(function_declaration);
1246 const clang::CXXConversionDecl* conversion_declaration = llvm::dyn_cast<
const clang::CXXConversionDecl>(function_declaration);
1250 (constructor_declaration && constructor_declaration->isExplicit()) ||
1251 (conversion_declaration && conversion_declaration->isExplicit())
1254 const clang::CXXMethodDecl* method_declaration = llvm::dyn_cast<
const clang::CXXMethodDecl>(function_declaration);
1259 const clang::FunctionType* function_type = function_declaration->getFunctionType();
1260 const clang::FunctionProtoType* function_prototype =
static_cast<
const clang::FunctionProtoType*>(function_type);
1262 if (function_prototype) {
1263 clang::FunctionProtoType::ExceptionSpecInfo exception_specification = function_prototype->getExceptionSpecInfo();
1265 if (exception_specification.Type !=
clang::ExceptionSpecificationType::EST_None) {
1266 const std::string exception_specification_spelling =
1267 exception_specification.NoexceptExpr ? get_expression_as_string(
1268 exception_specification.NoexceptExpr,
1269 function_declaration->getASTContext()
1272 if (exception_specification_spelling !=
"false")
1273 fn->markNoexcept(QString::fromStdString(exception_specification_spelling));
1277 CXRefQualifierKind refQualKind = clang_Type_getCXXRefQualifier(funcType);
1278 if (refQualKind == CXRefQualifier_LValue)
1280 else if (refQualKind == CXRefQualifier_RValue)
1289 parameters
.reserve(function_declaration->getNumParams()
);
1291 for (clang::ParmVarDecl*
const parameter_declaration : function_declaration->parameters()) {
1292 clang::QualType parameter_type = parameter_declaration->getOriginalType();
1294 parameters.append(QString::fromStdString(get_fully_qualified_type_name(
1296 parameter_declaration->getASTContext()
1299 if (!parameter_type.isCanonical())
1300 parameters.last().setCanonicalType(QString::fromStdString(get_fully_qualified_type_name(
1301 parameter_type.getCanonicalType(),
1302 parameter_declaration->getASTContext()
1307 if (parameters
.last().type().endsWith(QLatin1String(
"QPrivateSignal"))) {
1313 if (clang_isFunctionTypeVariadic(funcType))
1314 parameters.append(QStringLiteral(
"..."));
1315 readParameterNamesAndAttributes(fn, cursor);
1317 if (declaration->getFriendObjectKind() !=
clang::Decl::FOK_None)
1323 if (!spelling.startsWith(QLatin1String(
"Q_PROPERTY"))
1324 && !spelling.startsWith(QLatin1String(
"QDOC_PROPERTY"))
1325 && !spelling.startsWith(QLatin1String(
"Q_OVERRIDE")))
1328 qsizetype lpIdx = spelling.indexOf(QChar(
'('));
1329 qsizetype rpIdx = spelling.lastIndexOf(QChar(
')'));
1330 if (lpIdx <= 0 || rpIdx <= lpIdx)
1333 QString signature = spelling.mid(lpIdx + 1, rpIdx - lpIdx - 1);
1334 signature = signature.simplified();
1335 QStringList parts = signature.split(QChar(
' '), Qt::SkipEmptyParts);
1337 static const QStringList attrs =
1338 QStringList() <<
"READ" <<
"MEMBER" <<
"WRITE"
1339 <<
"NOTIFY" <<
"CONSTANT" <<
"FINAL"
1340 <<
"REQUIRED" <<
"BINDABLE" <<
"DESIGNABLE"
1341 <<
"RESET" <<
"REVISION" <<
"SCRIPTABLE"
1342 <<
"STORED" <<
"USER";
1346 auto it =
std::find_if(parts.cbegin(), parts.cend(),
1347 [](
const QString &attr) ->
bool {
1348 return attrs.contains(attr);
1351 if (it == parts.cend() ||
std::distance(parts.cbegin(), it) < 2)
1354 QStringList typeParts;
1355 std::copy(parts.cbegin(), it,
std::back_inserter(typeParts));
1356 parts.erase(parts.cbegin(), it);
1357 QString name = typeParts.takeLast();
1360 while (!name.isEmpty() && name.front() == QChar(
'*')) {
1361 typeParts.last().push_back(name.front());
1366 if (parts.size() < 2 || name.isEmpty())
1370 property->setAccess(Access::Public);
1371 property->setLocation(loc);
1372 property->setDataType(typeParts.join(QChar(
' ')));
1375 while (i < parts.size()) {
1376 const QString &key = parts.at(i++);
1378 if (key ==
"CONSTANT") {
1379 property->setConstant();
1380 }
else if (key ==
"REQUIRED") {
1381 property->setRequired();
1383 if (i < parts.size()) {
1384 QString value = parts.at(i++);
1385 if (key ==
"READ") {
1387 }
else if (key ==
"WRITE") {
1389 property->setWritable(
true);
1390 }
else if (key ==
"MEMBER") {
1391 property->setWritable(
true);
1392 }
else if (key ==
"STORED") {
1393 property->setStored(value.toLower() ==
"true");
1394 }
else if (key ==
"BINDABLE") {
1397 }
else if (key ==
"RESET") {
1399 }
else if (key ==
"NOTIFY") {
1408
1409
1410
1411
1412
1416 clang_getPresumedLocation(loc,
nullptr, &docloc.line, &docloc.column);
1417 auto decl_it = declMap_.upperBound(docloc);
1418 if (decl_it == declMap_.end())
1421 unsigned int declLine = decl_it.key().line;
1422 unsigned int nextCommentLine;
1423 clang_getPresumedLocation(nextCommentLoc,
nullptr, &nextCommentLine,
nullptr);
1424 if (nextCommentLine < declLine)
1428 if (decl_it != declMap_.begin()) {
1429 CXSourceLocation prevDeclEnd = clang_getRangeEnd(clang_getCursorExtent(*(
std::prev(decl_it))));
1430 unsigned int prevDeclLine;
1431 clang_getPresumedLocation(prevDeclEnd,
nullptr, &prevDeclLine,
nullptr);
1432 if (prevDeclLine >= docloc.line) {
1435 auto parent = clang_getCursorLexicalParent(*decl_it);
1436 if (!clang_equalCursors(parent, *(
std::prev(decl_it))))
1440 auto *node = findNodeForCursor(qdb_, *decl_it);
1442 if (node && node->isFunction(
Node::CPP))
1443 readParameterNamesAndAttributes(
static_cast<
FunctionNode *>(node), *decl_it);
1450 const std::vector<QByteArray>& include_paths,
1451 const QList<QByteArray>& defines,
1458 m_allHeaders = config.getHeaderFiles();
1463
1464
1465
1466
1467
1468#if LIBCLANG_VERSION_MAJOR == 15
1476 "-fms-compatibility-version=19",
1480 "-DQT_DISABLE_DEPRECATED_UP_TO=0",
1481 "-DQT_ANNOTATE_CLASS(type,...)=static_assert(sizeof(#__VA_ARGS__),#type);",
1482 "-DQT_ANNOTATE_CLASS2(type,a1,a2)=static_assert(sizeof(#a1,#a2),#type);",
1483 "-DQT_ANNOTATE_FUNCTION(a)=__attribute__((annotate(#a)))",
1484 "-DQT_ANNOTATE_ACCESS_SPECIFIER(a)=__attribute__((annotate(#a)))",
1485 "-Wno-constant-logical-operand",
1486 "-Wno-macro-redefined",
1487 "-Wno-nullability-completeness",
1488 "-fvisibility=default",
1490 (
"-I" CLANG_RESOURCE_DIR)
1494
1495
1496
1503 for (
const auto &p : std::as_const(defines))
1504 args.push_back(p.constData());
1509 QList<QByteArray> result;
1510 for (
const auto& [header_path, _] : allHeaders) {
1511 const QByteArray path =
"-I" + header_path.toLatin1();
1512 const QByteArray parent =
1513 "-I" + QDir::cleanPath(header_path + QLatin1String(
"/../")).toLatin1();
1520
1521
1522
1524 const std::vector<QByteArray>& include_paths,
1525 const std::set<Config::HeaderFilePath>& all_headers,
1526 std::vector<
const char*>& args
1528 if (include_paths.empty()) {
1530
1531
1532
1533
1534 qCWarning(lcQdoc) <<
"No include paths passed to qdoc; guessing reasonable include paths";
1536 QString basicIncludeDir = QDir::cleanPath(QString(Config::installDir +
"/../include"));
1537 args.emplace_back(QByteArray(
"-I" + basicIncludeDir.toLatin1()).constData());
1539 auto include_paths_from_headers = includePathsFromHeaders(all_headers);
1540 args.insert(args.end(), include_paths_from_headers.begin(), include_paths_from_headers.end());
1542 std::copy(include_paths.begin(), include_paths.end(),
std::back_inserter(args));
1547
1548
1549
1550
1553 QString module_header,
1554 const std::set<Config::HeaderFilePath>& all_headers,
1555 const std::vector<QByteArray>& include_paths,
1556 const QList<QByteArray>& defines
1558 static std::vector<
const char*> arguments{};
1560 if (module_header.isEmpty())
return std::nullopt;
1562 getDefaultArgs(defines, arguments);
1563 getMoreArgs(include_paths, all_headers, arguments);
1565 flags_ =
static_cast<CXTranslationUnit_Flags>(CXTranslationUnit_Incomplete
1566 | CXTranslationUnit_SkipFunctionBodies
1567 | CXTranslationUnit_KeepGoing);
1571 QTemporaryDir pch_directory{QDir::tempPath() + QLatin1String(
"/qdoc_pch")};
1572 if (!pch_directory.isValid())
return std::nullopt;
1574 const QByteArray module = module_header.toUtf8();
1577 qCDebug(lcQdoc) <<
"Build and visit PCH for" << module_header;
1580 struct FindPredicate
1582 enum SearchType { Any, Module };
1583 QByteArray &candidate_;
1584 const QByteArray &module_;
1586 FindPredicate(QByteArray &candidate,
const QByteArray &module,
1587 SearchType type = Any)
1588 : candidate_(candidate), module_(module), type_(type)
1592 bool operator()(
const QByteArray &p)
const
1594 if (type_ != Any && !p.endsWith(module_))
1596 candidate_ = p +
"/";
1597 candidate_.append(module_);
1598 if (p.startsWith(
"-I"))
1599 candidate_ = candidate_.mid(2);
1600 return QFile::exists(QString::fromUtf8(candidate_));
1605 QByteArray candidate;
1606 auto it =
std::find_if(include_paths.begin(), include_paths.end(),
1607 FindPredicate(candidate, module, FindPredicate::Module));
1608 if (it == include_paths.end())
1609 it =
std::find_if(include_paths.begin(), include_paths.end(),
1610 FindPredicate(candidate, module, FindPredicate::Any));
1611 if (it != include_paths.end())
1614 if (header.isEmpty()) {
1615 qWarning() <<
"(qdoc) Could not find the module header in include paths for module"
1616 << module <<
" (include paths: " << include_paths <<
")";
1617 qWarning() <<
" Artificial module header built from header dirs in qdocconf "
1620 arguments.push_back(
"-xc++");
1624 QString tmpHeader = pch_directory.path() +
"/" + module;
1625 if (QFile tmpHeaderFile(tmpHeader); tmpHeaderFile.open(QIODevice::Text | QIODevice::WriteOnly)) {
1626 QTextStream out(&tmpHeaderFile);
1627 if (header.isEmpty()) {
1628 for (
const auto& [header_path, header_name] : all_headers) {
1629 if (!header_name.endsWith(QLatin1String(
"_p.h"))
1630 && !header_name.startsWith(QLatin1String(
"moc_"))) {
1631 QString line = QLatin1String(
"#include \"") + header_path
1632 + QLatin1String(
"/") + header_name + QLatin1String(
"\"");
1633 out << line <<
"\n";
1638 QFileInfo headerFile(header);
1639 if (!headerFile.exists()) {
1640 qWarning() <<
"Could not find module header file" << header;
1641 return std::nullopt;
1643 out << QLatin1String(
"#include \"") + header + QLatin1String(
"\"");
1648 clang_parseTranslationUnit2(index, tmpHeader.toLatin1().data(), arguments.data(),
1649 static_cast<
int>(arguments.size()),
nullptr, 0,
1650 flags_ | CXTranslationUnit_ForSerialization, &tu
.tu);
1651 qCDebug(lcQdoc) <<
__FUNCTION__ <<
"clang_parseTranslationUnit2(" << tmpHeader << arguments
1652 <<
") returns" << err;
1657 qCCritical(lcQdoc) <<
"Could not create PCH file for " << module_header;
1658 return std::nullopt;
1661 QByteArray pch_name = pch_directory.path().toUtf8() +
"/" + module +
".pch";
1662 auto error = clang_saveTranslationUnit(tu, pch_name.constData(),
1663 clang_defaultSaveOptions(tu));
1665 qCCritical(lcQdoc) <<
"Could not save PCH file for" << module_header;
1666 return std::nullopt;
1671 CXCursor cur = clang_getTranslationUnitCursor(tu);
1674 qCDebug(lcQdoc) <<
"PCH built and visited for" << module_header;
1676 return std::make_optional(
PCHFile{
std::move(pch_directory), pch_name});
1681 if (t.count(QChar(
'.')) > 1)
1682 t.truncate(t.lastIndexOf(QChar(
'.')));
1687
1688
1689
1690
1691
1692
1695 flags_ =
static_cast<CXTranslationUnit_Flags>(CXTranslationUnit_Incomplete
1696 | CXTranslationUnit_SkipFunctionBodies
1697 | CXTranslationUnit_KeepGoing);
1701 getDefaultArgs(m_defines, m_args);
1702 if (m_pch && !filePath.endsWith(
".mm")) {
1703 m_args.push_back(
"-w");
1704 m_args.push_back(
"-include-pch");
1705 m_args.push_back((*m_pch).get().name.constData());
1707 getMoreArgs(m_includePaths, m_allHeaders, m_args);
1711 clang_parseTranslationUnit2(index, filePath.toLocal8Bit(), m_args.data(),
1712 static_cast<
int>(m_args.size()),
nullptr, 0, flags_, &tu.tu);
1713 qCDebug(lcQdoc) <<
__FUNCTION__ <<
"clang_parseTranslationUnit2(" << filePath << m_args
1714 <<
") returns" << err;
1718 qWarning() <<
"(qdoc) Could not parse source file" << filePath <<
" error code:" << err;
1722 ParsedCppFileIR parse_result{};
1724 CXCursor tuCur = clang_getTranslationUnitCursor(tu);
1729 unsigned int numTokens = 0;
1730 const QSet<QString> &commands = CppCodeParser::topic_commands + CppCodeParser::meta_commands;
1731 clang_tokenize(tu, clang_getCursorExtent(tuCur), &tokens, &numTokens);
1733 for (
unsigned int i = 0; i < numTokens; ++i) {
1734 if (clang_getTokenKind(tokens[i]) != CXToken_Comment)
1736 QString comment = fromCXString(clang_getTokenSpelling(tu, tokens[i]));
1737 if (!comment.startsWith(
"/*!"))
1740 auto commentLoc = clang_getTokenLocation(tu, tokens[i]);
1743 Doc::trimCStyleComment(loc, comment);
1746 Doc doc(loc, end_loc, comment, commands, CppCodeParser::topic_commands);
1752 if (i + 1 < numTokens) {
1754 CXSourceLocation nextCommentLoc = commentLoc;
1755 while (i + 2 < numTokens && clang_getTokenKind(tokens[i + 1]) != CXToken_Comment)
1757 nextCommentLoc = clang_getTokenLocation(tu, tokens[i + 1]);
1764 bool future =
false;
1766 QString sinceVersion = doc.metaCommandArgs(
COMMAND_SINCE).at(0).first;
1767 if (getUnpatchedVersion(sinceVersion) >
1768 getUnpatchedVersion(Config::instance().get(
CONFIG_VERSION).asString()))
1773 QStringLiteral(
"Cannot tie this documentation to anything"),
1774 QStringLiteral(
"qdoc found a /*! ... */ comment, but there was no "
1775 "topic command (e.g., '\\%1', '\\%2') in the "
1776 "comment and no function definition following "
1784 CXCursor cur = clang_getCursor(tu, commentLoc);
1786 CXCursorKind kind = clang_getCursorKind(cur);
1787 if (clang_isTranslationUnit(kind) || clang_isInvalid(kind))
1789 if (kind == CXCursor_Namespace) {
1790 parse_result.untied.back().context << fromCXString(clang_getCursorSpelling(cur));
1792 cur = clang_getCursorLexicalParent(cur);
1797 clang_disposeTokens(tu, tokens, numTokens);
1798 m_namespaceScope.clear();
1801 return parse_result;
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1817 const QString &idTag, QStringList context)
1819 Node *fnNode =
nullptr;
1821
1822
1823
1824
1825
1826 if (!idTag.isEmpty()) {
1827 fnNode = m_qdb->findFunctionNodeForTag(idTag);
1830 QStringLiteral(
"tag \\fn [%1] not used in any include file in current module").arg(idTag));
1833
1834
1835
1836
1838 QStringList leftParenSplit = fnSignature.mid(fnSignature.indexOf(fn->name())).split(
'(');
1839 if (leftParenSplit.size() > 1) {
1840 QStringList rightParenSplit = leftParenSplit[1].split(
')');
1841 if (!rightParenSplit.empty()) {
1842 QString params = rightParenSplit[0];
1843 if (!params.isEmpty()) {
1844 QStringList commaSplit = params.split(
',');
1846 if (parameters
.count() == commaSplit.size()) {
1847 for (
int i = 0; i < parameters
.count(); ++i) {
1848 QStringList blankSplit = commaSplit[i].split(
' ', Qt::SkipEmptyParts);
1849 if (blankSplit.size() > 1) {
1850 QString pName = blankSplit.last();
1852 auto it =
std::find_if(
std::begin(pName),
std::end(pName),
1853 [](
const QChar &c) {
return c.isLetter(); });
1854 parameters
[i
].setName(
1855 pName.remove(0,
std::distance(
std::begin(pName), it)));
1865 auto flags =
static_cast<CXTranslationUnit_Flags>(CXTranslationUnit_Incomplete
1866 | CXTranslationUnit_SkipFunctionBodies
1867 | CXTranslationUnit_KeepGoing);
1871 getDefaultArgs(m_defines, m_args);
1874 m_args.push_back(
"-w");
1875 m_args.push_back(
"-include-pch");
1876 m_args.push_back((*m_pch).get().name.constData());
1881 for (
const auto &ns : std::as_const(context))
1882 s_fn.prepend(
"namespace " + ns.toUtf8() +
" {");
1883 s_fn += fnSignature.toUtf8();
1884 if (!s_fn.endsWith(
";"))
1886 s_fn.append(context.size(),
'}');
1889 CXUnsavedFile unsavedFile { dummyFileName, s_fn.constData(),
1890 static_cast<
unsigned long>(s_fn.size()) };
1891 CXErrorCode err = clang_parseTranslationUnit2(index, dummyFileName, m_args.data(),
1892 int(m_args.size()), &unsavedFile, 1, flags, &tu.tu);
1893 qCDebug(lcQdoc) <<
__FUNCTION__ <<
"clang_parseTranslationUnit2(" << dummyFileName << m_args
1894 <<
") returns" << err;
1897 location.error(QStringLiteral(
"clang could not parse \\fn %1").arg(fnSignature));
1901
1902
1903
1904
1905
1906 CXCursor cur = clang_getTranslationUnitCursor(tu);
1908 bool ignoreSignature =
false;
1912 unsigned diagnosticCount = clang_getNumDiagnostics(tu);
1913 const auto &config = Config::instance();
1914 if (diagnosticCount > 0 && (!config.preparing() || config.singleExec())) {
1915 return FnMatchError{ fnSignature, location };
static const clang::Decl * get_cursor_declaration(CXCursor cursor)
Returns the underlying Decl that cursor represents.
static QString reconstructQualifiedPathForCursor(CXCursor cur)
Reconstruct the qualified path name of a function that is being overridden.
QString functionName(CXCursor cursor)
Returns the function name from a given cursor representing a function declaration.
static std::string get_default_value_initializer_as_string(const clang::TemplateTemplateParmDecl *parameter)
static QString fromCXString(CXString &&string)
convert a CXString to a QString, and dispose the CXString
static QDebug operator<<(QDebug debug, const std::vector< T > &v)
static QString getSpelling(CXSourceRange range)
static void setOverridesForFunction(FunctionNode *fn, CXCursor cursor)
static QList< QByteArray > includePathsFromHeaders(const std::set< Config::HeaderFilePath > &allHeaders)
static const auto kClangDontDisplayDiagnostics
void getMoreArgs(const std::vector< QByteArray > &include_paths, const std::set< Config::HeaderFilePath > &all_headers, std::vector< const char * > &args)
Load the include paths into moreArgs.
static std::string get_default_value_initializer_as_string(const clang::ParmVarDecl *parameter)
void getDefaultArgs(const QList< QByteArray > &defines, std::vector< const char * > &args)
Load the default arguments and the defines into args.
static std::string get_expression_as_string(const clang::Expr *expression, const clang::ASTContext &declaration_context)
bool visitChildrenLambda(CXCursor cursor, T &&lambda)
Call clang_visitChildren on the given cursor with the lambda as a callback T can be any functor that ...
static std::string get_default_value_initializer_as_string(const clang::NamedDecl *declaration)
static RelaxedTemplateDeclaration get_template_declaration(const clang::TemplateDecl *template_declaration)
static std::string get_default_value_initializer_as_string(const clang::NonTypeTemplateParmDecl *parameter)
static QString fromCache(const QByteArray &cache, unsigned int offset1, unsigned int offset2)
static float getUnpatchedVersion(QString t)
std::optional< PCHFile > buildPCH(QDocDatabase *qdb, QString module_header, const std::set< Config::HeaderFilePath > &all_headers, const std::vector< QByteArray > &include_paths, const QList< QByteArray > &defines)
Building the PCH must be possible when there are no .cpp files, so it is moved here to its own member...
static Location fromCXSourceLocation(CXSourceLocation location)
convert a CXSourceLocation to a qdoc Location
static Access fromCX_CXXAccessSpecifier(CX_CXXAccessSpecifier spec)
convert a CX_CXXAccessSpecifier to Node::Access
static std::string get_default_value_initializer_as_string(const clang::TemplateTypeParmDecl *parameter)
constexpr const char fnDummyFileName[]
static CXTranslationUnit_Flags flags_
static Node * findNodeForCursor(QDocDatabase *qdb, CXCursor cur)
Find the node from the QDocDatabase qdb that corresponds to the declaration represented by the cursor...
static std::string get_fully_qualified_type_name(clang::QualType type, const clang::ASTContext &declaration_context)
Returns a string representing the name of type as if it was referred to at the end of the translation...
static void printDiagnostics(const CXTranslationUnit &translationUnit)
static const char * defaultArgs_[]
static QString readFile(CXFile cxFile, unsigned int offset1, unsigned int offset2)
void addChild(Node *child)
Adds the child to this node's child list and sets the child's parent pointer to this Aggregate.
ParsedCppFileIR parse_cpp_file(const QString &filePath)
Get ready to parse the C++ cpp file identified by filePath and add its parsed contents to the databas...
ClangCodeParser(QDocDatabase *qdb, Config &, const std::vector< QByteArray > &include_paths, const QList< QByteArray > &defines, std::optional< std::reference_wrapper< const PCHFile > > pch)
ClangVisitor(QDocDatabase *qdb, const std::set< Config::HeaderFilePath > &allHeaders)
Node * nodeForCommentAtLocation(CXSourceLocation loc, CXSourceLocation nextCommentLoc)
Given a comment at location loc, return a Node for this comment nextCommentLoc is the location of the...
CXChildVisitResult visitChildren(CXCursor cursor)
CXChildVisitResult visitFnArg(CXCursor cursor, Node **fnNode, bool &ignoreSignature)
The ClassNode represents a C++ class.
void addResolvedBaseClass(Access access, ClassNode *node)
Adds the base class node to this class's list of base classes.
static bool isWorthWarningAbout(const Doc &doc)
Test for whether a doc comment warrants warnings.
The Config class contains the configuration variables for controlling how qdoc produces documentation...
const Location & location() const
Returns the starting location of a qdoc comment.
TopicList topicsUsed() const
Returns a reference to the list of topic commands used in the current qdoc comment.
void setFlagsType(TypedefNode *typedefNode)
This node is used to represent any kind of function being documented.
void setVirtualness(Virtualness virtualness)
bool isNonvirtual() const
void setInvokable(bool b)
void setMetaness(Metaness metaness)
Parameters & parameters()
The Location class provides a way to mark a location in a file.
This class represents a C++ namespace.
void setAccess(Access t)
Sets the node's access type to t.
NodeType
An unsigned char value that identifies an object as a particular subclass of Node.
bool isNamespace() const
Returns true if the node type is Namespace.
bool isTypedef() const
Returns true if the node type is Typedef.
bool isFunction(Genus g=DontCare) const
Returns true if this is a FunctionNode and its Genus is set to g.
bool isEnumType() const
Returns true if the node type is Enum.
bool isVariable() const
Returns true if the node type is Variable.
void setLocation(const Location &t)
Sets the node's declaration location, its definition location, or both, depending on the suffix of th...
virtual bool isAggregate() const
Returns true if this node is an aggregate, which means it inherits Aggregate and can therefore have c...
virtual void setRelatedNonmember(bool b)
Sets a flag in the node indicating whether this node is a related nonmember of something.
bool isClass() const
Returns true if the node type is Class.
LinkType
An unsigned char value that probably should be moved out of the Node base class.
virtual bool isClassNode() const
Returns true if this is an instance of ClassNode.
A class for parsing and managing a function parameter list.
Parameter & operator[](int index)
This class describes one instance of using the Q_PROPERTY macro.
This class provides exclusive access to the qdoc database, which consists of a forrest of trees and a...
NamespaceNode * primaryTreeRoot()
Returns a pointer to the root node of the primary tree.
bool hasTooManyTopics(const Doc &doc)
Checks if there are too many topic commands in doc.
std::string getFullyQualifiedName(QualType QT, const ASTContext &Ctx, const PrintingPolicy &Policy, bool WithGlobalNsPrefix=false)
QList< Node * > NodeVector
Returns the spelling in the file for a source range.
std::variant< Node *, FnMatchError > operator()(const Location &location, const QString &fnSignature, const QString &idTag, QStringList context)
Use clang to parse the function signature from a function command.
Encapsulates information about.
operator CXTranslationUnit()