diff --git a/clang/include/clang/Tooling/Syntax/Nodes.h b/clang/include/clang/Tooling/Syntax/Nodes.h --- a/clang/include/clang/Tooling/Syntax/Nodes.h +++ b/clang/include/clang/Tooling/Syntax/Nodes.h @@ -50,6 +50,7 @@ StringLiteralExpression, BoolLiteralExpression, CxxNullPtrExpression, + UserDefinedLiteralExpression, IdExpression, // Statements. @@ -325,6 +326,17 @@ syntax::Leaf *nullPtrKeyword(); }; +/// Expression for user-defined literal. C++ [lex.ext] +class UserDefinedLiteralExpression final : public Expression { +public: + UserDefinedLiteralExpression() + : Expression(NodeKind::UserDefinedLiteralExpression) {} + static bool classof(const Node *N) { + return N->kind() == NodeKind::UserDefinedLiteralExpression; + } + syntax::Leaf *literalToken(); +}; + /// An abstract class for prefix and postfix unary operators. class UnaryOperatorExpression : public Expression { public: diff --git a/clang/lib/Tooling/Syntax/BuildTree.cpp b/clang/lib/Tooling/Syntax/BuildTree.cpp --- a/clang/lib/Tooling/Syntax/BuildTree.cpp +++ b/clang/lib/Tooling/Syntax/BuildTree.cpp @@ -627,6 +627,26 @@ return NNS; } + bool TraverseUserDefinedLiteral(UserDefinedLiteral *S) { + // The user-defined literal `1.2_w` corresponds to *one* token. The semantic + // node for it however may have two children nodes, both with valid + // `SourceLocation`s. As a result one of these nodes has a valid + // `SourceLocation` that doesn't point to a token. + // + // If we traverse the children of a user-defined literal, we then arrive to + // a semantic node that doesn't have a token, and that breaks an invariant + // of the syntax tree. For that reason we skip traversing user-defined + // literal children. + + return WalkUpFromUserDefinedLiteral(S); + } + + bool WalkUpFromUserDefinedLiteral(UserDefinedLiteral *S) { + Builder.markChildToken(S->getBeginLoc(), syntax::NodeRole::LiteralToken); + Builder.foldNode(Builder.getExprRange(S), + new (allocator()) syntax::UserDefinedLiteralExpression, S); + return true; + } bool WalkUpFromDeclRefExpr(DeclRefExpr *S) { if (auto *NNS = BuildNestedNameSpecifier(S->getQualifierLoc())) Builder.markChild(NNS, syntax::NodeRole::IdExpression_qualifier); diff --git a/clang/lib/Tooling/Syntax/Nodes.cpp b/clang/lib/Tooling/Syntax/Nodes.cpp --- a/clang/lib/Tooling/Syntax/Nodes.cpp +++ b/clang/lib/Tooling/Syntax/Nodes.cpp @@ -32,6 +32,8 @@ return OS << "BoolLiteralExpression"; case NodeKind::CxxNullPtrExpression: return OS << "CxxNullPtrExpression"; + case NodeKind::UserDefinedLiteralExpression: + return OS << "UserDefinedLiteralExpression"; case NodeKind::PrefixUnaryOperatorExpression: return OS << "PrefixUnaryOperatorExpression"; case NodeKind::PostfixUnaryOperatorExpression: @@ -252,6 +254,11 @@ findChild(syntax::NodeRole::LiteralToken)); } +syntax::Leaf *syntax::UserDefinedLiteralExpression::literalToken() { + return llvm::cast_or_null( + findChild(syntax::NodeRole::LiteralToken)); +} + syntax::Expression *syntax::BinaryOperatorExpression::lhs() { return llvm::cast_or_null( findChild(syntax::NodeRole::BinaryOperatorExpression_leftHandSide)); diff --git a/clang/unittests/Tooling/Syntax/TreeTest.cpp b/clang/unittests/Tooling/Syntax/TreeTest.cpp --- a/clang/unittests/Tooling/Syntax/TreeTest.cpp +++ b/clang/unittests/Tooling/Syntax/TreeTest.cpp @@ -1184,6 +1184,93 @@ )txt")); } +TEST_P(SyntaxTreeTest, UserDefinedLiteral) { + if (!GetParam().isCXX11OrLater()) { + return; + } + EXPECT_TRUE(treeDumpEqual( + R"cpp( +long double operator "" _w(long double); +unsigned operator "" _w(const char*); +template unsigned operator "" _x(); +int main() { + 1.2_w; // calls operator "" _w(1.2L) + 12_w; // calls operator "" _w("12") + 12_x; // calls operator<'1', '2'> "" _x() +} + )cpp", + R"txt( +*: TranslationUnit +|-SimpleDeclaration +| |-long +| |-double +| |-SimpleDeclarator +| | |-operator +| | |-"" +| | |-_w +| | `-ParametersAndQualifiers +| | |-( +| | |-SimpleDeclaration +| | | |-long +| | | `-double +| | `-) +| `-; +|-SimpleDeclaration +| |-unsigned +| |-SimpleDeclarator +| | |-operator +| | |-"" +| | |-_w +| | `-ParametersAndQualifiers +| | |-( +| | |-SimpleDeclaration +| | | |-const +| | | |-char +| | | `-SimpleDeclarator +| | | `-* +| | `-) +| `-; +|-TemplateDeclaration +| |-template +| |-< +| |-SimpleDeclaration +| | `-char +| |-... +| |-> +| `-SimpleDeclaration +| |-unsigned +| |-SimpleDeclarator +| | |-operator +| | |-"" +| | |-_x +| | `-ParametersAndQualifiers +| | |-( +| | `-) +| `-; +`-SimpleDeclaration + |-int + |-SimpleDeclarator + | |-main + | `-ParametersAndQualifiers + | |-( + | `-) + `-CompoundStatement + |-{ + |-ExpressionStatement + | |-UserDefinedLiteralExpression + | | `-1.2_w + | `-; + |-ExpressionStatement + | |-UserDefinedLiteralExpression + | | `-12_w + | `-; + |-ExpressionStatement + | |-UserDefinedLiteralExpression + | | `-12_x + | `-; + `-} +)txt")); +} TEST_P(SyntaxTreeTest, IntegerLiteral) { EXPECT_TRUE(treeDumpEqual( R"cpp(