r330876 - [analyzer] Enable analysis of WebKit "unified sources".

Artem Dergachev via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 25 14:51:27 PDT 2018


Author: dergachev
Date: Wed Apr 25 14:51:26 2018
New Revision: 330876

URL: http://llvm.org/viewvc/llvm-project?rev=330876&view=rev
Log:
[analyzer] Enable analysis of WebKit "unified sources".

Normally the analyzer begins path-sensitive analysis from functions within
the main file, even though the path is allowed to go through any functions
within the translation unit.

When a recent version of WebKit is compiled, the "unified sources" technique
is used, that assumes #including multiple code files into a single main file.
Such file would have no functions defined in it, so the analyzer wouldn't be
able to find any entry points for path-sensitive analysis.

This patch pattern-matches unified file names that are similar to those
used by WebKit and allows the analyzer to find entry points in the included
code files. A more aggressive/generic approach is being planned as well.

Differential Revision: https://reviews.llvm.org/D45839

Added:
    cfe/trunk/test/Analysis/unified-sources/
    cfe/trunk/test/Analysis/unified-sources/UnifiedSource-1.cpp
    cfe/trunk/test/Analysis/unified-sources/container.h
    cfe/trunk/test/Analysis/unified-sources/source1.cpp
    cfe/trunk/test/Analysis/unified-sources/source2.cpp
Modified:
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
    cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
    cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h?rev=330876&r1=330875&r2=330876&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h Wed Apr 25 14:51:26 2018
@@ -126,6 +126,36 @@ public:
   AnalysisDeclContext *getAnalysisDeclContext(const Decl *D) {
     return AnaCtxMgr.getContext(D);
   }
+
+  static bool isInCodeFile(SourceLocation SL, const SourceManager &SM) {
+    if (SM.isInMainFile(SL))
+      return true;
+
+    // Support the "unified sources" compilation method (eg. WebKit) that
+    // involves producing non-header files that include other non-header files.
+    // We should be included directly from a UnifiedSource* file
+    // and we shouldn't be a header - which is a very safe defensive check.
+    SourceLocation IL = SM.getIncludeLoc(SM.getFileID(SL));
+    if (!IL.isValid() || !SM.isInMainFile(IL))
+      return false;
+    // Should rather be "file name starts with", but the current .getFilename
+    // includes the full path.
+    if (SM.getFilename(IL).contains("UnifiedSource")) {
+      // It might be great to reuse FrontendOptions::getInputKindForExtension()
+      // but for now it doesn't discriminate between code and header files.
+      return llvm::StringSwitch<bool>(SM.getFilename(SL).rsplit('.').second)
+          .Cases("c", "m", "mm", "C", "cc", "cp", true)
+          .Cases("cpp", "CPP", "c++", "cxx", "cppm", true)
+          .Default(false);
+    }
+
+    return false;
+  }
+
+  bool isInCodeFile(SourceLocation SL) {
+    const SourceManager &SM = getASTContext().getSourceManager();
+    return isInCodeFile(SL, SM);
+  }
 };
 
 } // enAnaCtxMgrspace

