Commit 8c3794f9 authored by Nikolai Kosjar's avatar Nikolai Kosjar Committed by Erik Verbruggen
Browse files

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: default avatarErik Verbruggen <erik.verbruggen@digia.com>
parent b6a9d58f
......@@ -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
......
......@@ -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
......
......@@ -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);
if (_text.startsWith(QLatin1Char('&')))
_text.prepend(QLatin1Char(' '));
const bool isIndirectionToFunction = type->elementType().type()->isFunctionType();
const bool isIndirectionToArray = type->elementType().type()->isArrayType();
const IndirectionType indirectionType = type->isRvalueReference()
? aRvalueReferenceType : aReferenceType;
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()
......
......@@ -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
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment