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,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()

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