alexey.knyshev updated this revision to Diff 126293.
alexey.knyshev added a comment.

1. Now implemented via MatchFinder
2. Added missing License header
3. Pass all StringRefs by value
4. Method names now start from small letter
5. Using StringRef::edit_distance instead of custom "similarity" metric
6. Various other formating fixes




Repository:
  rC Clang

https://reviews.llvm.org/D40715

Files:
  include/clang/StaticAnalyzer/Checkers/Checkers.td
  lib/StaticAnalyzer/Checkers/CMakeLists.txt
  lib/StaticAnalyzer/Checkers/LabelInsideSwitchChecker.cpp
  test/Analysis/label-inside-switch.c

Index: test/Analysis/label-inside-switch.c
===================================================================
--- test/Analysis/label-inside-switch.c
+++ test/Analysis/label-inside-switch.c
@@ -0,0 +1,67 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core.LabelInsideSwitch -w -verify %s
+
+int caseAndDefaultMissprint(unsigned count) {
+  int res = 0;
+  switch (count) {
+  case 1:
+    res = 1;
+    break;
+  cas: // expected-warning {{label inside switch (did you mean 'case'?)}}
+  case 2:
+    res = 5;
+    break;
+  case 3:
+    exit(1);
+  defaul: // expected-warning {{label inside switch (did you mean 'default'?)}}
+    return -1;
+  }
+
+  return res;
+}
+
+int nestedSwitch(unsigned x, unsigned y) {
+  int res = 0;
+  switch (x) {
+  case 1:
+    res = 1;
+    break;
+  case 2:
+    res = 5;
+    break;
+  case 3:
+    switch (y) {
+    case 1:
+    case 2:
+    case 4:
+      res = x * y;
+      break;
+    defaul:; // expected-warning {{label inside switch (did you mean 'default'?)}}
+    }
+    break;
+  default:;
+  }
+
+  return res;
+}
+
+int arbitaryLabelInSwitch(int arg) {
+  switch (arg) {
+  case 1:
+  case 2:
+  label: // expected-warning {{label inside switch}}
+  case 3:
+    break;
+  }
+
+  return 0;
+}
+
+int unreachableLabelInSwitch(int arg) {
+  switch (arg) {
+  unreachable: // expected-warning {{label inside switch}}
+  case 1:
+    return 0;
+  default:
+    return arg;
+  }
+}
Index: lib/StaticAnalyzer/Checkers/LabelInsideSwitchChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/LabelInsideSwitchChecker.cpp
+++ lib/StaticAnalyzer/Checkers/LabelInsideSwitchChecker.cpp
@@ -0,0 +1,104 @@
+//== LabelInsideSwitchChecker.cpp - Lable inside switch checker -*- C++ -*--==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines LabelInsideSwitchChecker, which looks for typos in switch
+// cases like missprinting 'defualt', 'cas' or other accidental insertion
+// of labeled statement.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+using namespace clang;
+using namespace ento;
+using namespace ast_matchers;
+
+namespace {
+class LabelInsideSwitchChecker : public Checker<check::ASTCodeBody> {
+public:
+  void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,
+                        BugReporter &BR) const;
+};
+
+static StringRef suggestTypoFix(StringRef Str) {
+  StringRef DefaultStr("default");
+  const unsigned DefaultStrED =
+      Str.edit_distance(DefaultStr, true, DefaultStr.size() / 2);
+
+  if (DefaultStrED <= DefaultStr.size() / 2)
+    return DefaultStr;
+
+  StringRef CaseStr("case");
+  const unsigned CaseStrED =
+      Str.edit_distance(CaseStr, true, CaseStr.size() / 2);
+
+  if (CaseStrED <= CaseStr.size() / 2)
+    return CaseStr;
+
+  return StringRef();
+}
+
+class Callback : public MatchFinder::MatchCallback {
+  const CheckerBase *C;
+  BugReporter &BR;
+  AnalysisDeclContext *AC;
+
+  void report(const LabelStmt *L) {
+    StringRef Suggest = suggestTypoFix(L->getName());
+
+    SmallString<64> Message;
+    llvm::raw_svector_ostream OS(Message);
+    OS << "label inside switch";
+    if (!Suggest.empty())
+      OS << " (did you mean '" << Suggest << "'?)";
+
+    PathDiagnosticLocation Loc =
+        PathDiagnosticLocation::createBegin(L, BR.getSourceManager(), AC);
+    BR.EmitBasicReport(AC->getDecl(), C, "Labeled statement inside switch",
+                       categories::LogicError, Message, Loc,
+                       L->getSourceRange());
+  }
+
+public:
+  Callback(const CheckerBase *C, BugReporter &BR, AnalysisDeclContext *AC)
+      : C(C), BR(BR), AC(AC) {}
+
+  virtual void run(const MatchFinder::MatchResult &Result) override {
+    if (const LabelStmt *L = Result.Nodes.getNodeAs<LabelStmt>("label"))
+      report(L);
+    if (const LabelStmt *L = Result.Nodes.getNodeAs<LabelStmt>("label_in_case"))
+      report(L);
+  }
+};
+} // end anonymous namespace
+
+void LabelInsideSwitchChecker::checkASTCodeBody(const Decl *D,
+                                                AnalysisManager &Mgr,
+                                                BugReporter &BR) const {
+  auto LabelStmt = stmt(hasDescendant(switchStmt(
+      eachOf(has(compoundStmt(forEach(labelStmt().bind("label")))),
+             forEachSwitchCase(forEach(labelStmt().bind("label_in_case")))))));
+
+  MatchFinder F;
+  Callback CB(this, BR, Mgr.getAnalysisDeclContext(D));
+
+  F.addMatcher(LabelStmt, &CB);
+  F.match(*D->getBody(), Mgr.getASTContext());
+}
+
+namespace clang {
+namespace ento {
+void registerLabelInsideSwitchChecker(CheckerManager &Mgr) {
+  Mgr.registerChecker<LabelInsideSwitchChecker>();
+}
+} // namespace ento
+} // namespace clang
Index: lib/StaticAnalyzer/Checkers/CMakeLists.txt
===================================================================
--- lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -43,6 +43,7 @@
   IteratorChecker.cpp
   IvarInvalidationChecker.cpp
   LLVMConventionsChecker.cpp
+  LabelInsideSwitchChecker.cpp
   LocalizationChecker.cpp
   MacOSKeychainAPIChecker.cpp
   MacOSXAPIChecker.cpp
Index: include/clang/StaticAnalyzer/Checkers/Checkers.td
===================================================================
--- include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -160,6 +160,10 @@
   HelpText<"Warn about unintended use of identical expressions in operators">,
   DescFile<"IdenticalExprChecker.cpp">;
 
+def LabelInsideSwitchChecker : Checker<"LabelInsideSwitch">,
+  HelpText<"Warn about labeled statements inside switch">,
+  DescFile<"LabelInsideSwitchChecker.cpp">;
+
 def FixedAddressChecker : Checker<"FixedAddr">,
   HelpText<"Check for assignment of a fixed address to a pointer">,
   DescFile<"FixedAddressChecker.cpp">;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to