Modified: cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp?rev=330876&r1=330875&r2=330876&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp Wed Apr 25 14:51:26 2018
@@ -939,15 +939,14 @@ const ObjCPropertyDecl *ObjCMethodCall::
 bool ObjCMethodCall::canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl,
                                              Selector Sel) const {
   assert(IDecl);
-  const SourceManager &SM =
-    getState()->getStateManager().getContext().getSourceManager();
-
+  AnalysisManager &AMgr =
+      getState()->getStateManager().getOwningEngine()->getAnalysisManager();
   // If the class interface is declared inside the main file, assume it is not
   // subcassed.
   // TODO: It could actually be subclassed if the subclass is private as well.
   // This is probably very rare.
   SourceLocation InterfLoc = IDecl->getEndOfDefinitionLoc();
-  if (InterfLoc.isValid() && SM.isInMainFile(InterfLoc))
+  if (InterfLoc.isValid() && AMgr.isInCodeFile(InterfLoc))
     return false;
 
   // Assume that property accessors are not overridden.
@@ -969,7 +968,7 @@ bool ObjCMethodCall::canBeOverridenInSub
       return false;
 
     // If outside the main file,
-    if (D->getLocation().isValid() && !SM.isInMainFile(D->getLocation()))
+    if (D->getLocation().isValid() && !AMgr.isInCodeFile(D->getLocation()))
       return true;
 
     if (D->isOverriding()) {

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp?rev=330876&r1=330875&r2=330876&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp Wed Apr 25 14:51:26 2018
@@ -806,8 +806,9 @@ static bool isCXXSharedPtrDtor(const Fun
 /// This checks static properties of the function, such as its signature and
 /// CFG, to determine whether the analyzer should ever consider inlining it,
 /// in any context.
-static bool mayInlineDecl(AnalysisDeclContext *CalleeADC,
-                          AnalyzerOptions &Opts) {
+static bool mayInlineDecl(AnalysisManager &AMgr,
+                          AnalysisDeclContext *CalleeADC) {
+  AnalyzerOptions &Opts = AMgr.getAnalyzerOptions();
   // FIXME: Do not inline variadic calls.
   if (CallEvent::isVariadic(CalleeADC->getDecl()))
     return false;
@@ -830,7 +831,7 @@ static bool mayInlineDecl(AnalysisDeclCo
       // Conditionally control the inlining of methods on objects that look
       // like C++ containers.
       if (!Opts.mayInlineCXXContainerMethods())
-        if (!Ctx.getSourceManager().isInMainFile(FD->getLocation()))
+        if (!AMgr.isInCodeFile(FD->getLocation()))
           if (isContainerMethod(Ctx, FD))
             return false;
 
@@ -891,7 +892,7 @@ bool ExprEngine::shouldInlineCall(const
   } else {
     // We haven't actually checked the static properties of this function yet.
     // Do that now, and record our decision in the function summaries.
-    if (mayInlineDecl(CalleeADC, Opts)) {
+    if (mayInlineDecl(getAnalysisManager(), CalleeADC)) {
       Engine.FunctionSummaries->markMayInline(D);
     } else {
       Engine.FunctionSummaries->markShouldNotInline(D);

Modified: cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp?rev=330876&r1=330875&r2=330876&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp Wed Apr 25 14:51:26 2018
@@ -29,6 +29,7 @@
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
 #include "llvm/ADT/ArrayRef.h"
@@ -148,11 +149,11 @@ getFirstStackedCallToHeaderFile(PathDiag
   if (CallLoc.isMacroID())
     return nullptr;
 
-  assert(SMgr.isInMainFile(CallLoc) &&
-         "The call piece should be in the main file.");
+  assert(AnalysisManager::isInCodeFile(CallLoc, SMgr) &&
+         "The call piece should not be in a header file.");
 
   // Check if CP represents a path through a function outside of the main file.
-  if (!SMgr.isInMainFile(CP->callEnterWithin.asLocation()))
+  if (!AnalysisManager::isInCodeFile(CP->callEnterWithin.asLocation(), SMgr))
     return CP;
 
   const PathPieces &Path = CP->path;

Modified: cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp?rev=330876&r1=330875&r2=330876&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp Wed Apr 25 14:51:26 2018
@@ -678,7 +678,7 @@ AnalysisConsumer::getModeForDecl(Decl *D
   SourceLocation SL = Body ? Body->getLocStart() : D->getLocation();
   SL = SM.getExpansionLoc(SL);
 
-  if (!Opts->AnalyzeAll && !SM.isWrittenInMainFile(SL)) {
+  if (!Opts->AnalyzeAll && !Mgr->isInCodeFile(SL)) {
     if (SL.isInvalid() || SM.isInSystemHeader(SL))
       return AM_None;
     return Mode & ~AM_Path;

Added: cfe/trunk/test/Analysis/unified-sources/UnifiedSource-1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/unified-sources/UnifiedSource-1.cpp?rev=330876&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/unified-sources/UnifiedSource-1.cpp (added)
+++ cfe/trunk/test/Analysis/unified-sources/UnifiedSource-1.cpp Wed Apr 25 14:51:26 2018
@@ -0,0 +1,5 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
+
+// There should still be diagnostics within included files.
+#include "source1.cpp"
+#include "source2.cpp"

Added: cfe/trunk/test/Analysis/unified-sources/container.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/unified-sources/container.h?rev=330876&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/unified-sources/container.h (added)
+++ cfe/trunk/test/Analysis/unified-sources/container.h Wed Apr 25 14:51:26 2018
@@ -0,0 +1,10 @@
+class ContainerInHeaderFile {
+  class Iterator {
+  };
+
+public:
+  Iterator begin() const;
+  Iterator end() const;
+
+  int method() { return 0; }
+};

Added: cfe/trunk/test/Analysis/unified-sources/source1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/unified-sources/source1.cpp?rev=330876&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/unified-sources/source1.cpp (added)
+++ cfe/trunk/test/Analysis/unified-sources/source1.cpp Wed Apr 25 14:51:26 2018
@@ -0,0 +1,15 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
+
+// This test tests that the warning is here when it is included from
+// the unified sources file. The run-line in this file is there
+// only to suppress LIT warning for the complete lack of run-line.
+int foo(int x) {
+  if (x) {}
+  return 1 / x; // expected-warning{{}}
+}
+
+// Let's see if the container inlining heuristic still works.
+#include "container.h"
+int testContainerMethodInHeaderFile(ContainerInHeaderFile Cont) {
+  return 1 / Cont.method(); // no-warning
+}

Added: cfe/trunk/test/Analysis/unified-sources/source2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/unified-sources/source2.cpp?rev=330876&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/unified-sources/source2.cpp (added)
+++ cfe/trunk/test/Analysis/unified-sources/source2.cpp Wed Apr 25 14:51:26 2018
@@ -0,0 +1,25 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
+
+// This test tests that the warning is here when it is included from
+// the unified sources file. The run-line in this file is there
+// only to suppress LIT warning for the complete lack of run-line.
+int testNullDereference() {
+  int *x = 0;
+  return *x; // expected-warning{{}}
+}
+
+// Let's see if the container inlining heuristic still works.
+class ContainerInCodeFile {
+  class Iterator {
+  };
+
+public:
+  Iterator begin() const;
+  Iterator end() const;
+
+  int method() { return 0; }
+};
+
+int testContainerMethodInCodeFile(ContainerInCodeFile Cont) {
+  return 1 / Cont.method(); // expected-warning{{}}
+}




More information about the cfe-commits mailing list