diff options
Diffstat (limited to 'compilerplugins/clang/stringconstant.cxx')
-rw-r--r-- | compilerplugins/clang/stringconstant.cxx | 97 |
1 files changed, 70 insertions, 27 deletions
diff --git a/compilerplugins/clang/stringconstant.cxx b/compilerplugins/clang/stringconstant.cxx index 5c237afa1924..344125dd4df0 100644 --- a/compilerplugins/clang/stringconstant.cxx +++ b/compilerplugins/clang/stringconstant.cxx @@ -86,7 +86,7 @@ bool hasOverloads(FunctionDecl const * decl, unsigned arguments) { CXXConstructExpr const * lookForCXXConstructExpr(Expr const * expr) { if (auto e = dyn_cast<MaterializeTemporaryExpr>(expr)) { - expr = compat::getSubExpr(e); + expr = e->getSubExpr(); } if (auto e = dyn_cast<CXXFunctionalCastExpr>(expr)) { expr = e->getSubExpr(); @@ -96,7 +96,7 @@ CXXConstructExpr const * lookForCXXConstructExpr(Expr const * expr) { } if (auto const e = dyn_cast<CXXMemberCallExpr>(expr)) { // Look through OString::operator std::string_view: - if (auto const d = dyn_cast_or_null<CXXConversionDecl>(e->getCalleeDecl())) { + if (isa_and_nonnull<CXXConversionDecl>(e->getCalleeDecl())) { return lookForCXXConstructExpr(e->getImplicitObjectArgument()->IgnoreParenImpCasts()); } } @@ -118,56 +118,56 @@ public: void run() override; bool TraverseFunctionDecl(FunctionDecl * decl) { - returnTypes_.push(compat::getDeclaredReturnType(decl)); + returnTypes_.push(decl->getDeclaredReturnType()); auto const ret = RecursiveASTVisitor::TraverseFunctionDecl(decl); assert(!returnTypes_.empty()); - assert(returnTypes_.top() == compat::getDeclaredReturnType(decl)); + assert(returnTypes_.top() == decl->getDeclaredReturnType()); returnTypes_.pop(); return ret; } bool TraverseCXXDeductionGuideDecl(CXXDeductionGuideDecl * decl) { - returnTypes_.push(compat::getDeclaredReturnType(decl)); + returnTypes_.push(decl->getDeclaredReturnType()); auto const ret = RecursiveASTVisitor::TraverseCXXDeductionGuideDecl( decl); assert(!returnTypes_.empty()); - assert(returnTypes_.top() == compat::getDeclaredReturnType(decl)); + assert(returnTypes_.top() == decl->getDeclaredReturnType()); returnTypes_.pop(); return ret; } bool TraverseCXXMethodDecl(CXXMethodDecl * decl) { - returnTypes_.push(compat::getDeclaredReturnType(decl)); + returnTypes_.push(decl->getDeclaredReturnType()); auto const ret = RecursiveASTVisitor::TraverseCXXMethodDecl(decl); assert(!returnTypes_.empty()); - assert(returnTypes_.top() == compat::getDeclaredReturnType(decl)); + assert(returnTypes_.top() == decl->getDeclaredReturnType()); returnTypes_.pop(); return ret; } bool TraverseCXXConstructorDecl(CXXConstructorDecl * decl) { - returnTypes_.push(compat::getDeclaredReturnType(decl)); + returnTypes_.push(decl->getDeclaredReturnType()); auto const ret = RecursiveASTVisitor::TraverseCXXConstructorDecl(decl); assert(!returnTypes_.empty()); - assert(returnTypes_.top() == compat::getDeclaredReturnType(decl)); + assert(returnTypes_.top() == decl->getDeclaredReturnType()); returnTypes_.pop(); return ret; } bool TraverseCXXDestructorDecl(CXXDestructorDecl * decl) { - returnTypes_.push(compat::getDeclaredReturnType(decl)); + returnTypes_.push(decl->getDeclaredReturnType()); auto const ret = RecursiveASTVisitor::TraverseCXXDestructorDecl(decl); assert(!returnTypes_.empty()); - assert(returnTypes_.top() == compat::getDeclaredReturnType(decl)); + assert(returnTypes_.top() == decl->getDeclaredReturnType()); returnTypes_.pop(); return ret; } bool TraverseCXXConversionDecl(CXXConversionDecl * decl) { - returnTypes_.push(compat::getDeclaredReturnType(decl)); + returnTypes_.push(decl->getDeclaredReturnType()); auto const ret = RecursiveASTVisitor::TraverseCXXConversionDecl(decl); assert(!returnTypes_.empty()); - assert(returnTypes_.top() == compat::getDeclaredReturnType(decl)); + assert(returnTypes_.top() == decl->getDeclaredReturnType()); returnTypes_.pop(); return ret; } @@ -191,6 +191,8 @@ public: bool VisitCallExpr(CallExpr const * expr); + bool VisitCXXMemberCallExpr(CXXMemberCallExpr const * expr); + bool VisitCXXConstructExpr(CXXConstructExpr const * expr); bool VisitReturnStmt(ReturnStmt const * stmt); @@ -424,7 +426,7 @@ bool StringConstant::VisitCallExpr(CallExpr const * expr) { // u.equalsIngoreAsciiCase("foo"): auto file = getFilenameOfLocation( - compiler.getSourceManager().getSpellingLoc(compat::getBeginLoc(expr))); + compiler.getSourceManager().getSpellingLoc(expr->getBeginLoc())); if (loplugin::isSamePathname( file, SRCDIR "/sal/qa/rtl/strings/test_oustring_compare.cxx")) { @@ -442,7 +444,7 @@ bool StringConstant::VisitCallExpr(CallExpr const * expr) { // u.equalsIgnoreAsciiCaseAsciiL("foo", 3) -> // u.equalsIngoreAsciiCase("foo"): auto file = getFilenameOfLocation( - compiler.getSourceManager().getSpellingLoc(compat::getBeginLoc(expr))); + compiler.getSourceManager().getSpellingLoc(expr->getBeginLoc())); if (loplugin::isSamePathname( file, SRCDIR "/sal/qa/rtl/strings/test_oustring_compare.cxx")) { @@ -816,7 +818,7 @@ bool StringConstant::VisitCallExpr(CallExpr const * expr) { // b.append("foo", 3) -> b.append("foo"): auto file = getFilenameOfLocation( compiler.getSourceManager().getSpellingLoc( - compat::getBeginLoc(expr))); + expr->getBeginLoc())); if (loplugin::isSamePathname( file, SRCDIR "/sal/qa/OStringBuffer/rtl_OStringBuffer.cxx")) @@ -856,6 +858,47 @@ bool StringConstant::VisitCallExpr(CallExpr const * expr) { return true; } +bool StringConstant::VisitCXXMemberCallExpr(CXXMemberCallExpr const * expr) { + if (ignoreLocation(expr)) { + return true; + } + FunctionDecl const * fdecl = expr->getDirectCallee(); + if (fdecl == nullptr) { + return true; + } + auto const c = loplugin::DeclCheck(fdecl).Function("getStr"); + if ((c.Class("OString").Namespace("rtl").GlobalNamespace() + || c.Class("OUString").Namespace("rtl").GlobalNamespace()) + && fdecl->getNumParams() == 0) + { + auto const e1 = expr->getImplicitObjectArgument()->IgnoreImplicit()->IgnoreParens(); + if (auto const e2 = dyn_cast<CXXTemporaryObjectExpr>(e1)) { + if (e2->getNumArgs() != 0) { + return true; + } + report( + DiagnosticsEngine::Warning, + "in call of '%0', replace default-constructed %1 directly with an empty %select{ordinary|UTF-16}2 string literal", + expr->getExprLoc()) + << fdecl->getQualifiedNameAsString() << e2->getType() << bool(loplugin::TypeCheck(e2->getType()).Class("OUString")) << expr->getSourceRange(); + return true; + } + if (auto const e2 = dyn_cast<CXXFunctionalCastExpr>(e1)) { + auto const e3 = dyn_cast<clang::StringLiteral>(e2->getSubExprAsWritten()->IgnoreParens()); + if (e3 == nullptr) { + return true; + } + report( + DiagnosticsEngine::Warning, + "in call of '%0', replace %1 constructed from a string literal directly with %select{the|a UTF-16}2 string literal", + expr->getExprLoc()) + << fdecl->getQualifiedNameAsString() << e2->getType() << (loplugin::TypeCheck(e2->getType()).Class("OUString") && !e3->isUTF16()) << expr->getSourceRange(); + return true; + } + } + return true; +} + bool StringConstant::VisitCXXConstructExpr(CXXConstructExpr const * expr) { if (ignoreLocation(expr)) { return true; @@ -1067,7 +1110,7 @@ bool StringConstant::VisitCXXConstructExpr(CXXConstructExpr const * expr) { for (auto i(argsBeg); i != argsEnd; ++i) { Expr const * e = (*i)->IgnoreParenImpCasts(); if (isa<MaterializeTemporaryExpr>(e)) { - e = compat::getSubExpr(cast<MaterializeTemporaryExpr>(e)) + e = cast<MaterializeTemporaryExpr>(e)->getSubExpr() ->IgnoreParenImpCasts(); } if (isa<CXXFunctionalCastExpr>(e)) { @@ -1173,7 +1216,7 @@ bool StringConstant::VisitCXXConstructExpr(CXXConstructExpr const * expr) { auto file = getFilenameOfLocation( compiler.getSourceManager() .getSpellingLoc( - compat::getBeginLoc(expr))); + expr->getBeginLoc())); if (loplugin::isSamePathname( file, (SRCDIR @@ -1186,7 +1229,7 @@ bool StringConstant::VisitCXXConstructExpr(CXXConstructExpr const * expr) { return true; } } - auto loc = compat::getBeginLoc(expr->getArg(0)); + auto loc = expr->getArg(0)->getBeginLoc(); while (compiler.getSourceManager() .isMacroArgExpansion(loc)) { @@ -1314,7 +1357,7 @@ bool StringConstant::VisitReturnStmt(ReturnStmt const * stmt) { { return true; } - report(DiagnosticsEngine::Warning, "elide constructor call", compat::getBeginLoc(e1)) + report(DiagnosticsEngine::Warning, "elide constructor call", e1->getBeginLoc()) << e1->getSourceRange(); return true; } @@ -1385,7 +1428,7 @@ bool StringConstant::isStringConstant( } clang::StringLiteral const * lit = dyn_cast<clang::StringLiteral>(expr); if (lit != nullptr) { - if (!(lit->isAscii() || lit->isUTF8())) { + if (!(compat::isOrdinary(lit) || lit->isUTF8())) { return false; } unsigned n = lit->getLength(); @@ -2034,7 +2077,7 @@ void StringConstant::handleStringCtor( } //TODO: cont, emb, trm if (rewriter != nullptr) { - auto loc1 = compat::getBeginLoc(e3); + auto loc1 = e3->getBeginLoc(); auto range = e3->getParenOrBraceRange(); if (loc1.isFileID() && range.getBegin().isFileID() && range.getEnd().isFileID()) @@ -2046,7 +2089,7 @@ void StringConstant::handleStringCtor( if (!first) { StringRef s( compiler.getSourceManager().getCharacterData(loc2), n); - while (s.startswith("\\\n")) { + while (compat::starts_with(s, "\\\n")) { s = s.drop_front(2); while (!s.empty() && (s.front() == ' ' || s.front() == '\t' @@ -2056,7 +2099,7 @@ void StringConstant::handleStringCtor( s = s.drop_front(1); } } - if (!(s.empty() || s.startswith("/*") || s.startswith("//") + if (!(s.empty() || compat::starts_with(s, "/*") || compat::starts_with(s, "//") || s == "\\")) { break; @@ -2072,7 +2115,7 @@ void StringConstant::handleStringCtor( unsigned n = Lexer::MeasureTokenLength( l, compiler.getSourceManager(), compiler.getLangOpts()); StringRef s(compiler.getSourceManager().getCharacterData(l), n); - while (s.startswith("\\\n")) { + while (compat::starts_with(s, "\\\n")) { s = s.drop_front(2); while (!s.empty() && (s.front() == ' ' || s.front() == '\t' @@ -2082,7 +2125,7 @@ void StringConstant::handleStringCtor( s = s.drop_front(1); } } - if (!(s.empty() || s.startswith("/*") || s.startswith("//") + if (!(s.empty() || compat::starts_with(s, "/*") || compat::starts_with(s, "//") || s == "\\")) { break; |