From 8c3794f9d104a39b7f91764b7725dad8726fbde0 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Thu, 10 Jan 2013 17:11:03 +0100 Subject: [PATCH] C++: Add star binding to TypePrettyPrinter Now we can specify if we want to print a whitespace before and/or after '*'/'&' when printing pointer and reference types. Task-number: QTCREATORBUG-6169 Change-Id: Ida1b035aa4fd79be9108934b75f236db9f7238af Reviewed-by: Erik Verbruggen --- src/libs/cplusplus/Overview.cpp | 9 +- src/libs/cplusplus/Overview.h | 59 ++- src/libs/cplusplus/TypePrettyPrinter.cpp | 141 +++++-- src/libs/cplusplus/TypePrettyPrinter.h | 29 +- .../tst_typeprettyprinter.cpp | 395 +++++++++++++----- 5 files changed, 493 insertions(+), 140 deletions(-) diff --git a/src/libs/cplusplus/Overview.cpp b/src/libs/cplusplus/Overview.cpp index 748033d8599..330d2a62dd1 100644 --- a/src/libs/cplusplus/Overview.cpp +++ b/src/libs/cplusplus/Overview.cpp @@ -38,14 +38,15 @@ using namespace CPlusPlus; Overview::Overview() - : markedArgument(0), - markedArgumentBegin(0), - markedArgumentEnd(0), + : starBindFlags(BindToIdentifier), // default to "Qt Style" showArgumentNames(false), showReturnTypes(false), showFunctionSignatures(true), showDefaultArguments(true), - showTemplateParameters(false) + showTemplateParameters(false), + markedArgument(0), + markedArgumentBegin(0), + markedArgumentEnd(0) { } QString Overview::prettyName(const Name *name) const diff --git a/src/libs/cplusplus/Overview.h b/src/libs/cplusplus/Overview.h index 344c976f998..339a6d8fc7a 100644 --- a/src/libs/cplusplus/Overview.h +++ b/src/libs/cplusplus/Overview.h @@ -37,6 +37,16 @@ namespace CPlusPlus { +/*! + \class Overview + + \brief Converts a FullySpecifiedType and/or any qualified name, + to its string representation. + + The public data members (except the ones starting with "marked") + determine what exactly and how to print. + */ + class CPLUSPLUS_EXPORT Overview { Overview(const Overview &other); @@ -60,14 +70,57 @@ public: QString prettyType(const FullySpecifiedType &type, const QString &name) const; public: - unsigned markedArgument; - int markedArgumentBegin; - int markedArgumentEnd; + /*! + \enum Overview::StarBindFlag + + The StarBindFlags describe how the '*' and '&' in pointers/references + should be bound in the string representation. + + This also applies to rvalue references ('&&'), but not to + pointers to functions or arrays like in + + void (*p)() + void (*p)[] + + since it seems to be quite uncommon to use spaces there. + + See the examples below. These assume that exactly one + flag is set. That is, it may look different with + flag combinations. + + \value BindToIdentifier + e.g. "char *foo", but not "char * foo" + \value BindToTypeName + e.g. "char*", but not "char *" + \value BindToLeftSpecifier + e.g. "char * const* const", but not "char * const * const" + \value BindToRightSpecifier + e.g. "char *const", but not "char * const" + */ + enum StarBindFlag { + BindToIdentifier = 0x1, + BindToTypeName = 0x2, + BindToLeftSpecifier = 0x4, + BindToRightSpecifier = 0x8 + }; + Q_DECLARE_FLAGS(StarBindFlags, StarBindFlag) + + StarBindFlags starBindFlags; bool showArgumentNames: 1; bool showReturnTypes: 1; bool showFunctionSignatures: 1; bool showDefaultArguments: 1; bool showTemplateParameters: 1; + + /*! + You can get the start and end position of a function argument + in the resulting string. Set "markedArgument" to the desired + argument. After processing, "markedArgumentBegin" and + "markedArgumentEnd" will contain the positions. + */ + unsigned markedArgument; + int markedArgumentBegin; + int markedArgumentEnd; }; } // namespace CPlusPlus diff --git a/src/libs/cplusplus/TypePrettyPrinter.cpp b/src/libs/cplusplus/TypePrettyPrinter.cpp index 8c5bdf51102..84f602337f3 100644 --- a/src/libs/cplusplus/TypePrettyPrinter.cpp +++ b/src/libs/cplusplus/TypePrettyPrinter.cpp @@ -44,6 +44,8 @@ using namespace CPlusPlus; TypePrettyPrinter::TypePrettyPrinter(const Overview *overview) : _overview(overview) , _needsParens(false) + , _isIndirectionType(false) + , _isIndirectionToArrayOrFunction(false) { } TypePrettyPrinter::~TypePrettyPrinter() @@ -91,13 +93,28 @@ QString TypePrettyPrinter::switchName(const QString &name) const QString previousName = _name; _name = name; return previousName; + } -QString TypePrettyPrinter::switchText(const QString &name) +bool TypePrettyPrinter::switchIsIndirectionType(bool isIndirectionType) { - QString previousName = _text; - _text = name; - return previousName; + bool previousIsIndirectionType = _isIndirectionType; + _isIndirectionType = isIndirectionType; + return previousIsIndirectionType; +} + +bool TypePrettyPrinter::switchIsIndirectionToArrayOrFunction(bool isIndirectionToArrayOrFunction) +{ + bool previousIsIndirectionToArrayOrFunction = _isIndirectionToArrayOrFunction; + _isIndirectionToArrayOrFunction = isIndirectionToArrayOrFunction; + return previousIsIndirectionToArrayOrFunction; +} + +QString TypePrettyPrinter::switchText(const QString &text) +{ + QString previousText = _text; + _text = text; + return previousText; } bool TypePrettyPrinter::switchNeedsParens(bool needsParens) @@ -175,6 +192,46 @@ void TypePrettyPrinter::visit(Enum *type) prependCv(_fullySpecifiedType); } +void TypePrettyPrinter::visitIndirectionType( + const TypePrettyPrinter::IndirectionType indirectionType, + const FullySpecifiedType &elementType, + bool isIndirectionToArrayOrFunction) +{ + QLatin1Char indirectionSign = indirectionType == aPointerType + ? QLatin1Char('*') : QLatin1Char('&'); + + const bool prevIsIndirectionType = switchIsIndirectionType(true); + const bool hasName = ! _name.isEmpty(); + if (hasName) { + _text.prepend(_name); + _name.clear(); + } + prependCv(_fullySpecifiedType); + + if (_text.startsWith(QLatin1Char('&')) && indirectionType != aPointerType) + _text.prepend(QLatin1Char(' ')); + + const bool prevIsIndirectionToArrayOrFunction + = switchIsIndirectionToArrayOrFunction(isIndirectionToArrayOrFunction); + + // Space after indirectionSign? + prependSpaceAfterIndirection(hasName); + + // Write indirectionSign or reference + if (indirectionType == aRvalueReferenceType) + _text.prepend(QLatin1String("&&")); + else + _text.prepend(indirectionSign); + + // Space before indirectionSign? + prependSpaceBeforeIndirection(elementType); + + _needsParens = true; + acceptType(elementType); + (bool) switchIsIndirectionToArrayOrFunction(prevIsIndirectionToArrayOrFunction); + (bool) switchIsIndirectionType(prevIsIndirectionType); +} + void TypePrettyPrinter::visit(IntegerType *type) { prependSpaceUnlessBracket(); @@ -246,35 +303,54 @@ void TypePrettyPrinter::visit(PointerToMemberType *type) acceptType(type->elementType()); } +void TypePrettyPrinter::prependSpaceBeforeIndirection(const FullySpecifiedType &type) +{ + const bool elementTypeIsPointerOrReference = type.type()->isPointerType() + || type.type()->isReferenceType(); + const bool elementIsConstPointerOrReference = elementTypeIsPointerOrReference && type.isConst(); + const bool shouldBindToLeftSpecifier = _overview->starBindFlags & Overview::BindToLeftSpecifier; + if (elementIsConstPointerOrReference && ! shouldBindToLeftSpecifier) + _text.prepend(QLatin1String(" ")); +} + +void TypePrettyPrinter::prependSpaceAfterIndirection(bool hasName) +{ + const bool hasCvSpecifier = _fullySpecifiedType.isConst() || _fullySpecifiedType.isVolatile(); + const bool shouldBindToIdentifier = _overview->starBindFlags & Overview::BindToIdentifier; + const bool shouldBindToRightSpecifier = + _overview->starBindFlags & Overview::BindToRightSpecifier; + + const bool spaceBeforeNameNeeded = hasName && ! shouldBindToIdentifier + && ! _isIndirectionToArrayOrFunction; + const bool spaceBeforeSpecifierNeeded = hasCvSpecifier && ! shouldBindToRightSpecifier; + + const bool case1 = hasCvSpecifier && spaceBeforeSpecifierNeeded; + const bool case2 = ! hasCvSpecifier && spaceBeforeNameNeeded; + // case 3: In "char *argv[]", put a space between '*' and "argv" when requested + const bool case3 = ! hasCvSpecifier && ! shouldBindToIdentifier + && ! _isIndirectionToArrayOrFunction && _text.size() && _text.at(0).isLetter(); + if (case1 || case2 || case3) + _text.prepend(QLatin1String(" ")); +} + void TypePrettyPrinter::visit(PointerType *type) { - if (! _name.isEmpty()) { - _text.prepend(_name); - _name.clear(); - } - prependCv(_fullySpecifiedType); - _text.prepend(QLatin1String("*")); - _needsParens = true; - acceptType(type->elementType()); + const bool isIndirectionToFunction = type->elementType().type()->isFunctionType(); + const bool isIndirectionToArray = type->elementType().type()->isArrayType(); + + visitIndirectionType(aPointerType, type->elementType(), + isIndirectionToFunction || isIndirectionToArray); } void TypePrettyPrinter::visit(ReferenceType *type) { - if (! _name.isEmpty()) { - _text.prepend(_name); - _name.clear(); - } - prependCv(_fullySpecifiedType); + const bool isIndirectionToFunction = type->elementType().type()->isFunctionType(); + const bool isIndirectionToArray = type->elementType().type()->isArrayType(); + const IndirectionType indirectionType = type->isRvalueReference() + ? aRvalueReferenceType : aReferenceType; - if (_text.startsWith(QLatin1Char('&'))) - _text.prepend(QLatin1Char(' ')); - - if (type->isRvalueReference()) - _text.prepend(QLatin1String("&&")); - else - _text.prepend(QLatin1String("&")); - _needsParens = true; - acceptType(type->elementType()); + visitIndirectionType(indirectionType, type->elementType(), + isIndirectionToFunction || isIndirectionToArray); } void TypePrettyPrinter::visit(ArrayType *type) @@ -326,6 +402,7 @@ void TypePrettyPrinter::visit(Function *type) if (_overview->showFunctionSignatures) { Overview argumentText; + argumentText.starBindFlags = _overview->starBindFlags; argumentText.showReturnTypes = true; argumentText.showArgumentNames = false; argumentText.showFunctionSignatures = true; @@ -393,8 +470,16 @@ void TypePrettyPrinter::prependSpaceUnlessBracket() const QChar ch = _text.at(0); - if (ch != QLatin1Char('[')) - _text.prepend(QLatin1Char(' ')); + if (ch != QLatin1Char('[')) { + const bool shouldBindToTypeNam = _overview->starBindFlags & Overview::BindToTypeName; + const bool caseNoIndirection = ! _isIndirectionType; + const bool caseIndirectionToArrayOrFunction = _isIndirectionType + && _isIndirectionToArrayOrFunction; + const bool casePointerNoBind = _isIndirectionType && ! _isIndirectionToArrayOrFunction + && ! shouldBindToTypeNam; + if (caseNoIndirection || caseIndirectionToArrayOrFunction || casePointerNoBind) + _text.prepend(QLatin1Char(' ')); + } } void TypePrettyPrinter::prependWordSeparatorSpace() diff --git a/src/libs/cplusplus/TypePrettyPrinter.h b/src/libs/cplusplus/TypePrettyPrinter.h index ffda3113c14..1628306d0ac 100644 --- a/src/libs/cplusplus/TypePrettyPrinter.h +++ b/src/libs/cplusplus/TypePrettyPrinter.h @@ -39,6 +39,14 @@ namespace CPlusPlus { class Overview; class FullySpecifiedType; +/*! + \class TypePrettyPrinter + + \brief Helper class for Overview. Does the main type conversation work. + + Don't use this class directly, use Overview instead. + */ + class CPLUSPLUS_EXPORT TypePrettyPrinter: protected TypeVisitor { public: @@ -50,11 +58,7 @@ public: QString operator()(const FullySpecifiedType &type); QString operator()(const FullySpecifiedType &type, const QString &name); -protected: - QString switchText(const QString &text = QString()); - bool switchNeedsParens(bool needsParens); - QString switchName(const QString &name); - +private: void acceptType(const FullySpecifiedType &ty); virtual void visit(UndefinedType *type); @@ -72,17 +76,30 @@ protected: virtual void visit(Class *type); virtual void visit(Enum *type); + QString switchName(const QString &name); + QString switchText(const QString &text = QString()); + bool switchNeedsParens(bool needsParens); + bool switchIsIndirectionType(bool isIndirectionType); + bool switchIsIndirectionToArrayOrFunction(bool isIndirectionToArrayOrFunction); + void appendSpace(); void prependSpaceUnlessBracket(); void prependWordSeparatorSpace(); void prependCv(const FullySpecifiedType &ty); + void prependSpaceAfterIndirection(bool hasName); + void prependSpaceBeforeIndirection(const FullySpecifiedType &type); + + enum IndirectionType { aPointerType, aReferenceType, aRvalueReferenceType }; + void visitIndirectionType(const IndirectionType indirectionType, + const FullySpecifiedType &elementType, bool isIndirectionToArrayOrFunction); -private: const Overview *_overview; QString _name; QString _text; FullySpecifiedType _fullySpecifiedType; bool _needsParens; + bool _isIndirectionType; + bool _isIndirectionToArrayOrFunction; }; } // namespace CPlusPlus diff --git a/tests/auto/cplusplus/typeprettyprinter/tst_typeprettyprinter.cpp b/tests/auto/cplusplus/typeprettyprinter/tst_typeprettyprinter.cpp index 01af1421873..8c40558937e 100644 --- a/tests/auto/cplusplus/typeprettyprinter/tst_typeprettyprinter.cpp +++ b/tests/auto/cplusplus/typeprettyprinter/tst_typeprettyprinter.cpp @@ -27,25 +27,23 @@ ** ****************************************************************************/ -#include #include -#include +#include -#include -#include #include -#include -#include -#include -#include +#include #include #include -#include +#include +#include #include //TESTED_COMPONENT=src/libs/cplusplus using namespace CPlusPlus; +Q_DECLARE_METATYPE(CPlusPlus::FullySpecifiedType) +Q_DECLARE_METATYPE(Overview::StarBindFlags) + class tst_TypePrettyPrinter: public QObject { Q_OBJECT @@ -55,160 +53,359 @@ private Q_SLOTS: void basic_data(); }; -Q_DECLARE_METATYPE(CPlusPlus::FullySpecifiedType); - -TranslationUnit *unit; - -const Identifier *nameId(const QString &name) +static const Identifier *nameId(const QString &name) { return new Identifier(name.toLatin1().constData(), name.toLatin1().size()); } -Argument *arg(const QString &name, const FullySpecifiedType &ty) +static Argument *arg(const QString &name, const FullySpecifiedType &ty) { - Argument *a = new Argument(unit, 0, nameId(name)); + Argument *a = new Argument(0, 0, nameId(name)); a->setType(ty); return a; } -FullySpecifiedType voidTy() +static FullySpecifiedType voidTy() { return FullySpecifiedType(new VoidType); } -FullySpecifiedType intTy() +static FullySpecifiedType intTy() { return FullySpecifiedType(new IntegerType(IntegerType::Int)); } -FullySpecifiedType fnTy(const QString &name, const FullySpecifiedType &ret) +static FullySpecifiedType fnTy(const QString &name, const FullySpecifiedType &ret) { - Function *fn = new Function(unit, 0, nameId(name)); + Function *fn = new Function(0, 0, nameId(name)); fn->setReturnType(ret); return FullySpecifiedType(fn); } -FullySpecifiedType fnTy(const QString &name, const FullySpecifiedType &ret, const FullySpecifiedType &a0) +static FullySpecifiedType fnTy(const QString &name, const FullySpecifiedType &ret, + const FullySpecifiedType &a0) { - Function *fn = new Function(unit, 0, nameId(name)); + Function *fn = new Function(0, 0, nameId(name)); fn->setReturnType(ret); fn->addMember(arg("a0", a0)); return FullySpecifiedType(fn); } -FullySpecifiedType ptr(const FullySpecifiedType &el) +static FullySpecifiedType fnTy(const QString &name, const FullySpecifiedType &ret, + const FullySpecifiedType &a0, const FullySpecifiedType &a1, + const FullySpecifiedType &a2) +{ + Function *fn = new Function(0, 0, nameId(name)); + fn->setReturnType(ret); + fn->addMember(arg("a0", a0)); + fn->addMember(arg("a1", a1)); + fn->addMember(arg("a1", a2)); + return FullySpecifiedType(fn); +} + +static FullySpecifiedType ptr(const FullySpecifiedType &el) { return FullySpecifiedType(new PointerType(el)); } -FullySpecifiedType ref(const FullySpecifiedType &el) +static FullySpecifiedType ref(const FullySpecifiedType &el) { return FullySpecifiedType(new ReferenceType(el, false)); } -FullySpecifiedType rref(const FullySpecifiedType &el) +static FullySpecifiedType rref(const FullySpecifiedType &el) { return FullySpecifiedType(new ReferenceType(el, true)); } -FullySpecifiedType arr(const FullySpecifiedType &el) +static FullySpecifiedType arr(const FullySpecifiedType &el) { return FullySpecifiedType(new ArrayType(el, 4)); } -FullySpecifiedType cnst(const FullySpecifiedType &el) +static FullySpecifiedType cnst(const FullySpecifiedType &el) { FullySpecifiedType r(el); r.setConst(true); return r; } - - -void addRow(const FullySpecifiedType &f, QString result, QString name = QString()) +static QString toString(Overview::StarBindFlags starBindFlags) { - QTest::newRow(result.toLatin1().constData()) << f << name << result; + QString result; + if (starBindFlags & Overview::BindToIdentifier) + result += QLatin1Char('n'); + if (starBindFlags & Overview::BindToTypeName) + result += QLatin1Char('t'); + if (starBindFlags & Overview::BindToLeftSpecifier) + result += QLatin1String("Sl"); + if (starBindFlags & Overview::BindToRightSpecifier) + result += QLatin1String("Sr"); + return result; +} + +static void addRow(const FullySpecifiedType &f, Overview::StarBindFlags starBindFlags, + const QString &result, const QString &name = QString()) +{ + const QString dataTag + = QString::fromLatin1("'%1' with star binding '%2'").arg(result, toString(starBindFlags)); + QTest::newRow(dataTag.toLatin1().constData()) << f << starBindFlags << name << result; } void tst_TypePrettyPrinter::basic_data() { - // seems it now works without a translation unit -// Control c; -// TranslationUnit t(&c, 0); -// unit = 0; - QTest::addColumn("type"); + QTest::addColumn("starBindFlags"); QTest::addColumn("name"); QTest::addColumn("result"); - addRow(voidTy(), "void"); - addRow(cnst(voidTy()), "const void"); - addRow(ptr(fnTy("foo", voidTy())), "void (*)()"); - addRow(ptr(fnTy("foo", voidTy())), "void (*foo)()", "foo"); + // Define some often used flag combinations. + const Overview::StarBindFlags bindToNothing = 0; + const Overview::StarBindFlags bindToBothSpecifiers + = Overview::StarBindFlags(Overview::BindToLeftSpecifier | Overview::BindToRightSpecifier); + const Overview::StarBindFlags bindToNameAndType + = Overview::StarBindFlags(Overview::BindToIdentifier | Overview::BindToTypeName); + const Overview::StarBindFlags bindToTypeAndRightSpecifier + = Overview::StarBindFlags(Overview::BindToTypeName | Overview::BindToRightSpecifier); + const Overview::StarBindFlags bindToAll = Overview::StarBindFlags(Overview::BindToIdentifier + | Overview::BindToTypeName | Overview::BindToLeftSpecifier | Overview::BindToRightSpecifier); - // named types - addRow(voidTy(), "void foo", "foo"); - addRow(ptr(voidTy()), "void *foo", "foo"); - addRow(cnst(ptr(voidTy())), "void *const foo", "foo"); - addRow(arr(voidTy()), "void foo[]", "foo"); - addRow(ptr(arr(voidTy())), "void (*foo)[]", "foo"); + // The star bindings should not affect declarations without a star or reference sign. + addRow(voidTy(), bindToNothing, "void"); + addRow(voidTy(), bindToAll, "void"); + addRow(voidTy(), bindToAll, "void foo", "foo"); + addRow(voidTy(), bindToNothing, "void foo", "foo"); - // pointers - addRow(ptr(voidTy()), "void *"); - addRow(ptr(ptr(voidTy())), "void **"); + addRow(cnst(voidTy()), bindToNothing, "const void"); + addRow(cnst(voidTy()), bindToAll, "const void"); + addRow(cnst(voidTy()), bindToNothing, "const void foo", "foo"); + addRow(cnst(voidTy()), bindToAll, "const void foo", "foo"); - addRow(ptr(cnst(voidTy())), "const void *"); - addRow(cnst(ptr(cnst(voidTy()))), "const void *const"); - addRow(cnst(ptr(voidTy())), "void *const"); + addRow(arr(voidTy()), bindToNothing, "void[]"); + addRow(arr(voidTy()), bindToAll, "void[]"); + addRow(arr(voidTy()), bindToNothing, "void foo[]", "foo"); + addRow(arr(voidTy()), bindToAll, "void foo[]", "foo"); - addRow(ptr(ptr(cnst(voidTy()))), "const void **"); - addRow(ptr(cnst(ptr(cnst(voidTy())))), "const void *const*"); - addRow(cnst(ptr(ptr(cnst(voidTy())))), "const void **const"); - addRow(cnst(ptr(cnst(ptr(cnst(voidTy()))))), "const void *const*const"); - addRow(ptr(cnst(ptr(voidTy()))), "void *const*"); - addRow(cnst(ptr(ptr(voidTy()))), "void **const"); - addRow(cnst(ptr(cnst(ptr(voidTy())))), "void *const*const"); + addRow(fnTy("foo", voidTy(), intTy()), bindToNothing, "void foo(int)", "foo"); + addRow(fnTy("foo", voidTy(), intTy()), bindToAll, "void foo(int)", "foo"); - addRow(arr(voidTy()), "void[]"); - addRow(arr(ptr(voidTy())), "void *[]"); - addRow(ptr(arr(voidTy())), "void (*)[]"); - addRow(ptr(arr(arr(voidTy()))), "void (*)[][]"); - addRow(ptr(arr(ptr(voidTy()))), "void *(*)[]"); - addRow(arr(ptr(arr(voidTy()))), "void (*[])[]"); + // Pointers to functions and arrays are also excluded. It seems to be quite unusal to have + // a space there. + addRow(ptr(fnTy("foo", voidTy())), bindToAll, "void (*)()"); + addRow(ptr(fnTy("foo", voidTy())), bindToNothing, "void (*)()"); + addRow(ptr(fnTy("foo", voidTy())), bindToAll, "void (*foo)()", "foo"); + addRow(ptr(fnTy("foo", voidTy())), bindToNothing, "void (*foo)()", "foo"); - // references - addRow(ref(voidTy()), "void &"); - addRow(ref(ref(voidTy())), "void & &"); + addRow(ptr(arr(voidTy())), bindToNothing, "void (*)[]"); + addRow(ptr(arr(voidTy())), bindToAll, "void (*)[]"); - addRow(ref(cnst(voidTy())), "const void &"); - addRow(cnst(ref(cnst(voidTy()))), "const void &const"); - addRow(cnst(ref(voidTy())), "void &const"); + addRow(ptr(arr(arr(voidTy()))), bindToNothing, "void (*)[][]"); + addRow(ptr(arr(arr(voidTy()))), bindToAll, "void (*)[][]"); - addRow(ref(ref(cnst(voidTy()))), "const void & &"); - addRow(ref(cnst(ref(cnst(voidTy())))), "const void &const&"); - addRow(cnst(ref(ref(cnst(voidTy())))), "const void & &const"); - addRow(cnst(ref(cnst(ref(cnst(voidTy()))))), "const void &const&const"); - addRow(ref(cnst(ref(voidTy()))), "void &const&"); - addRow(cnst(ref(ref(voidTy()))), "void & &const"); - addRow(cnst(ref(cnst(ref(voidTy())))), "void &const&const"); + // Pointers only + addRow(ptr(voidTy()), Overview::BindToTypeName, "void*"); + addRow(ptr(voidTy()), bindToAll, "void*"); + addRow(ptr(voidTy()), bindToNothing, "void *"); + addRow(ptr(voidTy()), Overview::BindToIdentifier, "void *foo", "foo"); + addRow(ptr(voidTy()), Overview::BindToTypeName, "void* foo", "foo"); + addRow(ptr(voidTy()), bindToNameAndType, "void*foo", "foo"); + addRow(ptr(voidTy()), bindToAll, "void*foo", "foo"); + addRow(ptr(voidTy()), bindToNothing, "void * foo", "foo"); - addRow(arr(voidTy()), "void[]"); - addRow(arr(ref(voidTy())), "void &[]"); - addRow(ref(arr(voidTy())), "void (&)[]"); - addRow(ref(arr(arr(voidTy()))), "void (&)[][]"); - addRow(ref(arr(ref(voidTy()))), "void &(&)[]"); - addRow(arr(ref(arr(voidTy()))), "void (&[])[]"); + addRow(ptr(ptr(voidTy())), Overview::BindToTypeName, "void**"); + addRow(ptr(ptr(voidTy())), bindToAll, "void**"); + addRow(ptr(ptr(voidTy())), bindToNothing, "void **"); + addRow(ptr(ptr(voidTy())), Overview::BindToIdentifier, "void **foo", "foo"); + addRow(ptr(ptr(voidTy())), Overview::BindToTypeName, "void** foo", "foo"); + addRow(ptr(ptr(voidTy())), bindToNameAndType, "void**foo", "foo"); + addRow(ptr(ptr(voidTy())), bindToAll, "void**foo", "foo"); + addRow(ptr(ptr(voidTy())), bindToNothing, "void ** foo", "foo"); - // rvalue references - addRow(rref(voidTy()), "void &&"); - addRow(rref(cnst(voidTy())), "const void &&"); + addRow(ptr(cnst(voidTy())), bindToAll, "const void*"); + addRow(ptr(cnst(voidTy())), bindToNothing, "const void *"); - addRow(rref(arr(voidTy())), "void (&&)[]"); - addRow(rref(arr(arr(voidTy()))), "void (&&)[][]"); + addRow(cnst(ptr(voidTy())), Overview::BindToIdentifier, "void * const foo", "foo"); + addRow(cnst(ptr(voidTy())), Overview::BindToTypeName, "void* const foo", "foo"); + addRow(cnst(ptr(voidTy())), Overview::BindToRightSpecifier, "void *const foo", "foo"); + addRow(cnst(ptr(voidTy())), bindToTypeAndRightSpecifier, "void*const foo", "foo"); + addRow(cnst(ptr(voidTy())), bindToAll, "void*const foo", "foo"); + addRow(cnst(ptr(voidTy())), bindToNothing, "void * const foo", "foo"); - // simple functions - addRow(ptr(fnTy("foo", voidTy(), intTy())), "void (*foo)(int)", "foo"); - addRow(ptr(fnTy("foo", voidTy(), ptr(voidTy()))), "void (*foo)(void *)", "foo"); - addRow(fnTy("foo", voidTy(), intTy()), "void foo(int)", "foo"); - addRow(fnTy("foo", voidTy(), ptr(voidTy())), "void foo(void *)", "foo"); + addRow(cnst(ptr(cnst(voidTy()))), bindToAll, "const void*const"); + addRow(cnst(ptr(cnst(voidTy()))), Overview::BindToTypeName, "const void* const"); + addRow(cnst(ptr(cnst(voidTy()))), Overview::BindToRightSpecifier, "const void *const"); + addRow(cnst(ptr(cnst(voidTy()))), bindToNothing, "const void * const"); - // functions with ptr or ref returns - addRow(ptr(fnTy("foo", ptr(voidTy()), intTy())), "void *(*foo)(int)", "foo"); - addRow(ptr(fnTy("foo", ref(voidTy()), ptr(voidTy()))), "void &(*foo)(void *)", "foo"); - addRow(fnTy("foo", ptr(voidTy()), intTy()), "void *foo(int)", "foo"); - addRow(fnTy("foo", ref(voidTy()), ptr(voidTy())), "void &foo(void *)", "foo"); + addRow(cnst(ptr(voidTy())), Overview::BindToIdentifier, "void * const"); + addRow(cnst(ptr(voidTy())), Overview::BindToTypeName, "void* const"); + addRow(cnst(ptr(voidTy())), Overview::BindToRightSpecifier, "void *const"); + addRow(cnst(ptr(voidTy())), bindToTypeAndRightSpecifier, "void*const"); + addRow(cnst(ptr(voidTy())), bindToAll, "void*const"); + addRow(cnst(ptr(voidTy())), bindToNothing, "void * const"); + + addRow(ptr(ptr(cnst(voidTy()))), Overview::BindToIdentifier, "const void **"); + addRow(ptr(cnst(ptr(cnst(voidTy())))), Overview::BindToIdentifier, "const void * const *"); + addRow(cnst(ptr(ptr(cnst(voidTy())))), Overview::BindToIdentifier, "const void ** const"); + + addRow(ptr(cnst(ptr(voidTy()))), bindToNothing, "void * const *"); + addRow(ptr(cnst(ptr(voidTy()))), bindToAll, "void*const*"); + addRow(cnst(ptr(ptr(voidTy()))), bindToNothing, "void ** const"); + addRow(cnst(ptr(ptr(voidTy()))), bindToAll, "void**const"); + + addRow(cnst(ptr(cnst(ptr(voidTy())))), bindToNothing, "void * const * const"); + addRow(cnst(ptr(cnst(ptr(voidTy())))), bindToAll, "void*const*const"); + addRow(cnst(ptr(ptr(cnst(ptr(voidTy()))))), bindToNothing, "void * const ** const"); + addRow(cnst(ptr(ptr(cnst(ptr(voidTy()))))), bindToAll, "void*const**const"); + + addRow(cnst(ptr(cnst(ptr(cnst(voidTy()))))), Overview::BindToLeftSpecifier, "const void * const* const"); + addRow(cnst(ptr(cnst(ptr(cnst(voidTy()))))), Overview::BindToRightSpecifier, "const void *const *const"); + addRow(cnst(ptr(cnst(ptr(cnst(voidTy()))))), bindToBothSpecifiers, "const void *const*const"); + addRow(cnst(ptr(cnst(ptr(cnst(voidTy()))))), bindToNothing, "const void * const * const"); + addRow(cnst(ptr(cnst(ptr(cnst(voidTy()))))), bindToAll, "const void*const*const"); + + // Pointers and arrays + addRow(arr(ptr(voidTy())), bindToNothing, "void * argv[]", "argv"); + addRow(arr(ptr(voidTy())), bindToAll, "void*argv[]", "argv"); + + addRow(arr(ptr(voidTy())), bindToNothing, "void *[]"); + addRow(arr(ptr(voidTy())), bindToAll, "void*[]"); + + addRow(ptr(arr(ptr(voidTy()))), bindToNothing, "void *(*)[]"); + addRow(ptr(arr(ptr(voidTy()))), bindToAll, "void*(*)[]"); + + addRow(arr(ptr(arr(voidTy()))), bindToNothing, "void (*[])[]"); + addRow(arr(ptr(arr(voidTy()))), bindToAll, "void (*[])[]"); + + addRow(ptr(arr(voidTy())), bindToAll, "void (*foo)[]", "foo"); + addRow(ptr(arr(voidTy())), bindToNothing, "void (*foo)[]", "foo"); + + // Pointers to functions + addRow(ptr(fnTy("foo", voidTy(), intTy())), bindToNothing, "void (*foo)(int)", "foo"); + addRow(ptr(fnTy("foo", voidTy(), intTy())), bindToAll, "void (*foo)(int)", "foo"); + + addRow(ptr(fnTy("foo", voidTy(), ptr(voidTy()))), bindToNothing, "void (*foo)(void *)", "foo"); + addRow(ptr(fnTy("foo", voidTy(), ptr(voidTy()))), bindToAll, "void (*foo)(void*)", "foo"); + + // Pointers in more complex declarations + FullySpecifiedType complexType1 + = ptr(fnTy("foo", voidTy(), intTy(), ptr(voidTy()), ptr(ptr(intTy())))); + addRow(complexType1, bindToNothing, "void (*foo)(int, void *, int **)", "foo"); + addRow(complexType1, bindToAll, "void (*foo)(int, void*, int**)", "foo"); + + FullySpecifiedType complexType2 = ptr(fnTy("foo", voidTy(), + intTy(), cnst(ptr(cnst(voidTy()))), cnst(ptr(cnst(ptr(intTy())))))); + addRow(complexType2, Overview::BindToLeftSpecifier, + "void (*foo)(int, const void * const, int * const* const)", "foo"); + addRow(complexType2, Overview::BindToRightSpecifier, + "void (*foo)(int, const void *const, int *const *const)", "foo"); + addRow(complexType2, bindToBothSpecifiers, + "void (*foo)(int, const void *const, int *const*const)", "foo"); + addRow(complexType2, bindToNothing, + "void (*foo)(int, const void * const, int * const * const)", "foo"); + addRow(complexType2, bindToAll, + "void (*foo)(int, const void*const, int*const*const)", "foo"); + + // References only + addRow(ref(voidTy()), bindToNothing, "void &"); + addRow(ref(voidTy()), bindToAll, "void&"); + + addRow(ref(ref(voidTy())), bindToNothing, "void & &"); + addRow(ref(ref(voidTy())), bindToAll, "void& &"); + + addRow(ref(cnst(voidTy())), bindToNothing, "const void &"); + addRow(ref(cnst(voidTy())), bindToAll, "const void&"); + + addRow(cnst(ref(cnst(voidTy()))), Overview::BindToRightSpecifier, "const void &const"); + addRow(cnst(ref(cnst(voidTy()))), Overview::BindToTypeName, "const void& const"); + addRow(cnst(ref(cnst(voidTy()))), bindToNothing, "const void & const"); + addRow(cnst(ref(cnst(voidTy()))), bindToAll, "const void&const"); + + addRow(cnst(ref(voidTy())), Overview::BindToRightSpecifier, "void &const"); + addRow(cnst(ref(voidTy())), Overview::BindToTypeName, "void& const"); + addRow(cnst(ref(voidTy())), bindToNothing, "void & const"); + addRow(cnst(ref(voidTy())), bindToAll, "void&const"); + + addRow(ref(ref(cnst(voidTy()))), bindToNothing, "const void & &"); + addRow(ref(ref(cnst(voidTy()))), bindToAll, "const void& &"); + + addRow(ref(cnst(ref(cnst(voidTy())))), Overview::BindToTypeName, "const void& const &"); + addRow(ref(cnst(ref(cnst(voidTy())))), Overview::BindToLeftSpecifier, "const void & const&"); + addRow(ref(cnst(ref(cnst(voidTy())))), Overview::BindToRightSpecifier, "const void &const &"); + addRow(ref(cnst(ref(cnst(voidTy())))), bindToBothSpecifiers, "const void &const&"); + addRow(ref(cnst(ref(cnst(voidTy())))), bindToNothing, "const void & const &"); + addRow(ref(cnst(ref(cnst(voidTy())))), bindToAll, "const void&const&"); + + addRow(cnst(ref(ref(cnst(voidTy())))), bindToBothSpecifiers, "const void & &const"); + addRow(cnst(ref(ref(cnst(voidTy())))), bindToNothing, "const void & & const"); + addRow(cnst(ref(ref(cnst(voidTy())))), bindToAll, "const void& &const"); + + addRow(cnst(ref(cnst(ref(cnst(voidTy()))))), Overview::BindToLeftSpecifier, "const void & const& const"); + addRow(cnst(ref(cnst(ref(cnst(voidTy()))))), Overview::BindToRightSpecifier, "const void &const &const"); + addRow(cnst(ref(cnst(ref(cnst(voidTy()))))), bindToBothSpecifiers, "const void &const&const"); + addRow(cnst(ref(cnst(ref(cnst(voidTy()))))), bindToNothing, "const void & const & const"); + addRow(cnst(ref(cnst(ref(cnst(voidTy()))))), bindToAll, "const void&const&const"); + + addRow(ref(cnst(ref(voidTy()))), bindToNothing, "void & const &"); + addRow(ref(cnst(ref(voidTy()))), bindToAll, "void&const&"); + + addRow(cnst(ref(ref(voidTy()))), bindToNothing, "void & & const"); + addRow(cnst(ref(ref(voidTy()))), bindToAll, "void& &const"); + + addRow(cnst(ref(cnst(ref(voidTy())))), Overview::BindToLeftSpecifier, "void & const& const"); + addRow(cnst(ref(cnst(ref(voidTy())))), Overview::BindToRightSpecifier, "void &const &const"); + addRow(cnst(ref(cnst(ref(voidTy())))), bindToBothSpecifiers, "void &const&const"); + addRow(cnst(ref(cnst(ref(voidTy())))), bindToNothing, "void & const & const"); + addRow(cnst(ref(cnst(ref(voidTy())))), bindToAll, "void&const&const"); + + addRow(ref(fnTy("foo", voidTy())), bindToNothing, "void (&foo)()", "foo"); + addRow(ref(fnTy("foo", voidTy())), bindToAll, "void (&foo)()", "foo"); + + addRow(arr(ref(voidTy())), bindToNothing, "void &[]"); + addRow(arr(ref(voidTy())), bindToAll, "void&[]"); + + addRow(ref(arr(voidTy())), bindToNothing, "void (&)[]"); + addRow(ref(arr(voidTy())), bindToAll, "void (&)[]"); + + addRow(ref(arr(arr(voidTy()))), bindToNothing, "void (&)[][]"); + addRow(ref(arr(arr(voidTy()))), bindToAll, "void (&)[][]"); + + addRow(ref(arr(ref(voidTy()))), bindToNothing, "void &(&)[]"); + addRow(ref(arr(ref(voidTy()))), bindToAll, "void&(&)[]"); + + addRow(arr(ref(arr(voidTy()))), bindToNothing, "void (&[])[]"); + addRow(arr(ref(arr(voidTy()))), bindToAll, "void (&[])[]"); + + // Rvalue References + addRow(rref(voidTy()), bindToNothing, "void &&"); + addRow(rref(voidTy()), bindToAll, "void&&"); + + addRow(rref(cnst(voidTy())), bindToNothing, "const void &&"); + addRow(rref(cnst(voidTy())), bindToAll, "const void&&"); + + addRow(rref(cnst(voidTy())), bindToNothing, "const void && foo", "foo"); + addRow(rref(cnst(voidTy())), bindToAll, "const void&&foo", "foo"); + + addRow(rref(arr(voidTy())), bindToNothing, "void (&&)[]"); + addRow(rref(arr(voidTy())), bindToAll, "void (&&)[]"); + + addRow(rref(arr(arr(voidTy()))), bindToNothing, "void (&&)[][]"); + addRow(rref(arr(arr(voidTy()))), bindToAll, "void (&&)[][]"); + + // Pointers and references mixed + addRow(cnst(ref(ptr(voidTy()))), bindToBothSpecifiers, "void *&const"); + addRow(cnst(ref(ptr(voidTy()))), bindToNothing, "void *& const"); + addRow(cnst(ref(ptr(voidTy()))), bindToAll, "void*&const"); + + // Functions with pointer parameters + addRow(fnTy("foo", voidTy(), ptr(voidTy())), bindToNothing, "void foo(void *)", "foo"); + addRow(fnTy("foo", voidTy(), ptr(voidTy())), bindToAll, "void foo(void*)", "foo"); + + // Functions with pointer or reference returns + addRow(ptr(fnTy("foo", ptr(voidTy()), intTy())), bindToNothing, "void *(*foo)(int)", "foo"); + addRow(ptr(fnTy("foo", ptr(voidTy()), intTy())), bindToAll, "void*(*foo)(int)", "foo"); + + addRow(ptr(fnTy("foo", ref(voidTy()), ptr(voidTy()))), bindToNothing, "void &(*foo)(void *)", "foo"); + addRow(ptr(fnTy("foo", ref(voidTy()), ptr(voidTy()))), bindToAll, "void&(*foo)(void*)", "foo"); + + addRow(fnTy("foo", ptr(voidTy()), intTy()), bindToNothing, "void *foo(int)", "foo"); + addRow(fnTy("foo", ptr(voidTy()), intTy()), bindToAll, "void*foo(int)", "foo"); + + addRow(fnTy("foo", ref(voidTy()), ptr(voidTy())), bindToNothing, "void &foo(void *)", "foo"); + addRow(fnTy("foo", ref(voidTy()), ptr(voidTy())), bindToAll, "void&foo(void*)", "foo"); } void tst_TypePrettyPrinter::basic() { QFETCH(FullySpecifiedType, type); + QFETCH(Overview::StarBindFlags, starBindFlags); QFETCH(QString, name); QFETCH(QString, result); Overview o; o.showReturnTypes = true; + o.starBindFlags = starBindFlags; TypePrettyPrinter pp(&o); QCOMPARE(pp(type, name), result); }