ymandel created this revision.
ymandel added reviewers: xazax.hun, sgatev.
Herald added subscribers: tschuett, steakhal, rnkovacs.
Herald added a project: All.
ymandel requested review of this revision.
Herald added a project: clang.

Google's protobufs are often quite large and their internal state is never worth
modeling in the environment. Exclude them during value construction.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D123032

Files:
  clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
  clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp

Index: clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
===================================================================
--- clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
+++ clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
@@ -20,8 +20,8 @@
 
 using namespace clang;
 using namespace dataflow;
-using ::testing::ElementsAre;
-using ::testing::Pair;
+using ::testing::IsNull;
+using ::testing::NotNull;
 
 class EnvironmentTest : public ::testing::Test {
   DataflowAnalysisContext Context;
@@ -98,4 +98,70 @@
   EXPECT_NE(PV, nullptr);
 }
 
+TEST_F(EnvironmentTest, ExcludeProtobufTypes) {
+  using namespace ast_matchers;
+
+  std::string Code = R"cc(
+    namespace proto2 {
+    struct Message {};
+    }
+
+    namespace google {
+    namespace protobuf {
+    struct Message {};
+    }
+    }
+
+    namespace other {
+    namespace google {
+    namespace protobuf {
+    struct Message {};
+    }
+    }
+    }
+
+    struct Foo : public proto2::Message {
+      bool Field;
+    };
+
+    struct Bar : public google::protobuf::Message {
+      bool Field;
+    };
+
+    // Not a protobuf, but looks like it. Verify that it is *not* excluded.
+    struct Zab : public other::google::protobuf::Message {
+      bool Field;
+    };
+
+    void target() {
+      Foo F;
+      Bar B;
+      Zab Z;
+      (void)0;
+      /*[[check]]*/
+    }
+  )cc";
+
+  auto Unit =
+      tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++11"});
+  auto &Context = Unit->getASTContext();
+
+  ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U);
+
+  auto Results = match(varDecl(eachOf(varDecl(hasName("F")).bind("varF"),
+                                      varDecl(hasName("B")).bind("varB"),
+                                      varDecl(hasName("Z")).bind("varZ"))),
+                       Context);
+  const auto *F = selectFirst<VarDecl>("varF", Results);
+  ASSERT_TRUE(F != nullptr);
+  const auto *B = selectFirst<VarDecl>("varB", Results);
+  ASSERT_TRUE(B != nullptr);
+  const auto *Z = selectFirst<VarDecl>("varZ", Results);
+  ASSERT_TRUE(Z != nullptr);
+
+  EXPECT_THAT(Env.createValue(F->getType()), IsNull());
+  EXPECT_THAT(Env.createValue(B->getType()), IsNull());
+  EXPECT_THAT(Env.createValue(Z->getType()), NotNull());
+}
+
 } // namespace
Index: clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
===================================================================
--- clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -493,6 +493,41 @@
   return Val;
 }
 
+// Hard code certain types to exclude from modeling. Currently, we limit to
+// Google protobufs, since they can be very large, and have no value in
+// modeling.
+static bool isExcludedRecordType(const RecordType *Ty) {
+  const auto *CD = dyn_cast<CXXRecordDecl>(Ty->getDecl());
+  if (CD == nullptr || !CD->hasDefinition() || CD->getNumBases() != 1)
+    return false;
+
+  QualType BQ = CD->bases_begin()->getType();
+  if (BQ.isNull())
+    return false;
+
+  const RecordType *BaseTy = BQ->getAs<RecordType>();
+  if (BaseTy == nullptr)
+    return false;
+
+  const RecordDecl *RD = BaseTy->getDecl();
+  if (RD->getIdentifier() == nullptr || RD->getName() != "Message")
+    return false;
+
+  const auto *ND = dyn_cast<NamespaceDecl>(RD->getDeclContext());
+  if (ND == nullptr || ND->getIdentifier() == nullptr)
+    return false;
+  if (ND->getName() == "proto2")
+    return true;
+
+  // Check for `::google::protobuf`:
+  if (ND->getName() != "protobuf")
+    return false;
+
+  ND = dyn_cast<NamespaceDecl>(ND->getDeclContext());
+  return ND != nullptr && ND->getParent()->isTranslationUnit() &&
+         ND->getIdentifier() != nullptr && ND->getName() == "google";
+}
+
 Value *Environment::createValueUnlessSelfReferential(
     QualType Type, llvm::DenseSet<QualType> &Visited, int Depth,
     int &CreatedValuesCount) {
@@ -549,7 +584,8 @@
     return &takeOwnership(std::make_unique<PointerValue>(PointeeLoc));
   }
 
-  if (Type->isStructureOrClassType()) {
+  if (Type->isStructureOrClassType() &&
+      !isExcludedRecordType(Type->getAs<RecordType>())) {
     CreatedValuesCount++;
     // FIXME: Initialize only fields that are accessed in the context that is
     // being analyzed.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to