aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp')
-rw-r--r--sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp135
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);
}
}