summaryrefslogtreecommitdiffstats
path: root/compilerplugins/clang/stringconstant.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'compilerplugins/clang/stringconstant.cxx')
-rw-r--r--compilerplugins/clang/stringconstant.cxx97
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;