aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp
diff options
context:
space:
mode:
authorFriedemann Kleint <friedemann.kleint@qt.io>2023-05-10 13:50:56 +0200
committerCristián Maureira-Fredes <cristian.maureira-fredes@qt.io>2025-11-24 12:06:06 +0100
commit845630ad239c4b37ff37e49ef5bb969a8946744b (patch)
tree5c65f2e270511459d346c14f0ad8d01f5e6e39a0 /sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp
parent3cf2077a1b060bbea3419ccde23c5da6485a2e24 (diff)
Move the shiboken-generator source around
THIS COMMIT WAS GENERATED BY A SCRIPT Task-number: PYSIDE-962 Task-number: PYSIDE-1587 Change-Id: I58b05c3d05606efb6303193f2d7f907a0ab5741b Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
Diffstat (limited to 'sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp')
-rw-r--r--sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp1331
1 files changed, 0 insertions, 1331 deletions
diff --git a/sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp b/sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp
deleted file mode 100644
index 407a7a9e7..000000000
--- a/sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp
+++ /dev/null
@@ -1,1331 +0,0 @@
-// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#include "clangbuilder.h"
-#include "compilersupport.h"
-#include "clangutils.h"
-#include "clangdebugutils.h"
-
-#include <codemodel.h>
-#include <reporthandler.h>
-
-#include "qtcompat.h"
-
-#include <QtCore/qdebug.h>
-#include <QtCore/qdir.h>
-#include <QtCore/qhash.h>
-#include <QtCore/qmap.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qstack.h>
-#include <QtCore/qlist.h>
-
-using namespace Qt::StringLiterals;
-
-namespace clang {
-
-static inline bool isClassCursor(const CXCursor &c)
-{
- return c.kind == CXCursor_ClassDecl || c.kind == CXCursor_StructDecl
- || c.kind == CXCursor_ClassTemplate
- || c.kind == CXCursor_ClassTemplatePartialSpecialization;
-}
-
-static inline bool isClassOrNamespaceCursor(const CXCursor &c)
-{
- return c.kind == CXCursor_Namespace || isClassCursor(c);
-}
-
-static inline bool withinClassDeclaration(const CXCursor &cursor)
-{
- return isClassCursor(clang_getCursorLexicalParent(cursor));
-}
-
-static QString fixTypeName(QString t)
-{
- // Fix "Foo &" -> "Foo&", similarly "Bar **" -> "Bar**"
- auto pos = t.size() - 1;
- for (; pos >= 0 && (t.at(pos) == u'&' || t.at(pos) == u'*'); --pos) {}
- if (pos > 0 && t.at(pos) == u' ')
- t.remove(pos, 1);
- return t;
-}
-
-// Insert template parameter to class name: "Foo<>" -> "Foo<T1>" -> "Foo<T1,T2>"
-// This needs to be done immediately when template parameters are encountered since
-// the class name "Foo<T1,T2>" is the scope for nested items.
-static bool insertTemplateParameterIntoClassName(const QString &parmName, QString *name)
-{
- if (Q_UNLIKELY(!name->endsWith(u'>')))
- return false;
- const bool needsComma = name->at(name->size() - 2) != u'<';
- const auto insertionPos = name->size() - 1;
- name->insert(insertionPos, parmName);
- if (needsComma)
- name->insert(insertionPos, u',');
- return true;
-}
-
-static inline bool insertTemplateParameterIntoClassName(const QString &parmName,
- const ClassModelItem &item)
-{
- QString name = item->name();
- const bool result = insertTemplateParameterIntoClassName(parmName, &name);
- item->setName(name);
- return result;
-}
-
-static inline Access accessPolicy(CX_CXXAccessSpecifier access)
-{
- Access result = Access::Public;
- switch (access) {
- case CX_CXXProtected:
- result = Access::Protected;
- break;
- case CX_CXXPrivate:
- result = Access::Private;
- break;
- default:
- break;
- }
- return result;
-}
-
-static bool isSigned(CXTypeKind kind)
-{
- switch (kind) {
- case CXType_UChar:
- case CXType_Char16:
- case CXType_Char32:
- case CXType_UShort:
- case CXType_UInt:
- case CXType_ULong:
- case CXType_ULongLong:
- case CXType_UInt128:
- return false;
- default:
- break;
- }
- return true;
-}
-
-class BuilderPrivate {
-public:
- Q_DISABLE_COPY_MOVE(BuilderPrivate)
-
- enum class SpecialSystemHeader : std::uint8_t {
- None,
- Types,
- OpenGL,
- WhiteListed,
- WhiteListedPath
- };
-
- using CursorClassHash = QHash<CXCursor, ClassModelItem>;
- using TypeInfoHash = QHash<CXType, TypeInfo>;
-
- explicit BuilderPrivate(BaseVisitor *bv) : m_baseVisitor(bv), m_model(new CodeModel)
- {
- m_scopeStack.push(NamespaceModelItem(new _FileModelItem(m_model)));
- }
- ~BuilderPrivate()
- {
- delete m_model;
- }
-
- // Determine scope from top item. Note that the scope list does not necessarily
- // match the scope stack in case of forward-declared inner classes whose definition
- // appears in the translation unit while the scope is the outer class.
- void updateScope()
- {
- if (m_scopeStack.size() <= 1)
- m_scope.clear();
- else
- m_scope = m_scopeStack.back()->scope() << m_scopeStack.back()->name();
- }
-
- void pushScope(const ScopeModelItem &i)
- {
- m_scopeStack.push(i);
- updateScope();
- }
-
- void popScope()
- {
- m_scopeStack.back()->purgeClassDeclarations();
- m_scopeStack.pop();
- updateScope();
- }
-
- bool addClass(const CXCursor &cursor, CodeModel::ClassType t);
- FunctionModelItem createFunction(const CXCursor &cursor,
- CodeModel::FunctionType t = CodeModel::Normal,
- bool isTemplateCode = false);
- FunctionModelItem createMemberFunction(const CXCursor &cursor,
- bool isTemplateCode = false);
- void qualifyConstructor(const CXCursor &cursor);
- TypeInfo createTypeInfoUncached(const CXType &type,
- bool *cacheable = nullptr) const;
- TypeInfo createTypeInfo(const CXType &type) const;
- TypeInfo createTypeInfo(const CXCursor &cursor) const
- { return createTypeInfo(clang_getCursorType(cursor)); }
- void addTemplateInstantiations(const CXType &type,
- QString *typeName,
- TypeInfo *t) const;
- bool addTemplateInstantiationsRecursion(const CXType &type, TypeInfo *t) const;
-
- void addTypeDef(const CXCursor &cursor, const CXType &cxType);
- ClassModelItem currentTemplateClass() const;
- void startTemplateTypeAlias(const CXCursor &cursor);
- void endTemplateTypeAlias(const CXCursor &typeAliasCursor);
-
- TemplateParameterModelItem createTemplateParameter(const CXCursor &cursor) const;
- TemplateParameterModelItem createNonTypeTemplateParameter(const CXCursor &cursor) const;
- void addField(const CXCursor &cursor);
-
- static QString cursorValueExpression(BaseVisitor *bv, const CXCursor &cursor);
- std::pair<QString, ClassModelItem> getBaseClass(CXType type) const;
- void addBaseClass(const CXCursor &cursor);
-
- SpecialSystemHeader specialSystemHeader(const QString &fileName) const;
- bool visitHeader(const QString &fileName) const;
- static const char *specialSystemHeaderReason(SpecialSystemHeader sh);
-
- void setFileName(const CXCursor &cursor, _CodeModelItem *item) const;
-
- BaseVisitor *m_baseVisitor;
- CodeModel *m_model;
-
- QStack<ScopeModelItem> m_scopeStack;
- QStringList m_scope;
- // Store all classes by cursor so that base classes can be found and inner
- // classes can be correctly parented in case of forward-declared inner classes
- // (QMetaObject::Connection)
- CursorClassHash m_cursorClassHash;
-
- mutable TypeInfoHash m_typeInfoHash; // Cache type information
- mutable QHash<QString, TemplateTypeAliasModelItem> m_templateTypeAliases;
-
- ClassModelItem m_currentClass;
- EnumModelItem m_currentEnum;
- FunctionModelItem m_currentFunction;
- ArgumentModelItem m_currentArgument;
- VariableModelItem m_currentField;
- TemplateTypeAliasModelItem m_currentTemplateTypeAlias;
- QStringList m_forceProcessSystemIncludes; // files, like "memory"
- QStringList m_forceProcessSystemIncludePaths; // paths, like "/usr/include/Qt/"
- QString m_usingTypeRef; // Base classes in "using Base::member;"
- bool m_withinUsingDeclaration = false;
-
- int m_anonymousEnumCount = 0;
- CodeModel::FunctionType m_currentFunctionType = CodeModel::Normal;
- bool m_withinFriendDecl = false;
- mutable QHash<QString, SpecialSystemHeader> m_systemHeaders;
-};
-
-bool BuilderPrivate::addClass(const CXCursor &cursor, CodeModel::ClassType t)
-{
- QString className = getCursorSpelling(cursor);
- m_currentClass = std::make_shared<_ClassModelItem>(m_model, className);
- setFileName(cursor, m_currentClass.get());
- m_currentClass->setClassType(t);
- // Some inner class? Note that it does not need to be (lexically) contained in a
- // class since it is possible to forward declare an inner class:
- // class QMetaObject { class Connection; }
- // class QMetaObject::Connection {}
- const CXCursor semPar = clang_getCursorSemanticParent(cursor);
- if (isClassCursor(semPar)) {
- const CursorClassHash::const_iterator it = m_cursorClassHash.constFind(semPar);
- if (it == m_cursorClassHash.constEnd()) {
- QString message;
- QTextStream(&message) << "Unable to find containing class \""
- << getCursorSpelling(semPar) << "\" of inner class \""
- << className << "\".";
- // PYSIDE-1501: Has been observed to fail for inner class of
- // template with separated implementation where a forward
- // declaration of the outer template is reported (Boost).
- const auto severity = semPar.kind == CXCursor_ClassTemplate
- ? CXDiagnostic_Warning : CXDiagnostic_Error;
- const Diagnostic d(message, cursor, severity);
- qWarning() << d;
- m_baseVisitor->appendDiagnostic(d);
- return false;
- }
- const ClassModelItem &containingClass = it.value();
- containingClass->addClass(m_currentClass);
- m_currentClass->setScope(containingClass->scope() << containingClass->name());
- } else {
- m_currentClass->setScope(m_scope);
- m_scopeStack.back()->addClass(m_currentClass);
- }
- pushScope(m_currentClass);
- m_cursorClassHash.insert(cursor, m_currentClass);
- return true;
-}
-
-static QString msgCannotDetermineException(const std::string_view &snippetV)
-{
- const auto newLine = snippetV.find('\n'); // Multiline noexcept specifications have been found in Qt
- const bool truncate = newLine != std::string::npos;
- const auto length = qsizetype(truncate ? newLine : snippetV.size());
- QString snippet = QString::fromUtf8(snippetV.data(), length);
- if (truncate)
- snippet += "..."_L1;
-
- return u"Cannot determine exception specification: \""_s + snippet + u'"';
-}
-
-// Return whether noexcept(<value>) throws. noexcept() takes a constexpr value.
-// Try to determine the simple cases (true|false) via code snippet.
-static ExceptionSpecification computedExceptionSpecificationFromClang(BaseVisitor *bv,
- const CXCursor &cursor,
- bool isTemplateCode)
-{
- const std::string_view snippet = bv->getCodeSnippet(cursor);
- if (snippet.empty())
- return ExceptionSpecification::Unknown; // Macro expansion, cannot tell
- if (snippet.find("noexcept(false)") != std::string::npos)
- return ExceptionSpecification::Throws;
- if (snippet.find("noexcept(true)") != std::string::npos)
- return ExceptionSpecification::NoExcept;
- // Warn about it unless it is some form of template code where it is common
- // to have complicated code, which is of no concern to shiboken, like:
- // "QList::emplace(T) noexcept(is_pod<T>)".
- if (!isTemplateCode && ReportHandler::isDebug(ReportHandler::FullDebug)) {
- const Diagnostic d(msgCannotDetermineException(snippet), cursor, CXDiagnostic_Warning);
- qWarning() << d;
- bv->appendDiagnostic(d);
- }
- return ExceptionSpecification::Unknown;
-}
-
-static ExceptionSpecification exceptionSpecificationFromClang(BaseVisitor *bv,
- const CXCursor &cursor,
- bool isTemplateCode)
-{
- const auto ce = clang_getCursorExceptionSpecificationType(cursor);
- switch (ce) {
- case CXCursor_ExceptionSpecificationKind_ComputedNoexcept:
- return computedExceptionSpecificationFromClang(bv, cursor, isTemplateCode);
- case CXCursor_ExceptionSpecificationKind_BasicNoexcept:
- case CXCursor_ExceptionSpecificationKind_DynamicNone: // throw()
- case CXCursor_ExceptionSpecificationKind_NoThrow:
- return ExceptionSpecification::NoExcept;
- case CXCursor_ExceptionSpecificationKind_Dynamic: // throw(t1..)
- case CXCursor_ExceptionSpecificationKind_MSAny: // throw(...)
- return ExceptionSpecification::Throws;
- default:
- // CXCursor_ExceptionSpecificationKind_None,
- // CXCursor_ExceptionSpecificationKind_Unevaluated,
- // CXCursor_ExceptionSpecificationKind_Uninstantiated
- break;
- }
- return ExceptionSpecification::Unknown;
-}
-
-FunctionModelItem BuilderPrivate::createFunction(const CXCursor &cursor,
- CodeModel::FunctionType t,
- bool isTemplateCode)
-{
- QString name = getCursorSpelling(cursor);
- // Apply type fixes to "operator X &" -> "operator X&"
- if (name.startsWith(u"operator "))
- name = fixTypeName(name);
- auto result = std::make_shared<_FunctionModelItem>(m_model, name);
- setFileName(cursor, result.get());
- const auto type = clang_getCursorResultType(cursor);
- result->setType(createTypeInfo(type));
- result->setScopeResolution(hasScopeResolution(type));
- result->setFunctionType(t);
- result->setScope(m_scope);
- result->setStatic(clang_Cursor_getStorageClass(cursor) == CX_SC_Static);
- result->setExceptionSpecification(exceptionSpecificationFromClang(m_baseVisitor, cursor, isTemplateCode));
- switch (clang_getCursorAvailability(cursor)) {
- case CXAvailability_Available:
- break;
- case CXAvailability_Deprecated:
- result->setAttribute(FunctionAttribute::Deprecated);
- break;
- case CXAvailability_NotAvailable: // "Foo(const Foo&) = delete;"
- result->setDeleted(true);
- break;
- case CXAvailability_NotAccessible:
- break;
- }
- return result;
-}
-
-static inline CodeModel::FunctionType functionTypeFromCursor(const CXCursor &cursor)
-{
- CodeModel::FunctionType result = CodeModel::Normal;
- switch (cursor.kind) {
- case CXCursor_Constructor:
- if (clang_CXXConstructor_isCopyConstructor(cursor) != 0)
- result = CodeModel::CopyConstructor;
- else if (clang_CXXConstructor_isMoveConstructor(cursor) != 0)
- result = CodeModel::MoveConstructor;
- else
- result = CodeModel::Constructor;
- break;
- case CXCursor_Destructor:
- result = CodeModel::Destructor;
- break;
- case CXCursor_CXXMethod:
-#ifdef CLANG_HAS_ASSIGNMENT_OPERATOR_CHECK
- if (clang_CXXMethod_isCopyAssignmentOperator(cursor) != 0)
- result = CodeModel::AssignmentOperator;
- else if (clang_CXXMethod_isMoveAssignmentOperator(cursor) != 0)
- result = CodeModel::MoveAssignmentOperator;
-#endif
- break;
- default:
- break;
- }
- return result;
-}
-
-FunctionModelItem BuilderPrivate::createMemberFunction(const CXCursor &cursor,
- bool isTemplateCode)
-{
- const CodeModel::FunctionType functionType =
- m_currentFunctionType == CodeModel::Signal || m_currentFunctionType == CodeModel::Slot
- ? m_currentFunctionType // by annotation
- : functionTypeFromCursor(cursor);
- isTemplateCode |= m_currentClass->name().endsWith(u'>');
- auto result = createFunction(cursor, functionType, isTemplateCode);
- result->setAccessPolicy(accessPolicy(clang_getCXXAccessSpecifier(cursor)));
- result->setConstant(clang_CXXMethod_isConst(cursor) != 0);
- result->setAttribute(FunctionAttribute::Static, clang_CXXMethod_isStatic(cursor) != 0);
- result->setAttribute(FunctionAttribute::Virtual, clang_CXXMethod_isVirtual(cursor) != 0);
- result->setAttribute(FunctionAttribute::Abstract, clang_CXXMethod_isPureVirtual(cursor) != 0);
- return result;
-}
-
-// For CXCursor_Constructor, on endToken().
-void BuilderPrivate::qualifyConstructor(const CXCursor &cursor)
-{
- // Clang does not tell us whether a constructor is explicit, preventing it
- // from being used for implicit conversions. Try to guess whether a
- // constructor is explicit in the C++99 sense (1 parameter) by checking for
- // isConvertingConstructor() == 0. Fixme: The notion of "isConvertingConstructor"
- // should be used in the code model instead of "explicit"
- if (clang_CXXConstructor_isDefaultConstructor(cursor) == 0
- && m_currentFunction->arguments().size() == 1
- && clang_CXXConstructor_isCopyConstructor(cursor) == 0
- && clang_CXXConstructor_isMoveConstructor(cursor) == 0) {
- m_currentFunction->setAttribute(FunctionAttribute::Explicit,
- clang_CXXConstructor_isConvertingConstructor(cursor) == 0);
- }
-}
-
-TemplateParameterModelItem BuilderPrivate::createTemplateParameter(const CXCursor &cursor) const
-{
- return std::make_shared<_TemplateParameterModelItem>(m_model, getCursorSpelling(cursor));
-}
-
-TemplateParameterModelItem BuilderPrivate::createNonTypeTemplateParameter(const CXCursor &cursor) const
-{
- TemplateParameterModelItem result = createTemplateParameter(cursor);
- result->setType(createTypeInfo(clang_getCursorType(cursor)));
- return result;
-}
-
-// CXCursor_VarDecl, CXCursor_FieldDecl cursors
-void BuilderPrivate::addField(const CXCursor &cursor)
-{
- auto field = std::make_shared<_VariableModelItem>(m_model, getCursorSpelling(cursor));
- field->setAccessPolicy(accessPolicy(clang_getCXXAccessSpecifier(cursor)));
- field->setScope(m_scope);
- field->setType(createTypeInfo(cursor));
- field->setMutable(clang_CXXField_isMutable(cursor) != 0);
- setFileName(cursor, field.get());
- m_currentField = field;
- m_scopeStack.back()->addVariable(field);
-}
-
-// Create qualified name "std::list<std::string>" -> ("std", "list<std::string>")
-static QStringList qualifiedName(const QString &t)
-{
- QStringList result;
- auto end = t.indexOf(u'<');
- if (end == -1)
- end = t.indexOf(u'(');
- if (end == -1)
- end = t.size();
- qsizetype lastPos = 0;
- while (true) {
- const auto nextPos = t.indexOf(u"::"_s, lastPos);
- if (nextPos < 0 || nextPos >= end)
- break;
- result.append(t.mid(lastPos, nextPos - lastPos));
- lastPos = nextPos + 2;
- }
- result.append(t.right(t.size() - lastPos));
- return result;
-}
-
-static bool isArrayType(CXTypeKind k)
-{
- return k == CXType_ConstantArray || k == CXType_IncompleteArray
- || k == CXType_VariableArray || k == CXType_DependentSizedArray;
-}
-
-static bool isPointerType(CXTypeKind k)
-{
- return k == CXType_Pointer || k == CXType_LValueReference || k == CXType_RValueReference;
-}
-
-bool BuilderPrivate::addTemplateInstantiationsRecursion(const CXType &type, TypeInfo *t) const
-{
- // Template arguments
- switch (type.kind) {
- case CXType_Elaborated:
- case CXType_Record:
- case CXType_Unexposed:
- if (const int numTemplateArguments = qMax(0, clang_Type_getNumTemplateArguments(type))) {
- for (unsigned tpl = 0; tpl < unsigned(numTemplateArguments); ++tpl) {
- const CXType argType = clang_Type_getTemplateArgumentAsType(type, tpl);
- // CXType_Invalid is returned when hitting on a specialization
- // of a non-type template (template <int v>).
- if (argType.kind == CXType_Invalid)
- return false;
- t->addInstantiation(createTypeInfoUncached(argType));
- }
- }
- break;
- default:
- break;
- }
- return true;
-}
-
-static void dummyTemplateArgumentHandler(int, QStringView) {}
-
-void BuilderPrivate::addTemplateInstantiations(const CXType &type,
- QString *typeName,
- TypeInfo *t) const
-{
- // In most cases, for templates like "Vector<A>", Clang will give us the
- // arguments by recursing down the type. However this will fail for example
- // within template classes (for functions like the copy constructor):
- // template <class T>
- // class Vector {
- // Vector(const Vector&);
- // };
- // In that case, have TypeInfo parse the list from the spelling.
- // Finally, remove the list "<>" from the type name.
- const bool parsed = addTemplateInstantiationsRecursion(type, t)
- && !t->instantiations().isEmpty();
- if (!parsed)
- t->setInstantiations({});
- const auto pos = parsed
- ? parseTemplateArgumentList(*typeName, dummyTemplateArgumentHandler)
- : t->parseTemplateArgumentList(*typeName);
- if (pos.first != -1 && pos.second != -1 && pos.second > pos.first)
- typeName->remove(pos.first, pos.second - pos.first);
-}
-
-static TypeCategory typeCategoryFromClang(CXTypeKind k)
-{
- switch (k) {
- case CXType_Void:
- return TypeCategory::Void;
- case CXType_Enum:
- return TypeCategory::Enum;
- case CXType_Pointer:
- case CXType_BlockPointer:
- return TypeCategory::Pointer;
- case CXType_FunctionNoProto:
- case CXType_FunctionProto:
- return TypeCategory::Function;
- default:
- break;
- }
- if (k >= CXType_FirstBuiltin && k <= CXType_LastBuiltin)
- return TypeCategory::Builtin;
- return TypeCategory::Other;
-}
-
-TypeInfo BuilderPrivate::createTypeInfoUncached(const CXType &type,
- bool *cacheable) const
-{
- if (type.kind == CXType_Pointer) { // Check for function pointers, first.
- const CXType pointeeType = clang_getPointeeType(type);
- const int argCount = clang_getNumArgTypes(pointeeType);
- if (argCount >= 0) {
- TypeInfo result = createTypeInfoUncached(clang_getResultType(pointeeType),
- cacheable);
- result.setTypeCategory(TypeCategory::Pointer);
- result.setFunctionPointer(true);
- for (int a = 0; a < argCount; ++a)
- result.addArgument(createTypeInfoUncached(clang_getArgType(pointeeType, unsigned(a)),
- cacheable));
- return result;
- }
- }
-
- TypeInfo typeInfo;
- typeInfo.setTypeCategory(typeCategoryFromClang(clang_getCanonicalType(type).kind));
-
- CXType nestedType = type;
- for (; isArrayType(nestedType.kind); nestedType = clang_getArrayElementType(nestedType)) {
- const long long size = clang_getArraySize(nestedType);
- typeInfo.addArrayElement(size >= 0 ? QString::number(size) : QString());
- }
-
- TypeInfo::Indirections indirections;
- for (; isPointerType(nestedType.kind); nestedType = clang_getPointeeType(nestedType)) {
- switch (nestedType.kind) {
- case CXType_Pointer:
- indirections.prepend(clang_isConstQualifiedType(nestedType) != 0
- ? Indirection::ConstPointer : Indirection::Pointer);
- break;
- case CXType_LValueReference:
- typeInfo.setReferenceType(LValueReference);
- break;
- case CXType_RValueReference:
- typeInfo.setReferenceType(RValueReference);
- break;
- default:
- break;
- }
- }
- typeInfo.setIndirectionsV(indirections);
-
- typeInfo.setConstant(clang_isConstQualifiedType(nestedType) != 0);
- typeInfo.setVolatile(clang_isVolatileQualifiedType(nestedType) != 0);
-
- QString typeName = getResolvedTypeName(nestedType);
- while (TypeInfo::stripLeadingConst(&typeName)
- || TypeInfo::stripLeadingVolatile(&typeName)) {
- }
-
- // For typedefs within templates or nested classes within templates (iterators):
- // "template <class T> class QList { using Value=T; .."
- // the typedef source is named "type-parameter-0-0". Convert it back to the
- // template parameter name. The CXTypes are the same for all templates and
- // must not be cached.
- if (m_currentClass && typeName.startsWith(u"type-parameter-0-")) {
- if (cacheable != nullptr)
- *cacheable = false;
- bool ok{};
- const int n = QStringView{typeName}.mid(17).toInt(&ok);
- if (ok) {
- auto currentTemplate = currentTemplateClass();
- if (currentTemplate && n < currentTemplate->templateParameters().size())
- typeName = currentTemplate->templateParameters().at(n)->name();
- }
- }
-
- // Obtain template instantiations if the name has '<' (thus excluding
- // typedefs like "std::string".
- if (typeName.contains(u'<'))
- addTemplateInstantiations(nestedType, &typeName, &typeInfo);
-
- typeInfo.setQualifiedName(qualifiedName(typeName));
- // 3320:CINDEX_LINKAGE int clang_getNumArgTypes(CXType T); function ptr types?
- typeInfo.simplifyStdType();
- return typeInfo;
-}
-
-TypeInfo BuilderPrivate::createTypeInfo(const CXType &type) const
-{
- const auto it = m_typeInfoHash.constFind(type);
- if (it != m_typeInfoHash.constEnd())
- return it.value();
- bool cacheable = true;
- TypeInfo result = createTypeInfoUncached(type, &cacheable);
- if (cacheable)
- m_typeInfoHash.insert(type, result);
- return result;
-}
-
-void BuilderPrivate::addTypeDef(const CXCursor &cursor, const CXType &cxType)
-{
- const QString target = getCursorSpelling(cursor);
- auto item = std::make_shared<_TypeDefModelItem>(m_model, target);
- setFileName(cursor, item.get());
- item->setType(createTypeInfo(cxType));
- item->setScope(m_scope);
- item->setAccessPolicy(accessPolicy(clang_getCXXAccessSpecifier(cursor)));
- m_scopeStack.back()->addTypeDef(item);
-}
-
-ClassModelItem BuilderPrivate::currentTemplateClass() const
-{
- for (auto i = m_scopeStack.size() - 1; i >= 0; --i) {
- auto klass = std::dynamic_pointer_cast<_ClassModelItem>(m_scopeStack.at(i));
- if (klass && klass->isTemplate())
- return klass;
- }
- return {};
-}
-
-void BuilderPrivate::startTemplateTypeAlias(const CXCursor &cursor)
-{
- const QString target = getCursorSpelling(cursor);
- m_currentTemplateTypeAlias = std::make_shared<_TemplateTypeAliasModelItem>(m_model, target);
- setFileName(cursor, m_currentTemplateTypeAlias.get());
- m_currentTemplateTypeAlias->setScope(m_scope);
-}
-
-void BuilderPrivate::endTemplateTypeAlias(const CXCursor &typeAliasCursor)
-{
- CXType type = clang_getTypedefDeclUnderlyingType(typeAliasCursor);
- // Usually "<elaborated>std::list<T>" or "<unexposed>Container1<T>",
- // as obtained with parser of PYSIDE-323
- if (type.kind == CXType_Unexposed || type.kind == CXType_Elaborated) {
- m_currentTemplateTypeAlias->setType(createTypeInfo(type));
- m_scopeStack.back()->addTemplateTypeAlias(m_currentTemplateTypeAlias);
- }
- m_currentTemplateTypeAlias.reset();
-}
-
-// extract an expression from the cursor via source
-// CXCursor_EnumConstantDecl, ParmDecl (a = Flag1 | Flag2)
-QString BuilderPrivate::cursorValueExpression(BaseVisitor *bv, const CXCursor &cursor)
-{
- const std::string_view snippet = bv->getCodeSnippet(cursor);
- auto equalSign = snippet.find('=');
- if (equalSign == std::string::npos)
- return {};
- ++equalSign;
- QString result = QString::fromLocal8Bit(snippet.data() + equalSign,
- qsizetype(snippet.size() - equalSign));
- // Fix a default expression as read from code. Simplify white space
- result.remove(u'\r');
- return result.contains(u'"') ? result.trimmed() : result.simplified();
-}
-
-// Resolve a type (loop over aliases/typedefs), for example for base classes
-// Note: TypeAliasTemplateDecl ("using QVector<T>=QList<T>") is automatically
-// resolved by clang_getTypeDeclaration(), but it stops at
-// TypeAliasDecl / TypedefDecl.
-
-struct TypeDeclaration
-{
- CXType type;
- CXCursor declaration;
-};
-
-static inline bool isTypeAliasDecl(const CXCursor &cursor)
-{
- const auto kind = clang_getCursorKind(cursor);
- return kind == CXCursor_TypeAliasDecl || kind == CXCursor_TypedefDecl;
-}
-
-static TypeDeclaration resolveBaseClassType(CXType type)
-{
- CXCursor decl = clang_getTypeDeclaration(type);
- auto resolvedType = clang_getCursorType(decl);
- if (resolvedType.kind != CXType_Invalid && resolvedType.kind != type.kind)
- type = resolvedType;
- while (isTypeAliasDecl(decl)) {
- type = clang_getTypedefDeclUnderlyingType(decl);
- decl = clang_getTypeDeclaration(type);
- }
- return {type, decl};
-}
-
-// Note: Return the baseclass for cursors like CXCursor_CXXBaseSpecifier,
-// where the cursor spelling has "struct baseClass".
-std::pair<QString, ClassModelItem> BuilderPrivate::getBaseClass(CXType type) const
-{
- const auto decl = resolveBaseClassType(type);
- // Note: spelling has "struct baseClass", use type
- QString baseClassName = getTypeName(decl.type);
- if (baseClassName.startsWith(u"std::")) // Simplify "std::" types
- baseClassName = createTypeInfo(decl.type).toString();
-
- auto it = m_cursorClassHash.constFind(decl.declaration);
- // Not found: Set unqualified name. This happens in cases like
- // "class X : public std::list<...>", "template<class T> class Foo : public T"
- // and standard types like true_type, false_type.
- if (it == m_cursorClassHash.constEnd())
- return {baseClassName, {}};
-
- // Completely qualify the class name by looking it up and taking its scope
- // plus the actual baseClass stripped off any scopes. Consider:
- // namespace std {
- // template <class T> class vector {};
- // namespace n {
- // class Foo : public vector<int> {};
- // }
- // }
- // should have "std::vector<int>" as base class (whereas the type of the base class is
- // "std::vector<T>").
- const QStringList &baseScope = it.value()->scope();
- if (!baseScope.isEmpty()) {
- const auto lastSep = baseClassName.lastIndexOf(u"::"_s);
- if (lastSep >= 0)
- baseClassName.remove(0, lastSep + u"::"_s.size());
- baseClassName.prepend(u"::"_s);
- baseClassName.prepend(baseScope.join(u"::"_s));
- }
- return {baseClassName, it.value()};
-}
-
-// Add a base class to the current class from CXCursor_CXXBaseSpecifier
-void BuilderPrivate::addBaseClass(const CXCursor &cursor)
-{
- Q_ASSERT(clang_getCursorKind(cursor) == CXCursor_CXXBaseSpecifier);
- const auto access = accessPolicy(clang_getCXXAccessSpecifier(cursor));
- const auto baseClass = getBaseClass(clang_getCursorType(cursor));
- m_currentClass->addBaseClass({baseClass.first, baseClass.second, access});
-}
-
-void BuilderPrivate::setFileName(const CXCursor &cursor, _CodeModelItem *item) const
-{
- const SourceRange range = getCursorRange(cursor);
- QString file = m_baseVisitor->getFileName(range.first.file);
- if (!file.isEmpty()) { // Has been observed to be 0 for invalid locations
- item->setFileName(QDir::cleanPath(file));
- item->setStartPosition(int(range.first.line), int(range.first.column));
- item->setEndPosition(int(range.second.line), int(range.second.column));
- }
-}
-
-Builder::Builder() :
- d(new BuilderPrivate(this))
-{
-}
-
-Builder::~Builder()
-{
- delete d;
-}
-
-static QString baseName(QString path)
-{
- qsizetype lastSlash = path.lastIndexOf(u'/');
-#ifdef Q_OS_WIN
- if (lastSlash < 0)
- lastSlash = path.lastIndexOf(u'\\');
-#endif
- if (lastSlash > 0)
- path.remove(0, lastSlash + 1);
- return path;
-}
-
-const char * BuilderPrivate::specialSystemHeaderReason(BuilderPrivate::SpecialSystemHeader sh)
-{
- static const QHash<SpecialSystemHeader, const char *> mapping {
- {SpecialSystemHeader::OpenGL, "OpenGL"},
- {SpecialSystemHeader::Types, "types"},
- {SpecialSystemHeader::WhiteListed, "white listed"},
- {SpecialSystemHeader::WhiteListedPath, "white listed path"}
- };
- return mapping.value(sh, "");
-}
-
-bool BuilderPrivate::visitHeader(const QString &fileName) const
-{
- auto it = m_systemHeaders.find(fileName);
- if (it == m_systemHeaders.end()) {
- it = m_systemHeaders.insert(fileName, specialSystemHeader(fileName));
- if (ReportHandler::isDebug(ReportHandler::MediumDebug)) {
- const QString &name = QDir::toNativeSeparators(fileName);
- if (it.value() == SpecialSystemHeader::None) {
- qCInfo(lcShiboken, "Skipping system header %s", qPrintable(name));
- } else {
- qCInfo(lcShiboken, "Parsing system header %s (%s)",
- qPrintable(name), specialSystemHeaderReason(it.value()));
- }
- }
- }
- return it.value() != SpecialSystemHeader::None;
-}
-
-BuilderPrivate::SpecialSystemHeader
- BuilderPrivate::specialSystemHeader(const QString &fileName) const
-{
- // Resolve OpenGL typedefs although the header is considered a system header.
- const QString baseName = clang::baseName(fileName);
- if (baseName == u"gl.h"
- || baseName == u"gl2.h"
- || baseName == u"gl3.h"
- || baseName == u"gl31.h"
- || baseName == u"gl32.h"
- || baseName == u"stdint.h" // Windows: int32_t, uint32_t
- || baseName == u"stddef.h") { // size_t`
- return SpecialSystemHeader::OpenGL;
- }
-
- switch (clang::optionsTriplet().platform()) {
- case Platform::Linux:
- case Platform::Unix:
- if (fileName == u"/usr/include/stdlib.h"
- || baseName == u"types.h"
- || baseName == u"stdint-intn.h" // int32_t
- || baseName == u"stdint-uintn.h") { // uint32_t
- return SpecialSystemHeader::Types;
- }
- break;
- case Platform::macOS:
- case Platform::iOS:
- // Parse the following system headers to get the correct typdefs for types like
- // int32_t, which are used in the macOS implementation of OpenGL framework.
- // They are installed under /Applications/Xcode.app/Contents/Developer/Platforms...
- if (baseName == u"gltypes.h"
- || fileName.contains(u"/usr/include/_types")
- || fileName.contains(u"/usr/include/sys/_types")) {
- return SpecialSystemHeader::Types;
- }
- break;
- default:
- break;
- }
-
- // When building against system Qt (as it happens with yocto / Boot2Qt), the Qt headers are
- // considered system headers by clang_Location_isInSystemHeader, and shiboken will not
- // process them. We need to explicitly process them by checking against the list of
- // include paths that were passed to shiboken's --force-process-system-include-paths option
- // or specified via the <system-include> xml tag.
- if (m_forceProcessSystemIncludes.contains(baseName))
- return SpecialSystemHeader::WhiteListed;
-
- if (std::any_of(m_forceProcessSystemIncludePaths.cbegin(),
- m_forceProcessSystemIncludePaths.cend(),
- [fileName](const QString &p) { return fileName.startsWith(p); })) {
- return SpecialSystemHeader::WhiteListedPath;
- }
-
- return SpecialSystemHeader::None;
-}
-
-bool Builder::visitLocation(const QString &fileName, LocationType locationType) const
-{
- return locationType != LocationType::System || d->visitHeader(fileName);
-}
-
-void Builder::setForceProcessSystemIncludes(const QStringList &systemIncludes)
-{
- for (const auto &i : systemIncludes) {
- QFileInfo fi(i);
- if (fi.exists() && fi.isDir())
- d->m_forceProcessSystemIncludePaths.append(i);
- else
- d->m_forceProcessSystemIncludes.append(i);
- }
-}
-
-FileModelItem Builder::dom() const
-{
- Q_ASSERT(!d->m_scopeStack.isEmpty());
- auto rootScope = d->m_scopeStack.constFirst();
- rootScope->purgeClassDeclarations();
- return std::dynamic_pointer_cast<_FileModelItem>(rootScope);
-}
-
-static QString msgOutOfOrder(const CXCursor &cursor, const char *expectedScope)
-{
- return getCursorKindName(cursor.kind) + u' '
- + getCursorSpelling(cursor) + u" encountered outside "_s
- + QLatin1StringView(expectedScope) + u'.';
-}
-
-static CodeModel::ClassType codeModelClassTypeFromCursor(CXCursorKind kind)
-{
- CodeModel::ClassType result = CodeModel::Class;
- if (kind == CXCursor_UnionDecl)
- result = CodeModel::Union;
- else if (kind == CXCursor_StructDecl)
- result = CodeModel::Struct;
- return result;
-}
-
-static NamespaceType namespaceType(const CXCursor &cursor)
-{
- if (clang_Cursor_isAnonymous(cursor))
- return NamespaceType::Anonymous;
-#if CINDEX_VERSION_MAJOR > 0 || CINDEX_VERSION_MINOR >= 59
- if (clang_Cursor_isInlineNamespace(cursor))
- return NamespaceType::Inline;
-#endif
- return NamespaceType::Default;
-}
-
-static QString enumType(const CXCursor &cursor)
-{
- QString name = getCursorSpelling(cursor); // "enum Foo { v1, v2 };"
- if (name.contains(u"unnamed enum")) // Clang 16.0
- return {};
- if (name.isEmpty()) {
- // PYSIDE-1228: For "typedef enum { v1, v2 } Foo;", type will return
- // "Foo" as expected. Care must be taken to exclude real anonymous enums.
- name = getTypeName(clang_getCursorType(cursor));
- if (name.contains(u"(unnamed") // Clang 12.0.1
- || name.contains(u"(anonymous")) { // earlier
- name.clear();
- }
- }
- return name;
-}
-
-BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor)
-{
- // Skip inline code
- if ((cursor.kind >= CXCursor_FirstExpr && cursor.kind <= CXCursor_LastExpr)
- || (cursor.kind >= CXCursor_FirstStmt && cursor.kind <= CXCursor_LastStmt)) {
- return Skip;
- }
-
- switch (cursor.kind) {
- case CXCursor_CXXAccessSpecifier:
- d->m_currentFunctionType = CodeModel::Normal;
- break;
- case CXCursor_AnnotateAttr: {
- const QString annotation = getCursorSpelling(cursor);
- if (annotation == u"qt_slot")
- d->m_currentFunctionType = CodeModel::Slot;
- else if (annotation == u"qt_signal")
- d->m_currentFunctionType = CodeModel::Signal;
- else
- d->m_currentFunctionType = CodeModel::Normal;
- }
- break;
- case CXCursor_CXXBaseSpecifier:
- if (!d->m_currentClass) {
- const Diagnostic d(msgOutOfOrder(cursor, "class"), cursor, CXDiagnostic_Error);
- qWarning() << d;
- appendDiagnostic(d);
- return Error;
- }
- d->addBaseClass(cursor);
- break;
- case CXCursor_ClassDecl:
- case CXCursor_UnionDecl:
- case CXCursor_StructDecl:
- if (d->m_withinFriendDecl || clang_isCursorDefinition(cursor) == 0
- || !d->addClass(cursor, codeModelClassTypeFromCursor(cursor.kind))) {
- return Skip;
- }
- break;
- case CXCursor_ClassTemplate:
- case CXCursor_ClassTemplatePartialSpecialization:
- if (d->m_withinFriendDecl || clang_isCursorDefinition(cursor) == 0
- || !d->addClass(cursor, CodeModel::Class)) {
- return Skip;
- }
- d->m_currentClass->setName(d->m_currentClass->name() + "<>"_L1);
- d->m_scope.back() += "<>"_L1;
- break;
- case CXCursor_EnumDecl: {
- QString name = enumType(cursor);
- EnumKind kind = CEnum;
- if (name.isEmpty()) {
- kind = AnonymousEnum;
- name = "enum_"_L1 + QString::number(++d->m_anonymousEnumCount);
-#if !CLANG_NO_ENUMDECL_ISSCOPED
- } else if (clang_EnumDecl_isScoped(cursor) != 0) {
-#else
- } else if (clang_EnumDecl_isScoped4(this, cursor) != 0) {
-#endif
- kind = EnumClass;
- }
- d->m_currentEnum = std::make_shared<_EnumModelItem>(d->m_model, name);
- d->setFileName(cursor, d->m_currentEnum.get());
- d->m_currentEnum->setScope(d->m_scope);
- d->m_currentEnum->setEnumKind(kind);
- if (clang_getCursorAvailability(cursor) == CXAvailability_Deprecated)
- d->m_currentEnum->setDeprecated(true);
- const auto enumType = fullyResolveType(clang_getEnumDeclIntegerType(cursor));
- d->m_currentEnum->setSigned(isSigned(enumType.kind));
- d->m_currentEnum->setUnderlyingType(getTypeName(enumType));
- if (std::dynamic_pointer_cast<_ClassModelItem>(d->m_scopeStack.back()))
- d->m_currentEnum->setAccessPolicy(accessPolicy(clang_getCXXAccessSpecifier(cursor)));
- }
- break;
- case CXCursor_EnumConstantDecl: {
- const QString name = getCursorSpelling(cursor);
- if (!d->m_currentEnum) {
- const Diagnostic d(msgOutOfOrder(cursor, "enum"), cursor, CXDiagnostic_Error);
- qWarning() << d;
- appendDiagnostic(d);
- return Error;
- }
- EnumValue enumValue;
- if (d->m_currentEnum->isSigned())
- enumValue.setValue(clang_getEnumConstantDeclValue(cursor));
- else
- enumValue.setUnsignedValue(clang_getEnumConstantDeclUnsignedValue(cursor));
- auto enumConstant = std::make_shared<_EnumeratorModelItem>(d->m_model, name);
- enumConstant->setStringValue(BuilderPrivate::cursorValueExpression(this, cursor));
- enumConstant->setValue(enumValue);
- if (clang_getCursorAvailability(cursor) == CXAvailability_Deprecated)
- enumConstant->setDeprecated(true);
- d->m_currentEnum->addEnumerator(enumConstant);
- }
- break;
- case CXCursor_VarDecl:
- // static class members are seen as CXCursor_VarDecl
- if (isClassOrNamespaceCursor(clang_getCursorSemanticParent(cursor))) {
- d->addField(cursor);
- d->m_currentField->setStatic(true);
- }
- break;
- case CXCursor_FieldDecl:
- d->addField(cursor);
- break;
- case CXCursor_FriendDecl:
- d->m_withinFriendDecl = true;
- break;
- case CXCursor_Constructor:
- case CXCursor_Destructor: // Note: Also use clang_CXXConstructor_is..Constructor?
- case CXCursor_CXXMethod:
- case CXCursor_ConversionFunction:
- // Member functions of other classes can be declared to be friends.
- // Skip inline member functions outside class, only go by declarations inside class
- if (d->m_withinFriendDecl || !withinClassDeclaration(cursor))
- return Skip;
- d->m_currentFunction = d->createMemberFunction(cursor, false);
- d->m_scopeStack.back()->addFunction(d->m_currentFunction);
- break;
- // Not fully supported, currently, seen as normal function
- // Note: May appear inside class (member template) or outside (free template).
- case CXCursor_FunctionTemplate: {
- const CXCursor semParent = clang_getCursorSemanticParent(cursor);
- if (isClassCursor(semParent)) {
- if (semParent == clang_getCursorLexicalParent(cursor)) {
- d->m_currentFunction = d->createMemberFunction(cursor, true);
- d->m_scopeStack.back()->addFunction(d->m_currentFunction);
- break;
- }
- return Skip; // inline member functions outside class
- }
- }
- d->m_currentFunction = d->createFunction(cursor, CodeModel::Normal, true);
- d->setFileName(cursor, d->m_currentFunction.get());
- d->m_scopeStack.back()->addFunction(d->m_currentFunction);
- break;
- case CXCursor_FunctionDecl:
- // Free functions or functions completely defined within "friend" (class
- // operators). Note: CXTranslationUnit_SkipFunctionBodies must be off for
- // clang_isCursorDefinition() to work here.
- if (!d->m_withinFriendDecl || clang_isCursorDefinition(cursor) != 0) {
- auto scope = d->m_scopeStack.size() - 1; // enclosing class
- if (d->m_withinFriendDecl) {
- // Friend declaration: go back to namespace or file scope.
- for (--scope; d->m_scopeStack.at(scope)->kind() == _CodeModelItem::Kind_Class; --scope) {
- }
- }
- d->m_currentFunction = d->createFunction(cursor, CodeModel::Normal, false);
- d->m_currentFunction->setHiddenFriend(d->m_withinFriendDecl);
- d->m_scopeStack.at(scope)->addFunction(d->m_currentFunction);
- }
- break;
- case CXCursor_Namespace: {
- const auto type = namespaceType(cursor);
- if (type == NamespaceType::Anonymous)
- return Skip;
- const QString name = getCursorSpelling(cursor);
- const auto parentNamespaceItem = std::dynamic_pointer_cast<_NamespaceModelItem>(d->m_scopeStack.back());
- if (!parentNamespaceItem) {
- const QString message = msgOutOfOrder(cursor, "namespace")
- + u" (current scope: "_s + d->m_scopeStack.back()->name() + u')';
- const Diagnostic d(message, cursor, CXDiagnostic_Error);
- qWarning() << d;
- appendDiagnostic(d);
- return Error;
- }
- // Treat namespaces separately to allow for extending namespaces
- // in subsequent modules.
- NamespaceModelItem namespaceItem = parentNamespaceItem->findNamespace(name);
- namespaceItem = std::make_shared<_NamespaceModelItem>(d->m_model, name);
- d->setFileName(cursor, namespaceItem.get());
- namespaceItem->setScope(d->m_scope);
- namespaceItem->setType(type);
- parentNamespaceItem->addNamespace(namespaceItem);
- d->pushScope(namespaceItem);
- }
- break;
- case CXCursor_ParmDecl:
- // Skip in case of nested CXCursor_ParmDecls in case one parameter is a function pointer
- // and function pointer typedefs.
- if (!d->m_currentArgument && d->m_currentFunction) {
- const QString name = getCursorSpelling(cursor);
- d->m_currentArgument = std::make_shared<_ArgumentModelItem>(d->m_model, name);
- const auto type = clang_getCursorType(cursor);
- d->m_currentArgument->setScopeResolution(hasScopeResolution(type));
- d->m_currentArgument->setType(d->createTypeInfo(type));
- d->m_currentFunction->addArgument(d->m_currentArgument);
- QString defaultValueExpression = BuilderPrivate::cursorValueExpression(this, cursor);
- if (!defaultValueExpression.isEmpty()) {
- d->m_currentArgument->setDefaultValueExpression(defaultValueExpression);
- d->m_currentArgument->setDefaultValue(true);
- }
- } else {
- return Skip;
- }
- break;
- case CXCursor_TemplateTypeParameter:
- case CXCursor_NonTypeTemplateParameter: {
- const TemplateParameterModelItem tItem = cursor.kind == CXCursor_TemplateTemplateParameter
- ? d->createTemplateParameter(cursor) : d->createNonTypeTemplateParameter(cursor);
- // Apply to function/member template?
- if (d->m_currentFunction) {
- d->m_currentFunction->setTemplateParameters(d->m_currentFunction->templateParameters() << tItem);
- } else if (d->m_currentTemplateTypeAlias) {
- d->m_currentTemplateTypeAlias->addTemplateParameter(tItem);
- } else if (d->m_currentClass) { // Apply to class
- const QString &tplParmName = tItem->name();
- if (Q_UNLIKELY(!insertTemplateParameterIntoClassName(tplParmName, d->m_currentClass)
- || !insertTemplateParameterIntoClassName(tplParmName, &d->m_scope.back()))) {
- const QString message = "Error inserting template parameter \""_L1 + tplParmName
- + "\" into "_L1 + d->m_currentClass->name();
- const Diagnostic d(message, cursor, CXDiagnostic_Error);
- qWarning() << d;
- appendDiagnostic(d);
- return Error;
- }
- d->m_currentClass->setTemplateParameters(d->m_currentClass->templateParameters() << tItem);
- }
- }
- break;
- case CXCursor_TypeAliasTemplateDecl:
- d->startTemplateTypeAlias(cursor);
- break;
- case CXCursor_TypeAliasDecl: // May contain nested CXCursor_TemplateTypeParameter
- if (!d->m_currentTemplateTypeAlias) {
- const CXType type = clang_getCanonicalType(clang_getCursorType(cursor));
- if (type.kind > CXType_Unexposed)
- d->addTypeDef(cursor, type);
- return Skip;
- } else {
- d->endTemplateTypeAlias(cursor);
- }
- break;
- case CXCursor_TypedefDecl: {
- auto underlyingType = clang_getTypedefDeclUnderlyingType(cursor);
- d->addTypeDef(cursor, underlyingType);
- // For "typedef enum/struct {} Foo;", skip the enum/struct
- // definition nested into the typedef (PYSIDE-1228).
- if (underlyingType.kind == CXType_Elaborated)
- return Skip;
- }
- break;
- // Using declarations look as follows:
- // 1) Normal, non-template case ("using QObject::parent"): UsingDeclaration, TypeRef
- // 2) Simple template case ("using QList::append()"): UsingDeclaration, TypeRef "QList<T>"
- // 3) Template case with parameters ("using QList<T>::append()"):
- // UsingDeclaration, TemplateRef "QList", TypeRef "T"
- case CXCursor_TemplateRef:
- if (d->m_withinUsingDeclaration && d->m_usingTypeRef.isEmpty())
- d->m_usingTypeRef = getCursorSpelling(cursor);
- break;
- case CXCursor_TypeRef:
- if (d->m_withinUsingDeclaration && d->m_usingTypeRef.isEmpty())
- d->m_usingTypeRef = d->getBaseClass(clang_getCursorType(cursor)).first;
- break;
- case CXCursor_CXXFinalAttr:
- if (d->m_currentFunction)
- d->m_currentFunction->setAttribute(FunctionAttribute::Final);
- else if (d->m_currentClass)
- d->m_currentClass->setFinal(true);
- break;
- case CXCursor_CXXOverrideAttr:
- if (d->m_currentFunction)
- d->m_currentFunction->setAttribute(FunctionAttribute::Override);
- break;
- case CXCursor_StaticAssert:
- // Check for Q_PROPERTY() (see PySide6/global.h.in for an explanation
- // how it is defined, and qdoc).
- if (clang_isDeclaration(cursor.kind) && d->m_currentClass) {
- auto snippet = getCodeSnippet(cursor);
- const auto length = snippet.size();
- if (length > 12 && *snippet.rbegin() == ')'
- && snippet.compare(0, 11, "Q_PROPERTY(") == 0) {
- const QString qProperty = QString::fromUtf8(snippet.data() + 11, length - 12);
- d->m_currentClass->addPropertyDeclaration(qProperty);
- }
- }
- break;
- // UsingDeclaration: consists of a TypeRef (base) and OverloadedDeclRef (member name)
- case CXCursor_UsingDeclaration:
- if (d->m_currentClass)
- d->m_withinUsingDeclaration = true;
- break;
- case CXCursor_OverloadedDeclRef:
- if (d->m_withinUsingDeclaration && !d->m_usingTypeRef.isEmpty()) {
- QString member = getCursorSpelling(cursor);
- if (member == d->m_currentClass->name())
- member = d->m_usingTypeRef; // Overloaded member is Constructor, use base
- const auto ap = accessPolicy(clang_getCXXAccessSpecifier(cursor));
- d->m_currentClass->addUsingMember(d->m_usingTypeRef, member, ap);
- }
- break;
- default:
- break;
- }
- return BaseVisitor::Recurse;
-}
-
-bool Builder::endToken(const CXCursor &cursor)
-{
- switch (cursor.kind) {
- case CXCursor_UnionDecl:
- case CXCursor_ClassDecl:
- case CXCursor_StructDecl:
- case CXCursor_ClassTemplate:
- case CXCursor_ClassTemplatePartialSpecialization:
- d->popScope();
- // Continue in outer class after leaving inner class?
- if (auto lastClass = std::dynamic_pointer_cast<_ClassModelItem>(d->m_scopeStack.back()))
- d->m_currentClass = lastClass;
- else
- d->m_currentClass.reset();
- d->m_currentFunctionType = CodeModel::Normal;
- break;
- case CXCursor_EnumDecl:
- if (d->m_currentEnum)
- d->m_scopeStack.back()->addEnum(d->m_currentEnum);
- d->m_currentEnum.reset();
- break;
- case CXCursor_FriendDecl:
- d->m_withinFriendDecl = false;
- break;
- case CXCursor_VarDecl:
- case CXCursor_FieldDecl:
- d->m_currentField.reset();
- break;
- case CXCursor_Constructor:
- d->qualifyConstructor(cursor);
- if (d->m_currentFunction) {
- d->m_currentFunction->_determineType();
- d->m_currentFunction.reset();
- }
- break;
- case CXCursor_Destructor:
- case CXCursor_CXXMethod:
- case CXCursor_FunctionDecl:
- case CXCursor_FunctionTemplate:
- if (d->m_currentFunction) {
- d->m_currentFunction->_determineType();
- d->m_currentFunction.reset();
- }
- break;
- case CXCursor_ConversionFunction:
- if (d->m_currentFunction) {
- d->m_currentFunction->setFunctionType(CodeModel::ConversionOperator);
- d->m_currentFunction.reset();
- }
- break;
- case CXCursor_Namespace:
- d->popScope();
- break;
- case CXCursor_ParmDecl:
- d->m_currentArgument.reset();
- break;
- case CXCursor_TypeAliasTemplateDecl:
- d->m_currentTemplateTypeAlias.reset();
- break;
- case CXCursor_UsingDeclaration:
- d->m_withinUsingDeclaration = false;
- d->m_usingTypeRef.clear();
- break;
- default:
- break;
- }
- return true;
-}
-
-} // namespace clang