summaryrefslogtreecommitdiff
path: root/compilerplugins
diff options
context:
space:
mode:
authorStephan Bergmann <sbergman@redhat.com>2023-08-23 22:09:07 +0200
committerStephan Bergmann <sbergman@redhat.com>2023-08-28 19:55:57 +0200
commite235e4bb7ce79d6738e1e6267c965f71960466a6 (patch)
treebe4f1bf01b26bb29fc3d0de5a071bf60c441dff6 /compilerplugins
parente9dfa816f7002c686ad155682a21a06ec6041b5f (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.cxx23
-rw-r--r--compilerplugins/clang/unnecessaryparen.cxx59
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())