aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken2/ApiExtractor/clangparser
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken2/ApiExtractor/clangparser')
-rw-r--r--sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp188
-rw-r--r--sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp2
-rw-r--r--sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp49
-rw-r--r--sources/shiboken2/ApiExtractor/clangparser/clangutils.h13
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 &);