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 <erik.verbruggen@digia.com>
This commit is contained in:
Nikolai Kosjar
2013-01-10 17:11:03 +01:00
committed by Erik Verbruggen
parent b6a9d58f69
commit 8c3794f9d1
5 changed files with 493 additions and 140 deletions

View File

@@ -38,14 +38,15 @@
using namespace CPlusPlus; using namespace CPlusPlus;
Overview::Overview() Overview::Overview()
: markedArgument(0), : starBindFlags(BindToIdentifier), // default to "Qt Style"
markedArgumentBegin(0),
markedArgumentEnd(0),
showArgumentNames(false), showArgumentNames(false),
showReturnTypes(false), showReturnTypes(false),
showFunctionSignatures(true), showFunctionSignatures(true),
showDefaultArguments(true), showDefaultArguments(true),
showTemplateParameters(false) showTemplateParameters(false),
markedArgument(0),
markedArgumentBegin(0),
markedArgumentEnd(0)
{ } { }
QString Overview::prettyName(const Name *name) const QString Overview::prettyName(const Name *name) const

View File

@@ -37,6 +37,16 @@
namespace CPlusPlus { 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 class CPLUSPLUS_EXPORT Overview
{ {
Overview(const Overview &other); Overview(const Overview &other);
@@ -60,14 +70,57 @@ public:
QString prettyType(const FullySpecifiedType &type, const QString &name) const; QString prettyType(const FullySpecifiedType &type, const QString &name) const;
public: public:
unsigned markedArgument; /*!
int markedArgumentBegin; \enum Overview::StarBindFlag
int markedArgumentEnd;
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 showArgumentNames: 1;
bool showReturnTypes: 1; bool showReturnTypes: 1;
bool showFunctionSignatures: 1; bool showFunctionSignatures: 1;
bool showDefaultArguments: 1; bool showDefaultArguments: 1;
bool showTemplateParameters: 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 } // namespace CPlusPlus

View File

@@ -44,6 +44,8 @@ using namespace CPlusPlus;
TypePrettyPrinter::TypePrettyPrinter(const Overview *overview) TypePrettyPrinter::TypePrettyPrinter(const Overview *overview)
: _overview(overview) : _overview(overview)
, _needsParens(false) , _needsParens(false)
, _isIndirectionType(false)
, _isIndirectionToArrayOrFunction(false)
{ } { }
TypePrettyPrinter::~TypePrettyPrinter() TypePrettyPrinter::~TypePrettyPrinter()
@@ -91,13 +93,28 @@ QString TypePrettyPrinter::switchName(const QString &name)
const QString previousName = _name; const QString previousName = _name;
_name = name; _name = name;
return previousName; return previousName;
} }
QString TypePrettyPrinter::switchText(const QString &name) bool TypePrettyPrinter::switchIsIndirectionType(bool isIndirectionType)
{ {
QString previousName = _text; bool previousIsIndirectionType = _isIndirectionType;
_text = name; _isIndirectionType = isIndirectionType;
return previousName; 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) bool TypePrettyPrinter::switchNeedsParens(bool needsParens)
@@ -175,6 +192,46 @@ void TypePrettyPrinter::visit(Enum *type)
prependCv(_fullySpecifiedType); 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) void TypePrettyPrinter::visit(IntegerType *type)
{ {
prependSpaceUnlessBracket(); prependSpaceUnlessBracket();
@@ -246,35 +303,54 @@ void TypePrettyPrinter::visit(PointerToMemberType *type)
acceptType(type->elementType()); 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) void TypePrettyPrinter::visit(PointerType *type)
{ {
if (! _name.isEmpty()) { const bool isIndirectionToFunction = type->elementType().type()->isFunctionType();
_text.prepend(_name); const bool isIndirectionToArray = type->elementType().type()->isArrayType();
_name.clear();
} visitIndirectionType(aPointerType, type->elementType(),
prependCv(_fullySpecifiedType); isIndirectionToFunction || isIndirectionToArray);
_text.prepend(QLatin1String("*"));
_needsParens = true;
acceptType(type->elementType());
} }
void TypePrettyPrinter::visit(ReferenceType *type) void TypePrettyPrinter::visit(ReferenceType *type)
{ {
if (! _name.isEmpty()) { const bool isIndirectionToFunction = type->elementType().type()->isFunctionType();
_text.prepend(_name); const bool isIndirectionToArray = type->elementType().type()->isArrayType();
_name.clear(); const IndirectionType indirectionType = type->isRvalueReference()
} ? aRvalueReferenceType : aReferenceType;
prependCv(_fullySpecifiedType);
if (_text.startsWith(QLatin1Char('&'))) visitIndirectionType(indirectionType, type->elementType(),
_text.prepend(QLatin1Char(' ')); isIndirectionToFunction || isIndirectionToArray);
if (type->isRvalueReference())
_text.prepend(QLatin1String("&&"));
else
_text.prepend(QLatin1String("&"));
_needsParens = true;
acceptType(type->elementType());
} }
void TypePrettyPrinter::visit(ArrayType *type) void TypePrettyPrinter::visit(ArrayType *type)
@@ -326,6 +402,7 @@ void TypePrettyPrinter::visit(Function *type)
if (_overview->showFunctionSignatures) { if (_overview->showFunctionSignatures) {
Overview argumentText; Overview argumentText;
argumentText.starBindFlags = _overview->starBindFlags;
argumentText.showReturnTypes = true; argumentText.showReturnTypes = true;
argumentText.showArgumentNames = false; argumentText.showArgumentNames = false;
argumentText.showFunctionSignatures = true; argumentText.showFunctionSignatures = true;
@@ -393,8 +470,16 @@ void TypePrettyPrinter::prependSpaceUnlessBracket()
const QChar ch = _text.at(0); const QChar ch = _text.at(0);
if (ch != QLatin1Char('[')) if (ch != QLatin1Char('[')) {
_text.prepend(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() void TypePrettyPrinter::prependWordSeparatorSpace()

View File

@@ -39,6 +39,14 @@ namespace CPlusPlus {
class Overview; class Overview;
class FullySpecifiedType; 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 class CPLUSPLUS_EXPORT TypePrettyPrinter: protected TypeVisitor
{ {
public: public:
@@ -50,11 +58,7 @@ public:
QString operator()(const FullySpecifiedType &type); QString operator()(const FullySpecifiedType &type);
QString operator()(const FullySpecifiedType &type, const QString &name); QString operator()(const FullySpecifiedType &type, const QString &name);
protected: private:
QString switchText(const QString &text = QString());
bool switchNeedsParens(bool needsParens);
QString switchName(const QString &name);
void acceptType(const FullySpecifiedType &ty); void acceptType(const FullySpecifiedType &ty);
virtual void visit(UndefinedType *type); virtual void visit(UndefinedType *type);
@@ -72,17 +76,30 @@ protected:
virtual void visit(Class *type); virtual void visit(Class *type);
virtual void visit(Enum *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 appendSpace();
void prependSpaceUnlessBracket(); void prependSpaceUnlessBracket();
void prependWordSeparatorSpace(); void prependWordSeparatorSpace();
void prependCv(const FullySpecifiedType &ty); 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; const Overview *_overview;
QString _name; QString _name;
QString _text; QString _text;
FullySpecifiedType _fullySpecifiedType; FullySpecifiedType _fullySpecifiedType;
bool _needsParens; bool _needsParens;
bool _isIndirectionType;
bool _isIndirectionToArrayOrFunction;
}; };
} // namespace CPlusPlus } // namespace CPlusPlus

View File

@@ -27,25 +27,23 @@
** **
****************************************************************************/ ****************************************************************************/
#include <QtTest>
#include <QObject> #include <QObject>
#include <QList> #include <QtTest>
#include <FullySpecifiedType.h>
#include <Type.h>
#include <CoreTypes.h> #include <CoreTypes.h>
#include <Symbols.h> #include <FullySpecifiedType.h>
#include <TranslationUnit.h>
#include <Control.h>
#include <Names.h>
#include <Literals.h> #include <Literals.h>
#include <Overview.h> #include <Overview.h>
#include <Scope.h> #include <Symbols.h>
#include <Type.h>
#include <TypePrettyPrinter.h> #include <TypePrettyPrinter.h>
//TESTED_COMPONENT=src/libs/cplusplus //TESTED_COMPONENT=src/libs/cplusplus
using namespace CPlusPlus; using namespace CPlusPlus;
Q_DECLARE_METATYPE(CPlusPlus::FullySpecifiedType)
Q_DECLARE_METATYPE(Overview::StarBindFlags)
class tst_TypePrettyPrinter: public QObject class tst_TypePrettyPrinter: public QObject
{ {
Q_OBJECT Q_OBJECT
@@ -55,160 +53,359 @@ private Q_SLOTS:
void basic_data(); void basic_data();
}; };
Q_DECLARE_METATYPE(CPlusPlus::FullySpecifiedType); static const Identifier *nameId(const QString &name)
TranslationUnit *unit;
const Identifier *nameId(const QString &name)
{ return new Identifier(name.toLatin1().constData(), name.toLatin1().size()); } { 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); a->setType(ty);
return a; return a;
} }
FullySpecifiedType voidTy() static FullySpecifiedType voidTy()
{ return FullySpecifiedType(new VoidType); } { return FullySpecifiedType(new VoidType); }
FullySpecifiedType intTy() static FullySpecifiedType intTy()
{ return FullySpecifiedType(new IntegerType(IntegerType::Int)); } { 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); fn->setReturnType(ret);
return FullySpecifiedType(fn); 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->setReturnType(ret);
fn->addMember(arg("a0", a0)); fn->addMember(arg("a0", a0));
return FullySpecifiedType(fn); 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)); } { return FullySpecifiedType(new PointerType(el)); }
FullySpecifiedType ref(const FullySpecifiedType &el) static FullySpecifiedType ref(const FullySpecifiedType &el)
{ return FullySpecifiedType(new ReferenceType(el, false)); } { return FullySpecifiedType(new ReferenceType(el, false)); }
FullySpecifiedType rref(const FullySpecifiedType &el) static FullySpecifiedType rref(const FullySpecifiedType &el)
{ return FullySpecifiedType(new ReferenceType(el, true)); } { return FullySpecifiedType(new ReferenceType(el, true)); }
FullySpecifiedType arr(const FullySpecifiedType &el) static FullySpecifiedType arr(const FullySpecifiedType &el)
{ return FullySpecifiedType(new ArrayType(el, 4)); } { 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; } { FullySpecifiedType r(el); r.setConst(true); return r; }
static QString toString(Overview::StarBindFlags starBindFlags)
void addRow(const FullySpecifiedType &f, QString result, QString name = QString())
{ {
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() void tst_TypePrettyPrinter::basic_data()
{ {
// seems it now works without a translation unit
// Control c;
// TranslationUnit t(&c, 0);
// unit = 0;
QTest::addColumn<FullySpecifiedType>("type"); QTest::addColumn<FullySpecifiedType>("type");
QTest::addColumn<Overview::StarBindFlags>("starBindFlags");
QTest::addColumn<QString>("name"); QTest::addColumn<QString>("name");
QTest::addColumn<QString>("result"); QTest::addColumn<QString>("result");
addRow(voidTy(), "void"); // Define some often used flag combinations.
addRow(cnst(voidTy()), "const void"); const Overview::StarBindFlags bindToNothing = 0;
addRow(ptr(fnTy("foo", voidTy())), "void (*)()"); const Overview::StarBindFlags bindToBothSpecifiers
addRow(ptr(fnTy("foo", voidTy())), "void (*foo)()", "foo"); = 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 // The star bindings should not affect declarations without a star or reference sign.
addRow(voidTy(), "void foo", "foo"); addRow(voidTy(), bindToNothing, "void");
addRow(ptr(voidTy()), "void *foo", "foo"); addRow(voidTy(), bindToAll, "void");
addRow(cnst(ptr(voidTy())), "void *const foo", "foo"); addRow(voidTy(), bindToAll, "void foo", "foo");
addRow(arr(voidTy()), "void foo[]", "foo"); addRow(voidTy(), bindToNothing, "void foo", "foo");
addRow(ptr(arr(voidTy())), "void (*foo)[]", "foo");
// pointers addRow(cnst(voidTy()), bindToNothing, "const void");
addRow(ptr(voidTy()), "void *"); addRow(cnst(voidTy()), bindToAll, "const void");
addRow(ptr(ptr(voidTy())), "void **"); addRow(cnst(voidTy()), bindToNothing, "const void foo", "foo");
addRow(cnst(voidTy()), bindToAll, "const void foo", "foo");
addRow(ptr(cnst(voidTy())), "const void *"); addRow(arr(voidTy()), bindToNothing, "void[]");
addRow(cnst(ptr(cnst(voidTy()))), "const void *const"); addRow(arr(voidTy()), bindToAll, "void[]");
addRow(cnst(ptr(voidTy())), "void *const"); addRow(arr(voidTy()), bindToNothing, "void foo[]", "foo");
addRow(arr(voidTy()), bindToAll, "void foo[]", "foo");
addRow(ptr(ptr(cnst(voidTy()))), "const void **"); addRow(fnTy("foo", voidTy(), intTy()), bindToNothing, "void foo(int)", "foo");
addRow(ptr(cnst(ptr(cnst(voidTy())))), "const void *const*"); addRow(fnTy("foo", voidTy(), intTy()), bindToAll, "void foo(int)", "foo");
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(arr(voidTy()), "void[]"); // Pointers to functions and arrays are also excluded. It seems to be quite unusal to have
addRow(arr(ptr(voidTy())), "void *[]"); // a space there.
addRow(ptr(arr(voidTy())), "void (*)[]"); addRow(ptr(fnTy("foo", voidTy())), bindToAll, "void (*)()");
addRow(ptr(arr(arr(voidTy()))), "void (*)[][]"); addRow(ptr(fnTy("foo", voidTy())), bindToNothing, "void (*)()");
addRow(ptr(arr(ptr(voidTy()))), "void *(*)[]"); addRow(ptr(fnTy("foo", voidTy())), bindToAll, "void (*foo)()", "foo");
addRow(arr(ptr(arr(voidTy()))), "void (*[])[]"); addRow(ptr(fnTy("foo", voidTy())), bindToNothing, "void (*foo)()", "foo");
// references addRow(ptr(arr(voidTy())), bindToNothing, "void (*)[]");
addRow(ref(voidTy()), "void &"); addRow(ptr(arr(voidTy())), bindToAll, "void (*)[]");
addRow(ref(ref(voidTy())), "void & &");
addRow(ref(cnst(voidTy())), "const void &"); addRow(ptr(arr(arr(voidTy()))), bindToNothing, "void (*)[][]");
addRow(cnst(ref(cnst(voidTy()))), "const void &const"); addRow(ptr(arr(arr(voidTy()))), bindToAll, "void (*)[][]");
addRow(cnst(ref(voidTy())), "void &const");
addRow(ref(ref(cnst(voidTy()))), "const void & &"); // Pointers only
addRow(ref(cnst(ref(cnst(voidTy())))), "const void &const&"); addRow(ptr(voidTy()), Overview::BindToTypeName, "void*");
addRow(cnst(ref(ref(cnst(voidTy())))), "const void & &const"); addRow(ptr(voidTy()), bindToAll, "void*");
addRow(cnst(ref(cnst(ref(cnst(voidTy()))))), "const void &const&const"); addRow(ptr(voidTy()), bindToNothing, "void *");
addRow(ref(cnst(ref(voidTy()))), "void &const&"); addRow(ptr(voidTy()), Overview::BindToIdentifier, "void *foo", "foo");
addRow(cnst(ref(ref(voidTy()))), "void & &const"); addRow(ptr(voidTy()), Overview::BindToTypeName, "void* foo", "foo");
addRow(cnst(ref(cnst(ref(voidTy())))), "void &const&const"); 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(ptr(ptr(voidTy())), Overview::BindToTypeName, "void**");
addRow(arr(ref(voidTy())), "void &[]"); addRow(ptr(ptr(voidTy())), bindToAll, "void**");
addRow(ref(arr(voidTy())), "void (&)[]"); addRow(ptr(ptr(voidTy())), bindToNothing, "void **");
addRow(ref(arr(arr(voidTy()))), "void (&)[][]"); addRow(ptr(ptr(voidTy())), Overview::BindToIdentifier, "void **foo", "foo");
addRow(ref(arr(ref(voidTy()))), "void &(&)[]"); addRow(ptr(ptr(voidTy())), Overview::BindToTypeName, "void** foo", "foo");
addRow(arr(ref(arr(voidTy()))), "void (&[])[]"); 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(ptr(cnst(voidTy())), bindToAll, "const void*");
addRow(rref(voidTy()), "void &&"); addRow(ptr(cnst(voidTy())), bindToNothing, "const void *");
addRow(rref(cnst(voidTy())), "const void &&");
addRow(rref(arr(voidTy())), "void (&&)[]"); addRow(cnst(ptr(voidTy())), Overview::BindToIdentifier, "void * const foo", "foo");
addRow(rref(arr(arr(voidTy()))), "void (&&)[][]"); 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(cnst(ptr(cnst(voidTy()))), bindToAll, "const void*const");
addRow(ptr(fnTy("foo", voidTy(), intTy())), "void (*foo)(int)", "foo"); addRow(cnst(ptr(cnst(voidTy()))), Overview::BindToTypeName, "const void* const");
addRow(ptr(fnTy("foo", voidTy(), ptr(voidTy()))), "void (*foo)(void *)", "foo"); addRow(cnst(ptr(cnst(voidTy()))), Overview::BindToRightSpecifier, "const void *const");
addRow(fnTy("foo", voidTy(), intTy()), "void foo(int)", "foo"); addRow(cnst(ptr(cnst(voidTy()))), bindToNothing, "const void * const");
addRow(fnTy("foo", voidTy(), ptr(voidTy())), "void foo(void *)", "foo");
// functions with ptr or ref returns addRow(cnst(ptr(voidTy())), Overview::BindToIdentifier, "void * const");
addRow(ptr(fnTy("foo", ptr(voidTy()), intTy())), "void *(*foo)(int)", "foo"); addRow(cnst(ptr(voidTy())), Overview::BindToTypeName, "void* const");
addRow(ptr(fnTy("foo", ref(voidTy()), ptr(voidTy()))), "void &(*foo)(void *)", "foo"); addRow(cnst(ptr(voidTy())), Overview::BindToRightSpecifier, "void *const");
addRow(fnTy("foo", ptr(voidTy()), intTy()), "void *foo(int)", "foo"); addRow(cnst(ptr(voidTy())), bindToTypeAndRightSpecifier, "void*const");
addRow(fnTy("foo", ref(voidTy()), ptr(voidTy())), "void &foo(void *)", "foo"); 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() void tst_TypePrettyPrinter::basic()
{ {
QFETCH(FullySpecifiedType, type); QFETCH(FullySpecifiedType, type);
QFETCH(Overview::StarBindFlags, starBindFlags);
QFETCH(QString, name); QFETCH(QString, name);
QFETCH(QString, result); QFETCH(QString, result);
Overview o; Overview o;
o.showReturnTypes = true; o.showReturnTypes = true;
o.starBindFlags = starBindFlags;
TypePrettyPrinter pp(&o); TypePrettyPrinter pp(&o);
QCOMPARE(pp(type, name), result); QCOMPARE(pp(type, name), result);
} }