diff options
Diffstat (limited to 'sources/shiboken2/ApiExtractor/clangparser')
10 files changed, 0 insertions, 2645 deletions
diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp b/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp deleted file mode 100644 index 1eaa36540..000000000 --- a/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp +++ /dev/null @@ -1,1175 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt for Python. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "clangbuilder.h" -#include "compilersupport.h" -#include "clangutils.h" - -#include <codemodel.h> - -#include <QtCore/QDebug> -#include <QtCore/QDir> -#include <QtCore/QHash> -#include <QtCore/QMap> -#include <QtCore/QString> -#include <QtCore/QStack> -#include <QtCore/QVector> - -#include <cstring> -#include <ctype.h> - -#if QT_VERSION < 0x050800 -# define Q_FALLTHROUGH() (void)0 -#endif - -namespace clang { - -static inline QString colonColon() { return QStringLiteral("::"); } -static inline QString templateBrackets() { return QStringLiteral("<>"); } - -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 withinClassDeclaration(const CXCursor &cursor) -{ - return isClassCursor(clang_getCursorLexicalParent(cursor)); -} - -static QString fixTypeName(QString t) -{ - // Fix "Foo &" -> "Foo&", similarly "Bar **" -> "Bar**" - int pos = t.size() - 1; - for (; pos >= 0 && (t.at(pos) == QLatin1Char('&') || t.at(pos) == QLatin1Char('*')); --pos) {} - if (pos > 0 && t.at(pos) == QLatin1Char(' ')) - 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(QLatin1Char('>')))) - return false; - const bool needsComma = name->at(name->size() - 2) != QLatin1Char('<'); - const int insertionPos = name->size() - 1; - name->insert(insertionPos, parmName); - if (needsComma) - name->insert(insertionPos, QLatin1Char(',')); - 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 CodeModel::AccessPolicy accessPolicy(CX_CXXAccessSpecifier access) -{ - CodeModel::AccessPolicy result = CodeModel::Public; - switch (access) { - case CX_CXXProtected: - result = CodeModel::Protected; - break; - case CX_CXXPrivate: - result = CodeModel::Private; - break; - default: - break; - } - return result; -} - -static void setFileName(const CXCursor &cursor, _CodeModelItem *item) -{ - const SourceRange range = getCursorRange(cursor); - if (!range.first.file.isEmpty()) { // Has been observed to be 0 for invalid locations - item->setFileName(QDir::cleanPath(range.first.file)); - item->setStartPosition(int(range.first.line), int(range.first.column)); - item->setEndPosition(int(range.second.line), int(range.second.column)); - } -} - -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: - using CursorClassHash = QHash<CXCursor, ClassModelItem>; - using CursorTypedefHash = QHash<CXCursor, TypeDefModelItem>; - using TypeInfoHash = QHash<CXType, TypeInfo>; - - explicit BuilderPrivate(BaseVisitor *bv) : m_baseVisitor(bv), m_model(new CodeModel) - { - m_scopeStack.push(NamespaceModelItem(new _FileModelItem(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.pop(); - updateScope(); - } - - bool addClass(const CXCursor &cursor, CodeModel::ClassType t); - FunctionModelItem createFunction(const CXCursor &cursor, - CodeModel::FunctionType t = CodeModel::Normal) const; - FunctionModelItem createMemberFunction(const CXCursor &cursor) const; - void qualifyConstructor(const CXCursor &cursor); - TypeInfo createTypeInfoHelper(const CXType &type) const; // uncashed - 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); - 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); - - QString cursorValueExpression(BaseVisitor *bv, const CXCursor &cursor) const; - void addBaseClass(const CXCursor &cursor); - - template <class Item> - void qualifyTypeDef(const CXCursor &typeRefCursor, const QSharedPointer<Item> &item) const; - - bool visitHeader(const char *cFileName) 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; - CursorTypedefHash m_cursorTypedefHash; - - 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; - QByteArrayList m_systemIncludes; // files, like "memory" - QByteArrayList m_systemIncludePaths; // paths, like "/usr/include/Qt/" - - int m_anonymousEnumCount = 0; - CodeModel::FunctionType m_currentFunctionType = CodeModel::Normal; -}; - -bool BuilderPrivate::addClass(const CXCursor &cursor, CodeModel::ClassType t) -{ - QString className = getCursorSpelling(cursor); - m_currentClass.reset(new _ClassModelItem(m_model, className)); - setFileName(cursor, m_currentClass.data()); - 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()) { - const QString message = QStringLiteral("Unable to find parent of inner class ") + className; - const Diagnostic d(message, cursor, CXDiagnostic_Error); - 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 inline ExceptionSpecification exceptionSpecificationFromClang(int ce) -{ - switch (ce) { - case CXCursor_ExceptionSpecificationKind_BasicNoexcept: - case CXCursor_ExceptionSpecificationKind_ComputedNoexcept: - case CXCursor_ExceptionSpecificationKind_DynamicNone: // throw() - 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) const -{ - QString name = getCursorSpelling(cursor); - // Apply type fixes to "operator X &" -> "operator X&" - if (name.startsWith(QLatin1String("operator "))) - name = fixTypeName(name); - FunctionModelItem result(new _FunctionModelItem(m_model, name)); - setFileName(cursor, result.data()); - result->setType(createTypeInfoHelper(clang_getCursorResultType(cursor))); - result->setFunctionType(t); - result->setScope(m_scope); - result->setStatic(clang_Cursor_getStorageClass(cursor) == CX_SC_Static); - result->setExceptionSpecification(exceptionSpecificationFromClang(clang_getCursorExceptionSpecificationType(cursor))); - switch (clang_getCursorAvailability(cursor)) { - case CXAvailability_Available: - break; - case CXAvailability_Deprecated: - result->setDeprecated(true); - 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; - default: - break; - } - return result; -} - -FunctionModelItem BuilderPrivate::createMemberFunction(const CXCursor &cursor) const -{ - const CodeModel::FunctionType functionType = - m_currentFunctionType == CodeModel::Signal || m_currentFunctionType == CodeModel::Slot - ? m_currentFunctionType // by annotation - : functionTypeFromCursor(cursor); - FunctionModelItem result = createFunction(cursor, functionType); - result->setAccessPolicy(accessPolicy(clang_getCXXAccessSpecifier(cursor))); - result->setConstant(clang_CXXMethod_isConst(cursor) != 0); - result->setStatic(clang_CXXMethod_isStatic(cursor) != 0); - result->setVirtual(clang_CXXMethod_isVirtual(cursor) != 0); - result->setAbstract(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->setExplicit(clang_CXXConstructor_isConvertingConstructor(cursor) == 0); - } -} - -TemplateParameterModelItem BuilderPrivate::createTemplateParameter(const CXCursor &cursor) const -{ - return TemplateParameterModelItem(new _TemplateParameterModelItem(m_model, getCursorSpelling(cursor))); -} - -TemplateParameterModelItem BuilderPrivate::createNonTypeTemplateParameter(const CXCursor &cursor) const -{ - TemplateParameterModelItem result = createTemplateParameter(cursor); - result->setType(createTypeInfoHelper(clang_getCursorType(cursor))); - return result; -} - -// CXCursor_VarDecl, CXCursor_FieldDecl cursors -void BuilderPrivate::addField(const CXCursor &cursor) -{ - VariableModelItem field(new _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); - m_currentField = field; - m_scopeStack.back()->addVariable(field); -} - -// Array helpers: Parse "a[2][4]" into a list of dimensions - -struct ArrayDimensionResult -{ - QVector<QStringRef> dimensions; - int position; -}; - -// Create qualified name "std::list<std::string>" -> ("std", "list<std::string>") -static QStringList qualifiedName(const QString &t) -{ - QStringList result; - int end = t.indexOf(QLatin1Char('<')); - if (end == -1) - end = t.indexOf(QLatin1Char('(')); - if (end == -1) - end = t.size(); - int lastPos = 0; - while (true) { - const int nextPos = t.indexOf(colonColon(), 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(createTypeInfoHelper(argType)); - } - } - break; - default: - break; - } - return true; -} - -static void dummyTemplateArgumentHandler(int, const QStringRef &) {} - -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 QPair<int, int> 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); -} - -TypeInfo BuilderPrivate::createTypeInfoHelper(const CXType &type) 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 = createTypeInfoHelper(clang_getResultType(pointeeType)); - result.setFunctionPointer(true); - for (int a = 0; a < argCount; ++a) - result.addArgument(createTypeInfoHelper(clang_getArgType(pointeeType, unsigned(a)))); - return result; - } - } - - TypeInfo typeInfo; - - 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 = getTypeName(nestedType); - while (TypeInfo::stripLeadingConst(&typeName) - || TypeInfo::stripLeadingVolatile(&typeName)) { - } - - // Obtain template instantiations if the name has '<' (thus excluding - // typedefs like "std::string". - if (typeName.contains(QLatin1Char('<'))) - 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 -{ - TypeInfoHash::iterator it = m_typeInfoHash.find(type); - if (it == m_typeInfoHash.end()) - it = m_typeInfoHash.insert(type, createTypeInfoHelper(type)); - return it.value(); -} - -void BuilderPrivate::addTypeDef(const CXCursor &cursor, const CXType &cxType) -{ - const QString target = getCursorSpelling(cursor); - TypeDefModelItem item(new _TypeDefModelItem(m_model, target)); - setFileName(cursor, item.data()); - item->setType(createTypeInfo(cxType)); - item->setScope(m_scope); - m_scopeStack.back()->addTypeDef(item); - m_cursorTypedefHash.insert(cursor, item); -} - -void BuilderPrivate::startTemplateTypeAlias(const CXCursor &cursor) -{ - const QString target = getCursorSpelling(cursor); - m_currentTemplateTypeAlias.reset(new _TemplateTypeAliasModelItem(m_model, target)); - setFileName(cursor, m_currentTemplateTypeAlias.data()); - 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 -{ - BaseVisitor::CodeSnippet snippet = bv->getCodeSnippet(cursor); - const char *equalSign = std::find(snippet.first, snippet.second, '='); - if (equalSign == snippet.second) - return QString(); - ++equalSign; - return QString::fromLocal8Bit(equalSign, int(snippet.second - equalSign)).trimmed(); -} - -// A hacky reimplementation of clang_EnumDecl_isScoped() for Clang < 5.0 -// which simply checks for a blank-delimited " class " keyword in the enum snippet. - -#define CLANG_NO_ENUMDECL_ISSCOPED \ - (CINDEX_VERSION_MAJOR == 0 && CINDEX_VERSION_MINOR < 43) - -#if CLANG_NO_ENUMDECL_ISSCOPED -static const char *indexOf(const BaseVisitor::CodeSnippet &snippet, const char *needle) -{ - const size_t snippetLength = snippet.first ? size_t(snippet.second - snippet.first) : 0; - const size_t needleLength = strlen(needle); - if (needleLength > snippetLength) - return nullptr; - for (const char *c = snippet.first, *end = snippet.second - needleLength; c < end; ++c) { - if (memcmp(c, needle, needleLength) == 0) - return c; - } - return nullptr; -} - -long clang_EnumDecl_isScoped4(BaseVisitor *bv, const CXCursor &cursor) -{ - BaseVisitor::CodeSnippet snippet = bv->getCodeSnippet(cursor); - const char *classSpec = indexOf(snippet, "class"); - const bool isClass = classSpec && classSpec > snippet.first - && isspace(*(classSpec - 1)) && isspace(*(classSpec + 5)); - return isClass ? 1 : 0; -} -#endif // CLANG_NO_ENUMDECL_ISSCOPED - -// Resolve declaration and type of a base class - -struct TypeDeclaration -{ - CXType type; - CXCursor declaration; -}; - -static TypeDeclaration resolveBaseSpecifier(const CXCursor &cursor) -{ - Q_ASSERT(clang_getCursorKind(cursor) == CXCursor_CXXBaseSpecifier); - CXType inheritedType = clang_getCursorType(cursor); - CXCursor decl = clang_getTypeDeclaration(inheritedType); - if (inheritedType.kind != CXType_Unexposed) { - while (true) { - auto kind = clang_getCursorKind(decl); - if (kind != CXCursor_TypeAliasDecl && kind != CXCursor_TypedefDecl) - break; - inheritedType = clang_getTypedefDeclUnderlyingType(decl); - decl = clang_getTypeDeclaration(inheritedType); - } - } - return {inheritedType, decl}; -} - -// Add a base class to the current class from CXCursor_CXXBaseSpecifier -void BuilderPrivate::addBaseClass(const CXCursor &cursor) -{ - Q_ASSERT(clang_getCursorKind(cursor) == CXCursor_CXXBaseSpecifier); - // Note: spelling has "struct baseClass", use type - QString baseClassName; - const auto decl = resolveBaseSpecifier(cursor); - if (decl.type.kind == CXType_Unexposed) { - // The type is unexposed when the base class is a template type alias: - // "class QItemSelection : public QList<X>" where QList is aliased to QVector. - // Try to resolve via code model. - TypeInfo info = createTypeInfo(decl.type); - auto parentScope = m_scopeStack.at(m_scopeStack.size() - 2); // Current is class. - auto resolved = TypeInfo::resolveType(info, parentScope); - if (resolved != info) - baseClassName = resolved.toString(); - } - if (baseClassName.isEmpty()) - baseClassName = getTypeName(decl.type); - - auto it = m_cursorClassHash.constFind(decl.declaration); - const CodeModel::AccessPolicy access = accessPolicy(clang_getCXXAccessSpecifier(cursor)); - if (it == m_cursorClassHash.constEnd()) { - // 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. - m_currentClass->addBaseClass(baseClassName, access); - return; - } - // 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 int lastSep = baseClassName.lastIndexOf(colonColon()); - if (lastSep >= 0) - baseClassName.remove(0, lastSep + colonColon().size()); - baseClassName.prepend(colonColon()); - baseClassName.prepend(baseScope.join(colonColon())); - } - m_currentClass->addBaseClass(baseClassName, access); -} - -static inline CXCursor definitionFromTypeRef(const CXCursor &typeRefCursor) -{ - Q_ASSERT(typeRefCursor.kind == CXCursor_TypeRef); - return clang_getTypeDeclaration(clang_getCursorType(typeRefCursor)); -} - -// Qualify function arguments or fields that are typedef'ed from another scope: -// enum ConversionFlag {}; -// typedef QFlags<ConversionFlag> ConversionFlags; -// class QTextCodec { -// enum ConversionFlag {}; -// typedef QFlags<ConversionFlag> ConversionFlags; -// struct ConverterState { -// explicit ConverterState(ConversionFlags); -// ^^ qualify to QTextCodec::ConversionFlags -// ConversionFlags m_flags; -// ^^ ditto - -template <class Item> // ArgumentModelItem, VariableModelItem -void BuilderPrivate::qualifyTypeDef(const CXCursor &typeRefCursor, const QSharedPointer<Item> &item) const -{ - TypeInfo type = item->type(); - if (type.qualifiedName().size() == 1) { // item's type is unqualified. - const auto it = m_cursorTypedefHash.constFind(definitionFromTypeRef(typeRefCursor)); - if (it != m_cursorTypedefHash.constEnd() && !it.value()->scope().isEmpty()) { - type.setQualifiedName(it.value()->scope() + type.qualifiedName()); - item->setType(type); - } - } -} - -Builder::Builder() -{ - d = new BuilderPrivate(this); -} - -Builder::~Builder() -{ - delete d; -} - -static const char *cBaseName(const char *fileName) -{ - const char *lastSlash = std::strrchr(fileName, '/'); -#ifdef Q_OS_WIN - if (lastSlash == nullptr) - lastSlash = std::strrchr(fileName, '\\'); -#endif - return lastSlash != nullptr ? (lastSlash + 1) : fileName; -} - -static inline bool cCompareFileName(const char *f1, const char *f2) -{ -#ifdef Q_OS_WIN - return _stricmp(f1, f2) == 0; -#else - return std::strcmp(f1, f2) == 0; -#endif -} - -#ifdef Q_OS_UNIX -template<size_t N> -static bool cStringStartsWith(const char *str, const char (&prefix)[N]) -{ - return std::strncmp(prefix, str, N - 1) == 0; -} -#endif - -static bool cStringStartsWith(const char *str, const QByteArray &prefix) -{ - return std::strncmp(prefix.constData(), str, int(prefix.size())) == 0; -} - -bool BuilderPrivate::visitHeader(const char *cFileName) const -{ - // Resolve OpenGL typedefs although the header is considered a system header. - const char *baseName = cBaseName(cFileName); - if (cCompareFileName(baseName, "gl.h")) - return true; -#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS) - if (cStringStartsWith(cFileName, "/usr/include/stdint.h")) - return true; -#endif -#ifdef Q_OS_LINUX - if (cStringStartsWith(cFileName, "/usr/include/stdlib.h") - || cStringStartsWith(cFileName, "/usr/include/sys/types.h")) { - return true; - } -#endif // Q_OS_LINUX -#ifdef Q_OS_MACOS - // 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. - if (cCompareFileName(baseName, "gltypes.h") - || cStringStartsWith(cFileName, "/usr/include/_types") - || cStringStartsWith(cFileName, "/usr/include/_types") - || cStringStartsWith(cFileName, "/usr/include/sys/_types")) { - return true; - } -#endif // Q_OS_MACOS - if (baseName) { - for (const auto &systemInclude : m_systemIncludes) { - if (systemInclude == baseName) - return true; - } - } - for (const auto &systemIncludePath : m_systemIncludePaths) { - if (cStringStartsWith(cFileName, systemIncludePath)) - return true; - } - return false; -} - -bool Builder::visitLocation(const CXSourceLocation &location) const -{ - if (clang_Location_isInSystemHeader(location) == 0) - return true; - CXFile file; // void * - unsigned line; - unsigned column; - unsigned offset; - clang_getExpansionLocation(location, &file, &line, &column, &offset); - const CXString cxFileName = clang_getFileName(file); - // Has been observed to be 0 for invalid locations - bool result = false; - if (const char *cFileName = clang_getCString(cxFileName)) { - result = d->visitHeader(cFileName); - clang_disposeString(cxFileName); - } - return result; -} - -void Builder::setSystemIncludes(const QByteArrayList &systemIncludes) -{ - for (const auto &i : systemIncludes) { - if (i.endsWith('/')) - d->m_systemIncludePaths.append(i); - else - d->m_systemIncludes.append(i); - } -} - -FileModelItem Builder::dom() const -{ - Q_ASSERT(!d->m_scopeStack.isEmpty()); - return qSharedPointerDynamicCast<_FileModelItem>(d->m_scopeStack.constFirst()); -} - -static QString msgOutOfOrder(const CXCursor &cursor, const char *expectedScope) -{ - return getCursorKindName(cursor.kind) + QLatin1Char(' ') - + getCursorSpelling(cursor) + QLatin1String(" encountered outside ") - + QLatin1String(expectedScope) + QLatin1Char('.'); -} - -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.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(QLatin1String("(anonymous"))) - name.clear(); - } - return name; -} - -BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor) -{ - switch (cursor.kind) { - case CXCursor_CXXAccessSpecifier: - d->m_currentFunctionType = CodeModel::Normal; - break; - case CXCursor_AnnotateAttr: { - const QString annotation = getCursorSpelling(cursor); - if (annotation == QLatin1String("qt_slot")) - d->m_currentFunctionType = CodeModel::Slot; - else if (annotation == QLatin1String("qt_signal")) - d->m_currentFunctionType = CodeModel::Signal; - else - d->m_currentFunctionType = CodeModel::Normal; - } - break; - case CXCursor_CXXBaseSpecifier: - if (d->m_currentClass.isNull()) { - 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 (clang_isCursorDefinition(cursor) == 0) - return Skip; - if (!d->addClass(cursor, codeModelClassTypeFromCursor(cursor.kind))) - return Error; - break; - case CXCursor_ClassTemplate: - case CXCursor_ClassTemplatePartialSpecialization: - if (clang_isCursorDefinition(cursor) == 0) - return Skip; - d->addClass(cursor, CodeModel::Class); - d->m_currentClass->setName(d->m_currentClass->name() + templateBrackets()); - d->m_scope.back() += templateBrackets(); - break; - case CXCursor_EnumDecl: { - QString name = enumType(cursor); - EnumKind kind = CEnum; - if (name.isEmpty()) { - kind = AnonymousEnum; - name = QStringLiteral("enum_") + 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.reset(new _EnumModelItem(d->m_model, name)); - setFileName(cursor, d->m_currentEnum.data()); - d->m_currentEnum->setScope(d->m_scope); - d->m_currentEnum->setEnumKind(kind); - d->m_currentEnum->setSigned(isSigned(clang_getEnumDeclIntegerType(cursor).kind)); - if (!qSharedPointerDynamicCast<_ClassModelItem>(d->m_scopeStack.back()).isNull()) - d->m_currentEnum->setAccessPolicy(accessPolicy(clang_getCXXAccessSpecifier(cursor))); - } - break; - case CXCursor_EnumConstantDecl: { - const QString name = getCursorSpelling(cursor); - if (d->m_currentEnum.isNull()) { - 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)); - EnumeratorModelItem enumConstant(new _EnumeratorModelItem(d->m_model, name)); - enumConstant->setStringValue(d->cursorValueExpression(this, cursor)); - enumConstant->setValue(enumValue); - d->m_currentEnum->addEnumerator(enumConstant); - } - break; - case CXCursor_VarDecl: - // static class members are seen as CXCursor_VarDecl - if (!d->m_currentClass.isNull() && isClassCursor(clang_getCursorSemanticParent(cursor))) { - d->addField(cursor); - d->m_currentField->setStatic(true); - } - break; - case CXCursor_FieldDecl: - d->addField(cursor); - break; -#if CINDEX_VERSION_MAJOR > 0 || CINDEX_VERSION_MINOR >= 37 // Clang 4.0 - case CXCursor_FriendDecl: - return Skip; -#endif - case CXCursor_Constructor: - case CXCursor_Destructor: // Note: Also use clang_CXXConstructor_is..Constructor? - case CXCursor_CXXMethod: - case CXCursor_ConversionFunction: - // Skip inline member functions outside class, only go by declarations inside class - if (!withinClassDeclaration(cursor)) - return Skip; - d->m_currentFunction = d->createMemberFunction(cursor); - 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); - d->m_scopeStack.back()->addFunction(d->m_currentFunction); - break; - } - return Skip; // inline member functions outside class - } - } - Q_FALLTHROUGH(); // fall through to free template function. - case CXCursor_FunctionDecl: - d->m_currentFunction = d->createFunction(cursor); - d->m_scopeStack.back()->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 NamespaceModelItem parentNamespaceItem = qSharedPointerDynamicCast<_NamespaceModelItem>(d->m_scopeStack.back()); - if (parentNamespaceItem.isNull()) { - const QString message = msgOutOfOrder(cursor, "namespace") - + QLatin1String(" (current scope: ") + d->m_scopeStack.back()->name() + QLatin1Char(')'); - 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.reset(new _NamespaceModelItem(d->m_model, name)); - setFileName(cursor, namespaceItem.data()); - 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.isNull() && !d->m_currentFunction.isNull()) { - const QString name = getCursorSpelling(cursor); - d->m_currentArgument.reset(new _ArgumentModelItem(d->m_model, name)); - d->m_currentArgument->setType(d->createTypeInfo(cursor)); - d->m_currentFunction->addArgument(d->m_currentArgument); - QString defaultValueExpression = d->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.isNull()) { - d->m_currentFunction->setTemplateParameters(d->m_currentFunction->templateParameters() << tItem); - } else if (!d->m_currentTemplateTypeAlias.isNull()) { - d->m_currentTemplateTypeAlias->addTemplateParameter(tItem); - } else if (!d->m_currentClass.isNull()) { // 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 = QStringLiteral("Error inserting template parameter \"") + tplParmName - + QStringLiteral("\" into ") + 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.isNull()) { - 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; - case CXCursor_TypeRef: - if (!d->m_currentFunction.isNull()) { - if (d->m_currentArgument.isNull()) - d->qualifyTypeDef(cursor, d->m_currentFunction); // return type - else - d->qualifyTypeDef(cursor, d->m_currentArgument); - } else if (!d->m_currentField.isNull()) { - d->qualifyTypeDef(cursor, d->m_currentField); - } - break; - case CXCursor_CXXFinalAttr: - if (!d->m_currentFunction.isNull()) - d->m_currentFunction->setFinal(true); - else if (!d->m_currentClass.isNull()) - d->m_currentClass->setFinal(true); - break; - case CXCursor_CXXOverrideAttr: - if (!d->m_currentFunction.isNull()) - d->m_currentFunction->setOverride(true); - 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 (ClassModelItem lastClass = qSharedPointerDynamicCast<_ClassModelItem>(d->m_scopeStack.back())) - d->m_currentClass = lastClass; - else - d->m_currentClass.clear(); - d->m_currentFunctionType = CodeModel::Normal; - break; - case CXCursor_EnumDecl: - // Add enum only if values were encountered, otherwise assume it - // is a forward declaration of an enum class. - if (!d->m_currentEnum.isNull() && d->m_currentEnum->hasValues()) - d->m_scopeStack.back()->addEnum(d->m_currentEnum); - d->m_currentEnum.clear(); - break; - case CXCursor_VarDecl: - case CXCursor_FieldDecl: - d->m_currentField.clear(); - break; - case CXCursor_Constructor: - d->qualifyConstructor(cursor); - d->m_currentFunction.clear(); - break; - case CXCursor_Destructor: - case CXCursor_CXXMethod: - case CXCursor_FunctionDecl: - case CXCursor_FunctionTemplate: - d->m_currentFunction.clear(); - break; - case CXCursor_Namespace: - d->popScope(); - break; - case CXCursor_ParmDecl: - d->m_currentArgument.clear(); - break; - case CXCursor_TypeAliasTemplateDecl: - d->m_currentTemplateTypeAlias.reset(); - break; - default: - break; - } - return true; -} - -} // namespace clang diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.h b/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.h deleted file mode 100644 index dc37dff0f..000000000 --- a/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.h +++ /dev/null @@ -1,62 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt for Python. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef CLANGBUILDER_H -#define CLANGBUILDER_H - -#include "clangparser.h" - -#include <codemodel_fwd.h> - -namespace clang { - -class BuilderPrivate; - -class Builder : public BaseVisitor { -public: - Q_DISABLE_COPY(Builder) - - Builder(); - ~Builder(); - - void setSystemIncludes(const QByteArrayList &systemIncludes); - - bool visitLocation(const CXSourceLocation &location) const override; - - StartTokenResult startToken(const CXCursor &cursor) override; - bool endToken(const CXCursor &cursor) override; - - FileModelItem dom() const; - -private: - BuilderPrivate *d; -}; - -} // namespace clang - -#endif // CLANGBUILDER_H diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangdebugutils.cpp b/sources/shiboken2/ApiExtractor/clangparser/clangdebugutils.cpp deleted file mode 100644 index d6915daab..000000000 --- a/sources/shiboken2/ApiExtractor/clangparser/clangdebugutils.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt for Python. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "clangdebugutils.h" -#include "clangutils.h" - -#include <QtCore/QDebug> -#include <QtCore/QString> - -#include <string.h> - -#ifndef QT_NO_DEBUG_STREAM - -#ifdef Q_OS_WIN -const char pathSep = '\\'; -#else -const char pathSep = '/'; -#endif - -static const char *baseName(const char *fileName) -{ - const char *b = strrchr(fileName, pathSep); - return b ? b + 1 : fileName; -} - -QDebug operator<<(QDebug s, const CXString &cs) -{ - s << clang_getCString(cs); - return s; -} - -QDebug operator<<(QDebug s, CXCursorKind cursorKind) // Enum -{ - const CXString kindName = clang_getCursorKindSpelling(cursorKind); - s << kindName; - clang_disposeString(kindName); - return s; -} - -static const char *accessSpecsStrings[] -{ - // CX_CXXInvalidAccessSpecifier, CX_CXXPublic, CX_CXXProtected, CX_CXXPrivate - "invalid", "public", "protected", "private" -}; - -QDebug operator<<(QDebug s, CX_CXXAccessSpecifier ac) -{ - s << accessSpecsStrings[ac]; - return s; -} - -QDebug operator<<(QDebug s, const CXType &t) -{ - CXString typeSpelling = clang_getTypeSpelling(t); - s << typeSpelling; - clang_disposeString(typeSpelling); - return s; -} - -QDebug operator<<(QDebug s, const CXCursor &cursor) -{ - QDebugStateSaver saver(s); - s.nospace(); - s.noquote(); - const CXCursorKind kind = clang_getCursorKind(cursor); - s << kind; - if (kind >= CXCursor_FirstInvalid && kind <= CXCursor_LastInvalid) - return s; - const CXType type = clang_getCursorType(cursor); - switch (kind) { - case CXCursor_CXXAccessSpecifier: - s << ' ' << clang_getCXXAccessSpecifier(cursor); - break; - case CXCursor_CXXBaseSpecifier: - s << ", inherits=\"" << clang::getCursorSpelling(clang_getTypeDeclaration(type)) << '"'; - break; - case CXCursor_CXXMethod: - case CXCursor_FunctionDecl: - case CXCursor_ConversionFunction: - s << ", result type=\"" << clang_getCursorResultType(cursor) << '"'; - break; - case CXCursor_TypedefDecl: - s << ", underlyingType=\"" << clang_getTypedefDeclUnderlyingType(cursor) << '"'; - break; - default: - break; - } - - if (type.kind != CXType_Invalid) - s << ", type=\"" << type << '"'; - if (clang_Cursor_hasAttrs(cursor)) - s << ", [attrs]"; - - const QString cursorSpelling = clang::getCursorSpelling(cursor); - if (!cursorSpelling.isEmpty()) - s << ", spelling=\"" << cursorSpelling << '"'; - CXString cursorDisplay = clang_getCursorDisplayName(cursor); - if (const char *dpy = clang_getCString(cursorDisplay)) { - const QString display = QString::fromUtf8(dpy); - if (display != cursorSpelling) - s << ", display=\"" << dpy << '"'; - } - clang_disposeString(cursorDisplay); - return s; -} - -QDebug operator<<(QDebug s, const CXSourceLocation &location) -{ - QDebugStateSaver saver(s); - s.nospace(); - CXFile file; // void * - unsigned line; - unsigned column; - unsigned offset; - clang_getExpansionLocation(location, &file, &line, &column, &offset); - const CXString cxFileName = clang_getFileName(file); - // Has been observed to be 0 for invalid locations - if (const char *cFileName = clang_getCString(cxFileName)) - s << baseName(cFileName) << ':'; - s << line << ':' << column; - clang_disposeString(cxFileName); - return s; -} - -#endif // !QT_NO_DEBUG_STREAM diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangdebugutils.h b/sources/shiboken2/ApiExtractor/clangparser/clangdebugutils.h deleted file mode 100644 index 2bbe526f7..000000000 --- a/sources/shiboken2/ApiExtractor/clangparser/clangdebugutils.h +++ /dev/null @@ -1,48 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt for Python. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef CLANGDEBUGUTILS_H -#define CLANGDEBUGUTILS_H - -#include <QtCore/QtGlobal> - -#include <clang-c/Index.h> - -QT_FORWARD_DECLARE_CLASS(QDebug) -QT_FORWARD_DECLARE_CLASS(QString) - -#ifndef QT_NO_DEBUG_STREAM -QDebug operator<<(QDebug s, const CXString &cs); -QDebug operator<<(QDebug s, CXCursorKind cursorKind); -QDebug operator<<(QDebug s, CX_CXXAccessSpecifier ac); -QDebug operator<<(QDebug s, const CXType &t); -QDebug operator<<(QDebug s, const CXCursor &cursor); -QDebug operator<<(QDebug s, const CXSourceLocation &location); -#endif // !QT_NO_DEBUG_STREAM - -#endif // CLANGDEBUGUTILS_H diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp b/sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp deleted file mode 100644 index 6303d09e5..000000000 --- a/sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp +++ /dev/null @@ -1,266 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt for Python. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "clangparser.h" -#include "clangutils.h" -#include "clangdebugutils.h" -#include "compilersupport.h" - -#include <QtCore/QByteArrayList> -#include <QtCore/QDebug> -#include <QtCore/QDir> -#include <QtCore/QFile> -#include <QtCore/QScopedArrayPointer> -#include <QtCore/QString> - -namespace clang { - -SourceFileCache::Snippet SourceFileCache::getCodeSnippet(const CXCursor &cursor) -{ - Snippet result(nullptr, nullptr); - const SourceRange range = getCursorRange(cursor); - if (range.first.file.isEmpty() || range.second.file != range.first.file) - return result; - FileBufferCache::Iterator it = m_fileBufferCache.find(range.first.file); - if (it == m_fileBufferCache.end()) { - QFile file(range.first.file); - if (!file.open(QIODevice::ReadOnly)) { - qWarning().noquote().nospace() - << "Can't open " << QDir::toNativeSeparators(range.first.file) - << ": " << file.errorString(); - return result; - } - it = m_fileBufferCache.insert(range.first.file, file.readAll()); - } - - const unsigned pos = range.first.offset; - const unsigned end = range.second.offset; - const QByteArray &contents = it.value(); - if (end >= unsigned(contents.size())) { - qWarning().noquote().nospace() << "Range end " << end << " is above size of " - << range.first.file << " (" << contents.size() << ')'; - return result; - } - result.first = contents.constData() + pos; - result.second = contents.constData() + end; - return result; -} - -BaseVisitor::BaseVisitor() = default; -BaseVisitor::~BaseVisitor() = default; - -bool BaseVisitor::visitLocation(const CXSourceLocation &location) const -{ - return clang_Location_isFromMainFile(location) != 0; -} - -BaseVisitor::StartTokenResult BaseVisitor::cbHandleStartToken(const CXCursor &cursor) -{ - switch (cursor.kind) { - default: - break; - } - - return startToken(cursor); -} - -bool BaseVisitor::cbHandleEndToken(const CXCursor &cursor, StartTokenResult startResult) -{ - const bool result = startResult != Recurse || endToken(cursor); - switch (cursor.kind) { - default: - break; - } - - return result; -} - -BaseVisitor::CodeSnippet BaseVisitor::getCodeSnippet(const CXCursor &cursor) -{ - CodeSnippet result = m_fileCache.getCodeSnippet(cursor); - if (result.first == nullptr) - appendDiagnostic(Diagnostic(QStringLiteral("Unable to retrieve code snippet."), cursor, CXDiagnostic_Error)); - return result; -} - -QString BaseVisitor::getCodeSnippetString(const CXCursor &cursor) -{ - CodeSnippet result = m_fileCache.getCodeSnippet(cursor); - return result.first != nullptr - ? QString::fromUtf8(result.first, int(result.second - result.first)) - : QString(); -} - -static CXChildVisitResult - visitorCallback(CXCursor cursor, CXCursor /* parent */, CXClientData clientData) -{ - auto *bv = reinterpret_cast<BaseVisitor *>(clientData); - - const CXSourceLocation location = clang_getCursorLocation(cursor); - if (!bv->visitLocation(location)) - return CXChildVisit_Continue; - - const BaseVisitor::StartTokenResult startResult = bv->cbHandleStartToken(cursor); - switch (startResult) { - case clang::BaseVisitor::Error: - return CXChildVisit_Break; - case clang::BaseVisitor::Skip: - break; - case clang::BaseVisitor::Recurse: - clang_visitChildren(cursor, visitorCallback, clientData); - break; - } - - if (!bv->cbHandleEndToken(cursor, startResult)) - return CXChildVisit_Break; - - return CXChildVisit_Continue; -} - -BaseVisitor::Diagnostics BaseVisitor::diagnostics() const -{ - return m_diagnostics; -} - -void BaseVisitor::setDiagnostics(const Diagnostics &d) -{ - m_diagnostics = d; -} - -void BaseVisitor::appendDiagnostic(const Diagnostic &d) -{ - m_diagnostics.append(d); -} - -static inline const char **byteArrayListToFlatArgV(const QByteArrayList &bl) -{ - const char **result = new const char *[bl.size() + 1]; - result[bl.size()] = nullptr; - std::transform(bl.cbegin(), bl.cend(), result, - [] (const QByteArray &a) { return a.constData(); }); - return result; -} - -static QByteArray msgCreateTranslationUnit(const QByteArrayList &clangArgs, unsigned flags) -{ - QByteArray result = "clang_parseTranslationUnit2(0x"; - result += QByteArray::number(flags, 16); - const int count = clangArgs.size(); - result += ", cmd[" + QByteArray::number(count) + "]="; - for (int i = 0; i < count; ++i) { - const QByteArray &arg = clangArgs.at(i); - if (i) - result += ' '; - const bool quote = arg.contains(' ') || arg.contains('('); - if (quote) - result += '"'; - result += arg; - if (quote) - result += '"'; - } - result += ')'; - return result; -} - -static CXTranslationUnit createTranslationUnit(CXIndex index, - const QByteArrayList &args, - unsigned flags = 0) -{ - // courtesy qdoc - const unsigned defaultFlags = CXTranslationUnit_SkipFunctionBodies - | CXTranslationUnit_Incomplete; - - static const QByteArrayList defaultArgs = { -#ifndef Q_OS_WIN - "-fPIC", -#endif -#ifdef Q_OS_MACOS - "-Wno-expansion-to-defined", // Workaround for warnings in Darwin stdlib, see - // https://github.com/darlinghq/darling/issues/204 -#endif - "-Wno-constant-logical-operand" - }; - - const QByteArrayList clangArgs = emulatedCompilerOptions() + defaultArgs + args; - QScopedArrayPointer<const char *> argv(byteArrayListToFlatArgV(clangArgs)); - qDebug().noquote().nospace() << msgCreateTranslationUnit(clangArgs, flags); - - CXTranslationUnit tu; - CXErrorCode err = clang_parseTranslationUnit2(index, nullptr, argv.data(), - clangArgs.size(), nullptr, 0, - defaultFlags | flags, &tu); - if (err || !tu) { - qWarning().noquote().nospace() << "Could not parse " - << clangArgs.constLast().constData() << ", error code: " << err; - return nullptr; - } - return tu; -} - -/* clangFlags are flags to clang_parseTranslationUnit2() such as - * CXTranslationUnit_KeepGoing (from CINDEX_VERSION_MAJOR/CINDEX_VERSION_MINOR 0.35) - */ - -bool parse(const QByteArrayList &clangArgs, unsigned clangFlags, BaseVisitor &bv) -{ - CXIndex index = clang_createIndex(0 /* excludeDeclarationsFromPCH */, - 1 /* displayDiagnostics */); - if (!index) { - qWarning() << "clang_createIndex() failed!"; - return false; - } - - CXTranslationUnit translationUnit = createTranslationUnit(index, clangArgs, clangFlags); - if (!translationUnit) - return false; - - CXCursor rootCursor = clang_getTranslationUnitCursor(translationUnit); - - clang_visitChildren(rootCursor, visitorCallback, reinterpret_cast<CXClientData>(&bv)); - - QVector<Diagnostic> diagnostics = getDiagnostics(translationUnit); - diagnostics.append(bv.diagnostics()); - bv.setDiagnostics(diagnostics); - - const bool ok = maxSeverity(diagnostics) < CXDiagnostic_Error; - if (!ok) { - QDebug debug = qWarning(); - debug.noquote(); - debug.nospace(); - debug << "Errors in " - << QDir::toNativeSeparators(QFile::decodeName(clangArgs.constLast())) << ":\n"; - for (const Diagnostic &diagnostic : qAsConst(diagnostics)) - debug << diagnostic << '\n'; - } - - clang_disposeTranslationUnit(translationUnit); - clang_disposeIndex(index); - return ok; -} - -} // namespace clang diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangparser.h b/sources/shiboken2/ApiExtractor/clangparser/clangparser.h deleted file mode 100644 index 4248be853..000000000 --- a/sources/shiboken2/ApiExtractor/clangparser/clangparser.h +++ /dev/null @@ -1,93 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt for Python. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef CLANGPARSER_H -#define CLANGPARSER_H - -#include <clang-c/Index.h> - -#include <QtCore/QByteArrayList> -#include <QtCore/QHash> -#include <QtCore/QPair> -#include <QtCore/QString> -#include <QtCore/QVector> - -namespace clang { - -struct Diagnostic; - -class SourceFileCache { -public: - using Snippet = QPair<const char *, const char *>; - - Snippet getCodeSnippet(const CXCursor &cursor); - -private: - using FileBufferCache = QHash<QString, QByteArray>; - - FileBufferCache m_fileBufferCache; -}; - -class BaseVisitor { - Q_DISABLE_COPY(BaseVisitor) -public: - using Diagnostics = QVector<Diagnostic>; - using CodeSnippet = SourceFileCache::Snippet; - - enum StartTokenResult { Error, Skip, Recurse }; - - BaseVisitor(); - virtual ~BaseVisitor(); - - // Whether location should be visited. - // defaults to clang_Location_isFromMainFile() - virtual bool visitLocation(const CXSourceLocation &location) const; - - virtual StartTokenResult startToken(const CXCursor &cursor) = 0; - virtual bool endToken(const CXCursor &cursor) = 0; - - StartTokenResult cbHandleStartToken(const CXCursor &cursor); - bool cbHandleEndToken(const CXCursor &cursor, StartTokenResult startResult); - - CodeSnippet getCodeSnippet(const CXCursor &cursor); - QString getCodeSnippetString(const CXCursor &cursor); - - Diagnostics diagnostics() const; - void setDiagnostics(const Diagnostics &d); - void appendDiagnostic(const Diagnostic &d); - -private: - SourceFileCache m_fileCache; - Diagnostics m_diagnostics; -}; - -bool parse(const QByteArrayList &clangArgs, unsigned clangFlags, BaseVisitor &ctx); - -} // namespace clang - -#endif // !CLANGPARSER_H diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp b/sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp deleted file mode 100644 index df2476100..000000000 --- a/sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp +++ /dev/null @@ -1,276 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt for Python. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "clangutils.h" - -#include <QtCore/QDebug> -#include <QtCore/QDir> -#include <QtCore/QHashFunctions> -#include <QtCore/QProcess> - -bool operator==(const CXCursor &c1, const CXCursor &c2) -{ - return c1.kind == c2.kind - && c1.xdata == c2.xdata - && std::equal(c1.data, c1.data + sizeof(c1.data) / sizeof(c1.data[0]), c2.data); -} - -QtCompatHashFunctionType qHash(const CXCursor &c, QtCompatHashFunctionType seed) -{ - return qHash(c.kind) ^ qHash(c.xdata) ^ qHash(c.data[0]) - ^ qHash(c.data[1]) ^ qHash(c.data[2]) ^ seed; -} - -bool operator==(const CXType &t1, const CXType &t2) -{ - return t1.kind == t2.kind && t1.data[0] == t2.data[0] - && t1.data[1] == t2.data[1]; -} - -QtCompatHashFunctionType qHash(const CXType &ct, QtCompatHashFunctionType seed) -{ - return QtCompatHashFunctionType(ct.kind) ^ QtCompatHashFunctionType(0xFFFFFFFF & quintptr(ct.data[0])) - ^ QtCompatHashFunctionType(0xFFFFFFFF & quintptr(ct.data[1])) ^ seed; -} - -namespace clang { - -SourceLocation getExpansionLocation(const CXSourceLocation &location) -{ - SourceLocation result; - CXFile file; // void * - clang_getExpansionLocation(location, &file, &result.line, &result.column, &result.offset); - const CXString cxFileName = clang_getFileName(file); - // Has been observed to be 0 for invalid locations - if (const char *cFileName = clang_getCString(cxFileName)) - result.file = QString::fromUtf8(cFileName); - clang_disposeString(cxFileName); - return result; -} - -SourceLocation getCursorLocation(const CXCursor &cursor) -{ - const CXSourceRange extent = clang_getCursorExtent(cursor); - return getExpansionLocation(clang_getRangeStart(extent)); -} - -CXString getFileNameFromLocation(const CXSourceLocation &location) -{ - CXFile file; - unsigned line; - unsigned column; - unsigned offset; - clang_getExpansionLocation(location, &file, &line, &column, &offset); - return clang_getFileName(file); -} - -SourceRange getCursorRange(const CXCursor &cursor) -{ - const CXSourceRange extent = clang_getCursorExtent(cursor); - return qMakePair(getExpansionLocation(clang_getRangeStart(extent)), - getExpansionLocation(clang_getRangeEnd(extent))); -} - -QString getCursorKindName(CXCursorKind cursorKind) -{ - CXString kindName = clang_getCursorKindSpelling(cursorKind); - const QString result = QString::fromUtf8(clang_getCString(kindName)); - clang_disposeString(kindName); - return result; -} - -QString getCursorSpelling(const CXCursor &cursor) -{ - CXString cursorSpelling = clang_getCursorSpelling(cursor); - const QString result = QString::fromUtf8(clang_getCString(cursorSpelling)); - clang_disposeString(cursorSpelling); - return result; -} - -QString getCursorDisplayName(const CXCursor &cursor) -{ - CXString displayName = clang_getCursorDisplayName(cursor); - const QString result = QString::fromUtf8(clang_getCString(displayName)); - clang_disposeString(displayName); - return result; -} - -QString getTypeName(const CXType &type) -{ - CXString typeSpelling = clang_getTypeSpelling(type); - const QString result = QString::fromUtf8(clang_getCString(typeSpelling)); - clang_disposeString(typeSpelling); - return result; -} - -Diagnostic::Diagnostic(const QString &m, const CXCursor &c, CXDiagnosticSeverity s) - : message(m), location(getCursorLocation(c)), source(Other), severity(s) -{ -} - -Diagnostic Diagnostic::fromCXDiagnostic(CXDiagnostic cd) -{ - Diagnostic result; - result.source = Clang; - CXString spelling = clang_getDiagnosticSpelling(cd); - result.message = QString::fromUtf8(clang_getCString(spelling)); - clang_disposeString(spelling); - result.severity = clang_getDiagnosticSeverity(cd); - result.location = getExpansionLocation(clang_getDiagnosticLocation(cd)); - - CXDiagnosticSet childDiagnostics = clang_getChildDiagnostics(cd); - if (const unsigned childCount = clang_getNumDiagnosticsInSet(childDiagnostics)) { - result.childMessages.reserve(int(childCount)); - const unsigned format = clang_defaultDiagnosticDisplayOptions(); - for (unsigned i = 0; i < childCount; ++i) { - CXDiagnostic childDiagnostic = clang_getDiagnosticInSet(childDiagnostics, i); - CXString cdm = clang_formatDiagnostic(childDiagnostic, format); - result.childMessages.append(QString::fromUtf8(clang_getCString(cdm))); - clang_disposeString(cdm); - clang_disposeDiagnostic(childDiagnostic); - } - } - - return result; -} - -QVector<Diagnostic> getDiagnostics(CXTranslationUnit tu) -{ - QVector<Diagnostic> result; - const unsigned count = clang_getNumDiagnostics(tu); - result.reserve(int(count)); - for (unsigned i = 0; i < count; ++i) { - const CXDiagnostic d = clang_getDiagnostic(tu, i); - result.append(Diagnostic::fromCXDiagnostic(d)); - clang_disposeDiagnostic(d); - } - return result; -} - -QPair<int, int> parseTemplateArgumentList(const QString &l, - const TemplateArgumentHandler &handler, - int from) -{ - const int ltPos = l.indexOf(QLatin1Char('<'), from); - if (ltPos == - 1) - return qMakePair(-1, -1); - int startPos = ltPos + 1; - int level = 1; - for (int p = startPos, end = l.size(); p < end; ) { - const char c = l.at(p).toLatin1(); - switch (c) { - case ',': - case '>': - handler(level, l.midRef(startPos, p - startPos).trimmed()); - ++p; - if (c == '>') { - if (--level == 0) - return qMakePair(ltPos, p); - // Skip over next ',': "a<b<c,d>,e>" - for (; p < end && (l.at(p).isSpace() || l.at(p) == QLatin1Char(',')); ++p) {} - } - startPos = p; - break; - case '<': - handler(level, l.midRef(startPos, p - startPos).trimmed()); - ++level; - startPos = ++p; - break; - default: - ++p; - break; - } - } - return qMakePair(-1, -1); -} - -CXDiagnosticSeverity maxSeverity(const QVector<Diagnostic> &ds) -{ - CXDiagnosticSeverity result = CXDiagnostic_Ignored; - for (const Diagnostic& d : ds) { - if (d.severity > result) - result = d.severity; - } - return result; -} - -#ifndef QT_NO_DEBUG_STREAM - -QDebug operator<<(QDebug s, const SourceLocation &l) -{ - QDebugStateSaver saver(s); - s.nospace(); - s.noquote(); - s << QDir::toNativeSeparators(l.file) << ':' << l.line; - if (l.column) - s << ':' << l.column; - return s; -} - -// Roughly follow g++ format: -// file.cpp:214:37: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] -QDebug operator<<(QDebug s, const Diagnostic &d) -{ - QDebugStateSaver saver(s); - s.nospace(); - s.noquote(); - s << d.location << ": "; - switch (d.severity) { - case CXDiagnostic_Ignored: - s << "ignored"; - break; - case CXDiagnostic_Note: - s << "note"; - break; - case CXDiagnostic_Warning: - s << "warning"; - break; - case CXDiagnostic_Error: - s << "error"; - break; - case CXDiagnostic_Fatal: - s << "fatal"; - break; - } - s << ": " << d.message; - - if (d.source != Diagnostic::Clang) - s << " [other]"; - - if (const int childMessagesCount = d.childMessages.size()) { - s << '\n'; - for (int i = 0; i < childMessagesCount; ++i) - s << " " << d.childMessages.at(i) << '\n'; - } - - return s; -} - -#endif // QT_NO_DEBUG_STREAM - -} // namespace clang diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangutils.h b/sources/shiboken2/ApiExtractor/clangparser/clangutils.h deleted file mode 100644 index 5f005bd5d..000000000 --- a/sources/shiboken2/ApiExtractor/clangparser/clangutils.h +++ /dev/null @@ -1,116 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt for Python. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef CLANGUTILS_H -#define CLANGUTILS_H - -#include <clang-c/Index.h> -#include <qtcompat.h> -#include <QtCore/QPair> -#include <QtCore/QString> -#include <QtCore/QStringList> -#include <QtCore/QVector> - -#include <functional> - -QT_FORWARD_DECLARE_CLASS(QDebug) - -bool operator==(const CXCursor &c1, const CXCursor &c2); -QtCompatHashFunctionType qHash(const CXCursor &c, QtCompatHashFunctionType seed = 0); - -bool operator==(const CXType &t1, const CXType &t2); -QtCompatHashFunctionType qHash(const CXType &ct, QtCompatHashFunctionType seed); - -namespace clang { - -QString getCursorKindName(CXCursorKind cursorKind); -QString getCursorSpelling(const CXCursor &cursor); -QString getCursorDisplayName(const CXCursor &cursor); -QString getTypeName(const CXType &type); -inline QString getCursorTypeName(const CXCursor &cursor) - { return getTypeName(clang_getCursorType(cursor)); } -inline QString getCursorResultTypeName(const CXCursor &cursor) - { return getTypeName(clang_getCursorResultType(cursor)); } - -inline bool isCursorValid(const CXCursor &c) -{ - return c.kind < CXCursor_FirstInvalid || c.kind > CXCursor_LastInvalid; -} - -struct SourceLocation -{ - int compare(const SourceLocation &rhs) const; - - QString file; - unsigned line = 0; - unsigned column = 0; - unsigned offset = 0; -}; - -SourceLocation getExpansionLocation(const CXSourceLocation &location); - -using SourceRange =QPair<SourceLocation, SourceLocation>; - -SourceLocation getCursorLocation(const CXCursor &cursor); -CXString getFileNameFromLocation(const CXSourceLocation &location); -SourceRange getCursorRange(const CXCursor &cursor); - -struct Diagnostic { - enum Source { Clang, Other }; - - Diagnostic() = default; - // Clang - static Diagnostic fromCXDiagnostic(CXDiagnostic cd); - // Other - explicit Diagnostic(const QString &m, const CXCursor &c, CXDiagnosticSeverity s = CXDiagnostic_Warning); - - QString message; - QStringList childMessages; - SourceLocation location; - Source source = Clang; - CXDiagnosticSeverity severity = CXDiagnostic_Warning; -}; - -QVector<Diagnostic> getDiagnostics(CXTranslationUnit tu); -CXDiagnosticSeverity maxSeverity(const QVector<Diagnostic> &ds); - -// Parse a template argument list "a<b<c,d>,e>" and invoke a handler -// with each match (level and string). Return begin and end of the list. -using TemplateArgumentHandler = std::function<void (int, const QStringRef &)>; - -QPair<int, int> parseTemplateArgumentList(const QString &l, - const TemplateArgumentHandler &handler, - int from = 0); - -#ifndef QT_NO_DEBUG_STREAM -QDebug operator<<(QDebug, const SourceLocation &); -QDebug operator<<(QDebug, const Diagnostic &); -#endif // QT_NO_DEBUG_STREAM -} // namespace clang - -#endif // CLANGUTILS_H diff --git a/sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp b/sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp deleted file mode 100644 index dac511003..000000000 --- a/sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp +++ /dev/null @@ -1,404 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt for Python. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "compilersupport.h" -#include "header_paths.h" - -#include <reporthandler.h> - -#include <QtCore/QDebug> -#include <QtCore/QDir> -#include <QtCore/QFile> -#include <QtCore/QFileInfo> -#include <QtCore/QProcess> -#include <QtCore/QStandardPaths> -#include <QtCore/QStringList> -#include <QtCore/QVersionNumber> - -#include <clang-c/Index.h> - -#include <string.h> -#include <algorithm> -#include <iterator> - -namespace clang { - -QVersionNumber libClangVersion() -{ - return QVersionNumber(CINDEX_VERSION_MAJOR, CINDEX_VERSION_MINOR); -} - -static bool runProcess(const QString &program, const QStringList &arguments, - QByteArray *stdOutIn = nullptr, QByteArray *stdErrIn = nullptr) -{ - QProcess process; - process.start(program, arguments, QProcess::ReadWrite); - if (!process.waitForStarted()) { - qWarning().noquote().nospace() << "Unable to start " - << process.program() << ": " << process.errorString(); - return false; - } - process.closeWriteChannel(); - const bool finished = process.waitForFinished(); - const QByteArray stdErr = process.readAllStandardError(); - if (stdErrIn) - *stdErrIn = stdErr; - if (stdOutIn) - *stdOutIn = process.readAllStandardOutput(); - - if (!finished) { - qWarning().noquote().nospace() << process.program() << " timed out: " << stdErr; - process.kill(); - return false; - } - - if (process.exitStatus() != QProcess::NormalExit) { - qWarning().noquote().nospace() << process.program() << " crashed: " << stdErr; - return false; - } - - if (process.exitCode() != 0) { - qWarning().noquote().nospace() << process.program() << " exited " - << process.exitCode() << ": " << stdErr; - return false; - } - - return true; -} - -#if defined(Q_CC_GNU) - -static QByteArray frameworkPath() { return QByteArrayLiteral(" (framework directory)"); } - -#if defined(Q_OS_MACOS) -static void filterHomebrewHeaderPaths(HeaderPaths &headerPaths) -{ - QByteArray homebrewPrefix = qgetenv("HOMEBREW_OPT"); - - // If HOMEBREW_OPT is found we assume that the build is happening - // inside a brew environment, which means we need to filter out - // the -isystem flags added by the brew clang shim. This is needed - // because brew passes the Qt include paths as system include paths - // and because our parser ignores system headers, Qt classes won't - // be found and thus compilation errors will occur. - if (homebrewPrefix.isEmpty()) - return; - - qCInfo(lcShiboken) << "Found HOMEBREW_OPT with value:" << homebrewPrefix - << "Assuming homebrew build environment."; - - HeaderPaths::iterator it = headerPaths.begin(); - while (it != headerPaths.end()) { - if (it->path.startsWith(homebrewPrefix)) { - qCInfo(lcShiboken) << "Filtering out homebrew include path: " - << it->path; - it = headerPaths.erase(it); - } else { - ++it; - } - } -} -#endif - -// Determine g++'s internal include paths from the output of -// g++ -E -x c++ - -v </dev/null -// Output looks like: -// #include <...> search starts here: -// /usr/local/include -// /System/Library/Frameworks (framework directory) -// End of search list. -static HeaderPaths gppInternalIncludePaths(const QString &compiler) -{ - HeaderPaths result; - QStringList arguments; - arguments << QStringLiteral("-E") << QStringLiteral("-x") << QStringLiteral("c++") - << QStringLiteral("-") << QStringLiteral("-v"); - QByteArray stdOut; - QByteArray stdErr; - if (!runProcess(compiler, arguments, &stdOut, &stdErr)) - return result; - const QByteArrayList stdErrLines = stdErr.split('\n'); - bool isIncludeDir = false; - for (const QByteArray &line : stdErrLines) { - if (isIncludeDir) { - if (line.startsWith(QByteArrayLiteral("End of search list"))) { - isIncludeDir = false; - } else { - HeaderPath headerPath{line.trimmed(), HeaderType::System}; - if (headerPath.path.endsWith(frameworkPath())) { - headerPath.type = HeaderType::FrameworkSystem; - headerPath.path.truncate(headerPath.path.size() - frameworkPath().size()); - } - result.append(headerPath); - } - } else if (line.startsWith(QByteArrayLiteral("#include <...> search starts here"))) { - isIncludeDir = true; - } - } - -#if defined(Q_OS_MACOS) - filterHomebrewHeaderPaths(result); -#endif - return result; -} -#endif // Q_CC_MSVC - -// Detect Vulkan as supported from Qt 5.10 by checking the environment variables. -static void detectVulkan(HeaderPaths *headerPaths) -{ - static const char *vulkanVariables[] = {"VULKAN_SDK", "VK_SDK_PATH"}; - for (const char *vulkanVariable : vulkanVariables) { - if (qEnvironmentVariableIsSet(vulkanVariable)) { - const QByteArray path = qgetenv(vulkanVariable) + QByteArrayLiteral("/include"); - headerPaths->append(HeaderPath{path, HeaderType::System}); - break; - } - } -} - -#if defined(Q_CC_GNU) -enum class LinuxDistribution { RedHat, CentOs, Other }; - -static LinuxDistribution linuxDistribution() -{ - const QString &productType = QSysInfo::productType(); - if (productType == QLatin1String("rhel")) - return LinuxDistribution::RedHat; - if (productType.compare(QLatin1String("centos"), Qt::CaseInsensitive) == 0) - return LinuxDistribution::CentOs; - return LinuxDistribution::Other; -} - -static bool checkProductVersion(const QVersionNumber &minimum, - const QVersionNumber &excludedMaximum) -{ - const QVersionNumber osVersion = QVersionNumber::fromString(QSysInfo::productVersion()); - return osVersion.isNull() || (osVersion >= minimum && osVersion < excludedMaximum); -} - -static inline bool needsGppInternalHeaders() -{ - const LinuxDistribution distro = linuxDistribution(); - switch (distro) { - case LinuxDistribution::RedHat: - case LinuxDistribution::CentOs: - return checkProductVersion(QVersionNumber(6, 10), QVersionNumber(8)); - case LinuxDistribution::Other: - break; - } - return false; -} -#endif // Q_CC_GNU - -// For MSVC, we set the MS compatibility version and let Clang figure out its own -// options and include paths. -// For the others, we pass "-nostdinc" since libclang tries to add it's own system -// include paths, which together with the clang compiler paths causes some clash -// which causes std types not being found and construct -I/-F options from the -// include paths of the host compiler. - -#ifdef Q_CC_CLANG -static QByteArray noStandardIncludeOption() { return QByteArrayLiteral("-nostdinc"); } -#endif - -// The clang builtin includes directory is used to find the definitions for -// intrinsic functions and builtin types. It is necessary to use the clang -// includes to prevent redefinition errors. The default toolchain includes -// should be picked up automatically by clang without specifying -// them implicitly. - -#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) -# define NEED_CLANG_BUILTIN_INCLUDES 1 -#else -# define NEED_CLANG_BUILTIN_INCLUDES 0 -#endif - -#if NEED_CLANG_BUILTIN_INCLUDES -static QString findClangLibDir() -{ - for (const char *envVar : {"LLVM_INSTALL_DIR", "CLANG_INSTALL_DIR"}) { - if (qEnvironmentVariableIsSet(envVar)) { - const QString path = QFile::decodeName(qgetenv(envVar)) + QLatin1String("/lib"); - if (QFileInfo::exists(path)) - return path; - } - } - const QString llvmConfig = - QStandardPaths::findExecutable(QLatin1String("llvm-config")); - if (!llvmConfig.isEmpty()) { - QByteArray stdOut; - if (runProcess(llvmConfig, QStringList{QLatin1String("--libdir")}, &stdOut)) { - const QString path = QFile::decodeName(stdOut.trimmed()); - if (QFileInfo::exists(path)) - return path; - } - } - return QString(); -} - -static QString findClangBuiltInIncludesDir() -{ - // Find the include directory of the highest version. - const QString clangPathLibDir = findClangLibDir(); - if (!clangPathLibDir.isEmpty()) { - QString candidate; - QVersionNumber lastVersionNumber(1, 0, 0); - QDir clangDir(clangPathLibDir + QLatin1String("/clang")); - const QFileInfoList versionDirs = - clangDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); - for (const QFileInfo &fi : versionDirs) { - const QString fileName = fi.fileName(); - if (fileName.at(0).isDigit()) { - const QVersionNumber versionNumber = QVersionNumber::fromString(fileName); - if (!versionNumber.isNull() && versionNumber > lastVersionNumber) { - candidate = fi.absoluteFilePath(); - lastVersionNumber = versionNumber; - } - } - } - if (!candidate.isEmpty()) - return candidate + QStringLiteral("/include"); - } - return QString(); -} -#endif // NEED_CLANG_BUILTIN_INCLUDES - -#if defined(Q_CC_CLANG) || defined(Q_CC_GNU) -static QString compilerFromCMake(const QString &defaultCompiler) -{ -// Added !defined(Q_OS_DARWIN) due to PYSIDE-1032 -# if defined(CMAKE_CXX_COMPILER) && !defined(Q_OS_DARWIN) - Q_UNUSED(defaultCompiler) - return QString::fromLocal8Bit(CMAKE_CXX_COMPILER); -# else - return defaultCompiler; -# endif -} -#endif // Q_CC_CLANG, Q_CC_GNU - -// Returns clang options needed for emulating the host compiler -QByteArrayList emulatedCompilerOptions() -{ - QByteArrayList result; -#if defined(Q_CC_MSVC) - HeaderPaths headerPaths; - result.append(QByteArrayLiteral("-fms-compatibility-version=19")); - result.append(QByteArrayLiteral("-Wno-microsoft-enum-value")); - // Fix yvals_core.h: STL1000: Unexpected compiler version, expected Clang 7 or newer (MSVC2017 update) - result.append(QByteArrayLiteral("-D_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH")); -#elif defined(Q_CC_CLANG) - HeaderPaths headerPaths = gppInternalIncludePaths(compilerFromCMake(QStringLiteral("clang++"))); - result.append(noStandardIncludeOption()); -#elif defined(Q_CC_GNU) - HeaderPaths headerPaths; - -#if NEED_CLANG_BUILTIN_INCLUDES - const QString clangBuiltinIncludesDir = - QDir::toNativeSeparators(findClangBuiltInIncludesDir()); - if (clangBuiltinIncludesDir.isEmpty()) { - qCWarning(lcShiboken, "Unable to locate Clang's built-in include directory " - "(neither by checking the environment variables LLVM_INSTALL_DIR, CLANG_INSTALL_DIR " - " nor running llvm-config). This may lead to parse errors."); - } else { - qCInfo(lcShiboken, "CLANG builtins includes directory: %s", - qPrintable(clangBuiltinIncludesDir)); - headerPaths.append(HeaderPath{QFile::encodeName(clangBuiltinIncludesDir), - HeaderType::System}); - } -#endif // NEED_CLANG_BUILTIN_INCLUDES - - // Append the c++ include paths since Clang is unable to find <list> etc - // on RHEL 7 with g++ 6.3 or CentOS 7.2. - // A fix for this has been added to Clang 5.0, so, the code can be removed - // once Clang 5.0 is the minimum version. - if (needsGppInternalHeaders()) { - const HeaderPaths gppPaths = gppInternalIncludePaths(compilerFromCMake(QStringLiteral("g++"))); - for (const HeaderPath &h : gppPaths) { - if (h.path.contains("c++") - || h.path.contains("sysroot")) { // centOS - headerPaths.append(h); - } - } - } -#else - HeaderPaths headerPaths; -#endif - detectVulkan(&headerPaths); - std::transform(headerPaths.cbegin(), headerPaths.cend(), - std::back_inserter(result), HeaderPath::includeOption); - return result; -} - -LanguageLevel emulatedCompilerLanguageLevel() -{ -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - return LanguageLevel::Cpp17; -#else -# if defined(Q_CC_MSVC) && _MSC_VER > 1900 - // Fixes constexpr errors in MSVC2017 library headers with Clang 4.1..5.X (0.45 == Clang 6). - if (libClangVersion() < QVersionNumber(0, 45)) - return LanguageLevel::Cpp1Z; -# endif // Q_CC_MSVC && _MSC_VER > 1900 - return LanguageLevel::Cpp14; // otherwise, t.h is parsed as "C" -#endif // Qt 5 -} - -struct LanguageLevelMapping -{ - const char *option; - LanguageLevel level; -}; - -static const LanguageLevelMapping languageLevelMapping[] = -{ - {"c++11", LanguageLevel::Cpp11}, - {"c++14", LanguageLevel::Cpp14}, - {"c++17", LanguageLevel::Cpp17}, - {"c++20", LanguageLevel::Cpp20}, - {"c++1z", LanguageLevel::Cpp1Z} -}; - -const char *languageLevelOption(LanguageLevel l) -{ - for (const LanguageLevelMapping &m : languageLevelMapping) { - if (m.level == l) - return m.option; - } - return nullptr; -} - -LanguageLevel languageLevelFromOption(const char *o) -{ - for (const LanguageLevelMapping &m : languageLevelMapping) { - if (!strcmp(m.option, o)) - return m.level; - } - return LanguageLevel::Default; -} - -} // namespace clang diff --git a/sources/shiboken2/ApiExtractor/clangparser/compilersupport.h b/sources/shiboken2/ApiExtractor/clangparser/compilersupport.h deleted file mode 100644 index d9e213e73..000000000 --- a/sources/shiboken2/ApiExtractor/clangparser/compilersupport.h +++ /dev/null @@ -1,55 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt for Python. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef COMPILERSUPPORT_H -#define COMPILERSUPPORT_H - -#include <QtCore/QByteArrayList> - -QT_FORWARD_DECLARE_CLASS(QVersionNumber) - -enum class LanguageLevel { - Default, - Cpp11, - Cpp14, - Cpp17, - Cpp20, - Cpp1Z -}; - -namespace clang { -QVersionNumber libClangVersion(); - -QByteArrayList emulatedCompilerOptions(); -LanguageLevel emulatedCompilerLanguageLevel(); - -const char *languageLevelOption(LanguageLevel l); -LanguageLevel languageLevelFromOption(const char *); -} // namespace clang - -#endif // COMPILERSUPPORT_H |