Skip to content

Commit

Permalink
Merge from 'master' to 'sycl-web' (#5)
Browse files Browse the repository at this point in the history
  CONFLICT (content): Merge conflict in clang/lib/Sema/Sema.cpp
  • Loading branch information
Fznamznon committed Feb 19, 2020
2 parents 1137134 + bcadb1f commit 68d4042
Show file tree
Hide file tree
Showing 1,494 changed files with 47,897 additions and 13,275 deletions.
204 changes: 190 additions & 14 deletions clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/FormatVariadic.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
Expand Down Expand Up @@ -304,6 +306,132 @@ static void transformSubToCanonicalAddExpr(BinaryOperatorKind &Opcode,
}
}

// to use in the template below
static OverloadedOperatorKind getOp(const BinaryOperator *Op) {
return BinaryOperator::getOverloadedOperator(Op->getOpcode());
}

static OverloadedOperatorKind getOp(const CXXOperatorCallExpr *Op) {
if (Op->getNumArgs() != 2)
return OO_None;
return Op->getOperator();
}

static std::pair<const Expr *, const Expr *>
getOperands(const BinaryOperator *Op) {
return {Op->getLHS()->IgnoreParenImpCasts(),
Op->getRHS()->IgnoreParenImpCasts()};
}

static std::pair<const Expr *, const Expr *>
getOperands(const CXXOperatorCallExpr *Op) {
return {Op->getArg(0)->IgnoreParenImpCasts(),
Op->getArg(1)->IgnoreParenImpCasts()};
}

template <typename TExpr>
static const TExpr *checkOpKind(const Expr *TheExpr,
OverloadedOperatorKind OpKind) {
const auto *AsTExpr = dyn_cast_or_null<TExpr>(TheExpr);
if (AsTExpr && getOp(AsTExpr) == OpKind)
return AsTExpr;

return nullptr;
}

// returns true if a subexpression has two directly equivalent operands and
// is already handled by operands/parametersAreEquivalent
template <typename TExpr, unsigned N>
static bool collectOperands(const Expr *Part,
SmallVector<const Expr *, N> &AllOperands,
OverloadedOperatorKind OpKind) {
if (const auto *BinOp = checkOpKind<TExpr>(Part, OpKind)) {
const std::pair<const Expr *, const Expr *> Operands = getOperands(BinOp);
if (areEquivalentExpr(Operands.first, Operands.second))
return true;
return collectOperands<TExpr>(Operands.first, AllOperands, OpKind) ||
collectOperands<TExpr>(Operands.second, AllOperands, OpKind);
}

AllOperands.push_back(Part);
return false;
}

template <typename TExpr>
static bool hasSameOperatorParent(const Expr *TheExpr,
OverloadedOperatorKind OpKind,
ASTContext &Context) {
// IgnoreParenImpCasts logic in reverse: skip surrounding uninteresting nodes
const DynTypedNodeList Parents = Context.getParents(*TheExpr);
for (ast_type_traits::DynTypedNode DynParent : Parents) {
if (const auto *Parent = DynParent.get<Expr>()) {
bool Skip = isa<ParenExpr>(Parent) || isa<ImplicitCastExpr>(Parent) ||
isa<FullExpr>(Parent) ||
isa<MaterializeTemporaryExpr>(Parent);
if (Skip && hasSameOperatorParent<TExpr>(Parent, OpKind, Context))
return true;
if (checkOpKind<TExpr>(Parent, OpKind))
return true;
}
}

return false;
}

