diff options
author | Nikolai Kosjar <[email protected]> | 2013-01-10 17:11:03 +0100 |
---|---|---|
committer | Erik Verbruggen <[email protected]> | 2013-01-23 14:30:39 +0100 |
commit | 8c3794f9d104a39b7f91764b7725dad8726fbde0 (patch) | |
tree | 0b370c80468fbf185b99cf9a3f4e452ff171d6b3 /src/libs | |
parent | b6a9d58f690834c7629762a21e520f72a282d2a8 (diff) |
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 <[email protected]>
Diffstat (limited to 'src/libs')
-rw-r--r-- | src/libs/cplusplus/Overview.cpp | 9 | ||||
-rw-r--r-- | src/libs/cplusplus/Overview.h | 59 | ||||
-rw-r--r-- | src/libs/cplusplus/TypePrettyPrinter.cpp | 141 | ||||
-rw-r--r-- | src/libs/cplusplus/TypePrettyPrinter.h | 29 |
4 files changed, 197 insertions, 41 deletions
diff --git a/src/libs/cplusplus/Overview.cpp b/src/libs/cplusplus/Overview.cpp index 748033d8599..330d2a62dd1 100644 --- a/src/libs/cplusplus/Overview.cpp +++ b/src/libs/cplusplus/Overview.cpp @@ -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 diff --git a/src/libs/cplusplus/Overview.h b/src/libs/cplusplus/Overview.h index 344c976f998..339a6d8fc7a 100644 --- a/src/libs/cplusplus/Overview.h +++ b/src/libs/cplusplus/Overview.h @@ -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 diff --git a/src/libs/cplusplus/TypePrettyPrinter.cpp b/src/libs/cplusplus/TypePrettyPrinter.cpp index 8c5bdf51102..84f602337f3 100644 --- a/src/libs/cplusplus/TypePrettyPrinter.cpp +++ b/src/libs/cplusplus/TypePrettyPrinter.cpp @@ -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() diff --git a/src/libs/cplusplus/TypePrettyPrinter.h b/src/libs/cplusplus/TypePrettyPrinter.h index ffda3113c14..1628306d0ac 100644 --- a/src/libs/cplusplus/TypePrettyPrinter.h +++ b/src/libs/cplusplus/TypePrettyPrinter.h @@ -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 |