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`. // +// - "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 @@ -61,6 +68,7 @@ bool IsPedantic; bool ShouldConvertNotesToWarnings; bool CheckPointeeInitialization; + std::string IgnoredRecordsWithFieldPattern; }; /// 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,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. //===----------------------------------------------------------------------===// @@ -223,6 +227,12 @@ R->getValueType()->getAs()->getDecl()->getDefinition(); assert(RD && "Referred record has no definition"); + if (!Opts.IgnoredRecordsWithFieldPattern.empty() && + shouldIgnoreRecord(RD, Opts.IgnoredRecordsWithFieldPattern)) { + IsAnyFieldInitialized = true; + return false; + } + bool ContainsUninitField = false; // Are all of this non-union's fields initialized? @@ -454,6 +464,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; +} + 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,7 @@ "NotesAsWarnings", /*DefaultVal*/ false, Chk); Opts.CheckPointeeInitialization = Mgr.getAnalyzerOptions().getBooleanOption( "CheckPointeeInitialization", /*DefaultVal*/ false, Chk); + Opts.IgnoredRecordsWithFieldPattern = + Mgr.getAnalyzerOptions().getOptionAsString("IgnoreRecordsWithField", + /*DefaultVal*/ "", Chk); } Index: test/Analysis/cxx-uninitialized-object-unionlike-constructs.cpp =================================================================== --- /dev/null +++ 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: www/analyzer/alpha_checks.html =================================================================== --- www/analyzer/alpha_checks.html +++ 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". +