Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h =================================================================== --- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h +++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObject.h @@ -35,6 +35,13 @@ // `-analyzer-config \ // alpha.cplusplus.UninitializedObject:CheckPointeeInitialization=true`. // +// - "IgnoreUnionlikeConstructs" (boolean). If set to false, the checker will +// not analyze structures that have a field a name or type name that +// contains "[Tt]ag" or "[Kk]ind". Defaults to false. +// +// `-analyzer-config \ +// alpha.cplusplus.UninitializedObject:IgnoreUnionlikeConstructs=true`. +// // 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 @@ -61,6 +68,7 @@ bool IsPedantic; bool ShouldConvertNotesToWarnings; bool CheckPointeeInitialization; + bool IgnoreUnionlikeConstructs; }; /// Represent a single field. This is only an interface to abstract away special Index: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp +++ lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp @@ -107,6 +107,11 @@ static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor, CheckerContext &Context); +/// Checks whether RD is a union-like construct. We'll consider a RecordDecl +/// union-like, if it has a field that has [Kk]ind or [Tt]ag in it's identifier +/// or type name. +static bool isUnionLike(const RecordDecl *RD); + //===----------------------------------------------------------------------===// // Methods for UninitializedObjectChecker. //===----------------------------------------------------------------------===// @@ -223,6 +228,11 @@ R->getValueType()->getAs()->getDecl()->getDefinition(); assert(RD && "Referred record has no definition"); + if (Opts.IgnoreUnionlikeConstructs && isUnionLike(RD)) { + IsAnyFieldInitialized = true; + return false; + } + bool ContainsUninitField = false; // Are all of this non-union's fields initialized? @@ -454,6 +464,19 @@ return false; } +static bool isUnionLike(const RecordDecl *RD) { + llvm::Regex ContainsKindOrTag("[kK]ind|[tT]ag"); + + for (const FieldDecl *FD : RD->fields()) { + if (ContainsKindOrTag.match(FD->getType().getAsString())) + return true; + if (ContainsKindOrTag.match(FD->getName())) + return true; + } + + return false; +} + StringRef 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 @@ -480,4 +503,6 @@ "NotesAsWarnings", /*DefaultVal*/ false, Chk); Opts.CheckPointeeInitialization = Mgr.getAnalyzerOptions().getBooleanOption( "CheckPointeeInitialization", /*DefaultVal*/ false, Chk); + Opts.IgnoreUnionlikeConstructs = Mgr.getAnalyzerOptions().getBooleanOption( + "IgnoreUnionlikeConstructs", /*DefaultVal*/ false, Chk); } Index: test/Analysis/cxx-uninitialized-object-unionlike-constructs.cpp =================================================================== --- /dev/null +++ test/Analysis/cxx-uninitialized-object-unionlike-constructs.cpp @@ -0,0 +1,110 @@ +// 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:IgnoreUnionlikeConstructs=true \ +// 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); +}