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;
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

View File

@@ -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

View File

@@ -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,9 +470,17 @@ void TypePrettyPrinter::prependSpaceUnlessBracket()
const QChar ch = _text.at(0);
if (ch != 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()
{

View File

@@ -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

View File

@@ -27,25 +27,23 @@
**
****************************************************************************/
#include <QtTest>
#include <QObject>
#include <QList>
#include <QtTest>
#include <FullySpecifiedType.h>
#include <Type.h>
#include <CoreTypes.h>
#include <Symbols.h>
#include <TranslationUnit.h>
#include <Control.h>
#include <Names.h>
#include <FullySpecifiedType.h>
#include <Literals.h>
#include <Overview.h>
#include <Scope.h>
#include <Symbols.h>
#include <Type.h>
#include <TypePrettyPrinter.h>
//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<FullySpecifiedType>("type");
QTest::addColumn<Overview::StarBindFlags>("starBindFlags");
QTest::addColumn<QString>("name");
QTest::addColumn<QString>("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);
}