From 4e8b7eee9ddf2feb8f7ced24bb9425539059e698 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 20 Oct 2022 13:43:10 +0200 Subject: [PATCH] Cpp: support space ship operator in lexer Fixes: QTCREATORBUG-27503 Change-Id: Idbff5a9b5b2e6e841e298ca6f706ef3c6aa1622b Reviewed-by: Christian Kandeler --- src/libs/3rdparty/cplusplus/Bind.cpp | 4 + src/libs/3rdparty/cplusplus/Lexer.cpp | 7 +- src/libs/3rdparty/cplusplus/Names.h | 5 +- src/libs/3rdparty/cplusplus/Parser.cpp | 39 +++++----- src/libs/3rdparty/cplusplus/Token.cpp | 1 + src/libs/3rdparty/cplusplus/Token.h | 2 + src/libs/cplusplus/NamePrettyPrinter.cpp | 3 + src/libs/cplusplus/pp-engine.cpp | 77 ++++++++++++------- .../cppeditor/cppcodemodelinspectordumper.cpp | 1 + src/plugins/cppeditor/projectpart.cpp | 1 + tests/auto/cplusplus/lexer/tst_lexer.cpp | 2 + 11 files changed, 93 insertions(+), 49 deletions(-) diff --git a/src/libs/3rdparty/cplusplus/Bind.cpp b/src/libs/3rdparty/cplusplus/Bind.cpp index effaac4b65a..7f10c79428c 100644 --- a/src/libs/3rdparty/cplusplus/Bind.cpp +++ b/src/libs/3rdparty/cplusplus/Bind.cpp @@ -915,6 +915,10 @@ OperatorNameId::Kind Bind::cppOperator(OperatorAST *ast) kind = OperatorNameId::ArrayAccessOp; break; + case T_LESS_EQUAL_GREATER: + kind = OperatorNameId::SpaceShipOp; + break; + default: kind = OperatorNameId::InvalidOp; } // switch diff --git a/src/libs/3rdparty/cplusplus/Lexer.cpp b/src/libs/3rdparty/cplusplus/Lexer.cpp index 8e1f7e2899e..e2f1b4e0e6b 100644 --- a/src/libs/3rdparty/cplusplus/Lexer.cpp +++ b/src/libs/3rdparty/cplusplus/Lexer.cpp @@ -612,7 +612,12 @@ void Lexer::scan_helper(Token *tok) tok->f.kind = T_LESS_LESS; } else if (_yychar == '=') { yyinp(); - tok->f.kind = T_LESS_EQUAL; + if (_languageFeatures.cxx20Enabled && _yychar == '>') { + yyinp(); + tok->f.kind = T_LESS_EQUAL_GREATER; + } else { + tok->f.kind = T_LESS_EQUAL; + } } else if (_yychar == ':') { if (*(_currentChar+1) != ':' || *(_currentChar+2) == ':' || *(_currentChar+2) == '>') { yyinp(); diff --git a/src/libs/3rdparty/cplusplus/Names.h b/src/libs/3rdparty/cplusplus/Names.h index 7913c9b0bc2..ede94eb7814 100644 --- a/src/libs/3rdparty/cplusplus/Names.h +++ b/src/libs/3rdparty/cplusplus/Names.h @@ -180,7 +180,7 @@ public: ! = < > += -= *= /= %= ^= &= |= << >> >>= <<= == != <= >= && || ++ -- , ->* -> - () [] + () [] <=> */ enum Kind { InvalidOp, @@ -225,7 +225,8 @@ public: ArrowStarOp, ArrowOp, FunctionCallOp, - ArrayAccessOp + ArrayAccessOp, + SpaceShipOp }; public: diff --git a/src/libs/3rdparty/cplusplus/Parser.cpp b/src/libs/3rdparty/cplusplus/Parser.cpp index 430b19efbe4..cb7bfa3a1b6 100644 --- a/src/libs/3rdparty/cplusplus/Parser.cpp +++ b/src/libs/3rdparty/cplusplus/Parser.cpp @@ -98,10 +98,11 @@ enum { And = 8, Equality = 9, Relational = 10, - Shift = 11, - Additive = 12, - Multiplicative = 13, - PointerToMember = 14 + ThreeWayComp = 11, + Shift = 12, + Additive = 13, + Multiplicative = 14, + PointerToMember = 15 }; } // namespace Precedece @@ -116,29 +117,30 @@ inline int precedence(int tokenKind, bool templateArguments) return Prec::Assignment; switch (tokenKind) { - case T_COMMA: return Prec::Comma; - case T_QUESTION: return Prec::Conditional; - case T_PIPE_PIPE: return Prec::LogicalOr; - case T_AMPER_AMPER: return Prec::LogicalAnd; - case T_PIPE: return Prec::InclusiveOr; - case T_CARET: return Prec::ExclusiveOr; - case T_AMPER: return Prec::And; + case T_COMMA: return Prec::Comma; + case T_QUESTION: return Prec::Conditional; + case T_PIPE_PIPE: return Prec::LogicalOr; + case T_AMPER_AMPER: return Prec::LogicalAnd; + case T_PIPE: return Prec::InclusiveOr; + case T_CARET: return Prec::ExclusiveOr; + case T_AMPER: return Prec::And; case T_EQUAL_EQUAL: - case T_EXCLAIM_EQUAL: return Prec::Equality; + case T_EXCLAIM_EQUAL: return Prec::Equality; case T_GREATER: case T_LESS: case T_LESS_EQUAL: - case T_GREATER_EQUAL: return Prec::Relational; + case T_GREATER_EQUAL: return Prec::Relational; + case T_LESS_EQUAL_GREATER: return Prec::ThreeWayComp; case T_LESS_LESS: - case T_GREATER_GREATER: return Prec::ExclusiveOr; + case T_GREATER_GREATER: return Prec::ExclusiveOr; case T_PLUS: - case T_MINUS: return Prec::Additive; + case T_MINUS: return Prec::Additive; case T_STAR: case T_SLASH: - case T_PERCENT: return Prec::Multiplicative; + case T_PERCENT: return Prec::Multiplicative; case T_ARROW_STAR: - case T_DOT_STAR: return Prec::PointerToMember; - default: return Prec::Unknown; + case T_DOT_STAR: return Prec::PointerToMember; + default: return Prec::Unknown; } } @@ -1300,6 +1302,7 @@ bool Parser::parseOperator(OperatorAST *&node) // ### FIXME case T_GREATER_EQUAL: case T_GREATER_GREATER_EQUAL: case T_LESS_EQUAL: + case T_LESS_EQUAL_GREATER: case T_LESS_LESS_EQUAL: case T_MINUS_EQUAL: case T_PERCENT_EQUAL: diff --git a/src/libs/3rdparty/cplusplus/Token.cpp b/src/libs/3rdparty/cplusplus/Token.cpp index 1d9127b2dda..31fdb2036c2 100644 --- a/src/libs/3rdparty/cplusplus/Token.cpp +++ b/src/libs/3rdparty/cplusplus/Token.cpp @@ -91,6 +91,7 @@ const char *token_names[] = { ("<="), ("<<"), ("<<="), + ("<=>"), ("-"), ("-="), ("--"), diff --git a/src/libs/3rdparty/cplusplus/Token.h b/src/libs/3rdparty/cplusplus/Token.h index f5459786694..3a04a44a86a 100644 --- a/src/libs/3rdparty/cplusplus/Token.h +++ b/src/libs/3rdparty/cplusplus/Token.h @@ -99,6 +99,7 @@ enum Kind { T_LESS_EQUAL, T_LESS_LESS, T_LESS_LESS_EQUAL, + T_LESS_EQUAL_GREATER, T_MINUS, T_MINUS_EQUAL, T_MINUS_MINUS, @@ -446,6 +447,7 @@ struct LanguageFeatures unsigned int cxxEnabled : 1; unsigned int cxx11Enabled : 1; unsigned int cxx14Enabled : 1; + unsigned int cxx20Enabled : 1; unsigned int objCEnabled : 1; unsigned int c99Enabled : 1; }; diff --git a/src/libs/cplusplus/NamePrettyPrinter.cpp b/src/libs/cplusplus/NamePrettyPrinter.cpp index 8a2ff8d6f3c..9685cdf2a1b 100644 --- a/src/libs/cplusplus/NamePrettyPrinter.cpp +++ b/src/libs/cplusplus/NamePrettyPrinter.cpp @@ -222,6 +222,9 @@ void NamePrettyPrinter::visit(const OperatorNameId *name) case OperatorNameId::ArrayAccessOp: _name += QLatin1String("[]"); break; + case OperatorNameId::SpaceShipOp: + _name += QLatin1String("<=>"); + break; } // switch } diff --git a/src/libs/cplusplus/pp-engine.cpp b/src/libs/cplusplus/pp-engine.cpp index 40b7d44e66e..50cd1241de8 100644 --- a/src/libs/cplusplus/pp-engine.cpp +++ b/src/libs/cplusplus/pp-engine.cpp @@ -202,6 +202,24 @@ struct Value inline bool is_zero () const { return l == 0; } + template static bool cmpImpl(T v1, T v2) + { + if (v1 < v2) + return -1; + if (v1 > v2) + return 1; + return 0; + } + Value cmp(const Value &other) const + { + Value v = *this; + if (v.is_ulong() || other.is_ulong()) + v.set_long(cmpImpl(v.ul, other.ul)); + else + v.set_long(cmpImpl(v.l, other.l)); + return v; + } + #define PP_DEFINE_BIN_OP(name, op) \ inline Value operator op(const Value &other) const \ { \ @@ -488,24 +506,25 @@ private: inline int precedence(int tokenKind) const { switch (tokenKind) { - case T_PIPE_PIPE: return 0; - case T_AMPER_AMPER: return 1; - case T_PIPE: return 2; - case T_CARET: return 3; - case T_AMPER: return 4; + case T_PIPE_PIPE: return 0; + case T_AMPER_AMPER: return 1; + case T_PIPE: return 2; + case T_CARET: return 3; + case T_AMPER: return 4; case T_EQUAL_EQUAL: - case T_EXCLAIM_EQUAL: return 5; + case T_EXCLAIM_EQUAL: return 5; case T_GREATER: case T_LESS: case T_LESS_EQUAL: - case T_GREATER_EQUAL: return 6; + case T_GREATER_EQUAL: return 6; + case T_LESS_EQUAL_GREATER: return 7; case T_LESS_LESS: - case T_GREATER_GREATER: return 7; + case T_GREATER_GREATER: return 8; case T_PLUS: - case T_MINUS: return 8; + case T_MINUS: return 9; case T_STAR: case T_SLASH: - case T_PERCENT: return 9; + case T_PERCENT: return 10; default: return -1; @@ -525,6 +544,7 @@ private: case T_GREATER: case T_LESS: case T_LESS_EQUAL: + case T_LESS_EQUAL_GREATER: case T_GREATER_EQUAL: case T_LESS_LESS: case T_GREATER_GREATER: @@ -543,24 +563,25 @@ private: static inline Value evaluate_expression(int tokenKind, const Value &lhs, const Value &rhs) { switch (tokenKind) { - case T_PIPE_PIPE: return lhs || rhs; - case T_AMPER_AMPER: return lhs && rhs; - case T_PIPE: return lhs | rhs; - case T_CARET: return lhs ^ rhs; - case T_AMPER: return lhs & rhs; - case T_EQUAL_EQUAL: return lhs == rhs; - case T_EXCLAIM_EQUAL: return lhs != rhs; - case T_GREATER: return lhs > rhs; - case T_LESS: return lhs < rhs; - case T_LESS_EQUAL: return lhs <= rhs; - case T_GREATER_EQUAL: return lhs >= rhs; - case T_LESS_LESS: return lhs << rhs; - case T_GREATER_GREATER: return lhs >> rhs; - case T_PLUS: return lhs + rhs; - case T_MINUS: return lhs - rhs; - case T_STAR: return lhs * rhs; - case T_SLASH: return rhs.is_zero() ? Value() : lhs / rhs; - case T_PERCENT: return rhs.is_zero() ? Value() : lhs % rhs; + case T_PIPE_PIPE: return lhs || rhs; + case T_AMPER_AMPER: return lhs && rhs; + case T_PIPE: return lhs | rhs; + case T_CARET: return lhs ^ rhs; + case T_AMPER: return lhs & rhs; + case T_EQUAL_EQUAL: return lhs == rhs; + case T_EXCLAIM_EQUAL: return lhs != rhs; + case T_GREATER: return lhs > rhs; + case T_LESS: return lhs < rhs; + case T_LESS_EQUAL: return lhs <= rhs; + case T_LESS_EQUAL_GREATER: return lhs.cmp(rhs); + case T_GREATER_EQUAL: return lhs >= rhs; + case T_LESS_LESS: return lhs << rhs; + case T_GREATER_GREATER: return lhs >> rhs; + case T_PLUS: return lhs + rhs; + case T_MINUS: return lhs - rhs; + case T_STAR: return lhs * rhs; + case T_SLASH: return rhs.is_zero() ? Value() : lhs / rhs; + case T_PERCENT: return rhs.is_zero() ? Value() : lhs % rhs; default: return Value(); diff --git a/src/plugins/cppeditor/cppcodemodelinspectordumper.cpp b/src/plugins/cppeditor/cppcodemodelinspectordumper.cpp index 8d77db098bd..45de8f30539 100644 --- a/src/plugins/cppeditor/cppcodemodelinspectordumper.cpp +++ b/src/plugins/cppeditor/cppcodemodelinspectordumper.cpp @@ -219,6 +219,7 @@ QString Utils::toString(CPlusPlus::Kind kind) TOKEN(T_LBRACKET); TOKEN(T_LESS); TOKEN(T_LESS_EQUAL); + TOKEN(T_LESS_EQUAL_GREATER); TOKEN(T_LESS_LESS); TOKEN(T_LESS_LESS_EQUAL); TOKEN(T_LPAREN); diff --git a/src/plugins/cppeditor/projectpart.cpp b/src/plugins/cppeditor/projectpart.cpp index 7660499bc9c..9cab9a6df2b 100644 --- a/src/plugins/cppeditor/projectpart.cpp +++ b/src/plugins/cppeditor/projectpart.cpp @@ -163,6 +163,7 @@ CPlusPlus::LanguageFeatures ProjectPart::deriveLanguageFeatures() const CPlusPlus::LanguageFeatures features; features.cxx11Enabled = languageVersion >= Utils::LanguageVersion::CXX11; features.cxx14Enabled = languageVersion >= Utils::LanguageVersion::CXX14; + features.cxx20Enabled = languageVersion >= Utils::LanguageVersion::CXX20; features.cxxEnabled = hasCxx; features.c99Enabled = languageVersion >= Utils::LanguageVersion::C99; features.objCEnabled = languageExtensions.testFlag(Utils::LanguageExtension::ObjectiveC); diff --git a/tests/auto/cplusplus/lexer/tst_lexer.cpp b/tests/auto/cplusplus/lexer/tst_lexer.cpp index a4c16bc8b07..641b62f248c 100644 --- a/tests/auto/cplusplus/lexer/tst_lexer.cpp +++ b/tests/auto/cplusplus/lexer/tst_lexer.cpp @@ -442,6 +442,7 @@ void tst_SimpleLexer::ppOpOrPunc() const QByteArray source = QTest::currentDataTag(); LanguageFeatures languageFeatures; languageFeatures.cxxEnabled = true; + languageFeatures.cxx20Enabled = true; run(source, toTokens({unsigned(expectedTokenKind)}), false, CompareKind, true, languageFeatures); } @@ -492,6 +493,7 @@ void tst_SimpleLexer::ppOpOrPunc_data() QTest::newRow("==") << T_EQUAL_EQUAL; QTest::newRow("!=") << T_EXCLAIM_EQUAL; QTest::newRow("<=") << T_LESS_EQUAL; + QTest::newRow("<=>") << T_LESS_EQUAL_GREATER; QTest::newRow(">=") << T_GREATER_EQUAL; QTest::newRow("&&") << T_AMPER_AMPER; QTest::newRow("||") << T_PIPE_PIPE;