forked from qt-creator/qt-creator
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:
committed by
Erik Verbruggen
parent
b6a9d58f69
commit
8c3794f9d1
@@ -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);
|
||||
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()
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user