template <typename TExpr>
static bool
markDuplicateOperands(const TExpr *TheExpr,
ast_matchers::internal::BoundNodesTreeBuilder *Builder,
ASTContext &Context) {
const OverloadedOperatorKind OpKind = getOp(TheExpr);
if (OpKind == OO_None)
return false;
// if there are no nested operators of the same kind, it's handled by
// operands/parametersAreEquivalent
const std::pair<const Expr *, const Expr *> Operands = getOperands(TheExpr);
if (!(checkOpKind<TExpr>(Operands.first, OpKind) ||
checkOpKind<TExpr>(Operands.second, OpKind)))
return false;

// if parent is the same kind of operator, it's handled by a previous call to
// markDuplicateOperands
if (hasSameOperatorParent<TExpr>(TheExpr, OpKind, Context))
return false;

SmallVector<const Expr *, 4> AllOperands;
if (collectOperands<TExpr>(Operands.first, AllOperands, OpKind))
return false;
if (collectOperands<TExpr>(Operands.second, AllOperands, OpKind))
return false;
size_t NumOperands = AllOperands.size();
llvm::SmallBitVector Duplicates(NumOperands);
for (size_t I = 0; I < NumOperands; I++) {
if (Duplicates[I])
continue;
bool FoundDuplicates = false;

for (size_t J = I + 1; J < NumOperands; J++) {
if (AllOperands[J]->HasSideEffects(Context))
break;

if (areEquivalentExpr(AllOperands[I], AllOperands[J])) {
FoundDuplicates = true;
Duplicates.set(J);
Builder->setBinding(
SmallString<11>(llvm::formatv("duplicate{0}", J)),
ast_type_traits::DynTypedNode::create(*AllOperands[J]));
}
}

if (FoundDuplicates)
Builder->setBinding(
SmallString<11>(llvm::formatv("duplicate{0}", I)),
ast_type_traits::DynTypedNode::create(*AllOperands[I]));
}

return Duplicates.any();
}

