20#include <QtCore/qdebug.h>
21#include <QtCore/qelapsedtimer.h>
22#include <QtCore/qfile.h>
23#include <QtCore/qscopedvaluerollback.h>
24#include <QtCore/qtemporarydir.h>
25#include <QtCore/qtextstream.h>
26#include <QtCore/qvarlengtharray.h>
28#include <clang-c/Index.h>
30#include <clang/AST/Decl.h>
31#include <clang/AST/DeclFriend.h>
32#include <clang/AST/DeclTemplate.h>
33#include <clang/AST/Expr.h>
34#include <clang/AST/Type.h>
35#include <clang/AST/TypeLoc.h>
36#include <clang/Basic/SourceLocation.h>
37#include <clang/Frontend/ASTUnit.h>
38#include <clang/Lex/Lexer.h>
39#include <llvm/Support/Casting.h>
41#include "clang/AST/QualTypeNames.h"
48struct CompilationIndex {
49 CXIndex index =
nullptr;
56 clang_disposeIndex(index);
61 CXTranslationUnit
tu =
nullptr;
72 clang_disposeTranslationUnit(
tu);
80static CXTranslationUnit_Flags
flags_ =
static_cast<CXTranslationUnit_Flags>(0);
84#ifndef QT_NO_DEBUG_STREAM
88 QDebugStateSaver saver(debug);
91 const size_t size = v.size();
92 debug <<
"std::vector<>[" << size <<
"](";
93 for (size_t i = 0; i < size; ++i) {
105 if (!lcQdocClang().isDebugEnabled())
108 static const auto displayOptions = CXDiagnosticDisplayOptions::CXDiagnostic_DisplaySourceLocation
109 | CXDiagnosticDisplayOptions::CXDiagnostic_DisplayColumn
110 | CXDiagnosticDisplayOptions::CXDiagnostic_DisplayOption;
112 for (
unsigned i = 0, numDiagnostics = clang_getNumDiagnostics(translationUnit); i < numDiagnostics; ++i) {
113 auto diagnostic = clang_getDiagnostic(translationUnit, i);
114 auto formattedDiagnostic = clang_formatDiagnostic(diagnostic, displayOptions);
115 qCDebug(lcQdocClang) << clang_getCString(formattedDiagnostic);
116 clang_disposeString(formattedDiagnostic);
117 clang_disposeDiagnostic(diagnostic);
122
123
124
125
126
127
128
129
130
131
132
133
135 assert(clang_isDeclaration(clang_getCursorKind(cursor)));
137 return static_cast<
const clang::Decl*>(cursor.data[0]);
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
167
172 declaration_context.getPrintingPolicy()
177
178
179
180
181
182
183
184
185
187 QString default_value = QString::fromStdString(clang::Lexer::getSourceText(
188 clang::CharSourceRange::getTokenRange(expression->getSourceRange()),
189 declaration_context.getSourceManager(),
190 declaration_context.getLangOpts()
193 if (default_value.startsWith(
"="))
194 default_value.remove(0, 1);
196 default_value = default_value.trimmed();
198 return default_value.toStdString();
202
203
204
205
206
207
208
209
211#if LIBCLANG_VERSION_MAJOR >= 19
212 return (parameter && parameter->hasDefaultArgument()) ?
213 get_fully_qualified_type_name(parameter->getDefaultArgument().getArgument().getAsType(), parameter->getASTContext()) :
216 return (parameter && parameter->hasDefaultArgument()) ?
217 get_fully_qualified_type_name(parameter->getDefaultArgument(), parameter->getASTContext()) :
224
225
226
227
228
229
230
231
233#if LIBCLANG_VERSION_MAJOR >= 19
234 return (parameter && parameter->hasDefaultArgument()) ?
235 get_expression_as_string(parameter->getDefaultArgument().getSourceExpression(), parameter->getASTContext()) :
"";
237 return (parameter && parameter->hasDefaultArgument()) ?
238 get_expression_as_string(parameter->getDefaultArgument(), parameter->getASTContext()) :
"";
244
245
246
247
248
249
250
251
253 std::string default_value{};
255 if (parameter && parameter->hasDefaultArgument()) {
256 const clang::TemplateName template_name = parameter->getDefaultArgument().getArgument().getAsTemplate();
258 llvm::raw_string_ostream ss{default_value};
259 template_name.print(ss, parameter->getASTContext().getPrintingPolicy(),
clang::TemplateName::Qualified::AsWritten);
262 return default_value;
266
267
268
269
270
271
272
273
274
275
277 if (!parameter || !parameter->hasDefaultArg() || parameter->hasUnparsedDefaultArg())
280 return get_expression_as_string(
281 parameter->hasUninstantiatedDefaultArg() ? parameter->getUninstantiatedDefaultArg() : parameter->getDefaultArg(),
282 parameter->getASTContext()
287
288
289
290
291
292
293
295 if (!declaration)
return "";
297 if (
auto type_template_parameter = llvm::dyn_cast<clang::TemplateTypeParmDecl>(declaration))
298 return get_default_value_initializer_as_string(type_template_parameter);
300 if (
auto non_type_template_parameter = llvm::dyn_cast<clang::NonTypeTemplateParmDecl>(declaration))
301 return get_default_value_initializer_as_string(non_type_template_parameter);
303 if (
auto template_template_parameter = llvm::dyn_cast<clang::TemplateTemplateParmDecl>(declaration)) {
304 return get_default_value_initializer_as_string(template_template_parameter);
307 if (
auto function_parameter = llvm::dyn_cast<clang::ParmVarDecl>(declaration)) {
308 return get_default_value_initializer_as_string(function_parameter);
315
316
317
318
322 CXCursorVisitor visitor = [](CXCursor c, CXCursor,
323 CXClientData client_data) -> CXChildVisitResult {
324 return (*
static_cast<T *>(client_data))(c);
326 return clang_visitChildren(cursor, visitor, &lambda);
330
331
334 QString ret = QString::fromUtf8(clang_getCString(string));
335 clang_disposeString(string);
340
341
342
344 assert(template_declaration);
348 auto template_parameters = template_declaration->getTemplateParameters();
349 for (
auto template_parameter : template_parameters->asArray()) {
350 auto kind{RelaxedTemplateParameter::Kind::TypeTemplateParameter};
353 if (
auto non_type_template_parameter = llvm::dyn_cast<clang::NonTypeTemplateParmDecl>(template_parameter)) {
354 kind = RelaxedTemplateParameter::Kind::NonTypeTemplateParameter;
355 type = get_fully_qualified_type_name(non_type_template_parameter->getType(), non_type_template_parameter->getASTContext());
387 if (QString::fromStdString(type).startsWith(
"typename ")) type.erase(0, std::string(
"typename ").size());
390 auto template_template_parameter = llvm::dyn_cast<clang::TemplateTemplateParmDecl>(template_parameter);
391 if (template_template_parameter) kind = RelaxedTemplateParameter::Kind::TemplateTemplateParameter;
393 template_declaration_ir.parameters.push_back({
395 template_parameter->isTemplateParameterPack(),
398 template_parameter->getNameAsString(),
399 get_default_value_initializer_as_string(template_parameter)
401 (template_template_parameter ?
402 std::optional<TemplateDeclarationStorage>(TemplateDeclarationStorage{
403 get_template_declaration(template_template_parameter).parameters
408 return template_declaration_ir;
412
413
416 unsigned int line, column;
418 clang_getPresumedLocation(location, &file, &line, &column);
426
427
432 return Access::Private;
433 case CX_CXXProtected:
434 return Access::Protected;
436 return Access::Public;
438 return Access::Public;
443
444
453 unsigned int offset1,
unsigned int offset2)
455 return QString::fromUtf8(cache.mid(offset1, offset2 - offset1));
458static QString
readFile(CXFile cxFile,
unsigned int offset1,
unsigned int offset2)
460 using FileCache = QList<FileCacheEntry>;
461 static FileCache cache;
463 CXString cxFileName = clang_getFileName(cxFile);
464 const QByteArray fileName = clang_getCString(cxFileName);
465 clang_disposeString(cxFileName);
467 for (
const auto &entry : std::as_const(cache)) {
468 if (fileName == entry.fileName)
469 return fromCache(entry.content, offset1, offset2);
472 QFile file(QString::fromUtf8(fileName));
473 if (file.open(QIODeviceBase::ReadOnly)) {
475 cache.prepend(entry);
476 while (cache.size() > 5)
478 return fromCache(entry.content, offset1, offset2);
485 auto start = clang_getRangeStart(range);
486 auto end = clang_getRangeEnd(range);
488 unsigned int offset1, offset2;
489 clang_getFileLocation(start, &file1,
nullptr,
nullptr, &offset1);
490 clang_getFileLocation(end, &file2,
nullptr,
nullptr, &offset2);
492 if (file1 != file2 || offset2 <= offset1)
495 return readFile(file1, offset1, offset2);
499
500
501
502
505 if (clang_getCursorKind(cursor) == CXCursor_ConversionFunction) {
509 auto conversion_declaration =
512 return QLatin1String(
"operator ") + QString::fromStdString(get_fully_qualified_type_name(
513 conversion_declaration->getConversionType(),
514 conversion_declaration->getASTContext()
518 QString name = fromCXString(clang_getCursorSpelling(cursor));
521 auto ltLoc = name.indexOf(
'<');
522 if (ltLoc > 0 && !name.startsWith(
"operator<"))
523 name = name.left(ltLoc);
528
529
530
534 auto kind = clang_getCursorKind(cur);
535 while (!clang_isInvalid(kind) && kind != CXCursor_TranslationUnit) {
537 case CXCursor_Namespace:
538 case CXCursor_StructDecl:
539 case CXCursor_ClassDecl:
540 case CXCursor_UnionDecl:
541 case CXCursor_ClassTemplate:
543 path.prepend(fromCXString(clang_getCursorSpelling(cur)));
545 case CXCursor_FunctionDecl:
546 case CXCursor_FunctionTemplate:
547 case CXCursor_CXXMethod:
548 case CXCursor_Constructor:
549 case CXCursor_Destructor:
550 case CXCursor_ConversionFunction:
551 path = functionName(cur);
556 cur = clang_getCursorSemanticParent(cur);
557 kind = clang_getCursorKind(cur);
563
564
565
568 auto kind = clang_getCursorKind(cur);
569 if (clang_isInvalid(kind))
571 if (kind == CXCursor_TranslationUnit)
579 case CXCursor_TemplateTypeParameter:
580 case CXCursor_NonTypeTemplateParameter:
581 case CXCursor_TemplateTemplateParameter:
591 auto parent =
static_cast<
Aggregate *>(p);
593 QString name = fromCXString(clang_getCursorSpelling(cur));
595 case CXCursor_Namespace:
597 case CXCursor_StructDecl:
598 case CXCursor_ClassDecl:
599 case CXCursor_UnionDecl:
600 case CXCursor_ClassTemplate:
602 case CXCursor_FunctionDecl:
603 case CXCursor_FunctionTemplate:
604 case CXCursor_CXXMethod:
605 case CXCursor_Constructor:
606 case CXCursor_Destructor:
607 case CXCursor_ConversionFunction: {
609 parent->findChildren(functionName(cur), candidates);
613 lexical_parent && lexical_parent
->isAggregate() && lexical_parent != parent) {
614 static_cast<Aggregate *>(lexical_parent)->findChildren(functionName(cur), candidates);
618 if (candidates.isEmpty())
621 CXType funcType = clang_getCursorType(cur);
622 auto numArg = clang_getNumArgTypes(funcType);
623 bool isVariadic = clang_isFunctionTypeVariadic(funcType);
624 QVarLengthArray<QString, 20> args;
627 if (kind == CXCursor_FunctionTemplate)
628 relaxed_template_declaration = get_template_declaration(
632 for (Node *candidate : std::as_const(candidates)) {
633 if (!candidate->isFunction(Node::CPP))
636 auto fn =
static_cast<FunctionNode *>(candidate);
638 if (!fn->templateDecl() && relaxed_template_declaration)
641 if (fn->templateDecl() && !relaxed_template_declaration)
644 if (fn->templateDecl() && relaxed_template_declaration &&
645 !are_template_declarations_substitutable(*fn->templateDecl(), *relaxed_template_declaration))
648 const Parameters ¶meters = fn->parameters();
650 if (parameters.count() != numArg + isVariadic)
653 if (fn->isConst() !=
bool(clang_CXXMethod_isConst(cur)))
656 if (isVariadic && parameters.last().type() != QLatin1String(
"..."))
659 if (fn->isRef() != (clang_Type_getCXXRefQualifier(funcType) == CXRefQualifier_LValue))
662 if (fn->isRefRef() != (clang_Type_getCXXRefQualifier(funcType) == CXRefQualifier_RValue))
665 auto function_declaration = get_cursor_declaration(cur)->getAsFunction();
667 bool different =
false;
668 for (
int i = 0; i < numArg; ++i) {
669 CXType argType = clang_getArgType(funcType, i);
671 if (args.size() <= i)
672 args.append(QString::fromStdString(get_fully_qualified_type_name(
673 function_declaration->getParamDecl(i)->getOriginalType(),
674 function_declaration->getASTContext()
677 QString recordedType = parameters.at(i).type();
678 QString typeSpelling = args.at(i);
680 different = recordedType != typeSpelling;
683 if (different && (argType.kind == CXType_Typedef || argType.kind == CXType_Elaborated)) {
684 QStringView canonicalType = parameters.at(i).canonicalType();
685 if (!canonicalType.isEmpty()) {
686 different = canonicalType !=
687 QString::fromStdString(get_fully_qualified_type_name(
688 function_declaration->getParamDecl(i)->getOriginalType().getCanonicalType(),
689 function_declaration->getASTContext()
704 case CXCursor_EnumDecl:
706 case CXCursor_FieldDecl:
707 case CXCursor_VarDecl:
709 case CXCursor_TypedefDecl:
718 CXCursor *overridden;
719 unsigned int numOverridden = 0;
720 clang_getOverriddenCursors(cursor, &overridden, &numOverridden);
721 for (uint i = 0; i < numOverridden; ++i) {
722 QString path = reconstructQualifiedPathForCursor(overridden[i]);
723 if (!path.isEmpty()) {
725 fn->setOverridesThis(path);
729 clang_disposeOverriddenCursors(overridden);
738 std::transform(allHeaders.cbegin(), allHeaders.cend(), std::inserter(allHeaders_, allHeaders_.begin()),
739 [](
const auto& header_file_path) {
return header_file_path.filename; });
746 auto ret = visitChildrenLambda(cursor, [&](CXCursor cur) {
747 auto loc = clang_getCursorLocation(cur);
748 if (clang_Location_isFromMainFile(loc))
749 return visitSource(cur, loc);
752 clang_getFileLocation(loc, &file,
nullptr,
nullptr,
nullptr);
753 bool isInteresting =
false;
754 auto it = isInterestingCache_.find(file);
755 if (it != isInterestingCache_.end()) {
758 QFileInfo fi(fromCXString(clang_getFileName(file)));
760 isInteresting = allHeaders_.find(fi.fileName()) != allHeaders_.end();
761 isInterestingCache_[file] = isInteresting;
764 return visitHeader(cur, loc);
767 return CXChildVisit_Continue;
769 return ret ? CXChildVisit_Break : CXChildVisit_Continue;
773
774
775
776 CXChildVisitResult
visitFnArg(CXCursor cursor,
Node **fnNode,
bool &ignoreSignature)
778 auto ret = visitChildrenLambda(cursor, [&](CXCursor cur) {
779 auto loc = clang_getCursorLocation(cur);
780 if (clang_Location_isFromMainFile(loc))
781 return visitFnSignature(cur, loc, fnNode, ignoreSignature);
782 return CXChildVisit_Continue;
784 return ret ? CXChildVisit_Break : CXChildVisit_Continue;
791
792
793
796 unsigned int line {}, column {};
797 friend bool operator<(
const SimpleLoc &a,
const SimpleLoc &b)
799 return a.line != b.line ? a.line < b.line : a.column < b.column;
803
804
805
806
807 QMap<SimpleLoc, CXCursor> declMap_;
811 std::set<QString> allHeaders_;
812 QHash<CXFile,
bool> isInterestingCache_;
815
816
817 bool ignoredSymbol(
const QString &symbolName)
819 if (symbolName == QLatin1String(
"QPrivateSignal"))
822 if (symbolName.startsWith(
"_qt_property_"))
825 if (symbolName.startsWith(
"<deduction guide"))
830 CXChildVisitResult visitSource(CXCursor cursor, CXSourceLocation loc);
831 CXChildVisitResult visitHeader(CXCursor cursor, CXSourceLocation loc);
832 CXChildVisitResult visitFnSignature(CXCursor cursor, CXSourceLocation loc,
Node **fnNode,
833 bool &ignoreSignature);
834 void processFunction(
FunctionNode *fn, CXCursor cursor);
835 bool parseProperty(
const QString &spelling,
const Location &loc);
836 void readParameterNamesAndAttributes(
FunctionNode *fn, CXCursor cursor);
837 Aggregate *getSemanticParent(CXCursor cursor);
841
842
843
844CXChildVisitResult
ClangVisitor::visitSource(CXCursor cursor, CXSourceLocation loc)
846 auto kind = clang_getCursorKind(cursor);
847 if (clang_isDeclaration(kind)) {
849 clang_getPresumedLocation(loc,
nullptr, &l.line, &l.column);
850 declMap_.insert(l, cursor);
851 return CXChildVisit_Recurse;
853 return CXChildVisit_Continue;
857
858
859
860
863 CXCursor sp = clang_getCursorSemanticParent(cursor);
864 CXCursor lp = clang_getCursorLexicalParent(cursor);
865 if (!clang_equalCursors(sp, lp) && clang_isDeclaration(clang_getCursorKind(sp))) {
874CXChildVisitResult
ClangVisitor::visitFnSignature(CXCursor cursor, CXSourceLocation,
Node **fnNode,
875 bool &ignoreSignature)
877 switch (clang_getCursorKind(cursor)) {
878 case CXCursor_Namespace:
879 return CXChildVisit_Recurse;
880 case CXCursor_FunctionDecl:
881 case CXCursor_FunctionTemplate:
882 case CXCursor_CXXMethod:
883 case CXCursor_Constructor:
884 case CXCursor_Destructor:
885 case CXCursor_ConversionFunction: {
886 ignoreSignature =
false;
887 if (ignoredSymbol(functionName(cursor))) {
889 ignoreSignature =
true;
895 readParameterNamesAndAttributes(fn, cursor);
899 if (
const auto function_declaration = declaration->getAsFunction()) {
900 auto declaredReturnType = function_declaration->getDeclaredReturnType();
901 if (llvm::dyn_cast_if_present<clang::AutoType>(declaredReturnType.getTypePtrOrNull()))
902 fn->setDeclaredReturnType(QString::fromStdString(declaredReturnType.getAsString()));
906 QString name = functionName(cursor);
907 if (ignoredSymbol(name))
908 return CXChildVisit_Continue;
909 Aggregate *semanticParent = getSemanticParent(cursor);
910 if (semanticParent && semanticParent
->isClass()) {
912 processFunction(candidate, cursor);
913 if (!candidate->isSpecialMemberFunction()) {
915 return CXChildVisit_Continue;
917 candidate->setDefault(
true);
927 return CXChildVisit_Continue;
930CXChildVisitResult
ClangVisitor::visitHeader(CXCursor cursor, CXSourceLocation loc)
932 auto kind = clang_getCursorKind(cursor);
935 case CXCursor_TypeAliasTemplateDecl:
936 case CXCursor_TypeAliasDecl: {
937 QString aliasDecl = getSpelling(clang_getCursorExtent(cursor)).simplified();
938 QStringList typeAlias = aliasDecl.split(QLatin1Char(
'='));
939 if (typeAlias.size() == 2) {
940 typeAlias[0] = typeAlias[0].trimmed();
941 const QLatin1String usingString(
"using ");
942 qsizetype usingPos = typeAlias[0].indexOf(usingString);
943 if (usingPos != -1) {
944 typeAlias[0].remove(0, usingPos + usingString.size());
945 typeAlias[0] = typeAlias[0].split(QLatin1Char(
' ')).first();
946 typeAlias[1] = typeAlias[1].trimmed();
947 auto *ta =
new TypeAliasNode(parent_, typeAlias[0], typeAlias[1]);
951 if (kind == CXCursor_TypeAliasTemplateDecl) {
953 ta->setTemplateDecl(get_template_declaration(template_decl));
957 return CXChildVisit_Continue;
959 case CXCursor_StructDecl:
960 case CXCursor_UnionDecl:
961 if (fromCXString(clang_getCursorSpelling(cursor)).isEmpty())
962 return CXChildVisit_Continue;
964 case CXCursor_ClassTemplate:
966 case CXCursor_ClassDecl: {
967 if (!clang_isCursorDefinition(cursor))
968 return CXChildVisit_Continue;
971 return CXChildVisit_Continue;
973 QString className = fromCXString(clang_getCursorSpelling(cursor));
975 Aggregate *semanticParent = getSemanticParent(cursor);
976 if (semanticParent && semanticParent->findNonfunctionChild(className, &
Node::isClassNode)) {
977 return CXChildVisit_Continue;
980 CXCursorKind actualKind = (kind == CXCursor_ClassTemplate) ?
981 clang_getTemplateCursorKind(cursor) : kind;
984 if (actualKind == CXCursor_StructDecl)
986 else if (actualKind == CXCursor_UnionDecl)
989 auto *classe =
new ClassNode(type, semanticParent, className);
993 if (kind == CXCursor_ClassTemplate) {
995 classe->setTemplateDecl(get_template_declaration(template_declaration));
998 QScopedValueRollback<Aggregate *> setParent(parent_, classe);
1001 case CXCursor_CXXBaseSpecifier: {
1003 return CXChildVisit_Continue;
1005 auto type = clang_getCursorType(cursor);
1006 auto baseCursor = clang_getTypeDeclaration(type);
1008 auto classe =
static_cast<
ClassNode *>(parent_);
1010 QString bcName = reconstructQualifiedPathForCursor(baseCursor);
1011 classe->addUnresolvedBaseClass(access,
1012 bcName.split(QLatin1String(
"::"), Qt::SkipEmptyParts));
1013 return CXChildVisit_Continue;
1015 auto baseClasse =
static_cast<
ClassNode *>(baseNode);
1017 return CXChildVisit_Continue;
1019 case CXCursor_Namespace: {
1020 QString namespaceName = fromCXString(clang_getCursorDisplayName(cursor));
1030 QScopedValueRollback<Aggregate *> setParent(parent_, ns);
1033 case CXCursor_FunctionTemplate:
1035 case CXCursor_FunctionDecl:
1036 case CXCursor_CXXMethod:
1037 case CXCursor_Constructor:
1038 case CXCursor_Destructor:
1039 case CXCursor_ConversionFunction: {
1041 return CXChildVisit_Continue;
1042 QString name = functionName(cursor);
1043 if (ignoredSymbol(name))
1044 return CXChildVisit_Continue;
1047 return CXChildVisit_Continue;
1050 CXSourceRange range = clang_Cursor_getCommentRange(cursor);
1051 if (!clang_Range_isNull(range)) {
1052 QString comment = getSpelling(range);
1053 if (comment.startsWith(
"//!")) {
1054 qsizetype tag = comment.indexOf(QChar(
'['));
1056 qsizetype end = comment.indexOf(QChar(
']'), ++tag);
1058 fn->setTag(comment.mid(tag, end - tag));
1063 processFunction(fn, cursor);
1065 if (kind == CXCursor_FunctionTemplate) {
1067 fn->setTemplateDecl(get_template_declaration(template_declaration));
1070 return CXChildVisit_Continue;
1072#if CINDEX_VERSION
>= 36
1073 case CXCursor_FriendDecl: {
1077 case CXCursor_EnumDecl: {
1079 if (en && en->items().size())
1080 return CXChildVisit_Continue;
1082 QString enumTypeName = fromCXString(clang_getCursorSpelling(cursor));
1084 if (clang_Cursor_isAnonymous(cursor)) {
1085 enumTypeName =
"anonymous";
1093 en =
new EnumNode(parent_, enumTypeName, clang_EnumDecl_isScoped(cursor));
1099 visitChildrenLambda(cursor, [&](CXCursor cur) {
1100 if (clang_getCursorKind(cur) != CXCursor_EnumConstantDecl)
1101 return CXChildVisit_Continue;
1104 visitChildrenLambda(cur, [&](CXCursor cur) {
1105 if (clang_isExpression(clang_getCursorKind(cur))) {
1106 value = getSpelling(clang_getCursorExtent(cur));
1107 return CXChildVisit_Break;
1109 return CXChildVisit_Continue;
1111 if (value.isEmpty()) {
1112 QLatin1String hex(
"0x");
1113 if (!en->items().isEmpty() && en->items().last().value().startsWith(hex)) {
1114 value = hex + QString::number(clang_getEnumConstantDeclValue(cur), 16);
1116 value = QString::number(clang_getEnumConstantDeclValue(cur));
1120 en->addItem(EnumItem(fromCXString(clang_getCursorSpelling(cur)), value));
1121 return CXChildVisit_Continue;
1123 return CXChildVisit_Continue;
1125 case CXCursor_FieldDecl:
1126 case CXCursor_VarDecl: {
1128 return CXChildVisit_Continue;
1130 auto value_declaration =
1132 assert(value_declaration);
1135 auto var =
new VariableNode(parent_, fromCXString(clang_getCursorSpelling(cursor)));
1137 var->setAccess(access);
1139 var->setLeftType(QString::fromStdString(get_fully_qualified_type_name(
1140 value_declaration->getType(),
1141 value_declaration->getASTContext()
1143 var->setStatic(kind == CXCursor_VarDecl && parent_
->isClassNode());
1145 return CXChildVisit_Continue;
1147 case CXCursor_TypedefDecl: {
1149 return CXChildVisit_Continue;
1150 auto *td =
new TypedefNode(parent_, fromCXString(clang_getCursorSpelling(cursor)));
1154 visitChildrenLambda(cursor, [&](CXCursor cur) {
1155 if (clang_getCursorKind(cur) != CXCursor_TemplateRef
1156 || fromCXString(clang_getCursorSpelling(cur)) != QLatin1String(
"QFlags"))
1157 return CXChildVisit_Continue;
1159 visitChildrenLambda(cursor, [&](CXCursor cur) {
1160 if (clang_getCursorKind(cur) != CXCursor_TypeRef)
1161 return CXChildVisit_Continue;
1166 return CXChildVisit_Break;
1168 return CXChildVisit_Break;
1170 return CXChildVisit_Continue;
1176 parseProperty(getSpelling(clang_getCursorExtent(cursor)),
1177 fromCXSourceLocation(loc));
1179 return CXChildVisit_Continue;
1188 visitChildrenLambda(cursor, [&](CXCursor cur) {
1189 auto kind = clang_getCursorKind(cur);
1190 if (kind == CXCursor_AnnotateAttr) {
1191 QString annotation = fromCXString(clang_getCursorDisplayName(cur));
1192 if (annotation == QLatin1String(
"qt_slot")) {
1194 }
else if (annotation == QLatin1String(
"qt_signal")) {
1197 if (annotation == QLatin1String(
"qt_invokable"))
1199 }
else if (kind == CXCursor_CXXOverrideAttr) {
1201 }
else if (kind == CXCursor_ParmDecl) {
1203 return CXChildVisit_Break;
1205 if (QString name = fromCXString(clang_getCursorSpelling(cur)); !name.isEmpty())
1206 parameters
[i
].setName(name);
1209 Q_ASSERT(parameter_declaration);
1213 if (!default_value.empty())
1214 parameters[i].setDefaultValue(QString::fromStdString(default_value));
1218 return CXChildVisit_Continue;
1224 CXCursorKind kind = clang_getCursorKind(cursor);
1225 CXType funcType = clang_getCursorType(cursor);
1232 : clang_CXXMethod_isPureVirtual(cursor)
1249 const clang::FunctionDecl* function_declaration = declaration->getAsFunction();
1251 if (kind == CXCursor_Constructor
1253 || (kind == CXCursor_FunctionTemplate && fn->name() == parent_->name()))
1255 else if (kind == CXCursor_Destructor)
1258 fn->setReturnType(QString::fromStdString(get_fully_qualified_type_name(
1259 function_declaration->getReturnType(),
1260 function_declaration->getASTContext()
1263 const clang::CXXConstructorDecl* constructor_declaration = llvm::dyn_cast<
const clang::CXXConstructorDecl>(function_declaration);
1268 const clang::CXXConversionDecl* conversion_declaration = llvm::dyn_cast<
const clang::CXXConversionDecl>(function_declaration);
1272 (constructor_declaration && constructor_declaration->isExplicit()) ||
1273 (conversion_declaration && conversion_declaration->isExplicit())
1276 const clang::CXXMethodDecl* method_declaration = llvm::dyn_cast<
const clang::CXXMethodDecl>(function_declaration);
1281 const clang::FunctionType* function_type = function_declaration->getFunctionType();
1282 const clang::FunctionProtoType* function_prototype =
static_cast<
const clang::FunctionProtoType*>(function_type);
1284 if (function_prototype) {
1285 clang::FunctionProtoType::ExceptionSpecInfo exception_specification = function_prototype->getExceptionSpecInfo();
1287 if (exception_specification.Type !=
clang::ExceptionSpecificationType::EST_None) {
1288 const std::string exception_specification_spelling =
1289 exception_specification.NoexceptExpr ? get_expression_as_string(
1290 exception_specification.NoexceptExpr,
1291 function_declaration->getASTContext()
1294 if (exception_specification_spelling !=
"false")
1295 fn->markNoexcept(QString::fromStdString(exception_specification_spelling));
1299 CXRefQualifierKind refQualKind = clang_Type_getCXXRefQualifier(funcType);
1300 if (refQualKind == CXRefQualifier_LValue)
1302 else if (refQualKind == CXRefQualifier_RValue)
1311 parameters
.reserve(function_declaration->getNumParams()
);
1313 for (clang::ParmVarDecl*
const parameter_declaration : function_declaration->parameters()) {
1314 clang::QualType parameter_type = parameter_declaration->getOriginalType();
1316 parameters.append(QString::fromStdString(get_fully_qualified_type_name(
1318 parameter_declaration->getASTContext()
1321 if (!parameter_type.isCanonical())
1322 parameters.last().setCanonicalType(QString::fromStdString(get_fully_qualified_type_name(
1323 parameter_type.getCanonicalType(),
1324 parameter_declaration->getASTContext()
1329 if (parameters
.last().type().endsWith(QLatin1String(
"QPrivateSignal"))) {
1335 if (clang_isFunctionTypeVariadic(funcType))
1336 parameters.append(QStringLiteral(
"..."));
1337 readParameterNamesAndAttributes(fn, cursor);
1339 if (declaration->getFriendObjectKind() !=
clang::Decl::FOK_None)
1345 if (!spelling.startsWith(QLatin1String(
"Q_PROPERTY"))
1346 && !spelling.startsWith(QLatin1String(
"QDOC_PROPERTY"))
1347 && !spelling.startsWith(QLatin1String(
"Q_OVERRIDE")))
1350 qsizetype lpIdx = spelling.indexOf(QChar(
'('));
1351 qsizetype rpIdx = spelling.lastIndexOf(QChar(
')'));
1352 if (lpIdx <= 0 || rpIdx <= lpIdx)
1355 QString signature = spelling.mid(lpIdx + 1, rpIdx - lpIdx - 1);
1356 signature = signature.simplified();
1357 QStringList parts = signature.split(QChar(
' '), Qt::SkipEmptyParts);
1359 static const QStringList attrs =
1360 QStringList() <<
"READ" <<
"MEMBER" <<
"WRITE"
1361 <<
"NOTIFY" <<
"CONSTANT" <<
"FINAL"
1362 <<
"REQUIRED" <<
"BINDABLE" <<
"DESIGNABLE"
1363 <<
"RESET" <<
"REVISION" <<
"SCRIPTABLE"
1364 <<
"STORED" <<
"USER";
1368 auto it =
std::find_if(parts.cbegin(), parts.cend(),
1369 [](
const QString &attr) ->
bool {
1370 return attrs.contains(attr);
1373 if (it == parts.cend() ||
std::distance(parts.cbegin(), it) < 2)
1376 QStringList typeParts;
1377 std::copy(parts.cbegin(), it,
std::back_inserter(typeParts));
1378 parts.erase(parts.cbegin(), it);
1379 QString name = typeParts.takeLast();
1382 while (!name.isEmpty() && name.front() == QChar(
'*')) {
1383 typeParts.last().push_back(name.front());
1388 if (parts.size() < 2 || name.isEmpty())
1392 property->setAccess(Access::Public);
1393 property->setLocation(loc);
1394 property->setDataType(typeParts.join(QChar(
' ')));
1397 while (i < parts.size()) {
1398 const QString &key = parts.at(i++);
1400 if (key ==
"CONSTANT") {
1401 property->setConstant();
1402 }
else if (key ==
"REQUIRED") {
1403 property->setRequired();
1405 if (i < parts.size()) {
1406 QString value = parts.at(i++);
1407 if (key ==
"READ") {
1409 }
else if (key ==
"WRITE") {
1411 property->setWritable(
true);
1412 }
else if (key ==
"MEMBER") {
1413 property->setWritable(
true);
1414 }
else if (key ==
"STORED") {
1415 property->setStored(value.toLower() ==
"true");
1416 }
else if (key ==
"BINDABLE") {
1419 }
else if (key ==
"RESET") {
1421 }
else if (key ==
"NOTIFY") {
1430
1431
1432
1433
1434
1438 clang_getPresumedLocation(loc,
nullptr, &docloc.line, &docloc.column);
1439 auto decl_it = declMap_.upperBound(docloc);
1440 if (decl_it == declMap_.end())
1443 unsigned int declLine = decl_it.key().line;
1444 unsigned int nextCommentLine;
1445 clang_getPresumedLocation(nextCommentLoc,
nullptr, &nextCommentLine,
nullptr);
1446 if (nextCommentLine < declLine)
1450 if (decl_it != declMap_.begin()) {
1451 CXSourceLocation prevDeclEnd = clang_getRangeEnd(clang_getCursorExtent(*(
std::prev(decl_it))));
1452 unsigned int prevDeclLine;
1453 clang_getPresumedLocation(prevDeclEnd,
nullptr, &prevDeclLine,
nullptr);
1454 if (prevDeclLine >= docloc.line) {
1457 auto parent = clang_getCursorLexicalParent(*decl_it);
1458 if (!clang_equalCursors(parent, *(
std::prev(decl_it))))
1462 auto *node = findNodeForCursor(qdb_, *decl_it);
1464 if (node && node->isFunction(
Node::CPP))
1465 readParameterNamesAndAttributes(
static_cast<
FunctionNode *>(node), *decl_it);
1472 const std::vector<QByteArray>& include_paths,
1473 const QList<QByteArray>& defines,
1480 m_allHeaders = config.getHeaderFiles();
1485
1486
1487
1488
1489
1490#if LIBCLANG_VERSION_MAJOR == 15
1498 "-fms-compatibility-version=19",
1502 "-DQT_DISABLE_DEPRECATED_UP_TO=0",
1503 "-DQT_ANNOTATE_CLASS(type,...)=static_assert(sizeof(#__VA_ARGS__),#type);",
1504 "-DQT_ANNOTATE_CLASS2(type,a1,a2)=static_assert(sizeof(#a1,#a2),#type);",
1505 "-DQT_ANNOTATE_FUNCTION(a)=__attribute__((annotate(#a)))",
1506 "-DQT_ANNOTATE_ACCESS_SPECIFIER(a)=__attribute__((annotate(#a)))",
1507 "-Wno-constant-logical-operand",
1508 "-Wno-macro-redefined",
1509 "-Wno-nullability-completeness",
1510 "-fvisibility=default",
1512 (
"-I" CLANG_RESOURCE_DIR),
1517
1518
1519
1526 for (
const auto &p : std::as_const(defines))
1527 args.push_back(p.constData());
1532 QList<QByteArray> result;
1533 for (
const auto& [header_path, _] : allHeaders) {
1534 const QByteArray path =
"-I" + header_path.toLatin1();
1535 const QByteArray parent =
1536 "-I" + QDir::cleanPath(header_path + QLatin1String(
"/../")).toLatin1();
1543
1544
1545
1547 const std::vector<QByteArray>& include_paths,
1548 const std::set<Config::HeaderFilePath>& all_headers,
1549 std::vector<
const char*>& args
1551 if (include_paths.empty()) {
1553
1554
1555
1556
1557 qCWarning(lcQdoc) <<
"No include paths passed to qdoc; guessing reasonable include paths";
1559 QString basicIncludeDir = QDir::cleanPath(QString(Config::installDir +
"/../include"));
1560 args.emplace_back(QByteArray(
"-I" + basicIncludeDir.toLatin1()).constData());
1562 auto include_paths_from_headers = includePathsFromHeaders(all_headers);
1563 args.insert(args.end(), include_paths_from_headers.begin(), include_paths_from_headers.end());
1565 std::copy(include_paths.begin(), include_paths.end(),
std::back_inserter(args));
1570
1571
1572
1573
1576 QString module_header,
1577 const std::set<Config::HeaderFilePath>& all_headers,
1578 const std::vector<QByteArray>& include_paths,
1579 const QList<QByteArray>& defines
1581 static std::vector<
const char*> arguments{};
1583 if (module_header.isEmpty())
return std::nullopt;
1585 getDefaultArgs(defines, arguments);
1586 getMoreArgs(include_paths, all_headers, arguments);
1588 flags_ =
static_cast<CXTranslationUnit_Flags>(CXTranslationUnit_Incomplete
1589 | CXTranslationUnit_SkipFunctionBodies
1590 | CXTranslationUnit_KeepGoing);
1594 QTemporaryDir pch_directory{QDir::tempPath() + QLatin1String(
"/qdoc_pch")};
1595 if (!pch_directory.isValid())
return std::nullopt;
1597 const QByteArray module = module_header.toUtf8();
1600 qCDebug(lcQdoc) <<
"Build and visit PCH for" << module_header;
1603 struct FindPredicate
1605 enum SearchType { Any, Module };
1606 QByteArray &candidate_;
1607 const QByteArray &module_;
1609 FindPredicate(QByteArray &candidate,
const QByteArray &module,
1610 SearchType type = Any)
1611 : candidate_(candidate), module_(module), type_(type)
1615 bool operator()(
const QByteArray &p)
const
1617 if (type_ != Any && !p.endsWith(module_))
1619 candidate_ = p +
"/";
1620 candidate_.append(module_);
1621 if (p.startsWith(
"-I"))
1622 candidate_ = candidate_.mid(2);
1623 return QFile::exists(QString::fromUtf8(candidate_));
1628 QByteArray candidate;
1629 auto it =
std::find_if(include_paths.begin(), include_paths.end(),
1630 FindPredicate(candidate, module, FindPredicate::Module));
1631 if (it == include_paths.end())
1632 it =
std::find_if(include_paths.begin(), include_paths.end(),
1633 FindPredicate(candidate, module, FindPredicate::Any));
1634 if (it != include_paths.end())
1637 if (header.isEmpty()) {
1638 qWarning() <<
"(qdoc) Could not find the module header in include paths for module"
1639 << module <<
" (include paths: " << include_paths <<
")";
1640 qWarning() <<
" Artificial module header built from header dirs in qdocconf "
1643 arguments.push_back(
"-xc++");
1647 QString tmpHeader = pch_directory.path() +
"/" + module;
1648 if (QFile tmpHeaderFile(tmpHeader); tmpHeaderFile.open(QIODevice::Text | QIODevice::WriteOnly)) {
1649 QTextStream out(&tmpHeaderFile);
1650 if (header.isEmpty()) {
1651 for (
const auto& [header_path, header_name] : all_headers) {
1652 if (!header_name.endsWith(QLatin1String(
"_p.h"))
1653 && !header_name.startsWith(QLatin1String(
"moc_"))) {
1654 QString line = QLatin1String(
"#include \"") + header_path
1655 + QLatin1String(
"/") + header_name + QLatin1String(
"\"");
1656 out << line <<
"\n";
1661 QFileInfo headerFile(header);
1662 if (!headerFile.exists()) {
1663 qWarning() <<
"Could not find module header file" << header;
1664 return std::nullopt;
1666 out << QLatin1String(
"#include \"") + header + QLatin1String(
"\"");
1671 clang_parseTranslationUnit2(index, tmpHeader.toLatin1().data(), arguments.data(),
1672 static_cast<
int>(arguments.size()),
nullptr, 0,
1673 flags_ | CXTranslationUnit_ForSerialization, &tu
.tu);
1674 qCDebug(lcQdoc) <<
__FUNCTION__ <<
"clang_parseTranslationUnit2(" << tmpHeader << arguments
1675 <<
") returns" << err;
1680 qCCritical(lcQdoc) <<
"Could not create PCH file for " << module_header;
1681 return std::nullopt;
1684 QByteArray pch_name = pch_directory.path().toUtf8() +
"/" + module +
".pch";
1685 auto error = clang_saveTranslationUnit(tu, pch_name.constData(),
1686 clang_defaultSaveOptions(tu));
1688 qCCritical(lcQdoc) <<
"Could not save PCH file for" << module_header;
1689 return std::nullopt;
1694 CXCursor cur = clang_getTranslationUnitCursor(tu);
1697 qCDebug(lcQdoc) <<
"PCH built and visited for" << module_header;
1699 return std::make_optional(
PCHFile{
std::move(pch_directory), pch_name});
1704 if (t.count(QChar(
'.')) > 1)
1705 t.truncate(t.lastIndexOf(QChar(
'.')));
1710
1711
1712
1713
1714
1715
1716
1717
1720 flags_ =
static_cast<CXTranslationUnit_Flags>(CXTranslationUnit_Incomplete
1721 | CXTranslationUnit_SkipFunctionBodies
1722 | CXTranslationUnit_KeepGoing);
1726 getDefaultArgs(m_defines, m_args);
1727 if (m_pch && !filePath.endsWith(
".mm")
1728 && !std::holds_alternative<CppHeaderSourceFile>(tag_source_file(filePath).second)) {
1729 m_args.push_back(
"-w");
1730 m_args.push_back(
"-include-pch");
1731 m_args.push_back((*m_pch).get().name.constData());
1733 getMoreArgs(m_includePaths, m_allHeaders, m_args);
1737 clang_parseTranslationUnit2(index, filePath.toLocal8Bit(), m_args.data(),
1738 static_cast<
int>(m_args.size()),
nullptr, 0, flags_, &tu.tu);
1739 qCDebug(lcQdoc) <<
__FUNCTION__ <<
"clang_parseTranslationUnit2(" << filePath << m_args
1740 <<
") returns" << err;
1744 qWarning() <<
"(qdoc) Could not parse source file" << filePath <<
" error code:" << err;
1748 ParsedCppFileIR parse_result{};
1750 CXCursor tuCur = clang_getTranslationUnitCursor(tu);
1755 unsigned int numTokens = 0;
1756 const QSet<QString> &commands = CppCodeParser::topic_commands + CppCodeParser::meta_commands;
1757 clang_tokenize(tu, clang_getCursorExtent(tuCur), &tokens, &numTokens);
1759 for (
unsigned int i = 0; i < numTokens; ++i) {
1760 if (clang_getTokenKind(tokens[i]) != CXToken_Comment)
1762 QString comment = fromCXString(clang_getTokenSpelling(tu, tokens[i]));
1763 if (!comment.startsWith(
"/*!"))
1766 auto commentLoc = clang_getTokenLocation(tu, tokens[i]);
1769 Doc::trimCStyleComment(loc, comment);
1772 Doc doc(loc, end_loc, comment, commands, CppCodeParser::topic_commands);
1778 if (i + 1 < numTokens) {
1780 CXSourceLocation nextCommentLoc = commentLoc;
1781 while (i + 2 < numTokens && clang_getTokenKind(tokens[i + 1]) != CXToken_Comment)
1783 nextCommentLoc = clang_getTokenLocation(tu, tokens[i + 1]);
1790 bool future =
false;
1792 QString sinceVersion = doc.metaCommandArgs(
COMMAND_SINCE).at(0).first;
1793 if (getUnpatchedVersion(sinceVersion) >
1794 getUnpatchedVersion(Config::instance().get(
CONFIG_VERSION).asString()))
1799 QStringLiteral(
"Cannot tie this documentation to anything"),
1800 QStringLiteral(
"qdoc found a /*! ... */ comment, but there was no "
1801 "topic command (e.g., '\\%1', '\\%2') in the "
1802 "comment and no function definition following "
1810 CXCursor cur = clang_getCursor(tu, commentLoc);
1812 CXCursorKind kind = clang_getCursorKind(cur);
1813 if (clang_isTranslationUnit(kind) || clang_isInvalid(kind))
1815 if (kind == CXCursor_Namespace) {
1816 parse_result.untied.back().context << fromCXString(clang_getCursorSpelling(cur));
1818 cur = clang_getCursorLexicalParent(cur);
1823 clang_disposeTokens(tu, tokens, numTokens);
1824 m_namespaceScope.clear();
1827 return parse_result;
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1843 const QString &idTag, QStringList context)
1845 Node *fnNode =
nullptr;
1847
1848
1849
1850
1851
1852 if (!idTag.isEmpty()) {
1853 fnNode = m_qdb->findFunctionNodeForTag(idTag);
1856 QStringLiteral(
"tag \\fn [%1] not used in any include file in current module").arg(idTag));
1859
1860
1861
1862
1864 QStringList leftParenSplit = fnSignature.mid(fnSignature.indexOf(fn->name())).split(
'(');
1865 if (leftParenSplit.size() > 1) {
1866 QStringList rightParenSplit = leftParenSplit[1].split(
')');
1867 if (!rightParenSplit.empty()) {
1868 QString params = rightParenSplit[0];
1869 if (!params.isEmpty()) {
1870 QStringList commaSplit = params.split(
',');
1872 if (parameters
.count() == commaSplit.size()) {
1873 for (
int i = 0; i < parameters
.count(); ++i) {
1874 QStringList blankSplit = commaSplit[i].split(
' ', Qt::SkipEmptyParts);
1875 if (blankSplit.size() > 1) {
1876 QString pName = blankSplit.last();
1878 auto it =
std::find_if(
std::begin(pName),
std::end(pName),
1879 [](
const QChar &c) {
return c.isLetter(); });
1880 parameters
[i
].setName(
1881 pName.remove(0,
std::distance(
std::begin(pName), it)));
1891 auto flags =
static_cast<CXTranslationUnit_Flags>(CXTranslationUnit_Incomplete
1892 | CXTranslationUnit_SkipFunctionBodies
1893 | CXTranslationUnit_KeepGoing);
1897 getDefaultArgs(m_defines, m_args);
1900 m_args.push_back(
"-w");
1901 m_args.push_back(
"-include-pch");
1902 m_args.push_back((*m_pch).get().name.constData());
1907 for (
const auto &ns : std::as_const(context))
1908 s_fn.prepend(
"namespace " + ns.toUtf8() +
" {");
1909 s_fn += fnSignature.toUtf8();
1910 if (!s_fn.endsWith(
";"))
1912 s_fn.append(context.size(),
'}');
1915 CXUnsavedFile unsavedFile { dummyFileName, s_fn.constData(),
1916 static_cast<
unsigned long>(s_fn.size()) };
1917 CXErrorCode err = clang_parseTranslationUnit2(index, dummyFileName, m_args.data(),
1918 int(m_args.size()), &unsavedFile, 1, flags, &tu.tu);
1919 qCDebug(lcQdoc) <<
__FUNCTION__ <<
"clang_parseTranslationUnit2(" << dummyFileName << m_args
1920 <<
") returns" << err;
1923 location.error(QStringLiteral(
"clang could not parse \\fn %1").arg(fnSignature));
1927
1928
1929
1930
1931
1932 CXCursor cur = clang_getTranslationUnitCursor(tu);
1934 bool ignoreSignature =
false;
1938 unsigned diagnosticCount = clang_getNumDiagnostics(tu);
1939 const auto &config = Config::instance();
1940 if (diagnosticCount > 0 && (!config.preparing() || config.singleExec())) {
1941 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()