Charusso updated this revision to Diff 207133.
Charusso edited the summary of this revision.
Charusso added a comment.

- Make it match the class name. (Whoops!)
- Reorder the tuple (swap the return value with the call name).
- Remove the Projects option.
- Remove unnecessary input validation.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63915/new/

https://reviews.llvm.org/D63915

Files:
  clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
  clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
  clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp
  clang/test/Analysis/analyzer-config.c
  clang/test/Analysis/return-value-guaranteed.cpp

Index: clang/test/Analysis/return-value-guaranteed.cpp
===================================================================
--- /dev/null
+++ clang/test/Analysis/return-value-guaranteed.cpp
@@ -0,0 +1,82 @@
+// RUN: %clang_analyze_cc1 \
+// RUN:  -analyzer-checker=core,debug.ExprInspection \
+// RUN:  -analyzer-checker=apiModeling.ReturnValue \
+// RUN:  -analyzer-config apiModeling.ReturnValue:Calls="true:error" \
+// RUN:  -verify %s
+// RUN: %clang_analyze_cc1 \
+// RUN:  -analyzer-checker=core,debug.ExprInspection \
+// RUN:  -analyzer-checker=apiModeling.ReturnValue \
+// RUN:  -analyzer-config \
+// RUN:   apiModeling.ReturnValue:Calls="true:error;false:error:ErrorHandler" \
+// RUN:  -verify %s
+
+// FIXME: expected-no-diagnostics
+
+void clang_analyzer_eval(bool);
+void clang_analyzer_warnIfReached();
+
+
+struct Foo { int Field; };
+bool error();
+bool problem();
+void doSomething();
+
+// We predefine the return value of 'error()' to 'true' and we cannot take the
+// false-branches where error would occur.
+namespace test_calls {
+bool parseFoo(Foo &F) {
+  if (problem())
+    return error();
+
+  F.Field = 0;
+  return false;
+}
+
+bool parseFile() {
+  clang_analyzer_eval(error() == true); // FIXME: xpected-warning{{TRUE}}
+
+  Foo F;
+  if (parseFoo(F))
+    return true;
+
+  if (F.Field == 0) {
+    // no-warning: "The left operand of '==' is a garbage value" was here.
+    doSomething();
+  }
+
+  return false;
+}
+} // namespace test_calls
+
+namespace test_classes {
+struct ErrorHandler {
+  static bool error();
+};
+
+bool parseFoo(Foo &F) {
+  if (problem())
+    return error();
+
+  F.Field = 0;
+  return ErrorHandler::error();
+}
+
+bool parseFile() {
+  Foo F;
+  if (parseFoo(F))
+    return true;
+
+  if (F.Field == 0) {
+    // no-warning: "The left operand of '==' is a garbage value" was here.
+    doSomething();
+  }
+
+  return false;
+}
+} // namespace test_classes
+
+void test_note() {
+  clang_analyzer_eval(error() == true); // FIXME: xpected-warning{{TRUE}}
+  if (error())
+    (void)(1 / !error());
+}
Index: clang/test/Analysis/analyzer-config.c
===================================================================
--- clang/test/Analysis/analyzer-config.c
+++ clang/test/Analysis/analyzer-config.c
@@ -9,6 +9,7 @@
 // CHECK-NEXT: alpha.clone.CloneChecker:ReportNormalClones = true
 // CHECK-NEXT: alpha.security.MmapWriteExec:MmapProtExec = 0x04
 // CHECK-NEXT: alpha.security.MmapWriteExec:MmapProtRead = 0x01
+// CHECK-NEXT: apiModeling.ReturnValue:Calls = ""
 // CHECK-NEXT: avoid-suppressing-null-argument-paths = false
 // CHECK-NEXT: c++-allocator-inlining = true
 // CHECK-NEXT: c++-container-inlining = false
@@ -88,4 +89,4 @@
 // CHECK-NEXT: unroll-loops = false
 // CHECK-NEXT: widen-loops = false
 // CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 85