AST_MATCHER(Expr, isIntegerConstantExpr) {
if (Node.isInstantiationDependent())
return false;
Expand All @@ -314,6 +442,10 @@ AST_MATCHER(BinaryOperator, operandsAreEquivalent) {
return areEquivalentExpr(Node.getLHS(), Node.getRHS());
}

AST_MATCHER(BinaryOperator, nestedOperandsAreEquivalent) {
return markDuplicateOperands(&Node, Builder, Finder->getASTContext());
}

AST_MATCHER(ConditionalOperator, expressionsAreEquivalent) {
return areEquivalentExpr(Node.getTrueExpr(), Node.getFalseExpr());
}
Expand All @@ -323,6 +455,10 @@ AST_MATCHER(CallExpr, parametersAreEquivalent) {
areEquivalentExpr(Node.getArg(0), Node.getArg(1));
}

AST_MATCHER(CXXOperatorCallExpr, nestedParametersAreEquivalent) {
return markDuplicateOperands(&Node, Builder, Finder->getASTContext());
}

AST_MATCHER(BinaryOperator, binaryOperatorIsInMacro) {
return Node.getOperatorLoc().isMacroID();
}
Expand Down Expand Up @@ -484,8 +620,15 @@ static bool isNonConstReferenceType(QualType ParamType) {
// is a temporary expression. Whether the second parameter is checked is
// controlled by the parameter `ParamsToCheckCount`.
static bool
canOverloadedOperatorArgsBeModified(const FunctionDecl *OperatorDecl,
canOverloadedOperatorArgsBeModified(const CXXOperatorCallExpr *OperatorCall,
bool checkSecondParam) {
const auto *OperatorDecl =
dyn_cast_or_null<FunctionDecl>(OperatorCall->getCalleeDecl());
// if we can't find the declaration, conservatively assume it can modify
// arguments
if (!OperatorDecl)
return true;

unsigned ParamCount = OperatorDecl->getNumParams();

// Overloaded operators declared inside a class have only one param.
Expand Down Expand Up @@ -527,14 +670,7 @@ static bool retrieveRelationalIntegerConstantExpr(
Value = APSInt(32, false);
} else if (const auto *OverloadedOperatorExpr =
Result.Nodes.getNodeAs<CXXOperatorCallExpr>(OverloadId)) {
const auto *OverloadedFunctionDecl = dyn_cast_or_null<FunctionDecl>(OverloadedOperatorExpr->getCalleeDecl());
if (!OverloadedFunctionDecl)
return false;

if (canOverloadedOperatorArgsBeModified(OverloadedFunctionDecl, false))
return false;

if (canOverloadedOperatorArgsBeModified(OverloadedFunctionDecl, false))
if (canOverloadedOperatorArgsBeModified(OverloadedOperatorExpr, false))
return false;

if (const auto *Arg = OverloadedOperatorExpr->getArg(1)) {
Expand Down Expand Up @@ -714,6 +850,21 @@ void RedundantExpressionCheck::registerMatchers(MatchFinder *Finder) {
.bind("binary"),
this);

// Logical or bitwise operator with equivalent nested operands, like (X && Y
// && X) or (X && (Y && X))
Finder->addMatcher(
binaryOperator(anyOf(hasOperatorName("|"), hasOperatorName("&"),
hasOperatorName("||"), hasOperatorName("&&"),
hasOperatorName("^")),
nestedOperandsAreEquivalent(),
// Filter noisy false positives.
unless(isInTemplateInstantiation()),
unless(binaryOperatorIsInMacro()),
// TODO: if the banned macros are themselves duplicated
unless(hasDescendant(BannedIntegerLiteral)))
.bind("nested-duplicates"),
this);

// Conditional (trenary) operator with equivalent operands, like (Y ? X : X).
Finder->addMatcher(conditionalOperator(expressionsAreEquivalent(),
// Filter noisy false positives.
Expand All @@ -740,6 +891,19 @@ void RedundantExpressionCheck::registerMatchers(MatchFinder *Finder) {
.bind("call"),
this);

// Overloaded operators with equivalent operands.
Finder->addMatcher(
cxxOperatorCallExpr(
anyOf(hasOverloadedOperatorName("|"), hasOverloadedOperatorName("&"),
hasOverloadedOperatorName("||"),
hasOverloadedOperatorName("&&"),
hasOverloadedOperatorName("^")),
nestedParametersAreEquivalent(), argumentCountIs(2),
// Filter noisy false positives.
unless(isMacro()), unless(isInTemplateInstantiation()))
.bind("nested-duplicates"),
this);

// Match expressions like: !(1 | 2 | 3)
Finder->addMatcher(
implicitCastExpr(
Expand Down Expand Up @@ -1061,17 +1225,29 @@ void RedundantExpressionCheck::check(const MatchFinder::MatchResult &Result) {
}

if (const auto *Call = Result.Nodes.getNodeAs<CXXOperatorCallExpr>("call")) {
const auto *OverloadedFunctionDecl = dyn_cast_or_null<FunctionDecl>(Call->getCalleeDecl());
if (!OverloadedFunctionDecl)
return;

if (canOverloadedOperatorArgsBeModified(OverloadedFunctionDecl, true))
if (canOverloadedOperatorArgsBeModified(Call, true))
return;

diag(Call->getOperatorLoc(),
"both sides of overloaded operator are equivalent");
}

if (const auto *Op = Result.Nodes.getNodeAs<Expr>("nested-duplicates")) {
const auto *Call = dyn_cast<CXXOperatorCallExpr>(Op);
if (Call && canOverloadedOperatorArgsBeModified(Call, true))
return;

StringRef Message =
Call ? "overloaded operator has equivalent nested operands"
: "operator has equivalent nested operands";

const auto Diag = diag(Op->getExprLoc(), Message);
for (const auto &KeyValue : Result.Nodes.getMap()) {
if (StringRef(KeyValue.first).startswith("duplicate"))
Diag << KeyValue.second.getSourceRange();
}
}

if (const auto *NegateOperator =
Result.Nodes.getNodeAs<UnaryOperator>("logical-bitwise-confusion")) {
SourceLocation OperatorLoc = NegateOperator->getOperatorLoc();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,10 @@ namespace clang {
namespace tidy {
namespace modernize {

static const llvm::SmallVector<StringRef, 5> DeprecatedTypes = {
{"::std::ios_base::io_state"},
{"::std::ios_base::open_mode"},
{"::std::ios_base::seek_dir"},
{"::std::ios_base::streamoff"},
{"::std::ios_base::streampos"}};
static constexpr std::array<StringRef, 5> DeprecatedTypes = {
"::std::ios_base::io_state", "::std::ios_base::open_mode",
"::std::ios_base::seek_dir", "::std::ios_base::streamoff",
"::std::ios_base::streampos"};

static const llvm::StringMap<StringRef> ReplacementTypes = {
{"io_state", "iostate"},
Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/clangd/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ if(CLANG_BUILT_STANDALONE)
endif()

set(CLANGD_ATOMIC_LIB "")
if(NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB)
if(NOT HAVE_CXX_ATOMICS_WITHOUT_LIB OR NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB)
list(APPEND CLANGD_ATOMIC_LIB "atomic")
endif()

Expand Down
5 changes: 5 additions & 0 deletions clang-tools-extra/clangd/unittests/XRefsTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -943,6 +943,11 @@ TEST(FindReferences, WithinAST) {
int x = [[MACRO]]([[MACRO]](1));
}
)cpp",

R"cpp(
int [[v^ar]] = 0;
void foo(int s = [[var]]);
)cpp",
};
for (const char *Test : Tests) {
Annotations T(Test);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ int TestSimpleEquivalent(int X, int Y) {
if (P2.a[P1.x + 2] < P2.x && P2.a[(P1.x) + (2)] < (P2.x)) return 1;
// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: both sides of operator are equivalent

if (X && Y && X) return 1;
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: operator has equivalent nested operands
if (X || (Y || X)) return 1;
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: operator has equivalent nested operands
if ((X ^ Y) ^ (Y ^ X)) return 1;
// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: operator has equivalent nested operands

return 0;
}

Expand All @@ -106,6 +113,7 @@ int Valid(int X, int Y) {
if (++X != ++X) return 1;
if (P.a[X]++ != P.a[X]++) return 1;
if (P.a[X++] != P.a[X++]) return 1;
if (X && X++ && X) return 1;

if ("abc" == "ABC") return 1;
if (foo(bar(0)) < (foo(bat(0, 1)))) return 1;
Expand Down Expand Up @@ -163,6 +171,15 @@ bool operator<(const MyStruct& lhs, const MyStruct& rhs) { return lhs.x < rhs.x;
bool operator>(const MyStruct& lhs, MyStruct& rhs) { rhs.x--; return lhs.x > rhs.x; }
bool operator||(MyStruct& lhs, const MyStruct& rhs) { lhs.x++; return lhs.x || rhs.x; }

struct MyStruct1 {
bool x;
MyStruct1(bool x) : x(x) {};
operator bool() { return x; }
};

MyStruct1 operator&&(const MyStruct1& lhs, const MyStruct1& rhs) { return lhs.x && rhs.x; }
MyStruct1 operator||(MyStruct1& lhs, MyStruct1& rhs) { return lhs.x && rhs.x; }

bool TestOverloadedOperator(MyStruct& S) {
if (S == Q) return false;

Expand All @@ -180,6 +197,15 @@ bool TestOverloadedOperator(MyStruct& S) {
if (S >= S) return true;
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of overloaded operator are equivalent

MyStruct1 U(false);
MyStruct1 V(true);

// valid because the operator is not const
if ((U || V) || U) return true;

if (U && V && U && V) return true;
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: overloaded operator has equivalent nested operands

return true;
}

Expand Down
2 changes: 1 addition & 1 deletion clang/bindings/python/tests/cindex/test_diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def test_diagnostic_children(self):
self.assertRegexpMatches(children[0].spelling,
'.*declared here')
self.assertEqual(children[0].location.line, 1)
self.assertEqual(children[0].location.column, 1)
self.assertEqual(children[0].location.column, 6)

def test_diagnostic_string_repr(self):
tu = get_tu('struct MissingSemicolon{}')
Expand Down
Loading

0 comments on commit 68d4042

Please sign in to comment.