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". +