1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #ifndef LO_CLANG_SHARED_PLUGINS
17 #include <unordered_set>
19 #include <clang/AST/CXXInheritance.h>
21 #include "config_clang.h"
27 look for unnecessary parentheses
32 // Like clang::Stmt::IgnoreImplicit (lib/AST/Stmt.cpp), but also ignoring CXXConstructExpr and
33 // looking through implicit UserDefinedConversion's member function call:
34 Expr
const * ignoreAllImplicit(Expr
const * expr
) {
38 if (auto const e
= dyn_cast
<ExprWithCleanups
>(expr
)) {
39 expr
= e
->getSubExpr();
41 else if (auto const e
= dyn_cast
<CXXConstructExpr
>(expr
)) {
42 if (e
->getNumArgs() == 1) {
46 else if (auto const e
= dyn_cast
<MaterializeTemporaryExpr
>(expr
)) {
47 expr
= compat::getSubExpr(e
);
49 else if (auto const e
= dyn_cast
<CXXBindTemporaryExpr
>(expr
)) {
50 expr
= e
->getSubExpr();
52 else if (auto const e
= dyn_cast
<ImplicitCastExpr
>(expr
)) {
53 expr
= e
->getSubExpr();
54 if (e
->getCastKind() == CK_UserDefinedConversion
) {
55 auto const ce
= cast
<CXXMemberCallExpr
>(expr
);
56 assert(ce
->getNumArgs() == 0);
57 expr
= ce
->getImplicitObjectArgument();
60 #if CLANG_VERSION >= 80000
61 else if (auto const e
= dyn_cast
<ConstantExpr
>(expr
)) {
62 expr
= e
->getSubExpr();
71 bool isParenWorthyOpcode(BinaryOperatorKind op
) {
72 return !(BinaryOperator::isMultiplicativeOp(op
) || BinaryOperator::isAdditiveOp(op
)
73 || compat::isPtrMemOp(op
));
76 class UnnecessaryParen
:
77 public loplugin::FilteringRewritePlugin
<UnnecessaryParen
>
80 explicit UnnecessaryParen(loplugin::InstantiationData
const & data
):
81 FilteringRewritePlugin(data
) {}
83 virtual bool preRun() override
85 StringRef
fn(handler
.getMainFileName());
86 // fixing this, makes the source in the .y files look horrible
87 if (loplugin::isSamePathname(fn
, WORKDIR
"/YaccTarget/unoidl/source/sourceprovider-parser.cxx"))
89 if (loplugin::isSamePathname(fn
, WORKDIR
"/YaccTarget/idlc/source/parser.cxx"))
93 virtual void run() override
96 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
99 bool VisitParenExpr(const ParenExpr
*);
100 bool VisitIfStmt(const IfStmt
*);
101 bool VisitDoStmt(const DoStmt
*);
102 bool VisitWhileStmt(const WhileStmt
*);
103 bool VisitForStmt(ForStmt
const * stmt
);
104 bool VisitSwitchStmt(const SwitchStmt
*);
105 bool VisitCaseStmt(const CaseStmt
*);
106 bool VisitReturnStmt(const ReturnStmt
* );
107 bool VisitCallExpr(const CallExpr
*);
108 bool VisitVarDecl(const VarDecl
*);
109 bool VisitCXXOperatorCallExpr(const CXXOperatorCallExpr
*);
110 bool VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr
const *);
111 bool VisitConditionalOperator(ConditionalOperator
const * expr
);
112 bool VisitBinaryConditionalOperator(BinaryConditionalOperator
const * expr
);
113 bool VisitMemberExpr(const MemberExpr
*f
);
114 bool VisitCXXDeleteExpr(const CXXDeleteExpr
*);
116 bool VisitImplicitCastExpr(ImplicitCastExpr
const * expr
) {
117 if (ignoreLocation(expr
)) {
120 if (expr
->getCastKind() != CK_UserDefinedConversion
) {
123 // Filter out a MemberExpr (resp. a ParenExpr sub-expr, if any, as would be found by
124 // VisitMemberExpr) that is part of a CXXMemberCallExpr which in turn is part of an
125 // ImplicitCastExpr, so that VisitMemberExpr doesn't erroneously pick it up (and note that
126 // CXXMemberCallExpr's getImplicitObjectArgument() skips past the underlying MemberExpr):
127 if (auto const e1
= dyn_cast
<CXXMemberCallExpr
>(expr
->getSubExpr())) {
128 if (auto const e2
= dyn_cast
<ParenExpr
>(
129 e1
->getImplicitObjectArgument()->IgnoreImpCasts()))
138 void VisitSomeStmt(Stmt
const * stmt
, const Expr
* cond
, StringRef stmtName
);
140 void handleUnreachableCodeConditionParens(Expr
const * expr
);
142 // Hack for libxml2's BAD_CAST object-like macro (expanding to "(xmlChar *)"), which is
143 // typically used as if it were a function-like macro, e.g., as "BAD_CAST(pName)" in
144 // SwNode::dumpAsXml (sw/source/core/docnode/node.cxx):
145 bool isPrecededBy_BAD_CAST(Expr
const * expr
);
147 bool badCombination(SourceLocation loc
, int prevOffset
, int nextOffset
);
149 bool removeParens(ParenExpr
const * expr
);
151 std::unordered_set
<ParenExpr
const *> handled_
;
154 bool UnnecessaryParen::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr
const * expr
)
156 if (expr
->getKind() == UETT_SizeOf
&& !expr
->isArgumentType()) {
157 if (auto const e
= dyn_cast
<ParenExpr
>(ignoreAllImplicit(expr
->getArgumentExpr()))) {
164 bool UnnecessaryParen::VisitConditionalOperator(ConditionalOperator
const * expr
) {
165 handleUnreachableCodeConditionParens(expr
->getCond());
169 bool UnnecessaryParen::VisitBinaryConditionalOperator(BinaryConditionalOperator
const * expr
) {
170 handleUnreachableCodeConditionParens(expr
->getCond());
174 bool UnnecessaryParen::VisitParenExpr(const ParenExpr
* parenExpr
)
176 if (ignoreLocation(parenExpr
))
178 if (compat::getBeginLoc(parenExpr
).isMacroID())
180 if (handled_
.find(parenExpr
) != handled_
.end())
183 auto subExpr
= ignoreAllImplicit(parenExpr
->getSubExpr());
185 if (auto subParenExpr
= dyn_cast
<ParenExpr
>(subExpr
))
187 if (compat::getBeginLoc(subParenExpr
).isMacroID())
190 DiagnosticsEngine::Warning
, "parentheses around parentheses",
191 compat::getBeginLoc(parenExpr
))
192 << parenExpr
->getSourceRange();
193 handled_
.insert(subParenExpr
);
196 // Somewhat redundantly add parenExpr to handled_, so that issues within InitListExpr don't get
197 // reported twice (without having to change TraverseInitListExpr to only either traverse the
198 // syntactic or semantic form, as other plugins do):
200 if (isa
<DeclRefExpr
>(subExpr
)) {
201 if (!isPrecededBy_BAD_CAST(parenExpr
)) {
203 DiagnosticsEngine::Warning
, "unnecessary parentheses around identifier",
204 compat::getBeginLoc(parenExpr
))
205 << parenExpr
->getSourceRange();
206 handled_
.insert(parenExpr
);
208 } else if (isa
<IntegerLiteral
>(subExpr
) || isa
<CharacterLiteral
>(subExpr
)
209 || isa
<FloatingLiteral
>(subExpr
) || isa
<ImaginaryLiteral
>(subExpr
)
210 || isa
<CXXBoolLiteralExpr
>(subExpr
) || isa
<CXXNullPtrLiteralExpr
>(subExpr
)
211 || isa
<ObjCBoolLiteralExpr
>(subExpr
))
213 auto const loc
= compat::getBeginLoc(subExpr
);
214 if (loc
.isMacroID() && compiler
.getSourceManager().isAtStartOfImmediateMacroExpansion(loc
))
216 // just in case the macro could also expand to something that /would/ require
221 DiagnosticsEngine::Warning
, "unnecessary parentheses around literal",
222 compat::getBeginLoc(parenExpr
))
223 << parenExpr
->getSourceRange();
224 handled_
.insert(parenExpr
);
225 } else if (auto const e
= dyn_cast
<clang::StringLiteral
>(subExpr
)) {
226 if (e
->getNumConcatenated() == 1 && !isPrecededBy_BAD_CAST(parenExpr
)) {
228 DiagnosticsEngine::Warning
,
229 "unnecessary parentheses around single-token string literal",
230 compat::getBeginLoc(parenExpr
))
231 << parenExpr
->getSourceRange();
232 handled_
.insert(parenExpr
);
234 } else if (auto const e
= dyn_cast
<UnaryOperator
>(subExpr
)) {
235 auto const op
= e
->getOpcode();
236 if (op
== UO_Plus
|| op
== UO_Minus
) {
237 auto const e2
= e
->getSubExpr();
238 if (isa
<IntegerLiteral
>(e2
) || isa
<FloatingLiteral
>(e2
) || isa
<ImaginaryLiteral
>(e2
)) {
240 DiagnosticsEngine::Warning
,
241 "unnecessary parentheses around signed numeric literal",
242 compat::getBeginLoc(parenExpr
))
243 << parenExpr
->getSourceRange();
244 handled_
.insert(parenExpr
);
247 } else if (isa
<CXXNamedCastExpr
>(subExpr
)) {
248 if (!removeParens(parenExpr
)) {
250 DiagnosticsEngine::Warning
, "unnecessary parentheses around cast",
251 compat::getBeginLoc(parenExpr
))
252 << parenExpr
->getSourceRange();
254 handled_
.insert(parenExpr
);
255 } else if (auto memberExpr
= dyn_cast
<MemberExpr
>(subExpr
)) {
256 if (isa
<CXXThisExpr
>(ignoreAllImplicit(memberExpr
->getBase()))) {
258 DiagnosticsEngine::Warning
, "unnecessary parentheses around member expr",
259 compat::getBeginLoc(parenExpr
))
260 << parenExpr
->getSourceRange();
261 handled_
.insert(parenExpr
);
268 bool UnnecessaryParen::VisitIfStmt(const IfStmt
* ifStmt
)
270 handleUnreachableCodeConditionParens(ifStmt
->getCond());
271 VisitSomeStmt(ifStmt
, ifStmt
->getCond(), "if");
275 bool UnnecessaryParen::VisitDoStmt(const DoStmt
* doStmt
)
277 VisitSomeStmt(doStmt
, doStmt
->getCond(), "do");
281 bool UnnecessaryParen::VisitWhileStmt(const WhileStmt
* whileStmt
)
283 handleUnreachableCodeConditionParens(whileStmt
->getCond());
284 VisitSomeStmt(whileStmt
, whileStmt
->getCond(), "while");
288 bool UnnecessaryParen::VisitForStmt(ForStmt
const * stmt
) {
289 if (auto const cond
= stmt
->getCond()) {
290 handleUnreachableCodeConditionParens(cond
);
295 bool UnnecessaryParen::VisitSwitchStmt(const SwitchStmt
* switchStmt
)
297 VisitSomeStmt(switchStmt
, switchStmt
->getCond(), "switch");
301 bool UnnecessaryParen::VisitCaseStmt(const CaseStmt
* caseStmt
)
303 VisitSomeStmt(caseStmt
, caseStmt
->getLHS(), "case");
307 bool UnnecessaryParen::VisitReturnStmt(const ReturnStmt
* returnStmt
)
309 if (ignoreLocation(returnStmt
))
312 if (!returnStmt
->getRetValue())
314 auto parenExpr
= dyn_cast
<ParenExpr
>(ignoreAllImplicit(returnStmt
->getRetValue()));
317 if (compat::getBeginLoc(parenExpr
).isMacroID())
319 // assignments need extra parentheses or they generate a compiler warning
320 auto binaryOp
= dyn_cast
<BinaryOperator
>(parenExpr
->getSubExpr());
321 if (binaryOp
&& binaryOp
->getOpcode() == BO_Assign
)
324 // only non-operator-calls for now
325 auto subExpr
= ignoreAllImplicit(parenExpr
->getSubExpr());
326 if (isa
<CallExpr
>(subExpr
) && !isa
<CXXOperatorCallExpr
>(subExpr
))
329 DiagnosticsEngine::Warning
, "parentheses immediately inside return statement",
330 compat::getBeginLoc(parenExpr
))
331 << parenExpr
->getSourceRange();
332 handled_
.insert(parenExpr
);
337 void UnnecessaryParen::VisitSomeStmt(const Stmt
* stmt
, const Expr
* cond
, StringRef stmtName
)
339 if (ignoreLocation(stmt
))
342 auto parenExpr
= dyn_cast
<ParenExpr
>(ignoreAllImplicit(cond
));
344 if (handled_
.find(parenExpr
) != handled_
.end()) {
347 if (compat::getBeginLoc(parenExpr
).isMacroID())
349 // assignments need extra parentheses or they generate a compiler warning
350 auto binaryOp
= dyn_cast
<BinaryOperator
>(parenExpr
->getSubExpr());
351 if (binaryOp
&& binaryOp
->getOpcode() == BO_Assign
)
353 if (auto const opCall
= dyn_cast
<CXXOperatorCallExpr
>(parenExpr
->getSubExpr())) {
354 if (opCall
->getOperator() == OO_Equal
) {
359 DiagnosticsEngine::Warning
, "parentheses immediately inside %0 statement",
360 compat::getBeginLoc(parenExpr
))
362 << parenExpr
->getSourceRange();
363 handled_
.insert(parenExpr
);
367 bool UnnecessaryParen::VisitCallExpr(const CallExpr
* callExpr
)
369 if (ignoreLocation(callExpr
))
371 if (callExpr
->getNumArgs() == 0 || isa
<CXXOperatorCallExpr
>(callExpr
))
374 // if we are calling a >1 arg method, are we using the defaults?
375 if (callExpr
->getNumArgs() > 1)
377 if (!isa
<CXXDefaultArgExpr
>(callExpr
->getArg(1)))
381 auto parenExpr
= dyn_cast
<ParenExpr
>(ignoreAllImplicit(callExpr
->getArg(0)));
384 if (compat::getBeginLoc(parenExpr
).isMacroID())
386 // assignments need extra parentheses or they generate a compiler warning
387 auto binaryOp
= dyn_cast
<BinaryOperator
>(parenExpr
->getSubExpr());
388 if (binaryOp
&& binaryOp
->getOpcode() == BO_Assign
)
391 DiagnosticsEngine::Warning
, "parentheses immediately inside single-arg call",
392 compat::getBeginLoc(parenExpr
))
393 << parenExpr
->getSourceRange();
394 handled_
.insert(parenExpr
);
398 bool UnnecessaryParen::VisitCXXDeleteExpr(const CXXDeleteExpr
* deleteExpr
)
400 if (ignoreLocation(deleteExpr
))
403 auto parenExpr
= dyn_cast
<ParenExpr
>(ignoreAllImplicit(deleteExpr
->getArgument()));
406 if (compat::getBeginLoc(parenExpr
).isMacroID())
408 // assignments need extra parentheses or they generate a compiler warning
409 auto binaryOp
= dyn_cast
<BinaryOperator
>(parenExpr
->getSubExpr());
410 if (binaryOp
&& binaryOp
->getOpcode() == BO_Assign
)
413 DiagnosticsEngine::Warning
, "parentheses immediately inside delete expr",
414 compat::getBeginLoc(parenExpr
))
415 << parenExpr
->getSourceRange();
416 handled_
.insert(parenExpr
);
420 bool UnnecessaryParen::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr
* callExpr
)
422 if (ignoreLocation(callExpr
))
424 if (callExpr
->getNumArgs() != 2)
427 // Same logic as CXXOperatorCallExpr::isAssignmentOp(), which our supported clang
429 auto Opc
= callExpr
->getOperator();
430 if (Opc
!= OO_Equal
&& Opc
!= OO_StarEqual
&&
431 Opc
!= OO_SlashEqual
&& Opc
!= OO_PercentEqual
&&
432 Opc
!= OO_PlusEqual
&& Opc
!= OO_MinusEqual
&&
433 Opc
!= OO_LessLessEqual
&& Opc
!= OO_GreaterGreaterEqual
&&
434 Opc
!= OO_AmpEqual
&& Opc
!= OO_CaretEqual
&&
437 auto parenExpr
= dyn_cast
<ParenExpr
>(ignoreAllImplicit(callExpr
->getArg(1)));
440 if (compat::getBeginLoc(parenExpr
).isMacroID())
442 // Sometimes parentheses make the RHS of an assignment easier to read by
443 // visually disambiguating the = from a call to ==
444 auto sub
= parenExpr
->getSubExpr();
445 #if CLANG_VERSION >= 100000
446 if (auto const e
= dyn_cast
<CXXRewrittenBinaryOperator
>(sub
)) {
447 if (isParenWorthyOpcode(e
->getDecomposedForm().Opcode
)) {
452 if (auto subBinOp
= dyn_cast
<BinaryOperator
>(sub
))
454 if (isParenWorthyOpcode(subBinOp
->getOpcode()))
457 if (auto subOperatorCall
= dyn_cast
<CXXOperatorCallExpr
>(sub
))
459 auto op
= subOperatorCall
->getOperator();
460 if (!((op
>= OO_Plus
&& op
<= OO_Exclaim
) || (op
>= OO_ArrowStar
&& op
<= OO_Subscript
)))
463 if (isa
<ConditionalOperator
>(sub
))
467 DiagnosticsEngine::Warning
, "parentheses immediately inside assignment",
468 compat::getBeginLoc(parenExpr
))
469 << parenExpr
->getSourceRange();
470 handled_
.insert(parenExpr
);
474 bool UnnecessaryParen::VisitVarDecl(const VarDecl
* varDecl
)
476 if (ignoreLocation(varDecl
))
478 if (!varDecl
->getInit())
481 auto parenExpr
= dyn_cast
<ParenExpr
>(ignoreAllImplicit(varDecl
->getInit()));
484 if (compat::getBeginLoc(parenExpr
).isMacroID())
487 // Sometimes parentheses make the RHS of an assignment easier to read by
488 // visually disambiguating the = from a call to ==
489 auto sub
= parenExpr
->getSubExpr();
490 #if CLANG_VERSION >= 100000
491 if (auto const e
= dyn_cast
<CXXRewrittenBinaryOperator
>(sub
)) {
492 sub
= e
->getDecomposedForm().InnerBinOp
;
495 if (auto subBinOp
= dyn_cast
<BinaryOperator
>(sub
))
497 if (!(subBinOp
->isMultiplicativeOp() || subBinOp
->isAdditiveOp() || subBinOp
->isPtrMemOp()))
500 if (auto subOperatorCall
= dyn_cast
<CXXOperatorCallExpr
>(sub
))
502 auto op
= subOperatorCall
->getOperator();
503 if (!((op
>= OO_Plus
&& op
<= OO_Exclaim
) || (op
>= OO_ArrowStar
&& op
<= OO_Subscript
)))
506 if (isa
<ConditionalOperator
>(sub
))
509 // these two are for "parentheses were disambiguated as a function declaration [-Werror,-Wvexing-parse]"
510 auto const sub2
= sub
->IgnoreImplicit();
511 if (isa
<CXXTemporaryObjectExpr
>(sub2
)
512 || isa
<CXXFunctionalCastExpr
>(sub2
))
516 DiagnosticsEngine::Warning
, "parentheses immediately inside vardecl statement",
517 compat::getBeginLoc(parenExpr
))
518 << parenExpr
->getSourceRange();
519 handled_
.insert(parenExpr
);
523 bool UnnecessaryParen::VisitMemberExpr(const MemberExpr
* memberExpr
)
525 if (ignoreLocation(memberExpr
))
528 auto parenExpr
= dyn_cast
<ParenExpr
>(ignoreAllImplicit(memberExpr
->getBase()));
531 if (handled_
.find(parenExpr
) != handled_
.end())
533 if (compat::getBeginLoc(parenExpr
).isMacroID())
536 auto sub
= parenExpr
->getSubExpr();
537 if (isa
<CallExpr
>(sub
)) {
538 if (isa
<CXXOperatorCallExpr
>(sub
))
540 } else if (isa
<CXXConstructExpr
>(sub
)) {
542 } else if (isa
<MemberExpr
>(sub
)) {
544 } else if (isa
<DeclRefExpr
>(sub
)) {
550 DiagnosticsEngine::Warning
, "unnecessary parentheses around member expr",
551 compat::getBeginLoc(parenExpr
))
552 << parenExpr
->getSourceRange();
553 handled_
.insert(parenExpr
);
557 // Conservatively assume any parenthesised integer or Boolean (incl. Objective-C ones) literal in
558 // certain condition expressions (i.e., those for which handleUnreachableCodeConditionParens is
559 // called) to be parenthesised to silence Clang -Wunreachable-code, if that is either the whole
560 // condition expression or appears as a certain sub-expression (looking at what isConfigurationValue
561 // in Clang's lib/Analysis/ReachableCode.cpp looks for, descending into certain unary and binary
563 void UnnecessaryParen::handleUnreachableCodeConditionParens(Expr
const * expr
) {
565 auto const e
= ignoreAllImplicit(expr
);
566 if (auto const e1
= dyn_cast
<ParenExpr
>(e
)) {
567 auto const sub
= e1
->getSubExpr();
568 if (isa
<IntegerLiteral
>(sub
) || isa
<CXXBoolLiteralExpr
>(sub
)
569 || isa
<ObjCBoolLiteralExpr
>(sub
))
573 } else if (auto const e1
= dyn_cast
<UnaryOperator
>(e
)) {
574 if (e1
->getOpcode() == UO_LNot
) {
575 handleUnreachableCodeConditionParens(e1
->getSubExpr());
577 } else if (auto const e1
= dyn_cast
<BinaryOperator
>(e
)) {
578 if (e1
->isLogicalOp() || e1
->isComparisonOp()) {
579 handleUnreachableCodeConditionParens(e1
->getLHS());
580 handleUnreachableCodeConditionParens(e1
->getRHS());
585 bool UnnecessaryParen::isPrecededBy_BAD_CAST(Expr
const * expr
) {
586 if (compat::getBeginLoc(expr
).isMacroID()) {
589 SourceManager
& SM
= compiler
.getSourceManager();
590 const char *p1
= SM
.getCharacterData( compat::getBeginLoc(expr
).getLocWithOffset(-10) );
591 const char *p2
= SM
.getCharacterData( compat::getBeginLoc(expr
) );
592 return std::string(p1
, p2
- p1
).find("BAD_CAST") != std::string::npos
;
597 bool badCombinationChar(char c
) {
598 return (c
>= 'A' && c
<= 'Z') || (c
>= 'a' && c
<= 'z') || (c
>= '0' && c
<= '9') || c
== '_'
599 || c
== '+' || c
== '-' || c
== '\'' || c
== '"';
604 bool UnnecessaryParen::badCombination(SourceLocation loc
, int prevOffset
, int nextOffset
) {
605 //TODO: check for start/end of file; take backslash-newline line concatenation into account
607 = compiler
.getSourceManager().getCharacterData(loc
.getLocWithOffset(prevOffset
))[0];
609 = compiler
.getSourceManager().getCharacterData(loc
.getLocWithOffset(nextOffset
))[0];
610 // An approximation of avoiding whatever combinations that would cause two adjacent tokens to be
611 // lexed differently, using, for now, letters (TODO: non-ASCII ones) and digits and '_'; '+' and
612 // '-' (to avoid ++, etc.); '\'' and '"' (to avoid u'x' or "foo"bar, etc.):
613 return badCombinationChar(c1
) && badCombinationChar(c2
);
616 bool UnnecessaryParen::removeParens(ParenExpr
const * expr
) {
617 if (rewriter
== nullptr) {
620 auto const firstBegin
= compat::getBeginLoc(expr
);
621 auto secondBegin
= compat::getEndLoc(expr
);
622 if (firstBegin
.isMacroID() || secondBegin
.isMacroID()) {
625 unsigned firstLen
= Lexer::MeasureTokenLength(
626 firstBegin
, compiler
.getSourceManager(), compiler
.getLangOpts());
627 for (auto l
= firstBegin
.getLocWithOffset(std::max
<unsigned>(firstLen
, 1));;
628 l
= l
.getLocWithOffset(1))
630 unsigned n
= Lexer::MeasureTokenLength(
631 l
, compiler
.getSourceManager(), compiler
.getLangOpts());
637 unsigned secondLen
= Lexer::MeasureTokenLength(
638 secondBegin
, compiler
.getSourceManager(), compiler
.getLangOpts());
640 auto l
= secondBegin
.getLocWithOffset(-1);
641 auto const c
= compiler
.getSourceManager().getCharacterData(l
)[0];
643 if (compiler
.getSourceManager().getCharacterData(l
.getLocWithOffset(-1))[0] == '\\') {
646 } else if (!(c
== ' ' || c
== '\t' || c
== '\v' || c
== '\f')) {
652 if (!replaceText(firstBegin
, firstLen
, badCombination(firstBegin
, -1, firstLen
) ? " " : "")) {
655 DiagnosticsEngine::Fatal
,
656 "TODO: cannot rewrite opening parenthesis, needs investigation",
659 DiagnosticsEngine::Note
, "when removing these parentheses", expr
->getExprLoc())
660 << expr
->getSourceRange();
664 if (!replaceText(secondBegin
, secondLen
, badCombination(secondBegin
, -1, secondLen
) ? " " : ""))
666 //TODO: roll back first change
669 DiagnosticsEngine::Fatal
,
670 "TODO: cannot rewrite closing parenthesis, needs investigation",
673 DiagnosticsEngine::Note
, "when removing these parentheses", expr
->getExprLoc())
674 << expr
->getSourceRange();
681 loplugin::Plugin::Registration
< UnnecessaryParen
> unnecessaryparen("unnecessaryparen", true);
685 #endif // LO_CLANG_SHARED_PLUGINS
687 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */