Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -1969,7 +1969,8 @@ def _all_warnings : Flag<["--"], "all-warnings">, Alias; def _analyze_auto : Flag<["--"], "analyze-auto">, Flags<[DriverOption]>; def _analyzer_no_default_checks : Flag<["--"], "analyzer-no-default-checks">, Flags<[DriverOption]>; -def _analyzer_output : JoinedOrSeparate<["--"], "analyzer-output">, Flags<[DriverOption]>; +def _analyzer_output : JoinedOrSeparate<["--"], "analyzer-output">, Flags<[DriverOption]>, + HelpText<"Static analyzer report output format (html|plist|plist-multi-file|plist-html|text).">; def _analyze : Flag<["--"], "analyze">, Flags<[DriverOption, CoreOption]>, HelpText<"Run the static analyzer">; def _assemble : Flag<["--"], "assemble">, Alias; Index: lib/StaticAnalyzer/Core/PathDiagnostic.cpp =================================================================== --- lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -211,6 +211,12 @@ const SourceManager &SMgr = D->path.front()->getLocation().getManager(); SmallVector WorkList; WorkList.push_back(&D->path); + SmallString<128> buf; + llvm::raw_svector_ostream warning(buf); + warning << "warning: Path diagnostic report is not generated. Current " + << "output format does not support diagnostics that cross file " + << "boundaries. Refer to --analyzer-output for valid output " + << "formats\n"; while (!WorkList.empty()) { const PathPieces &path = *WorkList.pop_back_val(); @@ -222,19 +228,25 @@ if (FID.isInvalid()) { FID = SMgr.getFileID(L); - } else if (SMgr.getFileID(L) != FID) - return; // FIXME: Emit a warning? + } else if (SMgr.getFileID(L) != FID) { + llvm::errs() << warning.str(); + return; + } // Check the source ranges. ArrayRef Ranges = piece->getRanges(); for (ArrayRef::iterator I = Ranges.begin(), E = Ranges.end(); I != E; ++I) { SourceLocation L = SMgr.getExpansionLoc(I->getBegin()); - if (!L.isFileID() || SMgr.getFileID(L) != FID) - return; // FIXME: Emit a warning? + if (!L.isFileID() || SMgr.getFileID(L) != FID) { + llvm::errs() << warning.str(); + return; + } L = SMgr.getExpansionLoc(I->getEnd()); - if (!L.isFileID() || SMgr.getFileID(L) != FID) - return; // FIXME: Emit a warning? + if (!L.isFileID() || SMgr.getFileID(L) != FID) { + llvm::errs() << warning.str(); + return; + } } if (const PathDiagnosticCallPiece *call = Index: test/Analysis/diagnostics/diag-cross-file-boundaries.h =================================================================== --- test/Analysis/diagnostics/diag-cross-file-boundaries.h +++ test/Analysis/diagnostics/diag-cross-file-boundaries.h @@ -0,0 +1,4 @@ +static void f() { + int *p = 0; + *p = 1; // expected-warning{{Dereference of null pointer}} +} Index: test/Analysis/diagnostics/diag-cross-file-boundaries.c =================================================================== --- test/Analysis/diagnostics/diag-cross-file-boundaries.c +++ test/Analysis/diagnostics/diag-cross-file-boundaries.c @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=html -o PR12421.html %s 2>&1 | FileCheck %s + +// Test for PR12421 +#include "diag-cross-file-boundaries.h" + +int main(){ + f(); + return 0; +} + +// CHECK: warning: Path diagnostic report is not generated.