bool VisitImplicitCastExpr(ImplicitCastExpr const * expr) { if (ignoreLocation(expr)) { returntrue;
} if (expr->getCastKind() != CK_UserDefinedConversion) { returntrue;
} // Filter out a MemberExpr (resp. a ParenExpr sub-expr, if any, as would be found by // VisitMemberExpr) that is part of a CXXMemberCallExpr which in turn is part of an // ImplicitCastExpr, so that VisitMemberExpr doesn't erroneously pick it up (and note that // CXXMemberCallExpr's getImplicitObjectArgument() skips past the underlying MemberExpr): if (autoconst e1 = dyn_cast<CXXMemberCallExpr>(expr->getSubExpr())) { if (autoconst e2 = dyn_cast<ParenExpr>(
e1->getImplicitObjectArgument()->IgnoreImpCasts()))
{
handled_.insert(e2);
}
} returntrue;
}
// Hack for libxml2's BAD_CAST object-like macro (expanding to "(xmlChar *)"), which is // typically used as if it were a function-like macro, e.g., as "BAD_CAST(pName)" in // SwNode::dumpAsXml (sw/source/core/docnode/node.cxx): bool isPrecededBy_BAD_CAST(Expr const * expr);
bool badCombination(SourceLocation loc, int prevOffset, int nextOffset);
bool removeParens(ParenExpr const * expr);
// Returns 0 if not a string literal at all: unsigned getStringLiteralTokenCount(Expr const * expr, Expr const * parenExpr) { if (autoconst e = dyn_cast<clang::StringLiteral>(expr)) { if (parenExpr == nullptr || !isPrecededBy_BAD_CAST(parenExpr)) { return e->getNumConcatenated();
}
} elseif (autoconst e = dyn_cast<UserDefinedLiteral>(expr)) {
clang::StringLiteral const * lit = nullptr; switch (e->getLiteralOperatorKind()) { case UserDefinedLiteral::LOK_Template:
{ autoconst decl = e->getDirectCallee();
assert(decl != nullptr); autoconst args = decl->getTemplateSpecializationArgs();
assert(args != nullptr); if (args->size() == 1 && (*args)[0].getKind() == TemplateArgument::Declaration)
{ if (autoconst d
= dyn_cast<TemplateParamObjectDecl>((*args)[0].getAsDecl()))
{ if (d->getValue().isStruct() || d->getValue().isUnion()) { //TODO: There appears to be no way currently to get at the original // clang::StringLiteral expression from which this struct/union // non-type template argument was constructed, so no way to tell // whether it was written as a single literal (=> in which case we // should warn about unnecessary parentheses) or as a concatenation // of multiple literals (=> in which case we should not warn). So // be conservative and not warn at all (by pretending to have more // than one token): return2;
}
}
} break;
} case UserDefinedLiteral::LOK_String:
assert(e->getNumArgs() == 2);
lit = dyn_cast<clang::StringLiteral>(e->getArg(0)->IgnoreImplicit()); break; default: break;
} if (lit != nullptr) { return lit->getNumConcatenated();
}
} return0;
}
bool UnnecessaryParen::VisitParenExpr(const ParenExpr* parenExpr)
{ if (ignoreLocation(parenExpr)) returntrue; if (parenExpr->getBeginLoc().isMacroID()) returntrue; if (handled_.find(parenExpr) != handled_.end()) returntrue;
auto subExpr = ignoreAllImplicit(parenExpr->getSubExpr());
if (auto subParenExpr = dyn_cast<ParenExpr>(subExpr))
{ if (subParenExpr->getBeginLoc().isMacroID()) returntrue;
report(
DiagnosticsEngine::Warning, "parentheses around parentheses",
parenExpr->getBeginLoc())
<< parenExpr->getSourceRange();
handled_.insert(subParenExpr);
}
// Somewhat redundantly add parenExpr to handled_, so that issues within InitListExpr don't get // reported twice (without having to change TraverseInitListExpr to only either traverse the // syntactic or semantic form, as other plugins do):
if (isa<DeclRefExpr>(subExpr)) { if (!isPrecededBy_BAD_CAST(parenExpr)) {
report(
DiagnosticsEngine::Warning, "unnecessary parentheses around identifier",
parenExpr->getBeginLoc())
<< parenExpr->getSourceRange();
handled_.insert(parenExpr);
}
} elseif (isa<IntegerLiteral>(subExpr) || isa<CharacterLiteral>(subExpr)
|| isa<FloatingLiteral>(subExpr) || isa<ImaginaryLiteral>(subExpr)
|| isa<CXXBoolLiteralExpr>(subExpr) || isa<CXXNullPtrLiteralExpr>(subExpr)
|| isa<ObjCBoolLiteralExpr>(subExpr))
{ autoconst loc = subExpr->getBeginLoc(); if (loc.isMacroID() && compiler.getSourceManager().isAtStartOfImmediateMacroExpansion(loc))
{ // just in case the macro could also expand to something that /would/ require // parentheses here returntrue;
}
report(
DiagnosticsEngine::Warning, "unnecessary parentheses around literal",
parenExpr->getBeginLoc())
<< parenExpr->getSourceRange();
handled_.insert(parenExpr);
} elseif (isa<clang::StringLiteral>(subExpr) || isa<UserDefinedLiteral>(subExpr)) { if (getStringLiteralTokenCount(subExpr, parenExpr) == 1) {
report(
DiagnosticsEngine::Warning, "unnecessary parentheses around single-token string literal",
parenExpr->getBeginLoc())
<< parenExpr->getSourceRange();
handled_.insert(parenExpr);
}
} elseif (autoconst e = dyn_cast<UnaryOperator>(subExpr)) { autoconst op = e->getOpcode(); if (op == UO_Plus || op == UO_Minus) { autoconst e2 = e->getSubExpr(); if (isa<IntegerLiteral>(e2) || isa<FloatingLiteral>(e2) || isa<ImaginaryLiteral>(e2)) {
report(
DiagnosticsEngine::Warning, "unnecessary parentheses around signed numeric literal",
parenExpr->getBeginLoc())
<< parenExpr->getSourceRange();
handled_.insert(parenExpr);
}
}
} elseif (isa<CXXNamedCastExpr>(subExpr)) { if (!removeParens(parenExpr)) {
report(
DiagnosticsEngine::Warning, "unnecessary parentheses around cast",
parenExpr->getBeginLoc())
<< parenExpr->getSourceRange();
}
handled_.insert(parenExpr);
} elseif (auto memberExpr = dyn_cast<MemberExpr>(subExpr)) { if (isa<CXXThisExpr>(ignoreAllImplicit(memberExpr->getBase()))) {
report(
DiagnosticsEngine::Warning, "unnecessary parentheses around member expr",
parenExpr->getBeginLoc())
<< parenExpr->getSourceRange();
handled_.insert(parenExpr);
}
}
bool UnnecessaryParen::VisitReturnStmt(const ReturnStmt* returnStmt)
{ if (ignoreLocation(returnStmt)) returntrue;
if (!returnStmt->getRetValue()) returntrue; auto parenExpr = dyn_cast<ParenExpr>(ignoreAllImplicit(returnStmt->getRetValue())); if (!parenExpr) returntrue; if (parenExpr->getBeginLoc().isMacroID()) returntrue; // assignments need extra parentheses or they generate a compiler warning auto binaryOp = dyn_cast<BinaryOperator>(parenExpr->getSubExpr()); if (binaryOp && binaryOp->getOpcode() == BO_Assign) returntrue;
// only non-operator-calls for now auto subExpr = ignoreAllImplicit(parenExpr->getSubExpr()); if (isa<CallExpr>(subExpr) && !isa<CXXOperatorCallExpr>(subExpr)
&& !isa<UserDefinedLiteral>(subExpr))
{
report(
DiagnosticsEngine::Warning, "parentheses immediately inside return statement",
parenExpr->getBeginLoc())
<< parenExpr->getSourceRange();
handled_.insert(parenExpr);
} returntrue;
}
auto parenExpr = dyn_cast<ParenExpr>(ignoreAllImplicit(cond)); if (parenExpr) { if (handled_.find(parenExpr) != handled_.end()) { return;
} if (parenExpr->getBeginLoc().isMacroID()) return; // assignments need extra parentheses or they generate a compiler warning auto binaryOp = dyn_cast<BinaryOperator>(parenExpr->getSubExpr()); if (binaryOp && binaryOp->getOpcode() == BO_Assign) return; if (autoconst opCall = dyn_cast<CXXOperatorCallExpr>(parenExpr->getSubExpr())) { if (opCall->getOperator() == OO_Equal) { return;
}
}
report(
DiagnosticsEngine::Warning, "parentheses immediately inside %0 statement",
parenExpr->getBeginLoc())
<< stmtName
<< parenExpr->getSourceRange();
handled_.insert(parenExpr);
}
}
bool UnnecessaryParen::VisitCallExpr(const CallExpr* callExpr)
{ if (ignoreLocation(callExpr)) returntrue; if (callExpr->getNumArgs() == 0 || isa<CXXOperatorCallExpr>(callExpr)) returntrue;
// if we are calling a >1 arg method, are we using the defaults? if (callExpr->getNumArgs() > 1)
{ if (!isa<CXXDefaultArgExpr>(callExpr->getArg(1))) returntrue;
}
auto parenExpr = dyn_cast<ParenExpr>(ignoreAllImplicit(callExpr->getArg(0))); if (!parenExpr) returntrue; if (parenExpr->getBeginLoc().isMacroID()) returntrue; // assignments need extra parentheses or they generate a compiler warning auto binaryOp = dyn_cast<BinaryOperator>(parenExpr->getSubExpr()); if (binaryOp && binaryOp->getOpcode() == BO_Assign) returntrue; if (getStringLiteralTokenCount(parenExpr->getSubExpr()->IgnoreImplicit(), nullptr) > 1) { returntrue;
}
report(
DiagnosticsEngine::Warning, "parentheses immediately inside single-arg call",
parenExpr->getBeginLoc())
<< parenExpr->getSourceRange();
handled_.insert(parenExpr); returntrue;
}
bool UnnecessaryParen::VisitCXXDeleteExpr(const CXXDeleteExpr* deleteExpr)
{ if (ignoreLocation(deleteExpr)) returntrue;
auto parenExpr = dyn_cast<ParenExpr>(ignoreAllImplicit(deleteExpr->getArgument())); if (!parenExpr) returntrue; if (parenExpr->getBeginLoc().isMacroID()) returntrue; // assignments need extra parentheses or they generate a compiler warning auto binaryOp = dyn_cast<BinaryOperator>(parenExpr->getSubExpr()); if (binaryOp && binaryOp->getOpcode() == BO_Assign) returntrue;
report(
DiagnosticsEngine::Warning, "parentheses immediately inside delete expr",
parenExpr->getBeginLoc())
<< parenExpr->getSourceRange();
handled_.insert(parenExpr); returntrue;
}
bool UnnecessaryParen::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr* callExpr)
{ if (ignoreLocation(callExpr)) returntrue; if (callExpr->getNumArgs() != 2) returntrue;
// Same logic as CXXOperatorCallExpr::isAssignmentOp(), which our supported clang // doesn't have yet. auto Opc = callExpr->getOperator(); if (Opc != OO_Equal && Opc != OO_StarEqual &&
Opc != OO_SlashEqual && Opc != OO_PercentEqual &&
Opc != OO_PlusEqual && Opc != OO_MinusEqual &&
Opc != OO_LessLessEqual && Opc != OO_GreaterGreaterEqual &&
Opc != OO_AmpEqual && Opc != OO_CaretEqual &&
Opc != OO_PipeEqual) returntrue; auto parenExpr = dyn_cast<ParenExpr>(ignoreAllImplicit(callExpr->getArg(1))); if (!parenExpr) returntrue; if (parenExpr->getBeginLoc().isMacroID()) returntrue; // Sometimes parentheses make the RHS of an assignment easier to read by // visually disambiguating the = from a call to == auto sub = parenExpr->getSubExpr(); if (autoconst e = dyn_cast<CXXRewrittenBinaryOperator>(sub)) { if (isParenWorthyOpcode(e->getDecomposedForm().Opcode)) { returntrue;
}
} if (auto subBinOp = dyn_cast<BinaryOperator>(sub))
{ if (isParenWorthyOpcode(subBinOp->getOpcode())) returntrue;
} if (auto subOperatorCall = dyn_cast<CXXOperatorCallExpr>(sub))
{ auto op = subOperatorCall->getOperator(); if (!((op >= OO_Plus && op <= OO_Exclaim) || (op >= OO_ArrowStar && op <= OO_Subscript))) returntrue;
} if (isa<ConditionalOperator>(sub)) returntrue;
bool UnnecessaryParen::VisitVarDecl(const VarDecl* varDecl)
{ if (ignoreLocation(varDecl)) returntrue; if (!varDecl->getInit()) returntrue;
auto parenExpr = dyn_cast<ParenExpr>(ignoreAllImplicit(varDecl->getInit())); if (!parenExpr) returntrue; if (parenExpr->getBeginLoc().isMacroID()) returntrue;
// Sometimes parentheses make the RHS of an assignment easier to read by // visually disambiguating the = from a call to == auto sub = parenExpr->getSubExpr(); if (autoconst e = dyn_cast<CXXRewrittenBinaryOperator>(sub)) {
sub = e->getDecomposedForm().InnerBinOp;
} if (auto subBinOp = dyn_cast<BinaryOperator>(sub))
{ if (!(subBinOp->isMultiplicativeOp() || subBinOp->isAdditiveOp() || subBinOp->isPtrMemOp())) returntrue;
} if (auto subOperatorCall = dyn_cast<CXXOperatorCallExpr>(sub))
{ auto op = subOperatorCall->getOperator(); if (!((op >= OO_Plus && op <= OO_Exclaim) || (op >= OO_ArrowStar && op <= OO_Subscript))) returntrue;
} if (isa<ConditionalOperator>(sub)) returntrue;
// these two are for "parentheses were disambiguated as a function declaration [-Werror,-Wvexing-parse]" autoconst sub2 = sub->IgnoreImplicit(); if (isa<CXXTemporaryObjectExpr>(sub2)
|| isa<CXXFunctionalCastExpr>(sub2)) returntrue;
bool UnnecessaryParen::VisitMemberExpr(const MemberExpr* memberExpr)
{ if (ignoreLocation(memberExpr)) returntrue;
auto parenExpr = dyn_cast<ParenExpr>(ignoreAllImplicit(memberExpr->getBase())); if (!parenExpr) returntrue; if (handled_.find(parenExpr) != handled_.end()) returntrue; if (parenExpr->getBeginLoc().isMacroID()) returntrue;
auto sub = parenExpr->getSubExpr(); if (isa<CallExpr>(sub)) { if (isa<CXXOperatorCallExpr>(sub)) returntrue;
} elseif (isa<CXXConstructExpr>(sub)) { // warn
} elseif (isa<MemberExpr>(sub)) { // warn
} elseif (isa<DeclRefExpr>(sub)) { // warn
} else returntrue;
report(
DiagnosticsEngine::Warning, "unnecessary parentheses around member expr",
parenExpr->getBeginLoc())
<< parenExpr->getSourceRange();
handled_.insert(parenExpr); returntrue;
}
// Conservatively assume any parenthesised integer or Boolean (incl. Objective-C ones) literal in // certain condition expressions (i.e., those for which handleUnreachableCodeConditionParens is // called) to be parenthesised to silence Clang -Wunreachable-code, if that is either the whole // condition expression or appears as a certain sub-expression (looking at what isConfigurationValue // in Clang's lib/Analysis/ReachableCode.cpp looks for, descending into certain unary and binary // operators): void UnnecessaryParen::handleUnreachableCodeConditionParens(Expr const * expr) { autoconst e = ignoreAllImplicit(expr); if (autoconst e1 = dyn_cast<ParenExpr>(e)) { autoconst sub = e1->getSubExpr(); if (isa<IntegerLiteral>(sub) || isa<CXXBoolLiteralExpr>(sub)
|| isa<ObjCBoolLiteralExpr>(sub))
{
handled_.insert(e1);
}
} elseif (autoconst e1 = dyn_cast<UnaryOperator>(e)) { if (e1->getOpcode() == UO_LNot) {
handleUnreachableCodeConditionParens(e1->getSubExpr());
}
} elseif (autoconst e1 = dyn_cast<BinaryOperator>(e)) { if (e1->isLogicalOp() || e1->isComparisonOp()) {
handleUnreachableCodeConditionParens(e1->getLHS());
handleUnreachableCodeConditionParens(e1->getRHS());
}
}
}
bool badCombinationChar(char c) { return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_'
|| c == '+' || c == '-' || c == '\'' || c == '"';
}
}
bool UnnecessaryParen::badCombination(SourceLocation loc, int prevOffset, int nextOffset) { //TODO: check for start/end of file; take backslash-newline line concatenation into account autoconst c1
= compiler.getSourceManager().getCharacterData(loc.getLocWithOffset(prevOffset))[0]; autoconst c2
= compiler.getSourceManager().getCharacterData(loc.getLocWithOffset(nextOffset))[0]; // An approximation of avoiding whatever combinations that would cause two adjacent tokens to be // lexed differently, using, for now, letters (TODO: non-ASCII ones) and digits and '_'; '+' and // '-' (to avoid ++, etc.); '\'' and '"' (to avoid u'x' or "foo"bar, etc.): return badCombinationChar(c1) && badCombinationChar(c2);
}
bool UnnecessaryParen::removeParens(ParenExpr const * expr) { if (rewriter == nullptr) { returnfalse;
} autoconst firstBegin = expr->getBeginLoc(); auto secondBegin = expr->getEndLoc(); if (firstBegin.isMacroID() || secondBegin.isMacroID()) { returnfalse;
} unsigned firstLen = Lexer::MeasureTokenLength(
firstBegin, compiler.getSourceManager(), compiler.getLangOpts()); for (auto l = firstBegin.getLocWithOffset(std::max<unsigned>(firstLen, 1));;
l = l.getLocWithOffset(1))
{ unsigned n = Lexer::MeasureTokenLength(
l, compiler.getSourceManager(), compiler.getLangOpts()); if (n != 0) { break;
}
++firstLen;
} unsigned secondLen = Lexer::MeasureTokenLength(
secondBegin, compiler.getSourceManager(), compiler.getLangOpts()); for (;;) { auto l = secondBegin.getLocWithOffset(-1); autoconst c = compiler.getSourceManager().getCharacterData(l)[0]; if (c == '\n') { if (compiler.getSourceManager().getCharacterData(l.getLocWithOffset(-1))[0] == '\\') { break;
}
} elseif (!(c == ' ' || c == '\t' || c == '\v' || c == '\f')) { break;
}
secondBegin = l;
++secondLen;
} if (!replaceText(firstBegin, firstLen, badCombination(firstBegin, -1, firstLen) ? " " : "")) { if (isDebugMode()) {
report(
DiagnosticsEngine::Fatal, "TODO: cannot rewrite opening parenthesis, needs investigation",
firstBegin);
report(
DiagnosticsEngine::Note, "when removing these parentheses", expr->getExprLoc())
<< expr->getSourceRange();
} returnfalse;
} if (!replaceText(secondBegin, secondLen, badCombination(secondBegin, -1, secondLen) ? " " : ""))
{ //TODO: roll back first change if (isDebugMode()) {
report(
DiagnosticsEngine::Fatal, "TODO: cannot rewrite closing parenthesis, needs investigation",
secondBegin);
report(
DiagnosticsEngine::Note, "when removing these parentheses", expr->getExprLoc())
<< expr->getSourceRange();
} returnfalse;
} returntrue;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.