diff options
Diffstat (limited to 'sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp')
-rw-r--r-- | sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp | 135 |
1 files changed, 72 insertions, 63 deletions
diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp b/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp index 73b1aca63..944445579 100644 --- a/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp +++ b/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp @@ -31,6 +31,7 @@ #include "clangutils.h" #include <codemodel.h> +#include <reporthandler.h> #include <QtCore/QDebug> #include <QtCore/QDir> @@ -43,10 +44,6 @@ #include <cstring> #include <ctype.h> -#if QT_VERSION < 0x050800 -# define Q_FALLTHROUGH() (void)0 -#endif - namespace clang { static inline QString colonColon() { return QStringLiteral("::"); } @@ -174,8 +171,10 @@ public: bool addClass(const CXCursor &cursor, CodeModel::ClassType t); FunctionModelItem createFunction(const CXCursor &cursor, - CodeModel::FunctionType t = CodeModel::Normal); - FunctionModelItem createMemberFunction(const CXCursor &cursor); + CodeModel::FunctionType t = CodeModel::Normal, + bool isTemplateCode = false); + FunctionModelItem createMemberFunction(const CXCursor &cursor, + bool isTemplateCode = false); void qualifyConstructor(const CXCursor &cursor); TypeInfo createTypeInfoHelper(const CXType &type) const; // uncashed TypeInfo createTypeInfo(const CXType &type) const; @@ -263,12 +262,54 @@ bool BuilderPrivate::addClass(const CXCursor &cursor, CodeModel::ClassType t) return true; } -static inline ExceptionSpecification exceptionSpecificationFromClang(int ce) +static QString msgCannotDetermineException(const std::string_view &snippetV) +{ + const auto newLine = snippetV.find('\n'); // Multiline noexcept specifications have been found in Qt + const bool truncate = newLine != std::string::npos; + const qsizetype length = qsizetype(truncate ? newLine : snippetV.size()); + QString snippet = QString::fromUtf8(snippetV.data(), length); + if (truncate) + snippet += QStringLiteral("..."); + + return QLatin1String("Cannot determine exception specification: \"") + + snippet + QLatin1Char('"'); +} + +// Return whether noexcept(<value>) throws. noexcept() takes a constexpr value. +// Try to determine the simple cases (true|false) via code snippet. +static ExceptionSpecification computedExceptionSpecificationFromClang(BaseVisitor *bv, + const CXCursor &cursor, + bool isTemplateCode) { + const std::string_view snippet = bv->getCodeSnippet(cursor); + if (snippet.empty()) + return ExceptionSpecification::Unknown; // Macro expansion, cannot tell + if (snippet.find("noexcept(false)") != std::string::npos) + return ExceptionSpecification::Throws; + if (snippet.find("noexcept(true)") != std::string::npos) + return ExceptionSpecification::NoExcept; + // Warn about it unless it is some form of template code where it is common + // to have complicated code, which is of no concern to shiboken, like: + // "QList::emplace(T) noexcept(is_pod<T>)". + if (!isTemplateCode && ReportHandler::isDebug(ReportHandler::FullDebug)) { + const Diagnostic d(msgCannotDetermineException(snippet), cursor, CXDiagnostic_Warning); + qWarning() << d; + bv->appendDiagnostic(d); + } + return ExceptionSpecification::Unknown; +} + +static ExceptionSpecification exceptionSpecificationFromClang(BaseVisitor *bv, + const CXCursor &cursor, + bool isTemplateCode) +{ + const auto ce = clang_getCursorExceptionSpecificationType(cursor); switch (ce) { - case CXCursor_ExceptionSpecificationKind_BasicNoexcept: case CXCursor_ExceptionSpecificationKind_ComputedNoexcept: + return computedExceptionSpecificationFromClang(bv, cursor, isTemplateCode); + case CXCursor_ExceptionSpecificationKind_BasicNoexcept: case CXCursor_ExceptionSpecificationKind_DynamicNone: // throw() + case CXCursor_ExceptionSpecificationKind_NoThrow: return ExceptionSpecification::NoExcept; case CXCursor_ExceptionSpecificationKind_Dynamic: // throw(t1..) case CXCursor_ExceptionSpecificationKind_MSAny: // throw(...) @@ -283,7 +324,8 @@ static inline ExceptionSpecification exceptionSpecificationFromClang(int ce) } FunctionModelItem BuilderPrivate::createFunction(const CXCursor &cursor, - CodeModel::FunctionType t) + CodeModel::FunctionType t, + bool isTemplateCode) { QString name = getCursorSpelling(cursor); // Apply type fixes to "operator X &" -> "operator X&" @@ -295,7 +337,7 @@ FunctionModelItem BuilderPrivate::createFunction(const CXCursor &cursor, result->setFunctionType(t); result->setScope(m_scope); result->setStatic(clang_Cursor_getStorageClass(cursor) == CX_SC_Static); - result->setExceptionSpecification(exceptionSpecificationFromClang(clang_getCursorExceptionSpecificationType(cursor))); + result->setExceptionSpecification(exceptionSpecificationFromClang(m_baseVisitor, cursor, isTemplateCode)); switch (clang_getCursorAvailability(cursor)) { case CXAvailability_Available: break; @@ -332,13 +374,15 @@ static inline CodeModel::FunctionType functionTypeFromCursor(const CXCursor &cur return result; } -FunctionModelItem BuilderPrivate::createMemberFunction(const CXCursor &cursor) +FunctionModelItem BuilderPrivate::createMemberFunction(const CXCursor &cursor, + bool isTemplateCode) { const CodeModel::FunctionType functionType = m_currentFunctionType == CodeModel::Signal || m_currentFunctionType == CodeModel::Slot ? m_currentFunctionType // by annotation : functionTypeFromCursor(cursor); - FunctionModelItem result = createFunction(cursor, functionType); + isTemplateCode |= m_currentClass->name().endsWith(QLatin1Char('>')); + auto result = createFunction(cursor, functionType, isTemplateCode); result->setAccessPolicy(accessPolicy(clang_getCXXAccessSpecifier(cursor))); result->setConstant(clang_CXXMethod_isConst(cursor) != 0); result->setStatic(clang_CXXMethod_isStatic(cursor) != 0); @@ -387,14 +431,6 @@ void BuilderPrivate::addField(const CXCursor &cursor) 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) { @@ -451,7 +487,7 @@ bool BuilderPrivate::addTemplateInstantiationsRecursion(const CXType &type, Type return true; } -static void dummyTemplateArgumentHandler(int, const QStringRef &) {} +static void dummyTemplateArgumentHandler(int, QStringView) {} void BuilderPrivate::addTemplateInstantiations(const CXType &type, QString *typeName, @@ -580,44 +616,15 @@ void BuilderPrivate::endTemplateTypeAlias(const CXCursor &typeAliasCursor) // 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) + const std::string_view snippet = bv->getCodeSnippet(cursor); + auto equalSign = snippet.find('='); + if (equalSign == std::string::npos) 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; + return QString::fromLocal8Bit(snippet.data() + equalSign, + qsizetype(snippet.size() - equalSign)).trimmed(); } -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 @@ -996,7 +1003,7 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor) // 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_currentFunction = d->createMemberFunction(cursor, false); d->m_scopeStack.back()->addFunction(d->m_currentFunction); break; // Not fully supported, currently, seen as normal function @@ -1005,16 +1012,18 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor) const CXCursor semParent = clang_getCursorSemanticParent(cursor); if (isClassCursor(semParent)) { if (semParent == clang_getCursorLexicalParent(cursor)) { - d->m_currentFunction = d->createMemberFunction(cursor); + d->m_currentFunction = d->createMemberFunction(cursor, true); d->m_scopeStack.back()->addFunction(d->m_currentFunction); break; } return Skip; // inline member functions outside class } } - Q_FALLTHROUGH(); // fall through to free template function. + d->m_currentFunction = d->createFunction(cursor, CodeModel::Normal, true); + d->m_scopeStack.back()->addFunction(d->m_currentFunction); + break; case CXCursor_FunctionDecl: - d->m_currentFunction = d->createFunction(cursor); + d->m_currentFunction = d->createFunction(cursor, CodeModel::Normal, false); d->m_scopeStack.back()->addFunction(d->m_currentFunction); break; case CXCursor_Namespace: { @@ -1130,10 +1139,10 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor) // how it is defined, and qdoc). if (clang_isDeclaration(cursor.kind) && !d->m_currentClass.isNull()) { auto snippet = getCodeSnippet(cursor); - const auto length = snippet.second - snippet.first; - if (length > 12 && *(snippet.second - 1) == ')' - && std::strncmp(snippet.first, "Q_PROPERTY(", 11) == 0) { - const QString qProperty = QString::fromUtf8(snippet.first + 11, length - 12); + const auto length = snippet.size(); + if (length > 12 && *snippet.rbegin() == ')' + && snippet.compare(0, 11, "Q_PROPERTY(") == 0) { + const QString qProperty = QString::fromUtf8(snippet.data() + 11, length - 12); d->m_currentClass->addPropertyDeclaration(qProperty); } } |