[PATCH] D41077: [analyser] different.CallArgsOrder checker implementation

Aleksei Sidorin via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Tue Dec 19 08:56:10 PST 2017


a.sidorin added a comment.

Hi Alexey,

This commit strongly needs testing on some real code. I cannot predict the TP rate of this checker now.
Regarding implementation, you can find some remarks inline.



================
Comment at: lib/StaticAnalyzer/Checkers/CallArgsOrderChecker.cpp:31
+
+class ParamsGroup {
+public:
----------------
We have a class without any private parts. This means that we should declare it as 'struct' or do some redesign - the way it is constructed (with expressions like `PGL.back().ParamsVec.push_back(std::move(p));` clearly indicates some design issues. I suggest at least adding a wrapper above ParamsGroupVec with methods:
 `ParamGroup &addParam(const ParmVarDecl *ParamVD)`; // adds a variable into existing group or creates new one
`void reclaimLastGroupIfSingle(); // deletes last added group if it has only a single element`
and moving some logic here.



================
Comment at: lib/StaticAnalyzer/Checkers/CallArgsOrderChecker.cpp:33
+public:
+  ParamsGroup() : StartIndex(0) { ParamsVec.reserve(4); }
+
----------------
You don't need to reserve  the amount of items same or less then SmallVector default size - they are already stack-allocated.


================
Comment at: lib/StaticAnalyzer/Checkers/CallArgsOrderChecker.cpp:112
+      checkCallExpr(CE);
+    if (const CXXConstructExpr *CE =
+            Result.Nodes.getNodeAs<CXXConstructExpr>("cxxConstructExpr"))
----------------
else if?


================
Comment at: lib/StaticAnalyzer/Checkers/CallArgsOrderChecker.cpp:119
+
+StringRefVec ParamsGroup::trimSame(StringRefVec StrVec) {
+  return rtrimSame(ltrimSame(StrVec));
----------------
trim* functions should be moved out of ParamsGroup because they are not related. 


================
Comment at: lib/StaticAnalyzer/Checkers/CallArgsOrderChecker.cpp:139
+
+    if (SamePrefixSize > StrSize) {
+      SamePrefix = SamePrefix.drop_back(SamePrefixSize - StrSize);
----------------
We can the code:
```
SamePrefix = SamePrefix.take_front(StrSize);
SamePrefixSize = SamePrefix.size();
```
instead. The behaviour of `StringRef::take_front(size_t N)` is well-defined if N >= size().

Same below: drop_front() can be replaced with take_back().


================
Comment at: lib/StaticAnalyzer/Checkers/CallArgsOrderChecker.cpp:144
+
+    for (size_t i = 0; i < SamePrefixSize; i++) {
+      if (Str[i] != SamePrefix[i]) {
----------------
What you are trying to do here (find common prefix of two strings) can be done easier using std::mismatch().


================
Comment at: lib/StaticAnalyzer/Checkers/CallArgsOrderChecker.cpp:157
+  const size_t SamePrefixSize = SamePrefix.size();
+  std::transform(StrVec.begin(), StrVec.end(), StrVec.begin(),
+                 [SamePrefixSize](const StringRef &Str) {
----------------
llvm::transform(StrVec, StrVec.begin(), ...)


================
Comment at: lib/StaticAnalyzer/Checkers/CallArgsOrderChecker.cpp:164
+
+StringRefVec ParamsGroup::rtrimSame(StringRefVec StrVec) {
+  if (StrVec.empty())
----------------
szepet wrote:
> Please add a comment to this function which describes its input, output, purpose.
With names like removeCommon[Pre/Suf]fix, the intention of these functions will be much cleaner. Also, please do not pass vectors by value.


================
Comment at: lib/StaticAnalyzer/Checkers/CallArgsOrderChecker.cpp:185
+
+    for (size_t i = StrSize, j = SameSuffixSize; i > 0 && j > 0; i--, j--) {
+      if (Str[i - 1] != SameSuffix[j - 1]) {
----------------
We can use std::mismatch with std::reverse_iterator (std::rbegin(), std::rend()).


================
Comment at: lib/StaticAnalyzer/Checkers/CallArgsOrderChecker.cpp:208
+CallArgsOrderChecker::getOrBuildParamsGroups(const FunctionDecl *FD) const {
+  const auto It = PGLCache.find(FD);
+  if (It != PGLCache.end())
----------------
We can use `try_emplace()` to construct the new item in-place.


================
Comment at: lib/StaticAnalyzer/Checkers/CallArgsOrderChecker.cpp:215
+  const unsigned NumParams = FD->getNumParams();
+  if (NumParams > 0) {
+    const ParmVarDecl *prevParam = FD->getParamDecl(0);
----------------
This is already check in the caller. I think, this can be replaced with an assertion.


================
Comment at: lib/StaticAnalyzer/Checkers/CallArgsOrderChecker.cpp:257
+
+static StringRef getExprName(const Expr *E) {
+  const Expr *OrigE = E->IgnoreParenCasts();
----------------
Could you please explain what kind of ExprName are you trying to get?


================
Comment at: lib/StaticAnalyzer/Checkers/CallArgsOrderChecker.cpp:259
+  const Expr *OrigE = E->IgnoreParenCasts();
+  if (!OrigE)
+    return StringRef();
----------------
As I remember, IgnoreParenCasts() can not return nullptr. So, we can turn this into assertion.


================
Comment at: lib/StaticAnalyzer/Checkers/CallArgsOrderChecker.cpp:262
+
+  if (const DeclRefExpr *DRE = dyn_cast_or_null<DeclRefExpr>(OrigE))
+    return DRE->getFoundDecl()->getName();
----------------
OrigE is not nullptr so we can use dyn_cast.


================
Comment at: lib/StaticAnalyzer/Checkers/CallArgsOrderChecker.cpp:278
+
+  End = Lexer::getLocForEndOfToken(End, 0, SM, LangOptions());
+  const char *Str = SM.getCharacterData(Start);
----------------
We have ASTContext so we can use getPrintingPolicy() and getLangOpts() instead of default values.


================
Comment at: lib/StaticAnalyzer/Checkers/CallArgsOrderChecker.cpp:279
+  End = Lexer::getLocForEndOfToken(End, 0, SM, LangOptions());
+  const char *Str = SM.getCharacterData(Start);
+  return StringRef(Str, SM.getCharacterData(End) - Str);
----------------
We can use Lexer::getSourceText() here.


================
Comment at: lib/StaticAnalyzer/Checkers/CallArgsOrderChecker.cpp:311
+void Callback::checkCXXConstructExpr(const CXXConstructExpr *CE) {
+  const FunctionDecl *FD = CE->getConstructor();
+  if (!FD)
----------------
Personally, I think that writing:
```
  if (const FunctionDecl *FD = CE->getConstructor())
    checkCall(FD, CE, /*FirstActualArgOffset=*/0);
``` 
is shorter and clearer. But it is so minor that I don't insist on this change.


================
Comment at: lib/StaticAnalyzer/Checkers/CallArgsOrderChecker.cpp:319
+template <typename CallExprT>
+void Callback::checkCall(const FunctionDecl *FD, const CallExprT *CE,
+                         unsigned FirstActualArgOffset) const {
----------------
The function is pretty long. I think we should split it.


================
Comment at: lib/StaticAnalyzer/Checkers/CallArgsOrderChecker.cpp:323
+  const unsigned NumArgs = CE->getNumArgs();
+  if (NumArgs <= FirstActualArgOffset)
+    return;
----------------
Should we check for `NumArgs <= FirstActualArgOffset + 1`, like in condition below?


================
Comment at: lib/StaticAnalyzer/Checkers/CallArgsOrderChecker.cpp:334
+  const ParamsGroupVec &PGV = C->getOrBuildParamsGroups(FD);
+  for (ParamsGroupVec::size_type PGVIndex = 0, PGVSize = PGV.size();
+       PGVIndex < PGVSize; PGVIndex++) {
----------------
This will look nicer with C++11-style loop.


================
Comment at: lib/StaticAnalyzer/Checkers/CallArgsOrderChecker.cpp:363
+      if (CurrParam.SimplifiedName.empty() || CurrArgExprName.empty())
+        return;
+
----------------
Should we return or just continue?


================
Comment at: lib/StaticAnalyzer/Checkers/CallArgsOrderChecker.cpp:415
+  auto CallExpr = stmt(
+      eachOf(forEachDescendant(callExpr().bind("callExpr")),
+             forEachDescendant(cxxConstructExpr().bind("cxxConstructExpr"))));
----------------
Instead of `eachOf(forEachDescendant(), forEachDescendant())` it is better to use `forEachDescendant(anyOf())`. This will avoid double iteration on descendant tree (the memoizing size for descendant tree is limited).


================
Comment at: test/Analysis/call-args-order.c:13
+  vp->height = height;
+  vp->aspectRatio = width / height;
+}
----------------
Please mark tests for true negatives as `// no warning`.


Repository:
  rC Clang

https://reviews.llvm.org/D41077





More information about the cfe-commits mailing list