From: Kristof Umann Date: Fri, 29 Jun 2018 11:25:24 +0000 (+0000) Subject: [analyzer][UninitializedObjectChecker] Added a NotesAsWarnings flag X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=41b9b9e380859e739ad6806921c230c12521d1aa;p=clang [analyzer][UninitializedObjectChecker] Added a NotesAsWarnings flag In order to better support consumers of the plist output that don't parse note entries just yet, a 'NotesAsWarnings' flag was added. If it's set to true, all notes will be converted to warnings. Differential Revision: https://reviews.llvm.org/D48285 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@335964 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp b/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp index d9168d037e..773fcb2269 100644 --- a/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp @@ -10,10 +10,19 @@ // This file defines a checker that reports uninitialized fields in objects // created after a constructor call. // -// This checker has an option "Pedantic" (boolean). If its not set or is set to -// false, the checker won't emit warnings for objects that don't have at least -// one initialized field. This may be set with -// `-analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true`. +// This checker has two options: +// - "Pedantic" (boolean). If its not set or is set to false, the checker +// won't emit warnings for objects that don't have at least one initialized +// field. This may be set with +// +// `-analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true`. +// +// - "NotesAsWarnings" (boolean). If set to true, the checker will emit a +// warning for each uninitalized field, as opposed to emitting one warning +// per constructor call, and listing the uninitialized fields that belongs +// to it in notes. Defaults to false. +// +// `-analyzer-config alpha.cplusplus.UninitializedObject:NotesAsWarnings=true`. // //===----------------------------------------------------------------------===// @@ -32,7 +41,9 @@ class UninitializedObjectChecker : public Checker { std::unique_ptr BT_uninitField; public: - bool IsPedantic; // Will be initialized when registering the checker. + // These fields will be initialized when registering the checker. + bool IsPedantic; + bool ShouldConvertNotesToWarnings; UninitializedObjectChecker() : BT_uninitField(new BuiltinBug(this, "Uninitialized fields")) {} @@ -216,6 +227,9 @@ bool isPrimitiveType(const QualType &T) { return T->isBuiltinType() || T->isEnumeralType(); } +/// Constructs a note message for a given FieldChainInfo object. +void printNoteMessage(llvm::raw_ostream &Out, const FieldChainInfo &Chain); + } // end of anonymous namespace //===----------------------------------------------------------------------===// @@ -264,6 +278,23 @@ void UninitializedObjectChecker::checkEndFunction( LocUsedForUniqueing = PathDiagnosticLocation::createBegin( CallSite, Context.getSourceManager(), Node->getLocationContext()); + // For Plist consumers that don't support notes just yet, we'll convert notes + // to warnings. + if (ShouldConvertNotesToWarnings) { + for (const auto &Chain : UninitFields) { + SmallString<100> WarningBuf; + llvm::raw_svector_ostream WarningOS(WarningBuf); + + printNoteMessage(WarningOS, Chain); + + auto Report = llvm::make_unique( + *BT_uninitField, WarningOS.str(), Node, LocUsedForUniqueing, + Node->getLocationContext()->getDecl()); + Context.emitReport(std::move(Report)); + } + return; + } + SmallString<100> WarningBuf; llvm::raw_svector_ostream WarningOS(WarningBuf); WarningOS << UninitFields.size() << " uninitialized field" @@ -274,29 +305,16 @@ void UninitializedObjectChecker::checkEndFunction( *BT_uninitField, WarningOS.str(), Node, LocUsedForUniqueing, Node->getLocationContext()->getDecl()); - // TODO: As of now, one warning is emitted per constructor call, and the - // uninitialized fields are listed in notes. Until there's a better support - // for notes avaible, a note-less version of this checker should be - // implemented. - for (const auto &FieldChain : UninitFields) { + for (const auto &Chain : UninitFields) { SmallString<200> NoteBuf; llvm::raw_svector_ostream NoteOS(NoteBuf); - if (FieldChain.isPointer()) { - if (FieldChain.isDereferenced()) - NoteOS << "uninitialized pointee 'this->"; - else - NoteOS << "uninitialized pointer 'this->"; - } else - NoteOS << "uninitialized field 'this->"; - FieldChain.print(NoteOS); - NoteOS << "'"; + printNoteMessage(NoteOS, Chain); Report->addNote(NoteOS.str(), - PathDiagnosticLocation::create(FieldChain.getEndOfChain(), + PathDiagnosticLocation::create(Chain.getEndOfChain(), Context.getSourceManager())); } - Context.emitReport(std::move(Report)); } @@ -662,10 +680,24 @@ bool isCalledByConstructor(const CheckerContext &Context) { return false; } +void printNoteMessage(llvm::raw_ostream &Out, const FieldChainInfo &Chain) { + if (Chain.isPointer()) { + if (Chain.isDereferenced()) + Out << "uninitialized pointee 'this->"; + else + Out << "uninitialized pointer 'this->"; + } else + Out << "uninitialized field 'this->"; + Chain.print(Out); + Out << "'"; +} + } // end of anonymous namespace void ento::registerUninitializedObjectChecker(CheckerManager &Mgr) { auto Chk = Mgr.registerChecker(); Chk->IsPedantic = Mgr.getAnalyzerOptions().getBooleanOption( "Pedantic", /*DefaultVal*/ false, Chk); + Chk->ShouldConvertNotesToWarnings = Mgr.getAnalyzerOptions().getBooleanOption( + "NotesAsWarnings", /*DefaultVal*/ false, Chk); } diff --git a/test/Analysis/cxx-uninitialized-object-notes-as-warnings.cpp b/test/Analysis/cxx-uninitialized-object-notes-as-warnings.cpp new file mode 100644 index 0000000000..a49507a1aa --- /dev/null +++ b/test/Analysis/cxx-uninitialized-object-notes-as-warnings.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject -analyzer-config alpha.cplusplus.UninitializedObject:NotesAsWarnings=true -std=c++11 -verify %s + +class NotesAsWarningsTest { + int a; + int b; + int dontGetFilteredByNonPedanticMode = 0; + +public: + NotesAsWarningsTest() {} // expected-warning{{uninitialized field 'this->a'}} + // expected-warning@-1{{uninitialized field 'this->b'}} +}; + +void fNotesAsWarningsTest() { + NotesAsWarningsTest(); +}