// Find cases where a variable of a OString/OUString type is initialized // with a literal value (incl. as an empty string) and used only once. Conservatively this only // covers local non-static variables that are not defined outside of the loop (if any) in which they // are used, as other cases may deliberately use the variable for performance (or even correctness, // if addresses are taken and compared) reasons. // // For one, the historically heavy syntax for such uses of string literals // (RTL_CONSTASCII_USTRINGPARAM etc.) probably explains many of these redundant variables, which can // now be considered cargo-cult baggage. For another, some of those variables are used as arguments // to functions which also have more efficient overloads directly taking string literals. And for // yet another, some cases with default-initialized variables turned out to be effectively unused // code that could be removed completely (d073cca5f7c04de3e1bcedda334d864e98ac7835 "Clean up dead // code", 91345e7dde6100496a7c9e815b72b2821ae82bc2 "Clean up dead code", // 868b0763ac47f765cb48c277897274a595b831d0 "Upcoming loplugin:elidestringvar: dbaccess" in // dbaccess/source/ui/app/AppController.cxx, bde0aac4ccf7b830b5ef21d5b9e75e62aee6aaf9 "Clean up dead // code", 354aefec42de856b4ab6201ada54a3a3c630b4bd "Upcoming loplugin:elidestringvar: cui" in // cui/source/dialogs/SpellDialog.cxx).
void postRun() override
{ for (autoconst& var : vars_)
{ if (!var.second.singleUse || *var.second.singleUse == nullptr)
{ continue;
} if (containsPreprocessingConditionalInclusion(
SourceRange(var.first->getBeginLoc(), (*var.second.singleUse)->getEndLoc())))
{ // This is not perfect, as additional uses can be hidden in conditional blocks that // only start after the (would-be) single use (as was the case in // 3bc5057f9689e024957cfa898a221ee2c4c4afe7 "Upcoming loplugin:elidestringvar: // testtools" when built with --enable-debug, but where also fixing the hidden // additional use was trivial). If this ever becomes a real problem, we can extend // the above check to cover more of the current function body's remainder. continue;
}
report(DiagnosticsEngine::Warning, "replace single use of literal %0 variable with a literal",
(*var.second.singleUse)->getExprLoc())
<< var.first->getType() << (*var.second.singleUse)->getSourceRange();
report(DiagnosticsEngine::Note, "literal %0 variable defined here",
var.first->getLocation())
<< var.first->getType() << var.first->getSourceRange();
}
}
bool VisitVarDecl(VarDecl const* decl)
{ if (ignoreLocation(decl))
{ returntrue;
} if (!decl->isThisDeclarationADefinition())
{ returntrue;
} if (isa<ParmVarDecl>(decl))
{ returntrue;
} if (decl->getStorageDuration() != SD_Automatic)
{ returntrue;
} if (!isStringType(decl->getType()))
{ returntrue;
} if (!decl->hasInit())
{ returntrue;
} autoconst e1 = dyn_cast<CXXConstructExpr>(decl->getInit()->IgnoreParenImpCasts()); if (e1 == nullptr)
{ returntrue;
} if (!isStringType(e1->getType()))
{ returntrue;
} switch (e1->getNumArgs())
{ case0: break; case1:
{ autoconst e2 = e1->getArg(0);
loplugin::TypeCheck const c(e2->getType()); if (c.Class("OStringLiteral").Namespace("rtl").GlobalNamespace()
|| c.Class("OUStringLiteral").Namespace("rtl").GlobalNamespace())
{ break;
} if (!e2->isValueDependent() && e2->isIntegerConstantExpr(compiler.getASTContext()))
{ break;
} returntrue;
} case2:
{ autoconst e2 = e1->getArg(0); autoconst t = e2->getType(); if (!(t.isConstQualified() && t->isConstantArrayType()))
{ returntrue;
} if (isa<AbstractConditionalOperator>(e2->IgnoreParenImpCasts()))
{ returntrue;
} autoconst e3 = e1->getArg(1); if (!(isa<CXXDefaultArgExpr>(e3)
&& loplugin::TypeCheck(e3->getType())
.Struct("Dummy")
.Namespace("libreoffice_internal")
.Namespace("rtl")
.GlobalNamespace()))
{ returntrue;
} break;
} default: returntrue;
} autoconst ok = vars_.emplace(decl, Data(getInnermostLoop()));
assert(ok.second);
(void)ok; returntrue;
}
bool VisitDeclRefExpr(DeclRefExpr const* expr)
{ if (ignoreLocation(expr))
{ returntrue;
} autoconst var = dyn_cast<VarDecl>(expr->getDecl()); if (var == nullptr)
{ returntrue;
} autoconst i = vars_.find(var); if (i == vars_.end())
{ returntrue;
}
i->second.singleUse
= i->second.singleUse || i->second.innermostLoop != getInnermostLoop() ? nullptr : expr; returntrue;
}
bool VisitMemberExpr(MemberExpr const* expr)
{ if (ignoreLocation(expr))
{ returntrue;
} autoconst e = dyn_cast<DeclRefExpr>(expr->getBase()->IgnoreParenImpCasts()); if (e == nullptr)
{ returntrue;
} autoconst var = dyn_cast<VarDecl>(e->getDecl()); if (var == nullptr)
{ returntrue;
} autoconst i = vars_.find(var); if (i == vars_.end())
{ returntrue;
}
i->second.singleUse = nullptr; returntrue;
}
bool VisitUnaryOperator(UnaryOperator const* expr)
{ if (ignoreLocation(expr))
{ returntrue;
} if (expr->getOpcode() != UO_AddrOf)
{ returntrue;
} autoconst e = dyn_cast<DeclRefExpr>(expr->getSubExpr()->IgnoreParenImpCasts()); if (e == nullptr)
{ returntrue;
} autoconst var = dyn_cast<VarDecl>(e->getDecl()); if (var == nullptr)
{ returntrue;
} autoconst i = vars_.find(var); if (i == vars_.end())
{ returntrue;
}
i->second.singleUse = nullptr; returntrue;
}
bool VisitCallExpr(CallExpr const* expr)
{ if (ignoreLocation(expr))
{ returntrue;
} autoconst fun = expr->getDirectCallee(); if (fun == nullptr)
{ returntrue;
} unsignedconst n = std::min(fun->getNumParams(), expr->getNumArgs()); for (unsigned i = 0; i != n; ++i)
{ if (!loplugin::TypeCheck(fun->getParamDecl(i)->getType())
.LvalueReference()
.NonConstVolatile())
{ continue;
} autoconst e = dyn_cast<DeclRefExpr>(expr->getArg(i)->IgnoreParenImpCasts()); if (e == nullptr)
{ continue;
} autoconst var = dyn_cast<VarDecl>(e->getDecl()); if (var == nullptr)
{ continue;
} autoconst j = vars_.find(var); if (j == vars_.end())
{ continue;
}
j->second.singleUse = nullptr;
} returntrue;
}
bool VisitCXXConstructExpr(CXXConstructExpr const* expr)
{ if (ignoreLocation(expr))
{ returntrue;
} autoconst ctor = expr->getConstructor(); unsignedconst n = std::min(ctor->getNumParams(), expr->getNumArgs()); for (unsigned i = 0; i != n; ++i)
{ if (!loplugin::TypeCheck(ctor->getParamDecl(i)->getType())
.LvalueReference()
.NonConstVolatile())
{ continue;
} autoconst e = dyn_cast<DeclRefExpr>(expr->getArg(i)->IgnoreParenImpCasts()); if (e == nullptr)
{ continue;
} autoconst var = dyn_cast<VarDecl>(e->getDecl()); if (var == nullptr)
{ continue;
} autoconst j = vars_.find(var); if (j == vars_.end())
{ continue;
}
j->second.singleUse = nullptr;
} returntrue;
}
bool TraverseWhileStmt(WhileStmt* stmt)
{ bool ret = true; if (PreTraverseWhileStmt(stmt))
{
ret = FilteringPlugin::TraverseWhileStmt(stmt);
PostTraverseWhileStmt(stmt, ret);
} return ret;
}
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.12Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-09-28)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.