+// CHECK-NEXT: num-entries = 86
Index: clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp
===================================================================
--- /dev/null
+++ clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp
@@ -0,0 +1,137 @@
+//===- ReturnValueChecker - Applies guaranteed return values ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines ReturnValueChecker, which checks for calls with guaranteed
+// boolean return value. It ensures the return value of each function call.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSet.h"
+
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+struct CallTy {
+  bool TruthValue;
+  StringRef Name;
+  Optional<StringRef> Class;
+};
+}
+
+namespace {
+class ReturnValueChecker : public Checker<check::PostCall> {
+public:
+  void checkPostCall(const CallEvent &CE, CheckerContext &C) const;
+  void setCalls(StringRef Calls);
+
+private:
+  SmallVector<CallTy, 13> CallVector;
+};
+} // namespace
+
+void ReturnValueChecker::checkPostCall(const CallEvent &CE,
+                                       CheckerContext &C) const {
+  // Match the calls.
+  const CallTy *Call = nullptr;
+  if (const IdentifierInfo *II = CE.getCalleeIdentifier()) {
+    for (const auto &CurrentCall : CallVector) {
+      // Match by call name.
+      if (!II->getName().equals_lower(CurrentCall.Name))
+        continue;
+
+      // We are in the mode when no class specified.
+      if (!CurrentCall.Class.hasValue()) {
+        Call = &CurrentCall;
+        break;
+      }
+
+      // Match by class name.
+      if (Optional<StringRef> ClassName = CurrentCall.Class)
+        if (const auto *MD = dyn_cast<CXXMethodDecl>(CE.getDecl()))
+          if (!MD->getParent()->getName().equals_lower(*ClassName))
+            continue;
+
+      Call = &CurrentCall;
+      break;
+    }
+  }
+
+  if (!Call)
+    return;
+
+  // Create a note.
+  const NoteTag *CallTag = C.getNoteTag([Call](BugReport &BR) -> std::string {
+    SmallString<128> Msg;
+    llvm::raw_svector_ostream Out(Msg);
+
+    Out << '\'' << Call->Class << "::" << Call->Name << "' always return "
+        << (Call->TruthValue ? "true" : "false");
+
+    return Out.str();
+  });
+
+  // Set the return value with the note.
+  ProgramStateRef State = C.getState();
+  SVal RetV = CE.getReturnValue();
+  Optional<DefinedOrUnknownSVal> RetDV = RetV.getAs<DefinedOrUnknownSVal>();
+
+  State = State->assume(*RetDV, Call->TruthValue);
+  C.addTransition(State, CallTag);
+}
+
+void ReturnValueChecker::setCalls(StringRef Calls) {
+  if (Calls == "\"\"" || Calls.size() == 0)
+    return;
+
+  SmallVector<StringRef, 13> RawTupleVector;
+  Calls.split(RawTupleVector, ';');
+
+  for (const auto &RawTuple : RawTupleVector) {
+    SmallVector<StringRef, 3> Tuple;
+    RawTuple.split(Tuple, ':');
+
+    CallTy Call;
+    Call.TruthValue = Tuple[0].trim().equals("true");
+    Call.Name = Tuple[1].trim();
+    Call.Class = Tuple.size() == 3 ? Tuple[2].trim() : Optional<StringRef>();
+
+    CallVector.push_back(Call);
+  }
+}
+
+void ento::registerReturnValueChecker(CheckerManager &Mgr) {
+  ReturnValueChecker *RVC = Mgr.registerChecker<ReturnValueChecker>();
+
+  // These are known in the LLVM project.
+  StringRef LLVMCalls = "true:printError:AsmParser;"
+                        "true:Error:LLLexer;"
+                        "true:Error:MCAsmParser;"
+                        "true:error:MIParser";
+  RVC->setCalls(LLVMCalls);
+
+  StringRef OptionalCalls =
+      Mgr.getAnalyzerOptions().getCheckerStringOption(RVC, "Calls");
+  RVC->setCalls(OptionalCalls);
+}
+
+bool ento::shouldRegisterReturnValueChecker(const LangOptions &LO) {
+  return true;
+}
Index: clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -83,6 +83,7 @@
   RetainCountChecker/RetainCountDiagnostics.cpp
   ReturnPointerRangeChecker.cpp
   ReturnUndefChecker.cpp
+  ReturnValueChecker.cpp
   RunLoopAutoreleaseLeakChecker.cpp
   SimpleStreamChecker.cpp
   SmartPtrModeling.cpp
Index: clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
===================================================================
--- clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -95,10 +95,10 @@
 def LLVM : Package<"llvm">;
 def LLVMAlpha : Package<"llvm">, ParentPackage<Alpha>;
 
-// The APIModeling package is for checkers that model APIs and don't perform
-// any diagnostics. These checkers are always turned on; this package is
-// intended for API modeling that is not controlled by the target triple.
-def APIModeling : Package<"apiModeling">, Hidden;
+// The APIModeling package is for checkers that model APIs. These checkers are
+// always turned on; this package is intended for API modeling that is not
+// controlled by the target triple.
+def APIModeling : Package<"apiModeling">;
 def GoogleAPIModeling : Package<"google">, ParentPackage<APIModeling>, Hidden;
 
 def Debug : Package<"debug">, Hidden;
@@ -274,6 +274,20 @@
 
 let ParentPackage = APIModeling in {
 
+def ReturnValueChecker : Checker<"ReturnValue">,
+  HelpText<"Model the guaranteed boolean return value of function calls">,
+  CheckerOptions<[
+    CmdLineOption<String,
+                  "Calls",
+                  "A semicolon separated list of tuples, each consists of a "
+                  "return value, call name and an optional class name "
+                  "separated by colons: \"return value:call:class;return...\". "
+                  "It ensures the boolean return value of each function call.",
+                  "\"\"",
+                  Released>,
+  ]>,
+  Documentation<HasDocumentation>;
+
 def StdCLibraryFunctionsChecker : Checker<"StdCLibraryFunctions">,
   HelpText<"Improve modeling of the C standard library functions">,
   Documentation<NotDocumented>;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to