Index: cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
===================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h
@@ -35,6 +35,13 @@
// `-analyzer-config \
// alpha.cplusplus.UninitializedObject:CheckPointeeInitialization=true`.
//
+// - "IgnoreRecordsWithField" (string). If supplied, the checker will not
+// analyze structures that have a field with a name or type name that
+// matches the given pattern. Defaults to "".
+//
+// `-analyzer-config \
+// alpha.cplusplus.UninitializedObject:IgnoreRecordsWithField="[Tt]ag|[Kk]ind"`.
+//
// TODO: With some clever heuristics, some pointers should be dereferenced
// by default. For example, if the pointee is constructed within the
// constructor call, it's reasonable to say that no external object
@@ -60,7 +67,8 @@
struct UninitObjCheckerOptions {
bool IsPedantic = false;
bool ShouldConvertNotesToWarnings = false;
- bool CheckPointeeInitialization = false;
+ bool CheckPointeeInitialization = false;
+ std::string IgnoredRecordsWithFieldPattern;
};
/// A lightweight polymorphic wrapper around FieldRegion *. We'll use this
Index: cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
===================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
@@ -109,6 +109,10 @@
static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
CheckerContext &Context);
+/// Checks whether RD contains a field with a name or type name that matches
+/// \p Pattern.
+static bool shouldIgnoreRecord(const RecordDecl *RD, StringRef Pattern);
+
//===----------------------------------------------------------------------===//
// Methods for UninitializedObjectChecker.
//===----------------------------------------------------------------------===//
@@ -228,6 +232,12 @@
return true;
}
+ if (!Opts.IgnoredRecordsWithFieldPattern.empty() &&
+ shouldIgnoreRecord(RD, Opts.IgnoredRecordsWithFieldPattern)) {
+ IsAnyFieldInitialized = true;
+ return false;
+ }
+
bool ContainsUninitField = false;
// Are all of this non-union's fields initialized?
@@ -442,6 +452,19 @@
return false;
}
+static bool shouldIgnoreRecord(const RecordDecl *RD, StringRef Pattern) {
+ llvm::Regex R(Pattern);
+
+ for (const FieldDecl *FD : RD->fields()) {
+ if (R.match(FD->getType().getAsString()))
+ return true;
+ if (R.match(FD->getName()))
+ return true;
+ }
+
+ return false;
+}
+
std::string clang::ento::getVariableName(const FieldDecl *Field) {
// If Field is a captured lambda variable, Field->getName() will return with
// an empty string. We can however acquire it's name from the lambda's
@@ -472,10 +495,13 @@
AnalyzerOptions &AnOpts = Mgr.getAnalyzerOptions();
UninitObjCheckerOptions &ChOpts = Chk->Opts;
- ChOpts.IsPedantic = AnOpts.getBooleanOption(
- "Pedantic", /*DefaultVal*/ false, Chk);
- ChOpts.ShouldConvertNotesToWarnings = AnOpts.getBooleanOption(
- "NotesAsWarnings", /*DefaultVal*/ false, Chk);
+ ChOpts.IsPedantic =
+ AnOpts.getBooleanOption("Pedantic", /*DefaultVal*/ false, Chk);
+ ChOpts.ShouldConvertNotesToWarnings =
+ AnOpts.getBooleanOption("NotesAsWarnings", /*DefaultVal*/ false, Chk);
ChOpts.CheckPointeeInitialization = AnOpts.getBooleanOption(
"CheckPointeeInitialization", /*DefaultVal*/ false, Chk);
+ ChOpts.IgnoredRecordsWithFieldPattern =
+ AnOpts.getOptionAsString("IgnoreRecordsWithField",
+ /*DefaultVal*/ "", Chk);
}
Index: cfe/trunk/test/Analysis/cxx-uninitialized-object-unionlike-constructs.cpp
===================================================================
--- cfe/trunk/test/Analysis/cxx-uninitialized-object-unionlike-constructs.cpp
+++ cfe/trunk/test/Analysis/cxx-uninitialized-object-unionlike-constructs.cpp
@@ -0,0 +1,136 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject \
+// RUN: -analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true -DPEDANTIC \
+// RUN: -analyzer-config alpha.cplusplus.UninitializedObject:IgnoreRecordsWithField="[Tt]ag|[Kk]ind" \
+// RUN: -std=c++11 -verify %s
+
+// expected-no-diagnostics
+
+// Both type and name contains "kind".
+struct UnionLikeStruct1 {
+ enum Kind {
+ volume,
+ area
+ } kind;
+
+ int Volume;
+ int Area;
+
+ UnionLikeStruct1(Kind kind, int Val) : kind(kind) {
+ switch (kind) {
+ case volume:
+ Volume = Val;
+ break;
+ case area:
+ Area = Val;
+ break;
+ }
+ }
+};
+
+void fUnionLikeStruct1() {
+ UnionLikeStruct1 t(UnionLikeStruct1::volume, 10);
+}
+
+// Only name contains "kind".
+struct UnionLikeStruct2 {
+ enum Type {
+ volume,
+ area
+ } kind;
+
+ int Volume;
+ int Area;
+
+ UnionLikeStruct2(Type kind, int Val) : kind(kind) {
+ switch (kind) {
+ case volume:
+ Volume = Val;
+ break;
+ case area:
+ Area = Val;
+ break;
+ }
+ }
+};
+
+void fUnionLikeStruct2() {
+ UnionLikeStruct2 t(UnionLikeStruct2::volume, 10);
+}
+
+// Only type contains "kind".
+struct UnionLikeStruct3 {
+ enum Kind {
+ volume,
+ area
+ } type;
+
+ int Volume;
+ int Area;
+
+ UnionLikeStruct3(Kind type, int Val) : type(type) {
+ switch (type) {
+ case volume:
+ Volume = Val;
+ break;
+ case area:
+ Area = Val;
+ break;
+ }
+ }
+};
+
+void fUnionLikeStruct3() {
+ UnionLikeStruct3 t(UnionLikeStruct3::volume, 10);
+}
+
+// Only type contains "tag".
+struct UnionLikeStruct4 {
+ enum Tag {
+ volume,
+ area
+ } type;
+
+ int Volume;
+ int Area;
+
+ UnionLikeStruct4(Tag type, int Val) : type(type) {
+ switch (type) {
+ case volume:
+ Volume = Val;
+ break;
+ case area:
+ Area = Val;
+ break;
+ }
+ }
+};
+
+void fUnionLikeStruct4() {
+ UnionLikeStruct4 t(UnionLikeStruct4::volume, 10);
+}
+
+// Both name and type name contains but does not equal to tag/kind.
+struct UnionLikeStruct5 {
+ enum WhateverTagBlahBlah {
+ volume,
+ area
+ } FunnyKindName;
+
+ int Volume;
+ int Area;
+
+ UnionLikeStruct5(WhateverTagBlahBlah type, int Val) : FunnyKindName(type) {
+ switch (FunnyKindName) {
+ case volume:
+ Volume = Val;
+ break;
+ case area:
+ Area = Val;
+ break;
+ }
+ }
+};
+
+void fUnionLikeStruct5() {
+ UnionLikeStruct5 t(UnionLikeStruct5::volume, 10);
+}
Index: cfe/trunk/www/analyzer/alpha_checks.html
===================================================================
--- cfe/trunk/www/analyzer/alpha_checks.html
+++ cfe/trunk/www/analyzer/alpha_checks.html
@@ -356,6 +356,13 @@
whether the object itself is initialized. Defaults to false.
-analyzer-config alpha.cplusplus.UninitializedObject:CheckPointeeInitialization=true
.
+
IgnoreRecordsWithField
" (string). If supplied, the checker will not
+ analyze structures that have a field with a name or type name that
+ matches the given pattern. Defaults to ""
.
+
+ -analyzer-config alpha.cplusplus.UninitializedObject:IgnoreRecordsWithField="[Tt]ag|[Kk]ind"
.
+