diff options
author | Stephan Bergmann <sbergman@redhat.com> | 2023-08-23 22:09:07 +0200 |
---|---|---|
committer | Stephan Bergmann <sbergman@redhat.com> | 2023-08-28 19:55:57 +0200 |
commit | e235e4bb7ce79d6738e1e6267c965f71960466a6 (patch) | |
tree | be4f1bf01b26bb29fc3d0de5a071bf60c441dff6 /compilerplugins | |
parent | e9dfa816f7002c686ad155682a21a06ec6041b5f (diff) |
Adapt loplugin:unnecessaryparen to user-defined string literals
Change-Id: Ieab59fa456bce13145b61cb5e8b2fb9ff9b4c573
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/156193
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
Diffstat (limited to 'compilerplugins')
-rw-r--r-- | compilerplugins/clang/test/unnecessaryparen.cxx | 23 | ||||
-rw-r--r-- | compilerplugins/clang/unnecessaryparen.cxx | 59 |
2 files changed, 79 insertions, 3 deletions
diff --git a/compilerplugins/clang/test/unnecessaryparen.cxx b/compilerplugins/clang/test/unnecessaryparen.cxx index ccc2b4ce6556..89ca84da6ab2 100644 --- a/compilerplugins/clang/test/unnecessaryparen.cxx +++ b/compilerplugins/clang/test/unnecessaryparen.cxx @@ -7,6 +7,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include <cstddef> #include <memory> #include <string> #include <rtl/ustring.hxx> @@ -34,6 +35,13 @@ template <> struct typed_flags<BrowseMode> : is_typed_flags<BrowseMode, 0xf> }; } +void f(char const *); +char const * operator ""_s1(char const *, std::size_t); +#if __cplusplus >= 202002L +struct Str { constexpr Str(char const *) {} }; +template<Str> char const * operator ""_s2(); +#endif + int main() { int x = 1; @@ -115,6 +123,21 @@ int main() (void)nBits; OUString::number((v2+1)); // expected-error {{parentheses immediately inside single-arg call [loplugin:unnecessaryparen]}} + + (void) ("foo"); // expected-error {{unnecessary parentheses around single-token string literal [loplugin:unnecessaryparen]}} + (void) ("foo" "bar"); + f(("foo")); // expected-error {{parentheses immediately inside single-arg call [loplugin:unnecessaryparen]}} + f(("foo" "bar")); + (void) ("foo"_s1); // expected-error {{unnecessary parentheses around single-token string literal [loplugin:unnecessaryparen]}} + (void) ("foo" "bar"_s1); + f(("foo"_s1)); // expected-error {{parentheses immediately inside single-arg call [loplugin:unnecessaryparen]}} + f(("foo" "bar"_s1)); +#if __cplusplus >= 202002L + (void) ("foo"_s2); //TODO: expected error {{unnecessary parentheses around single-token string literal [loplugin:unnecessaryparen]}} + (void) ("foo" "bar"_s2); + f(("foo"_s2)); // TODO: expected error {{parentheses immediately inside single-arg call [loplugin:unnecessaryparen]}} + f(("foo" "bar"_s2)); +#endif }; struct B { operator bool() const; }; diff --git a/compilerplugins/clang/unnecessaryparen.cxx b/compilerplugins/clang/unnecessaryparen.cxx index 1d11aca4ab47..f31d570b9bdd 100644 --- a/compilerplugins/clang/unnecessaryparen.cxx +++ b/compilerplugins/clang/unnecessaryparen.cxx @@ -143,6 +143,55 @@ private: bool removeParens(ParenExpr const * expr); + // Returns 0 if not a string literal at all: + unsigned getStringLiteralTokenCount(Expr const * expr, Expr const * parenExpr) { + if (auto const e = dyn_cast<clang::StringLiteral>(expr)) { + if (parenExpr == nullptr || !isPrecededBy_BAD_CAST(parenExpr)) { + return e->getNumConcatenated(); + } + } else if (auto const e = dyn_cast<UserDefinedLiteral>(expr)) { + clang::StringLiteral const * lit = nullptr; + switch (e->getLiteralOperatorKind()) { + case UserDefinedLiteral::LOK_Template: + { + auto const decl = e->getDirectCallee(); + assert(decl != nullptr); + auto const args = decl->getTemplateSpecializationArgs(); + assert(args != nullptr); + if (args->size() == 1 && (*args)[0].getKind() == TemplateArgument::Declaration) + { + if (auto const 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 constructued, 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): + return 2; + } + } + } + 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(); + } + } + return 0; + } + std::unordered_set<ParenExpr const *> handled_; }; @@ -217,8 +266,8 @@ bool UnnecessaryParen::VisitParenExpr(const ParenExpr* parenExpr) parenExpr->getBeginLoc()) << parenExpr->getSourceRange(); handled_.insert(parenExpr); - } else if (auto const e = dyn_cast<clang::StringLiteral>(subExpr)) { - if (e->getNumConcatenated() == 1 && !isPrecededBy_BAD_CAST(parenExpr)) { + } else if (isa<clang::StringLiteral>(subExpr) || isa<UserDefinedLiteral>(subExpr)) { + if (getStringLiteralTokenCount(subExpr, parenExpr) == 1) { report( DiagnosticsEngine::Warning, "unnecessary parentheses around single-token string literal", @@ -320,7 +369,8 @@ bool UnnecessaryParen::VisitReturnStmt(const ReturnStmt* returnStmt) // only non-operator-calls for now auto subExpr = ignoreAllImplicit(parenExpr->getSubExpr()); - if (isa<CallExpr>(subExpr) && !isa<CXXOperatorCallExpr>(subExpr)) + if (isa<CallExpr>(subExpr) && !isa<CXXOperatorCallExpr>(subExpr) + && !isa<UserDefinedLiteral>(subExpr)) { report( DiagnosticsEngine::Warning, "parentheses immediately inside return statement", @@ -384,6 +434,9 @@ bool UnnecessaryParen::VisitCallExpr(const CallExpr* callExpr) auto binaryOp = dyn_cast<BinaryOperator>(parenExpr->getSubExpr()); if (binaryOp && binaryOp->getOpcode() == BO_Assign) return true; + if (getStringLiteralTokenCount(parenExpr->getSubExpr()->IgnoreImplicit(), nullptr) > 1) { + return true; + } report( DiagnosticsEngine::Warning, "parentheses immediately inside single-arg call", parenExpr->getBeginLoc()) |