diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -139,7 +139,6 @@ } bool isComparisonOp() const { return isComparisonOp(getOperator()); } - /// Is this written as an infix binary operator? bool isInfixBinaryOp() const; /// Returns the location of the operator symbol in the expression. diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -46,15 +46,18 @@ //===----------------------------------------------------------------------===// bool CXXOperatorCallExpr::isInfixBinaryOp() const { - // An infix binary operator is any operator with two arguments other than - // operator() and operator[]. Note that none of these operators can have - // default arguments, so it suffices to check the number of argument - // expressions. if (getNumArgs() != 2) return false; switch (getOperator()) { - case OO_Call: case OO_Subscript: + // operator() may have two arguments, but it's not a binary operator + case OO_Call: + // operator[] takes two arguments but it's not infix + case OO_Subscript: + // Postfix unary operators (++ and --) take 2 arguments to differ from their + // prefix counterparts + case OO_PlusPlus: + case OO_MinusMinus: return false; default: return true; diff --git a/clang/unittests/Tooling/CMakeLists.txt b/clang/unittests/Tooling/CMakeLists.txt --- a/clang/unittests/Tooling/CMakeLists.txt +++ b/clang/unittests/Tooling/CMakeLists.txt @@ -18,6 +18,7 @@ CastExprTest.cpp CommentHandlerTest.cpp CompilationDatabaseTest.cpp + CXXOperatorCallExprTest.cpp DependencyScannerTest.cpp DiagnosticsYamlTest.cpp ExecutionTest.cpp diff --git a/clang/unittests/Tooling/CXXOperatorCallExprTest.cpp b/clang/unittests/Tooling/CXXOperatorCallExprTest.cpp new file mode 100644 --- /dev/null +++ b/clang/unittests/Tooling/CXXOperatorCallExprTest.cpp @@ -0,0 +1,77 @@ +//===- unittests/Tooling/CXXOperatorCallExprTest.cpp ----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Unit tests for the predicates in CXXOperatorCallExpr. +// +//===----------------------------------------------------------------------===// + +#include "TestVisitor.h" +#include "gtest/gtest.h" + +namespace clang { +namespace { + +TEST(CXXOperatorPredicatesTest, InfixBinaryOp) { + const std::string Code = R"cpp( + struct X{ + friend X operator+(X, X); + }; + void test(X x){ + x + x; + } + )cpp"; + + struct Visitor : TestVisitor { + bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { + EXPECT_TRUE(E->isInfixBinaryOp()); + return true; + } + } visitor; + visitor.runOver(Code); +} + +TEST(CXXOperatorPredicatesTest, CallLikeOp) { + const std::string Code = R"cpp( + struct X{ + int operator[](int idx); + }; + void test(X x){ + x[1]; + } + )cpp"; + struct Visitor : TestVisitor { + bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { + EXPECT_FALSE(E->isInfixBinaryOp()); + return true; + } + } visitor; + + visitor.runOver(Code); +} + +TEST(CXXOperatorPredicatesTest, PostfixUnaryOp) { + const std::string Code = R"cpp( + struct X{ + X operator++(int); + }; + void test(X x){ + x++; + } + )cpp"; + + struct Visitor : TestVisitor { + bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { + EXPECT_FALSE(E->isInfixBinaryOp()); + return true; + } + } visitor; + + visitor.runOver(Code); +} +} // namespace +} // namespace clang