From: Jordan Rose Date: Fri, 16 Aug 2013 01:06:30 +0000 (+0000) Subject: [analyzer] Merge TextPathDiagnostics and ClangDiagPathDiagConsumer. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5fba5a789a238c29ef811a39a39be722443ec1b1;p=clang [analyzer] Merge TextPathDiagnostics and ClangDiagPathDiagConsumer. This once again restores notes to following their associated warnings in -analyzer-output=text mode. (This is still only intended for use as a debugging aid.) One twist is that the warning locations in "regular" analysis output modes (plist, multi-file-plist, html, and plist-html) are reported at a different location on the command line than in the output file, since the command line has no path context. This commit makes -analyzer-output=text behave like a normal output format, which means that the *command line output will be different* in -analyzer-text mode. Again, since -analyzer-text is a debugging aid and lo-fi stand-in for a regular output mode, this change makes sense. Along the way, remove a few pieces of stale code related to the path diagnostic consumers. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@188514 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/StaticAnalyzer/Core/Analyses.def b/include/clang/StaticAnalyzer/Core/Analyses.def index dc7945016b..3355f4b694 100644 --- a/include/clang/StaticAnalyzer/Core/Analyses.def +++ b/include/clang/StaticAnalyzer/Core/Analyses.def @@ -24,14 +24,14 @@ ANALYSIS_STORE(RegionStore, "region", "Use region-based analyzer store", CreateR ANALYSIS_CONSTRAINTS(RangeConstraints, "range", "Use constraint tracking of concrete value ranges", CreateRangeConstraintManager) #ifndef ANALYSIS_DIAGNOSTICS -#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) +#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) #endif -ANALYSIS_DIAGNOSTICS(HTML, "html", "Output analysis results using HTML", createHTMLDiagnosticConsumer, false) -ANALYSIS_DIAGNOSTICS(PLIST, "plist", "Output analysis results using Plists", createPlistDiagnosticConsumer, true) -ANALYSIS_DIAGNOSTICS(PLIST_MULTI_FILE, "plist-multi-file", "Output analysis results using Plists (allowing for mult-file bugs)", createPlistMultiFileDiagnosticConsumer, true) -ANALYSIS_DIAGNOSTICS(PLIST_HTML, "plist-html", "Output analysis results using HTML wrapped with Plists", createPlistHTMLDiagnosticConsumer, true) -ANALYSIS_DIAGNOSTICS(TEXT, "text", "Text output of analysis results", createTextPathDiagnosticConsumer, true) +ANALYSIS_DIAGNOSTICS(HTML, "html", "Output analysis results using HTML", createHTMLDiagnosticConsumer) +ANALYSIS_DIAGNOSTICS(PLIST, "plist", "Output analysis results using Plists", createPlistDiagnosticConsumer) +ANALYSIS_DIAGNOSTICS(PLIST_MULTI_FILE, "plist-multi-file", "Output analysis results using Plists (allowing for mult-file bugs)", createPlistMultiFileDiagnosticConsumer) +ANALYSIS_DIAGNOSTICS(PLIST_HTML, "plist-html", "Output analysis results using HTML wrapped with Plists", createPlistHTMLDiagnosticConsumer) +ANALYSIS_DIAGNOSTICS(TEXT, "text", "Text output of analysis results", createTextPathDiagnosticConsumer) #ifndef ANALYSIS_PURGE #define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) diff --git a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h index 2ef802d607..618782e5d7 100644 --- a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -52,7 +52,7 @@ NumConstraints /// AnalysisDiagClients - Set of available diagnostic clients for rendering /// analysis results. enum AnalysisDiagClients { -#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREAT) PD_##NAME, +#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN) PD_##NAME, #include "clang/StaticAnalyzer/Core/Analyses.def" NUM_ANALYSIS_DIAG_CLIENTS }; diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h index abcd13daf9..0e827841d0 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h @@ -97,7 +97,6 @@ public: enum PathGenerationScheme { None, Minimal, Extensive, AlternateExtensive }; virtual PathGenerationScheme getGenerationScheme() const { return Minimal; } virtual bool supportsLogicalOpControlFlow() const { return false; } - virtual bool supportsAllBlockEdges() const { return false; } /// Return true if the PathDiagnosticConsumer supports individual /// PathDiagnostics that span multiple files. diff --git a/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h b/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h index b856de7dc6..43e9166b3c 100644 --- a/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h +++ b/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h @@ -27,18 +27,12 @@ namespace ento { class PathDiagnosticConsumer; typedef std::vector PathDiagnosticConsumers; -#define CREATE_CONSUMER(NAME)\ -void create ## NAME ## DiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,\ - PathDiagnosticConsumers &C,\ - const std::string& prefix,\ - const Preprocessor &PP); - -CREATE_CONSUMER(HTML) -CREATE_CONSUMER(Plist) -CREATE_CONSUMER(PlistMultiFile) -CREATE_CONSUMER(TextPath) - -#undef CREATE_CONSUMER +#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN)\ +void CREATEFN(AnalyzerOptions &AnalyzerOpts,\ + PathDiagnosticConsumers &C,\ + const std::string &Prefix,\ + const Preprocessor &PP); +#include "clang/StaticAnalyzer/Core/Analyses.def" } // end 'ento' namespace } // end 'clang' namespace diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index a4a84127c0..9e60619008 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -167,7 +167,7 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, if (Arg *A = Args.getLastArg(OPT_analyzer_output)) { StringRef Name = A->getValue(); AnalysisDiagClients Value = llvm::StringSwitch(Name) -#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREAT) \ +#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN) \ .Case(CMDFLAG, PD_##NAME) #include "clang/StaticAnalyzer/Core/Analyses.def" .Default(NUM_ANALYSIS_DIAG_CLIENTS); diff --git a/lib/StaticAnalyzer/Core/CMakeLists.txt b/lib/StaticAnalyzer/Core/CMakeLists.txt index 91f15b31da..18ca67e70c 100644 --- a/lib/StaticAnalyzer/Core/CMakeLists.txt +++ b/lib/StaticAnalyzer/Core/CMakeLists.txt @@ -38,7 +38,6 @@ add_clang_library(clangStaticAnalyzerCore Store.cpp SubEngine.cpp SymbolManager.cpp - TextPathDiagnostics.cpp ) add_dependencies(clangStaticAnalyzerCore diff --git a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp index 087ab5a8a2..7f7881b5f4 100644 --- a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp +++ b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp @@ -50,7 +50,6 @@ namespace { PathGenerationScheme getGenerationScheme() const { return Extensive; } bool supportsLogicalOpControlFlow() const { return true; } - bool supportsAllBlockEdges() const { return true; } virtual bool supportsCrossFileDiagnostics() const { return SupportsCrossFileDiagnostics; } diff --git a/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp b/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp deleted file mode 100644 index d5706d6dbb..0000000000 --- a/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp +++ /dev/null @@ -1,72 +0,0 @@ -//===--- TextPathDiagnostics.cpp - Text Diagnostics for Paths ---*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the TextPathDiagnostics object. -// -//===----------------------------------------------------------------------===// - -#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" -#include "llvm/Support/raw_ostream.h" -using namespace clang; -using namespace ento; -using namespace llvm; - -namespace { - -/// \brief Simple path diagnostic client used for outputting as diagnostic notes -/// the sequence of events. -class TextPathDiagnostics : public PathDiagnosticConsumer { - const std::string OutputFile; - DiagnosticsEngine &Diag; - -public: - TextPathDiagnostics(const std::string& output, DiagnosticsEngine &diag) - : OutputFile(output), Diag(diag) {} - - void FlushDiagnosticsImpl(std::vector &Diags, - FilesMade *filesMade); - - virtual StringRef getName() const { - return "TextPathDiagnostics"; - } - - PathGenerationScheme getGenerationScheme() const { return Minimal; } - bool supportsLogicalOpControlFlow() const { return true; } - bool supportsAllBlockEdges() const { return true; } - virtual bool supportsCrossFileDiagnostics() const { return true; } -}; - -} // end anonymous namespace - -void ento::createTextPathDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts, - PathDiagnosticConsumers &C, - const std::string& out, - const Preprocessor &PP) { - C.push_back(new TextPathDiagnostics(out, PP.getDiagnostics())); -} - -void TextPathDiagnostics::FlushDiagnosticsImpl( - std::vector &Diags, - FilesMade *) { - for (std::vector::iterator it = Diags.begin(), - et = Diags.end(); it != et; ++it) { - const PathDiagnostic *D = *it; - - PathPieces FlatPath = D->path.flatten(/*ShouldFlattenMacros=*/true); - for (PathPieces::const_iterator I = FlatPath.begin(), E = FlatPath.end(); - I != E; ++I) { - unsigned diagID = - Diag.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Note, - (*I)->getString()); - Diag.Report((*I)->getLocation().asLocation(), diagID); - } - } -} diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index 64ba5f6484..abc1e9fc52 100644 --- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -66,23 +66,52 @@ STATISTIC(MaxCFGSize, "The maximum number of basic blocks in a function."); // Special PathDiagnosticConsumers. //===----------------------------------------------------------------------===// -static void createPlistHTMLDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts, - PathDiagnosticConsumers &C, - const std::string &prefix, - const Preprocessor &PP) { +void ento::createPlistHTMLDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts, + PathDiagnosticConsumers &C, + const std::string &prefix, + const Preprocessor &PP) { createHTMLDiagnosticConsumer(AnalyzerOpts, C, llvm::sys::path::parent_path(prefix), PP); createPlistDiagnosticConsumer(AnalyzerOpts, C, prefix, PP); } +void ento::createTextPathDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts, + PathDiagnosticConsumers &C, + const std::string &Prefix, + const clang::Preprocessor &PP) { + llvm_unreachable("'text' consumer should be enabled on ClangDiags"); +} + namespace { class ClangDiagPathDiagConsumer : public PathDiagnosticConsumer { DiagnosticsEngine &Diag; + bool IncludePath; public: - ClangDiagPathDiagConsumer(DiagnosticsEngine &Diag) : Diag(Diag) {} + ClangDiagPathDiagConsumer(DiagnosticsEngine &Diag) + : Diag(Diag), IncludePath(false) {} virtual ~ClangDiagPathDiagConsumer() {} virtual StringRef getName() const { return "ClangDiags"; } - virtual PathGenerationScheme getGenerationScheme() const { return None; } + + virtual bool supportsLogicalOpControlFlow() const { return true; } + virtual bool supportsCrossFileDiagnostics() const { return true; } + + virtual PathGenerationScheme getGenerationScheme() const { + return IncludePath ? Minimal : None; + } + + void enablePaths() { + IncludePath = true; + } + + void emitDiag(SourceLocation L, unsigned DiagID, + ArrayRef Ranges) { + DiagnosticBuilder DiagBuilder = Diag.Report(L, DiagID); + + for (ArrayRef::iterator I = Ranges.begin(), E = Ranges.end(); + I != E; ++I) { + DiagBuilder << *I; + } + } void FlushDiagnosticsImpl(std::vector &Diags, FilesMade *filesMade) { @@ -102,14 +131,20 @@ public: unsigned ErrorDiag = Diag.getCustomDiagID(DiagnosticsEngine::Warning, TmpStr); SourceLocation L = PD->getLocation().asLocation(); - DiagnosticBuilder diagBuilder = Diag.Report(L, ErrorDiag); + emitDiag(L, ErrorDiag, PD->path.back()->getRanges()); + + if (!IncludePath) + continue; - // Get the ranges from the last point in the path. - ArrayRef Ranges = PD->path.back()->getRanges(); + PathPieces FlatPath = PD->path.flatten(/*ShouldFlattenMacros=*/true); + for (PathPieces::const_iterator PI = FlatPath.begin(), + PE = FlatPath.end(); + PI != PE; ++PI) { + unsigned NoteID = Diag.getCustomDiagID(DiagnosticsEngine::Note, + (*PI)->getString()); - for (ArrayRef::iterator I = Ranges.begin(), - E = Ranges.end(); I != E; ++I) { - diagBuilder << *I; + SourceLocation NoteLoc = (*PI)->getLocation().asLocation(); + emitDiag(NoteLoc, NoteID, (*PI)->getRanges()); } } } @@ -186,20 +221,21 @@ public: void DigestAnalyzerOptions() { // Create the PathDiagnosticConsumer. - PathConsumers.push_back(new ClangDiagPathDiagConsumer(PP.getDiagnostics())); + ClangDiagPathDiagConsumer *clangDiags = + new ClangDiagPathDiagConsumer(PP.getDiagnostics()); + PathConsumers.push_back(clangDiags); + + if (Opts->AnalysisDiagOpt == PD_TEXT) { + clangDiags->enablePaths(); - if (!OutDir.empty()) { + } else if (!OutDir.empty()) { switch (Opts->AnalysisDiagOpt) { default: -#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \ +#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) \ case PD_##NAME: CREATEFN(*Opts.getPtr(), PathConsumers, OutDir, PP);\ break; #include "clang/StaticAnalyzer/Core/Analyses.def" } - } else if (Opts->AnalysisDiagOpt == PD_TEXT) { - // Create the text client even without a specified output file since - // it just uses diagnostic notes. - createTextPathDiagnosticConsumer(*Opts.getPtr(), PathConsumers, "", PP); } // Create the analyzer component creators. diff --git a/test/Analysis/diagnostics/text-diagnostics.c b/test/Analysis/diagnostics/text-diagnostics.c new file mode 100644 index 0000000000..592521672f --- /dev/null +++ b/test/Analysis/diagnostics/text-diagnostics.c @@ -0,0 +1,21 @@ +// RUN: %clang --analyze -Xanalyzer -analyzer-output=text -fno-caret-diagnostics %s 2>&1 | FileCheck %s + +void testA() { + int *p = 0; + *p = 1; + + // CHECK-LABEL: text-diagnostics.c:{{.*}}:6: warning: Dereference of null pointer (loaded from variable 'p') + // CHECK-NEXT: text-diagnostics.c:[[@LINE-4]]:3: note: 'p' initialized to a null pointer value + // CHECK-NEXT: text-diagnostics.c:[[@LINE-4]]:6: note: Dereference of null pointer (loaded from variable 'p') +} + +void testB(int *q) { + if (q) + return; + *q = 1; + + // CHECK-LABEL: text-diagnostics.c:{{.*}}:6: warning: Dereference of null pointer (loaded from variable 'q') + // CHECK-NEXT: text-diagnostics.c:[[@LINE-5]]:7: note: Assuming 'q' is null + // CHECK-NEXT: text-diagnostics.c:[[@LINE-6]]:3: note: Taking false branch + // CHECK-NEXT: text-diagnostics.c:[[@LINE-5]]:6: note: Dereference of null pointer (loaded from variable 'q') +} diff --git a/test/Analysis/retain-release-path-notes-gc.m b/test/Analysis/retain-release-path-notes-gc.m index 364035d3cf..40592f008b 100644 --- a/test/Analysis/retain-release-path-notes-gc.m +++ b/test/Analysis/retain-release-path-notes-gc.m @@ -40,17 +40,17 @@ CFTypeRef CFGetSomething(); void creationViaCFCreate () { - CFTypeRef leaked = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected}} - return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} + CFTypeRef leaked = CFCreateSomething(); // expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected}} + return; // expected-warning{{leak}} expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} } void makeCollectable () { - CFTypeRef leaked = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected}} + CFTypeRef leaked = CFCreateSomething(); // expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected}} CFRetain(leaked); // expected-note{{Reference count incremented. The object now has a +2 retain count}} CFMakeCollectable(leaked); // expected-note{{In GC mode a call to 'CFMakeCollectable' decrements an object's retain count and registers the object with the garbage collector. An object must have a 0 retain count to be garbage collected. After this call its retain count is +1}} NSMakeCollectable(leaked); // expected-note{{In GC mode a call to 'NSMakeCollectable' decrements an object's retain count and registers the object with the garbage collector. Since it now has a 0 retain count the object can be automatically collected by the garbage collector}} CFRetain(leaked); // expected-note{{Reference count incremented. The object now has a +1 retain count. The object is not eligible for garbage collection until the retain count reaches 0 again}} - return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} + return; // expected-warning{{leak}} expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} } void retainReleaseIgnored () { @@ -63,13 +63,13 @@ void retainReleaseIgnored () { @implementation Foo (FundamentalRuleUnderGC) - (id)getViolation { - id object = (id) CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected}} - return object; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'object' and returned from method 'getViolation' is potentially leaked when using garbage collection. Callers of this method do not expect a returned object with a +1 retain count since they expect the object to be managed by the garbage collector}} + id object = (id) CFCreateSomething(); // expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected}} + return object; // expected-warning{{leak}} expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'object' and returned from method 'getViolation' is potentially leaked when using garbage collection. Callers of this method do not expect a returned object with a +1 retain count since they expect the object to be managed by the garbage collector}} } - (id)copyViolation { - id object = (id) CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected}} - return object; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'object' and returned from method 'copyViolation' is potentially leaked when using garbage collection. Callers of this method do not expect a returned object with a +1 retain count since they expect the object to be managed by the garbage collector}} + id object = (id) CFCreateSomething(); // expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count. Core Foundation objects are not automatically garbage collected}} + return object; // expected-warning{{leak}} expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'object' and returned from method 'copyViolation' is potentially leaked when using garbage collection. Callers of this method do not expect a returned object with a +1 retain count since they expect the object to be managed by the garbage collector}} } @end diff --git a/test/Analysis/retain-release-path-notes.m b/test/Analysis/retain-release-path-notes.m index cd76abbc15..d4479c3fb0 100644 --- a/test/Analysis/retain-release-path-notes.m +++ b/test/Analysis/retain-release-path-notes.m @@ -43,33 +43,33 @@ CFTypeRef CFGetSomething(); void creationViaAlloc () { - id leaked = [[NSObject alloc] init]; // expected-warning{{leak}} expected-note{{Method returns an Objective-C object with a +1 retain count}} - return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} + id leaked = [[NSObject alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}} + return; // expected-warning{{leak}} expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} } void creationViaCFCreate () { - CFTypeRef leaked = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}} - return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} + CFTypeRef leaked = CFCreateSomething(); // expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}} + return; // expected-warning{{leak}} expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} } void acquisitionViaMethod (Foo *foo) { - id leaked = [foo methodWithValue]; // expected-warning{{leak}} expected-note{{Method returns an Objective-C object with a +0 retain count}} + id leaked = [foo methodWithValue]; // expected-note{{Method returns an Objective-C object with a +0 retain count}} [leaked retain]; // expected-note{{Reference count incremented. The object now has a +1 retain count}} [leaked retain]; // expected-note{{Reference count incremented. The object now has a +2 retain count}} [leaked release]; // expected-note{{Reference count decremented. The object now has a +1 retain count}} - return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} + return; // expected-warning{{leak}} expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} } void acquisitionViaProperty (Foo *foo) { - id leaked = foo.propertyValue; // expected-warning{{leak}} expected-note{{Property returns an Objective-C object with a +0 retain count}} + id leaked = foo.propertyValue; // expected-note{{Property returns an Objective-C object with a +0 retain count}} [leaked retain]; // expected-note{{Reference count incremented. The object now has a +1 retain count}} - return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} + return; // expected-warning{{leak}} expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} } void acquisitionViaCFFunction () { - CFTypeRef leaked = CFGetSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain count}} + CFTypeRef leaked = CFGetSomething(); // expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain count}} CFRetain(leaked); // expected-note{{Reference count incremented. The object now has a +1 retain count}} - return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} + return; // expected-warning{{leak}} expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} } void explicitDealloc () { @@ -98,10 +98,10 @@ void autoreleaseUnowned (Foo *foo) { } void makeCollectableIgnored () { - CFTypeRef leaked = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}} + CFTypeRef leaked = CFCreateSomething(); // expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}} CFMakeCollectable(leaked); // expected-note{{When GC is not enabled a call to 'CFMakeCollectable' has no effect on its argument}} NSMakeCollectable(leaked); // expected-note{{When GC is not enabled a call to 'NSMakeCollectable' has no effect on its argument}} - return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} + return; // expected-warning{{leak}} expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}} } CFTypeRef CFCopyRuleViolation () { @@ -110,8 +110,8 @@ CFTypeRef CFCopyRuleViolation () { } CFTypeRef CFGetRuleViolation () { - CFTypeRef object = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}} - return object; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'object' is returned from a function whose name ('CFGetRuleViolation') does not contain 'Copy' or 'Create'. This violates the naming convention rules given in the Memory Management Guide for Core Foundation}} + CFTypeRef object = CFCreateSomething(); // expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}} + return object; // expected-warning{{leak}} expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'object' is returned from a function whose name ('CFGetRuleViolation') does not contain 'Copy' or 'Create'. This violates the naming convention rules given in the Memory Management Guide for Core Foundation}} } @implementation Foo (FundamentalMemoryManagementRules) @@ -131,8 +131,8 @@ CFTypeRef CFGetRuleViolation () { } - (id)getViolation { - id result = [[Foo alloc] init]; // expected-warning{{leak}} expected-note{{Method returns an Objective-C object with a +1 retain count}} - return result; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'result' is returned from a method whose name ('getViolation') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'. This violates the naming convention rules given in the Memory Management Guide for Cocoa}} + id result = [[Foo alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}} + return result; // expected-warning{{leak}} expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'result' is returned from a method whose name ('getViolation') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'. This violates the naming convention rules given in the Memory Management Guide for Cocoa}} } - (id)copyAutorelease { @@ -228,12 +228,12 @@ static int Cond; // expected-note@-3 {{Returning from 'initX'}} // expected-note@-4 {{Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1}} // initI is inlined because the allocation happens within initY - id y = [[MyObj alloc] initY]; // expected-warning {{Potential leak of an object}} + id y = [[MyObj alloc] initY]; // expected-note@-1 {{Calling 'initY'}} // expected-note@-2 {{Returning from 'initY'}} // initZ is not inlined - id z = [[MyObj alloc] initZ]; + id z = [[MyObj alloc] initZ]; // expected-warning {{Potential leak of an object}} // expected-note@-1 {{Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1}} [x release];