diff options
Diffstat (limited to 'sources/shiboken2/ApiExtractor/clangparser')
4 files changed, 175 insertions, 77 deletions
diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp b/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp index af7f96068..1623e6a6e 100644 --- a/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp +++ b/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp @@ -146,6 +146,7 @@ class BuilderPrivate { public: typedef QHash<CXCursor, ClassModelItem> CursorClassHash; typedef QHash<CXCursor, TypeDefModelItem> CursorTypedefHash; + typedef QHash<CXType, TypeInfo> TypeInfoHash; explicit BuilderPrivate(BaseVisitor *bv) : m_baseVisitor(bv), m_model(new CodeModel) { @@ -180,9 +181,14 @@ public: 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; TemplateParameterModelItem createTemplateParameter(const CXCursor &cursor) const; TemplateParameterModelItem createNonTypeTemplateParameter(const CXCursor &cursor) const; @@ -205,6 +211,8 @@ public: CursorClassHash m_cursorClassHash; CursorTypedefHash m_cursorTypedefHash; + mutable TypeInfoHash m_typeInfoHash; // Cache type information + ClassModelItem m_currentClass; EnumModelItem m_currentEnum; FunctionModelItem m_currentFunction; @@ -256,7 +264,7 @@ FunctionModelItem BuilderPrivate::createFunction(const CXCursor &cursor, name = fixTypeName(name); FunctionModelItem result(new _FunctionModelItem(m_model, name)); setFileName(cursor, result.data()); - result->setType(createTypeInfo(clang_getCursorResultType(cursor))); + result->setType(createTypeInfoHelper(clang_getCursorResultType(cursor))); result->setFunctionType(t); result->setScope(m_scope); result->setStatic(clang_Cursor_getStorageClass(cursor) == CX_SC_Static); @@ -335,7 +343,7 @@ TemplateParameterModelItem BuilderPrivate::createTemplateParameter(const CXCurso TemplateParameterModelItem BuilderPrivate::createNonTypeTemplateParameter(const CXCursor &cursor) const { TemplateParameterModelItem result = createTemplateParameter(cursor); - result->setType(createTypeInfo(cursor)); + result->setType(createTypeInfoHelper(clang_getCursorType(cursor))); return result; } @@ -359,38 +367,6 @@ struct ArrayDimensionResult int position; }; -static ArrayDimensionResult arrayDimensions(const QString &typeName) -{ - ArrayDimensionResult result; - result.position = typeName.indexOf(QLatin1Char('[')); - for (int openingPos = result.position; openingPos != -1; ) { - const int closingPos = typeName.indexOf(QLatin1Char(']'), openingPos + 1); - if (closingPos == -1) - break; - result.dimensions.append(typeName.midRef(openingPos + 1, closingPos - openingPos - 1)); - openingPos = typeName.indexOf(QLatin1Char('['), closingPos + 1); - } - return result; -} - -// Array helpers: Parse "a[2][4]" into a list of dimensions or "" for none -static QStringList parseArrayArgs(const CXType &type, QString *typeName) -{ - const ArrayDimensionResult dimensions = arrayDimensions(*typeName); - Q_ASSERT(!dimensions.dimensions.isEmpty()); - - QStringList result; - // get first dimension from clang, preferably. - // "a[]" is seen as pointer by Clang, set special indicator "" - const long long size = clang_getArraySize(type); - result.append(size >= 0 ? QString::number(size) : QString()); - // Parse out remaining dimensions - for (int i = 1, count = dimensions.dimensions.size(); i < count; ++i) - result.append(dimensions.dimensions.at(i).toString()); - typeName->truncate(dimensions.position); - return result; -} - // Create qualified name "std::list<std::string>" -> ("std", "list<std::string>") static QStringList qualifiedName(const QString &t) { @@ -412,71 +388,132 @@ static QStringList qualifiedName(const QString &t) return result; } -TypeInfo BuilderPrivate::createTypeInfo(const CXType &type) const +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(); + 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 = createTypeInfo(clang_getResultType(pointeeType)); + TypeInfo result = createTypeInfoHelper(clang_getResultType(pointeeType)); result.setFunctionPointer(true); for (int a = 0; a < argCount; ++a) - result.addArgument(createTypeInfo(clang_getArgType(pointeeType, unsigned(a)))); + result.addArgument(createTypeInfoHelper(clang_getArgType(pointeeType, unsigned(a)))); return result; } } TypeInfo typeInfo; - QString typeName = fixTypeName(getTypeName(type)); - - int indirections = 0; - // "int **" - for ( ; typeName.endsWith(QLatin1Char('*')) ; ++indirections) - typeName.chop(1); - typeInfo.setIndirections(indirections); - // "int &&" - if (typeName.endsWith(QLatin1String("&&"))) { - typeName.chop(2); - typeInfo.setReferenceType(RValueReference); - } else if (typeName.endsWith(QLatin1Char('&'))) { // "int &" - typeName.chop(1); - typeInfo.setReferenceType(LValueReference); - } - // "int [3], int[]" - if (type.kind == CXType_ConstantArray || type.kind == CXType_IncompleteArray - || type.kind == CXType_VariableArray || type.kind == CXType_DependentSizedArray) { - typeInfo.setArrayElements(parseArrayArgs(type, &typeName)); + 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()); } - bool isConstant = clang_isConstQualifiedType(type) != 0; - // A "char *const" parameter, is considered to be const-qualified by Clang, but - // not in the TypeInfo sense (corresponds to "char *" and not "const char *"). - if (type.kind == CXType_Pointer && isConstant && typeName.endsWith(QLatin1String("const"))) { - typeName.chop(5); - typeName = typeName.trimmed(); - isConstant = false; - } - // Clang has been observed to return false for "const int .." - if (!isConstant && typeName.startsWith(QLatin1String("const "))) { - typeName.remove(0, 6); - isConstant = true; + 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.setConstant(isConstant); + typeInfo.setIndirectionsV(indirections); - // clang_isVolatileQualifiedType() returns true for "volatile int", but not for "volatile int *" - if (typeName.startsWith(QLatin1String("volatile "))) { - typeName.remove(0, 9); - typeInfo.setVolatile(true); + typeInfo.setConstant(clang_isConstQualifiedType(nestedType) != 0); + typeInfo.setVolatile(clang_isVolatileQualifiedType(nestedType) != 0); + + QString typeName = getTypeName(nestedType); + while (TypeInfo::stripLeadingConst(&typeName) + || TypeInfo::stripLeadingVolatile(&typeName)) { } - typeName = typeName.trimmed(); + // 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? 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(); +} + // extract an expression from the cursor via source // CXCursor_EnumConstantDecl, ParmDecl (a = Flag1 | Flag2) QString BuilderPrivate::cursorValueExpression(BaseVisitor *bv, const CXCursor &cursor) const @@ -795,9 +832,8 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor) d->m_currentFunction = d->createMemberFunction(cursor); d->m_scopeStack.back()->addFunction(d->m_currentFunction); break; - } else { - return Skip; // inline member functions outside class } + return Skip; // inline member functions outside class } } Q_FALLTHROUGH(); // fall through to free template function. diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp b/sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp index ce0b6554d..e116f8b83 100644 --- a/sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp +++ b/sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp @@ -166,7 +166,7 @@ static inline const char **byteArrayListToFlatArgV(const QByteArrayList &bl) return result; } -static QByteArray msgCreateTranslationUnit(const QByteArrayList clangArgs, unsigned flags) +static QByteArray msgCreateTranslationUnit(const QByteArrayList &clangArgs, unsigned flags) { QByteArray result = "clang_parseTranslationUnit2(0x"; result += QByteArray::number(flags, 16); diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp b/sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp index 2ff18b23b..8bee28cdf 100644 --- a/sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp +++ b/sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp @@ -46,6 +46,18 @@ uint qHash(const CXCursor &c, uint seed) ^ 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]; +} + +uint qHash(const CXType &ct, uint seed) +{ + return uint(ct.kind) ^ uint(0xFFFFFFFF & quintptr(ct.data[0])) + ^ uint(0xFFFFFFFF & quintptr(ct.data[1])) ^ seed; +} + namespace clang { SourceLocation getExpansionLocation(const CXSourceLocation &location) @@ -160,6 +172,43 @@ QVector<Diagnostic> getDiagnostics(CXTranslationUnit tu) 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; diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangutils.h b/sources/shiboken2/ApiExtractor/clangparser/clangutils.h index 98d0c9752..b290aac9a 100644 --- a/sources/shiboken2/ApiExtractor/clangparser/clangutils.h +++ b/sources/shiboken2/ApiExtractor/clangparser/clangutils.h @@ -34,11 +34,16 @@ #include <QtCore/QString> #include <QtCore/QVector> +#include <functional> + QT_FORWARD_DECLARE_CLASS(QDebug) bool operator==(const CXCursor &c1, const CXCursor &c2); uint qHash(const CXCursor &c, uint seed = 0); +bool operator==(const CXType &t1, const CXType &t2); +uint qHash(const CXType &ct, uint seed); + namespace clang { QString getCursorKindName(CXCursorKind cursorKind); @@ -92,6 +97,14 @@ struct Diagnostic { 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. +typedef std::function<void(int /*level*/, const QStringRef &)> TemplateArgumentHandler; + +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 &); |