alexey.knyshev created this revision.
alexey.knyshev added a project: clang.
Herald added a subscriber: mgorny.

CallArgsOrderChecker which looks for accidental swap or skip of arguments in 
function, methods, constructors and operators calls


Repository:
  rC Clang

https://reviews.llvm.org/D41077

Files:
  include/clang/StaticAnalyzer/Checkers/Checkers.td
  lib/StaticAnalyzer/Checkers/CMakeLists.txt
  lib/StaticAnalyzer/Checkers/CallArgsOrderChecker.cpp
  test/Analysis/call-args-order.c
  test/Analysis/call-args-order.cpp

Index: test/Analysis/call-args-order.cpp
===================================================================
--- test/Analysis/call-args-order.cpp
+++ test/Analysis/call-args-order.cpp
@@ -0,0 +1,103 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core.CallArgsOrder -verify -x c++ %s
+
+typedef unsigned char byte;
+
+class Color {
+  byte r, g, b, a;
+
+public:
+  Color(byte R, byte G, byte B, byte A = 0)
+      : r(R), g(G), b(B), a(A) {}
+
+  void set(byte R, byte G, byte B, byte A = 0) {
+    r = R;
+    g = G;
+    b = B;
+    a = A;
+  }
+
+  void operator()(byte R, byte G, byte B, byte A = 0);
+  void operator+=(byte Delta);
+
+  byte getR() const { return r; }
+  byte getG() const { return g; }
+  byte getB() const { return b; }
+  byte getA() const { return a; }
+
+  static Color copy1(const Color &Color);
+  static Color copy2(const Color &Color);
+  static Color copy3(const Color &Color);
+  static Color copy4(const Color &Color);
+  static Color copy5(const Color &Color);
+  static Color copy6(const Color &Color);
+};
+
+void Color::operator()(byte R, byte G, byte B, byte A) {
+  set(R, B, G, A); // expected-warning {{possibly wrong order of args 'B' and 'G' passed as params 'G' and 'B'}}
+}
+
+void Color::operator+=(byte Delta) {
+  r += Delta;
+  g += Delta;
+  b += Delta;
+  a += Delta;
+}
+
+Color newRed1(byte r, byte b, byte a) {
+  return Color(r, b, a); // expected-warning {{possibly missing arg for param 'G'}}
+}
+
+Color newRed2(byte r, byte g, byte a) {
+  return Color(r, g, a); // expected-warning {{possibly missing arg for param 'B'}}
+}
+
+Color Color::copy1(const Color &o) {
+  return Color(o.r, o.b, o.g, o.a); // expected-warning {{possibly wrong order of args 'o.b' and 'o.g' passed as params 'G' and 'B'}}
+}
+
+Color Color::copy2(const Color &o) {
+  return Color(o.r, o.g, o.a, o.b); // expected-warning {{possibly wrong order of args 'o.a' and 'o.b' passed as params 'B' and 'A'}}
+}
+
+Color Color::copy3(const Color &o) {
+  return Color(o.r, o.g, o.g, o.g); // no-warning
+}
+
+Color Color::copy4(const Color &o) {
+  return Color(o.r, o.r, o.r, o.r); // no-warning
+}
+
+Color Color::copy5(const Color &o) {
+  return Color(o.getR(), o.getB(), o.getG(), o.getA()); // expected-warning {{possibly wrong order of args 'o.getB()' and 'o.getG()' passed as params 'G' and 'B'}}
+}
+
+Color Color::copy6(const Color &o) {
+  // totaly messed up (not sure if it's wrong or not)
+  return Color(o.a, o.r, o.g, o.b); // no-warning
+}
+
+Color newMagicColor() {
+  const byte r = 200;
+  const byte g = 150;
+  const byte b = 100;
+  const byte a = 0;
+
+  return Color(r, b, g, a); // expected-warning {{possibly wrong order of args 'b' and 'g' passed as params 'G' and 'B'}}
+}
+
+void modify(Color &c) {
+  int red = 1;
+  int green = 2;
+  int blue = 3;
+  c.set(red, green, blue);     // no-warning
+  c.set(red, blue, green);     // expected-warning {{possibly wrong order of args 'blue' and 'green' passed as params 'G' and 'B'}}
+  c.set(red, green, 0);        // no-warning
+  c.set(red, green, c.getA()); // no-warning
+
+  c(red, green, blue); // no-warning
+  c(green, red, blue); // expected-warning {{possibly wrong order of args 'green' and 'red' passed as params 'R' and 'G'}}
+
+  c += 1; // no-warning
+
+  c(red, blue, green, 0); // expected-warning {{possibly wrong order of args 'blue' and 'green' passed as params 'G' and 'B'}}
+}
Index: test/Analysis/call-args-order.c
===================================================================
--- test/Analysis/call-args-order.c
+++ test/Analysis/call-args-order.c
@@ -0,0 +1,57 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core.CallArgsOrder -verify -std=c99 %s
+
+struct Viewport {
+  int width;
+  int height;
+
+  float aspectRatio;
+};
+
+void setDimentions(struct Viewport *vp, int width, int height) {
+  vp->width = width;
+  vp->height = height;
+  vp->aspectRatio = width / height;
+}
+
+float getWidth(struct Viewport *vp) { return vp->width; }
+float getHeight(struct Viewport *vp) { return vp->height; }
+
+float getFloat() {
+  return 128.5;
+}
+
+int main() {
+  struct Viewport vp;
+
+  int newWidth = 800;
+  int newHeight = 600;
+  setDimentions(&vp, newHeight, newWidth);    // expected-warning {{possibly wrong order of args 'newHeight' and 'newWidth' passed as params 'width' and 'height'}}
+  setDimentions(&vp, newWidth, newHeight);    // no-warning
+  setDimentions(&vp, newWidth, newWidth);     // no-warning
+  setDimentions(&vp, newHeight, newHeight);   // no-warning
+  setDimentions(&vp, getFloat(), getFloat()); // no-warning
+
+  int w = 640;
+  int h = 480;
+  setDimentions(&vp, w, h); // no-warning
+  setDimentions(&vp, h, w); // expected-warning {{possibly wrong order of args 'h' and 'w' passed as params 'width' and 'height'}}
+  setDimentions(&vp, w, w); // no-warning
+  setDimentions(&vp, h, h); // no-warning
+
+  int w_big = 1920;
+  int h_big = 1080;
+
+  float w_big_f = 320.0;
+  float h_big_f = 240.0;
+
+  setDimentions(&vp, w_big, h_big); // no-warning
+  setDimentions(&vp, h_big, w_big); // expected-warning {{possibly wrong order of args 'h_big' and 'w_big' passed as params 'width' and 'height'}}
+  setDimentions(&vp, w_big, w_big); // no-warning
+  setDimentions(&vp, h_big, h_big); // no-warning
+
+  setDimentions(&vp, (int)h_big_f, -w_big_f);            // expected-warning {{possibly wrong order of args '(int)h_big_f' and '-w_big_f' passed as params 'width' and 'height'}}
+  setDimentions(&vp, (int)h_big_f, h_big_f);             // no-warning
+  setDimentions(&vp, -getHeight(&vp), getWidth(&vp));    // expected-warning {{possibly wrong order of args '-getHeight(&vp)' and 'getWidth(&vp)' passed as params 'width' and 'height'}}
+  setDimentions(&vp, -getHeight(&vp), getHeight(&vp));   // no-warning
+  setDimentions(&vp, getHeight(&vp) + 4, getWidth(&vp)); // no-warning
+}
Index: lib/StaticAnalyzer/Checkers/CallArgsOrderChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/CallArgsOrderChecker.cpp
+++ lib/StaticAnalyzer/Checkers/CallArgsOrderChecker.cpp
@@ -0,0 +1,431 @@
+//= CallArgsOrderChecker.cpp - Check for arguments order in calls -*- C++ -*-=//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines CallArgsOrderChecker, which looks for accidental swap or skip
+// of arguments in function, methods, constructors and operators calls.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ExprCXX.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
+
+using namespace clang;
+using namespace ento;
+using namespace ast_matchers;
+
+namespace {
+constexpr unsigned TypicalMaxParamsCount = 4;
+typedef SmallVector<StringRef, TypicalMaxParamsCount> StringRefVec;
+
+class ParamsGroup {
+public:
+  ParamsGroup() : StartIndex(0) { ParamsVec.reserve(4); }
+
+  static StringRefVec trimSame(StringRefVec StrVec);
+  static StringRefVec ltrimSame(StringRefVec StrVec);
+  static StringRefVec rtrimSame(StringRefVec StrVec);
+
+  void fillSimplifiedParamNames() {
+    StringRefVec ParamNames;
+    ParamNames.reserve(ParamsVec.size());
+    for (const Param &P : ParamsVec)
+      ParamNames.push_back(P.Decl->getName());
+
+    if (ParamNames.size() > 1)
+      ParamNames = trimSame(ParamNames);
+
+    for (StringRefVec::size_type i = 0, N = ParamsVec.size(); i < N; i++)
+      ParamsVec[i].SimplifiedName = ParamNames[i];
+  }
+
+  class Param {
+  public:
+    const ParmVarDecl *Decl;
+    StringRef SimplifiedName;
+
+    bool isNamedLike(StringRef Name) const {
+      if (SimplifiedName.size() < Name.size()) {
+        if (Name.startswith_lower(SimplifiedName))
+          return true;
+      } else {
+        if (SimplifiedName.startswith_lower(Name))
+          return true;
+      }
+
+      // We don't like false-positive matches on single-char
+      if (SimplifiedName.size() < 2 || Name.size() < 2)
+        return false;
+
+      if (SimplifiedName.size() < Name.size())
+        return Name.endswith_lower(SimplifiedName);
+      return SimplifiedName.endswith_lower(Name);
+    }
+  };
+
+  unsigned StartIndex;
+  SmallVector<Param, TypicalMaxParamsCount> ParamsVec;
+};
+
+typedef llvm::SmallVector<ParamsGroup, TypicalMaxParamsCount> ParamsGroupVec;
+
+class CallArgsOrderChecker : public Checker<check::ASTCodeBody> {
+  mutable llvm::DenseMap<const FunctionDecl *, ParamsGroupVec> PGLCache;
+
+public:
+  const ParamsGroupVec &getOrBuildParamsGroups(const FunctionDecl *FD) const;
+  void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,
+                        BugReporter &BR) const;
+};
+
+class Callback : public MatchFinder::MatchCallback {
+  const CallArgsOrderChecker *C;
+  BugReporter &BR;
+  SourceManager &SM;
+  AnalysisDeclContext *AC;
+
+  void checkCallExpr(const CallExpr *CE);
+  void checkCXXConstructExpr(const CXXConstructExpr *CE);
+
+  template <typename CallExprT>
+  void checkCall(const FunctionDecl *FD, const CallExprT *CE,
+                 unsigned FirstActualArgOffset) const;
+
+public:
+  Callback(const CallArgsOrderChecker *C, BugReporter &BR, SourceManager &SM,
+           AnalysisDeclContext *AC)
+      : C(C), BR(BR), SM(SM), AC(AC) {}
+
+  virtual void run(const MatchFinder::MatchResult &Result) override {
+    if (const CallExpr *CE = Result.Nodes.getNodeAs<CallExpr>("callExpr"))
+      checkCallExpr(CE);
+    if (const CXXConstructExpr *CE =
+            Result.Nodes.getNodeAs<CXXConstructExpr>("cxxConstructExpr"))
+      checkCXXConstructExpr(CE);
+  }
+};
+} // end of anonymous namespace
+
+StringRefVec ParamsGroup::trimSame(StringRefVec StrVec) {
+  return rtrimSame(ltrimSame(StrVec));
+}
+
+StringRefVec ParamsGroup::ltrimSame(StringRefVec StrVec) {
+  if (StrVec.empty())
+    return StrVec;
+
+  auto It = StrVec.begin();
+  const auto End = StrVec.end();
+
+  StringRef SamePrefix = *It;
+  It++;
+
+  for (; It != End; It++) {
+    const StringRef &Str = *It;
+
+    const size_t StrSize = Str.size();
+    size_t SamePrefixSize = SamePrefix.size();
+
+    if (SamePrefixSize > StrSize) {
+      SamePrefix = SamePrefix.drop_back(SamePrefixSize - StrSize);
+      SamePrefixSize = SamePrefix.size();
+    }
+
+    for (size_t i = 0; i < SamePrefixSize; i++) {
+      if (Str[i] != SamePrefix[i]) {
+        SamePrefix = SamePrefix.drop_back(SamePrefixSize - i);
+        break;
+      }
+    }
+
+    // No common prefix found
+    if (SamePrefix.empty())
+      return StrVec;
+  }
+
+  const size_t SamePrefixSize = SamePrefix.size();
+  std::transform(StrVec.begin(), StrVec.end(), StrVec.begin(),
+                 [SamePrefixSize](const StringRef &Str) {
+                   return Str.drop_front(SamePrefixSize);
+                 });
+  return StrVec;
+}
+
+StringRefVec ParamsGroup::rtrimSame(StringRefVec StrVec) {
+  if (StrVec.empty())
+    return StrVec;
+
+  auto It = StrVec.begin();
+  const auto End = StrVec.end();
+
+  StringRef SameSuffix = *It;
+  It++;
+
+  for (; It != End; It++) {
+    const StringRef &Str = *It;
+
+    const size_t StrSize = Str.size();
+    size_t SameSuffixSize = SameSuffix.size();
+
+    if (SameSuffixSize > StrSize) {
+      SameSuffix = SameSuffix.drop_front(SameSuffixSize - StrSize);
+      SameSuffixSize = SameSuffix.size();
+    }
+
+    for (size_t i = StrSize, j = SameSuffixSize; i > 0 && j > 0; i--, j--) {
+      if (Str[i - 1] != SameSuffix[j - 1]) {
+        SameSuffix = SameSuffix.drop_front(j);
+        break;
+      }
+    }
+
+    // No common suffix found
+    if (SameSuffix.empty())
+      return StrVec;
+  }
+
+  const size_t SameSuffixSize = SameSuffix.size();
+  std::transform(StrVec.begin(), StrVec.end(), StrVec.begin(),
+                 [SameSuffixSize](const StringRef &Str) {
+                   return Str.drop_back(SameSuffixSize);
+                 });
+  return StrVec;
+}
+
+// Split function params in groups with same qualified types
+const ParamsGroupVec &
+CallArgsOrderChecker::getOrBuildParamsGroups(const FunctionDecl *FD) const {
+  const auto It = PGLCache.find(FD);
+  if (It != PGLCache.end())
+    return It->second;
+
+  ParamsGroupVec PGL;
+
+  const unsigned NumParams = FD->getNumParams();
+  if (NumParams > 0) {
+    const ParmVarDecl *prevParam = FD->getParamDecl(0);
+    ParamsGroup PG;
+
+    ParamsGroup::Param p;
+    p.Decl = prevParam;
+
+    PG.ParamsVec.push_back(std::move(p));
+
+    PGL.push_back(std::move(PG));
+
+    for (unsigned ParamIndex = 1; ParamIndex < NumParams; ParamIndex++) {
+      const ParmVarDecl *currParam = FD->getParamDecl(ParamIndex);
+
+      QualType prevType = prevParam->getOriginalType().getCanonicalType();
+      QualType currType = currParam->getOriginalType().getCanonicalType();
+
+      ParamsGroup::Param p;
+      p.Decl = currParam;
+
+      if (currType == prevType) {
+        PGL.back().ParamsVec.push_back(std::move(p));
+      } else {
+        ParamsGroup PG;
+        PG.StartIndex = ParamIndex;
+
+        PG.ParamsVec.push_back(std::move(p));
+
+        PGL.push_back(PG);
+      }
+
+      prevParam = currParam;
+    }
+
+    for (ParamsGroup &PG : PGL)
+      PG.fillSimplifiedParamNames();
+  }
+
+  auto InsertRes = PGLCache.insert(std::make_pair(FD, std::move(PGL)));
+  return InsertRes.first->second;
+}
+
+static StringRef getExprName(const Expr *E) {
+  const Expr *OrigE = E->IgnoreParenCasts();
+  if (!OrigE)
+    return StringRef();
+
+  if (const DeclRefExpr *DRE = dyn_cast_or_null<DeclRefExpr>(OrigE))
+    return DRE->getFoundDecl()->getName();
+  else if (const UnaryOperator *UO = dyn_cast_or_null<UnaryOperator>(OrigE))
+    return getExprName(UO->getSubExpr());
+  else if (const CallExpr *CE = dyn_cast_or_null<CallExpr>(OrigE))
+    return getExprName(CE->getCallee());
+  else if (const MemberExpr *ME = dyn_cast_or_null<MemberExpr>(OrigE))
+    return ME->getMemberDecl()->getName();
+
+  return StringRef();
+}
+
+static StringRef getExprString(const Expr *E, SourceManager &SM) {
+  SourceLocation Start(E->getLocStart());
+  SourceLocation End(E->getLocEnd());
+
+  End = Lexer::getLocForEndOfToken(End, 0, SM, LangOptions());
+  const char *Str = SM.getCharacterData(Start);
+  return StringRef(Str, SM.getCharacterData(End) - Str);
+}
+
+template <typename CallExprT>
+static unsigned getDefaultArgsCount(const CallExprT *CE) {
+  const unsigned NumArgs = CE->getNumArgs();
+  for (unsigned ArgIndex = 0; ArgIndex < NumArgs; ArgIndex++)
+    if (isa<CXXDefaultArgExpr>(CE->getArg(ArgIndex)))
+      return NumArgs - ArgIndex;
+  return 0;
+}
+
+void Callback::checkCallExpr(const CallExpr *CE) {
+  unsigned FirstActualArgOffset = 0;
+  if (const CXXOperatorCallExpr *OCE =
+          dyn_cast_or_null<CXXOperatorCallExpr>(CE)) {
+    if (OCE->getOperator() != OO_Call)
+      return;
+
+    // Skipping first implicit object argument
+    FirstActualArgOffset = 1;
+  }
+
+  const FunctionDecl *FD = CE->getDirectCallee();
+  if (!FD)
+    return;
+
+  checkCall(FD, CE, FirstActualArgOffset);
+}
+
+void Callback::checkCXXConstructExpr(const CXXConstructExpr *CE) {
+  const FunctionDecl *FD = CE->getConstructor();
+  if (!FD)
+    return;
+
+  checkCall(FD, CE, /*FirstActualArgOffset=*/0);
+}
+
+template <typename CallExprT>
+void Callback::checkCall(const FunctionDecl *FD, const CallExprT *CE,
+                         unsigned FirstActualArgOffset) const {
+  // We are not interested in calls without arguments
+  const unsigned NumArgs = CE->getNumArgs();
+  if (NumArgs <= FirstActualArgOffset)
+    return;
+
+  const unsigned NumParams = FD->getNumParams();
+  // Args order permutation isn't possible if FD has < 2 params
+  if (NumParams <= 1)
+    return;
+
+  const unsigned DefNumArgs = getDefaultArgsCount(CE);
+
+  const ParamsGroupVec &PGV = C->getOrBuildParamsGroups(FD);
+  for (ParamsGroupVec::size_type PGVIndex = 0, PGVSize = PGV.size();
+       PGVIndex < PGVSize; PGVIndex++) {
+    const ParamsGroup &PG = PGV[PGVIndex];
+
+    const unsigned PVSize = PG.ParamsVec.size();
+    if (PVSize < 2)
+      continue;
+
+    StringRefVec SimplifiedArgNames;
+    SimplifiedArgNames.reserve(PVSize);
+    for (unsigned PVIndex = 0; PVIndex < PVSize; PVIndex++) {
+      const unsigned ArgIndex = PG.StartIndex + PVIndex + FirstActualArgOffset;
+      SimplifiedArgNames.push_back(getExprName(CE->getArg(ArgIndex)));
+    }
+
+    SimplifiedArgNames = ParamsGroup::trimSame(SimplifiedArgNames);
+
+    const unsigned InvalidMismatchIndex = ~unsigned(0);
+    unsigned FirstMismatchIndex = InvalidMismatchIndex;
+
+    for (unsigned PVIndex = 0; PVIndex < PVSize - 1; PVIndex++) {
+      const ParamsGroup::Param &CurrParam = PG.ParamsVec[PVIndex];
+      const ParamsGroup::Param &NextParam = PG.ParamsVec[PVIndex + 1];
+
+      StringRef CurrArgExprName = SimplifiedArgNames[PVIndex];
+      StringRef NextArgExprName = SimplifiedArgNames[PVIndex + 1];
+
+      // Skip invalid simplified names
+      if (CurrParam.SimplifiedName.empty() || CurrArgExprName.empty())
+        return;
+
+      // Looks like arg matches param
+      if (CurrParam.isNamedLike(CurrArgExprName))
+        continue;
+
+      const unsigned ArgIndex = PG.StartIndex + PVIndex + FirstActualArgOffset;
+      const Expr *CurrArg = CE->getArg(ArgIndex);
+      const Expr *NextArg = CE->getArg(ArgIndex + 1);
+
+      if (FirstMismatchIndex == InvalidMismatchIndex)
+        FirstMismatchIndex = PG.StartIndex + PVIndex;
+
+      if (NextParam.isNamedLike(CurrArgExprName)) {
+        PathDiagnosticLocation Loc =
+            PathDiagnosticLocation::createBegin(CurrArg, SM, AC);
+
+        SmallString<128> Message;
+        llvm::raw_svector_ostream OS(Message);
+
+        // Looks like arg for CurrParam is missing
+        // and args sequence is shifted towards the left
+        if (DefNumArgs > 0 && PG.StartIndex + PVIndex + 1 == NumParams - 1) {
+          OS << "possibly missing arg for param '"
+             << FD->getParamDecl(FirstMismatchIndex)->getName() << "', arg '"
+             << getExprString(CE->getArg(FirstMismatchIndex), SM)
+             << "' passed instead";
+          BR.EmitBasicReport(AC->getDecl(), C, "Possibly missing argument",
+                             categories::LogicError, Message, Loc,
+                             CurrArg->getSourceRange());
+          break;
+          // Looks like args are swapped
+        } else if (CurrParam.isNamedLike(NextArgExprName)) {
+          OS << "possibly wrong order of args '" << getExprString(CurrArg, SM)
+             << "' and '" << getExprString(NextArg, SM)
+             << "' passed as params '" << CurrParam.Decl->getName() << "' and '"
+             << NextParam.Decl->getName() << "'";
+          SourceRange Sr[2];
+          Sr[0] = CurrArg->getSourceRange();
+          Sr[1] = NextArg->getSourceRange();
+          BR.EmitBasicReport(AC->getDecl(), C,
+                             "Possibly wrong order of arguments",
+                             categories::LogicError, Message, Loc, Sr);
+        }
+      }
+    }
+  }
+}
+
+void CallArgsOrderChecker::checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,
+                                            BugReporter &BR) const {
+  auto CallExpr = stmt(
+      eachOf(forEachDescendant(callExpr().bind("callExpr")),
+             forEachDescendant(cxxConstructExpr().bind("cxxConstructExpr"))));
+
+  MatchFinder F;
+  Callback CB(this, BR, Mgr.getSourceManager(), Mgr.getAnalysisDeclContext(D));
+
+  F.addMatcher(CallExpr, &CB);
+  F.match(*D->getBody(), Mgr.getASTContext());
+}
+
+namespace clang {
+namespace ento {
+void registerCallArgsOrderChecker(CheckerManager &Mgr) {
+  Mgr.registerChecker<CallArgsOrderChecker>();
+}
+} // namespace ento
+} // namespace clang
Index: lib/StaticAnalyzer/Checkers/CMakeLists.txt
===================================================================
--- lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -15,6 +15,7 @@
   CStringChecker.cpp
   CStringSyntaxChecker.cpp
   CallAndMessageChecker.cpp
+  CallArgsOrderChecker.cpp
   CastSizeChecker.cpp
   CastToStructChecker.cpp
   CheckObjCDealloc.cpp
Index: include/clang/StaticAnalyzer/Checkers/Checkers.td
===================================================================
--- include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -144,6 +144,10 @@
   HelpText<"Warn about assigning non-{0,1} values to Boolean variables">,
   DescFile<"BoolAssignmentChecker.cpp">;
 
+def CallArgsOrderChecker : Checker<"CallArgsOrder">,
+  HelpText<"Warn about accidental args swap in various call expressions">,
+  DescFile<"CallArgsOrderChecker.cpp">;
+
 def CastSizeChecker : Checker<"CastSize">,
   HelpText<"Check when casting a malloc'ed type T, whether the size is a multiple of the size of T">,
   DescFile<"CastSizeChecker.cpp">;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to