15d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek//===--- PlistDiagnostics.cpp - Plist Diagnostics for Paths -----*- C++ -*-===//
25d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek//
35d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek//                     The LLVM Compiler Infrastructure
45d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek//
55d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek// This file is distributed under the University of Illinois Open Source
65d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek// License. See LICENSE.TXT for details.
75d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek//
85d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek//===----------------------------------------------------------------------===//
95d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek//
105d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek//  This file defines the PlistDiagnostics object.
115d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek//
125d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek//===----------------------------------------------------------------------===//
135d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek
149fcc2ab2ec5e00802880e205568ff3afbd70a773Ted Kremenek#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
155d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek#include "clang/Basic/FileManager.h"
16651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include "clang/Basic/PlistSupport.h"
17f238aa4f556c0aa3024abebaf3bdbf5f3f68fb94Anna Zaks#include "clang/Basic/SourceManager.h"
18f238aa4f556c0aa3024abebaf3bdbf5f3f68fb94Anna Zaks#include "clang/Basic/Version.h"
192c78b873f4f3823ae859c15674cb3d76c8554113Chris Lattner#include "clang/Lex/Preprocessor.h"
2055fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
21b99083e60325a28063fb588f458a871151971fdcChandler Carruth#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
225d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek#include "llvm/ADT/DenseMap.h"
235d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek#include "llvm/ADT/SmallVector.h"
2455fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "llvm/Support/Casting.h"
255d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenekusing namespace clang;
269ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenekusing namespace ento;
27651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesusing namespace markup;
28f7227709522ad70773467ffb2d620db0d43318d9Ted Kremenek
29f7227709522ad70773467ffb2d620db0d43318d9Ted Kremeneknamespace {
30ef3643fbbbf66247c5e205497fae0f46e240c143David Blaikie  class PlistDiagnostics : public PathDiagnosticConsumer {
31ddf32dabe71f00aa0943449f67201f587f0a04d6Ted Kremenek    const std::string OutputFile;
322c78b873f4f3823ae859c15674cb3d76c8554113Chris Lattner    const LangOptions &LangOpts;
3329af3c7425b791daf5c9ec0a820d6b5baab2ddccTed Kremenek    const bool SupportsCrossFileDiagnostics;
345d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek  public:
359fcc2ab2ec5e00802880e205568ff3afbd70a773Ted Kremenek    PlistDiagnostics(AnalyzerOptions &AnalyzerOpts,
369fcc2ab2ec5e00802880e205568ff3afbd70a773Ted Kremenek                     const std::string& prefix,
379fcc2ab2ec5e00802880e205568ff3afbd70a773Ted Kremenek                     const LangOptions &LangOpts,
38c4bac8e376b98d633bb00ee5f510d5e58449753cTed Kremenek                     bool supportsMultipleFiles);
39b697a4e4118d2d59dc0f38463c8417ddaf58a11fTed Kremenek
40bac341346f3c8e713a8f165120fd54b500ee3189Ted Kremenek    virtual ~PlistDiagnostics() {}
41b697a4e4118d2d59dc0f38463c8417ddaf58a11fTed Kremenek
42bac341346f3c8e713a8f165120fd54b500ee3189Ted Kremenek    void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
43651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                              FilesMade *filesMade) override;
44651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
45651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    virtual StringRef getName() const override {
46b697a4e4118d2d59dc0f38463c8417ddaf58a11fTed Kremenek      return "PlistDiagnostics";
47b697a4e4118d2d59dc0f38463c8417ddaf58a11fTed Kremenek    }
481eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
49651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    PathGenerationScheme getGenerationScheme() const override {
50651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      return Extensive;
51651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    }
52651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    bool supportsLogicalOpControlFlow() const override { return true; }
53651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    bool supportsCrossFileDiagnostics() const override {
5429af3c7425b791daf5c9ec0a820d6b5baab2ddccTed Kremenek      return SupportsCrossFileDiagnostics;
5529af3c7425b791daf5c9ec0a820d6b5baab2ddccTed Kremenek    }
561eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  };
575d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek} // end anonymous namespace
585d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek
599fcc2ab2ec5e00802880e205568ff3afbd70a773Ted KremenekPlistDiagnostics::PlistDiagnostics(AnalyzerOptions &AnalyzerOpts,
609fcc2ab2ec5e00802880e205568ff3afbd70a773Ted Kremenek                                   const std::string& output,
61f75560670bcdd59b051149bdece3eac14e313853Ted Kremenek                                   const LangOptions &LO,
62c4bac8e376b98d633bb00ee5f510d5e58449753cTed Kremenek                                   bool supportsMultipleFiles)
639fcc2ab2ec5e00802880e205568ff3afbd70a773Ted Kremenek  : OutputFile(output),
649fcc2ab2ec5e00802880e205568ff3afbd70a773Ted Kremenek    LangOpts(LO),
6529af3c7425b791daf5c9ec0a820d6b5baab2ddccTed Kremenek    SupportsCrossFileDiagnostics(supportsMultipleFiles) {}
665d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek
679fcc2ab2ec5e00802880e205568ff3afbd70a773Ted Kremenekvoid ento::createPlistDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
689fcc2ab2ec5e00802880e205568ff3afbd70a773Ted Kremenek                                         PathDiagnosticConsumers &C,
69c4bac8e376b98d633bb00ee5f510d5e58449753cTed Kremenek                                         const std::string& s,
70c4bac8e376b98d633bb00ee5f510d5e58449753cTed Kremenek                                         const Preprocessor &PP) {
719fcc2ab2ec5e00802880e205568ff3afbd70a773Ted Kremenek  C.push_back(new PlistDiagnostics(AnalyzerOpts, s,
729fcc2ab2ec5e00802880e205568ff3afbd70a773Ted Kremenek                                   PP.getLangOpts(), false));
7329af3c7425b791daf5c9ec0a820d6b5baab2ddccTed Kremenek}
7429af3c7425b791daf5c9ec0a820d6b5baab2ddccTed Kremenek
759fcc2ab2ec5e00802880e205568ff3afbd70a773Ted Kremenekvoid ento::createPlistMultiFileDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
769fcc2ab2ec5e00802880e205568ff3afbd70a773Ted Kremenek                                                  PathDiagnosticConsumers &C,
77c4bac8e376b98d633bb00ee5f510d5e58449753cTed Kremenek                                                  const std::string &s,
78c4bac8e376b98d633bb00ee5f510d5e58449753cTed Kremenek                                                  const Preprocessor &PP) {
799fcc2ab2ec5e00802880e205568ff3afbd70a773Ted Kremenek  C.push_back(new PlistDiagnostics(AnalyzerOpts, s,
809fcc2ab2ec5e00802880e205568ff3afbd70a773Ted Kremenek                                   PP.getLangOpts(), true));
815d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek}
825d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek
839c378f705405d37f49795d5e915989de774fe11fTed Kremenekstatic void ReportControlFlow(raw_ostream &o,
84082cb8d7bd9bdb3fe58e8e1a2897c79c4ebcc3a7Ted Kremenek                              const PathDiagnosticControlFlowPiece& P,
852c78b873f4f3823ae859c15674cb3d76c8554113Chris Lattner                              const FIDMap& FM,
862c78b873f4f3823ae859c15674cb3d76c8554113Chris Lattner                              const SourceManager &SM,
872c78b873f4f3823ae859c15674cb3d76c8554113Chris Lattner                              const LangOptions &LangOpts,
88082cb8d7bd9bdb3fe58e8e1a2897c79c4ebcc3a7Ted Kremenek                              unsigned indent) {
891eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
90082cb8d7bd9bdb3fe58e8e1a2897c79c4ebcc3a7Ted Kremenek  Indent(o, indent) << "<dict>\n";
91082cb8d7bd9bdb3fe58e8e1a2897c79c4ebcc3a7Ted Kremenek  ++indent;
921eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
93082cb8d7bd9bdb3fe58e8e1a2897c79c4ebcc3a7Ted Kremenek  Indent(o, indent) << "<key>kind</key><string>control</string>\n";
941eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
95f48fbc6cb1a7fa972d89f2e0adf5c4b5495160e3Ted Kremenek  // Emit edges.
96f48fbc6cb1a7fa972d89f2e0adf5c4b5495160e3Ted Kremenek  Indent(o, indent) << "<key>edges</key>\n";
97f48fbc6cb1a7fa972d89f2e0adf5c4b5495160e3Ted Kremenek  ++indent;
98f48fbc6cb1a7fa972d89f2e0adf5c4b5495160e3Ted Kremenek  Indent(o, indent) << "<array>\n";
99f48fbc6cb1a7fa972d89f2e0adf5c4b5495160e3Ted Kremenek  ++indent;
100f48fbc6cb1a7fa972d89f2e0adf5c4b5495160e3Ted Kremenek  for (PathDiagnosticControlFlowPiece::const_iterator I=P.begin(), E=P.end();
101f48fbc6cb1a7fa972d89f2e0adf5c4b5495160e3Ted Kremenek       I!=E; ++I) {
102f48fbc6cb1a7fa972d89f2e0adf5c4b5495160e3Ted Kremenek    Indent(o, indent) << "<dict>\n";
103f48fbc6cb1a7fa972d89f2e0adf5c4b5495160e3Ted Kremenek    ++indent;
1047453a72cd0dcc70f29006ba488b743f078072bc7Ted Kremenek
1057453a72cd0dcc70f29006ba488b743f078072bc7Ted Kremenek    // Make the ranges of the start and end point self-consistent with adjacent edges
1067453a72cd0dcc70f29006ba488b743f078072bc7Ted Kremenek    // by forcing to use only the beginning of the range.  This simplifies the layout
1077453a72cd0dcc70f29006ba488b743f078072bc7Ted Kremenek    // logic for clients.
108f48fbc6cb1a7fa972d89f2e0adf5c4b5495160e3Ted Kremenek    Indent(o, indent) << "<key>start</key>\n";
1097453a72cd0dcc70f29006ba488b743f078072bc7Ted Kremenek    SourceLocation StartEdge = I->getStart().asRange().getBegin();
110651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    EmitRange(o, SM, LangOpts, CharSourceRange::getTokenRange(StartEdge), FM,
111651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines              indent + 1);
1127453a72cd0dcc70f29006ba488b743f078072bc7Ted Kremenek
113f48fbc6cb1a7fa972d89f2e0adf5c4b5495160e3Ted Kremenek    Indent(o, indent) << "<key>end</key>\n";
1147453a72cd0dcc70f29006ba488b743f078072bc7Ted Kremenek    SourceLocation EndEdge = I->getEnd().asRange().getBegin();
115651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    EmitRange(o, SM, LangOpts, CharSourceRange::getTokenRange(EndEdge), FM,
116651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines              indent + 1);
1177453a72cd0dcc70f29006ba488b743f078072bc7Ted Kremenek
118f48fbc6cb1a7fa972d89f2e0adf5c4b5495160e3Ted Kremenek    --indent;
119f48fbc6cb1a7fa972d89f2e0adf5c4b5495160e3Ted Kremenek    Indent(o, indent) << "</dict>\n";
120f48fbc6cb1a7fa972d89f2e0adf5c4b5495160e3Ted Kremenek  }
121f48fbc6cb1a7fa972d89f2e0adf5c4b5495160e3Ted Kremenek  --indent;
122f48fbc6cb1a7fa972d89f2e0adf5c4b5495160e3Ted Kremenek  Indent(o, indent) << "</array>\n";
123f48fbc6cb1a7fa972d89f2e0adf5c4b5495160e3Ted Kremenek  --indent;
1241eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
125082cb8d7bd9bdb3fe58e8e1a2897c79c4ebcc3a7Ted Kremenek  // Output any helper text.
126082cb8d7bd9bdb3fe58e8e1a2897c79c4ebcc3a7Ted Kremenek  const std::string& s = P.getString();
127082cb8d7bd9bdb3fe58e8e1a2897c79c4ebcc3a7Ted Kremenek  if (!s.empty()) {
128b0b6f726ab78ca32d60c5970777ae1d383d047dfTed Kremenek    Indent(o, indent) << "<key>alternate</key>";
129b0b6f726ab78ca32d60c5970777ae1d383d047dfTed Kremenek    EmitString(o, s) << '\n';
130082cb8d7bd9bdb3fe58e8e1a2897c79c4ebcc3a7Ted Kremenek  }
1311eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
132082cb8d7bd9bdb3fe58e8e1a2897c79c4ebcc3a7Ted Kremenek  --indent;
1331eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  Indent(o, indent) << "</dict>\n";
134082cb8d7bd9bdb3fe58e8e1a2897c79c4ebcc3a7Ted Kremenek}
135082cb8d7bd9bdb3fe58e8e1a2897c79c4ebcc3a7Ted Kremenek
1369c378f705405d37f49795d5e915989de774fe11fTed Kremenekstatic void ReportEvent(raw_ostream &o, const PathDiagnosticPiece& P,
1372c78b873f4f3823ae859c15674cb3d76c8554113Chris Lattner                        const FIDMap& FM,
1382c78b873f4f3823ae859c15674cb3d76c8554113Chris Lattner                        const SourceManager &SM,
1392c78b873f4f3823ae859c15674cb3d76c8554113Chris Lattner                        const LangOptions &LangOpts,
140e881efe78596a6ce9219237b737ced4adb1f8251Ted Kremenek                        unsigned indent,
141d95b70175646829c26344d5f0bda1ec3009f2a5bAnna Zaks                        unsigned depth,
142d95b70175646829c26344d5f0bda1ec3009f2a5bAnna Zaks                        bool isKeyEvent = false) {
1431eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1445d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek  Indent(o, indent) << "<dict>\n";
1455d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek  ++indent;
146082cb8d7bd9bdb3fe58e8e1a2897c79c4ebcc3a7Ted Kremenek
147082cb8d7bd9bdb3fe58e8e1a2897c79c4ebcc3a7Ted Kremenek  Indent(o, indent) << "<key>kind</key><string>event</string>\n";
1481eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
149d95b70175646829c26344d5f0bda1ec3009f2a5bAnna Zaks  if (isKeyEvent) {
1505a8e1ad062420ef74707bf093889403d07664b17Anna Zaks    Indent(o, indent) << "<key>key_event</key><true/>\n";
151d95b70175646829c26344d5f0bda1ec3009f2a5bAnna Zaks  }
152d95b70175646829c26344d5f0bda1ec3009f2a5bAnna Zaks
1535d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek  // Output the location.
1545fb5dfb6646464db3cd6d54a6332375c8fe36b75Ted Kremenek  FullSourceLoc L = P.getLocation().asLocation();
1551eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1565d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek  Indent(o, indent) << "<key>location</key>\n";
1572c78b873f4f3823ae859c15674cb3d76c8554113Chris Lattner  EmitLocation(o, SM, LangOpts, L, FM, indent);
1581eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1595d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek  // Output the ranges (if any).
1602b2c49d2ac5adb34f900f7a854a3ad5a6b0dff3cTed Kremenek  ArrayRef<SourceRange> Ranges = P.getRanges();
1611eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1622b2c49d2ac5adb34f900f7a854a3ad5a6b0dff3cTed Kremenek  if (!Ranges.empty()) {
1635d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek    Indent(o, indent) << "<key>ranges</key>\n";
1645d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek    Indent(o, indent) << "<array>\n";
165d671c5a61605ab864768cbbb4feb9cd652609083Ted Kremenek    ++indent;
1662b2c49d2ac5adb34f900f7a854a3ad5a6b0dff3cTed Kremenek    for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
1672b2c49d2ac5adb34f900f7a854a3ad5a6b0dff3cTed Kremenek         I != E; ++I) {
168651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      EmitRange(o, SM, LangOpts, CharSourceRange::getTokenRange(*I), FM,
169651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                indent + 1);
1702b2c49d2ac5adb34f900f7a854a3ad5a6b0dff3cTed Kremenek    }
171d671c5a61605ab864768cbbb4feb9cd652609083Ted Kremenek    --indent;
1725d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek    Indent(o, indent) << "</array>\n";
1735d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek  }
174e881efe78596a6ce9219237b737ced4adb1f8251Ted Kremenek
175e881efe78596a6ce9219237b737ced4adb1f8251Ted Kremenek  // Output the call depth.
176ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Indent(o, indent) << "<key>depth</key>";
177ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EmitInteger(o, depth) << '\n';
1781eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1795d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek  // Output the text.
180082cb8d7bd9bdb3fe58e8e1a2897c79c4ebcc3a7Ted Kremenek  assert(!P.getString().empty());
18161dc71ab04ffb38a2387057e70885f260a5b1e32Ted Kremenek  Indent(o, indent) << "<key>extended_message</key>\n";
182b0b6f726ab78ca32d60c5970777ae1d383d047dfTed Kremenek  Indent(o, indent);
183b0b6f726ab78ca32d60c5970777ae1d383d047dfTed Kremenek  EmitString(o, P.getString()) << '\n';
1841eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
18561dc71ab04ffb38a2387057e70885f260a5b1e32Ted Kremenek  // Output the short text.
18661dc71ab04ffb38a2387057e70885f260a5b1e32Ted Kremenek  // FIXME: Really use a short string.
1875d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek  Indent(o, indent) << "<key>message</key>\n";
1887c06f036a3092a7e019979e1ca836a1fbe14edc7Ted Kremenek  Indent(o, indent);
189b0b6f726ab78ca32d60c5970777ae1d383d047dfTed Kremenek  EmitString(o, P.getString()) << '\n';
19007189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek
191082cb8d7bd9bdb3fe58e8e1a2897c79c4ebcc3a7Ted Kremenek  // Finish up.
192082cb8d7bd9bdb3fe58e8e1a2897c79c4ebcc3a7Ted Kremenek  --indent;
193082cb8d7bd9bdb3fe58e8e1a2897c79c4ebcc3a7Ted Kremenek  Indent(o, indent); o << "</dict>\n";
194082cb8d7bd9bdb3fe58e8e1a2897c79c4ebcc3a7Ted Kremenek}
195082cb8d7bd9bdb3fe58e8e1a2897c79c4ebcc3a7Ted Kremenek
1962042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenekstatic void ReportPiece(raw_ostream &o,
1972042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek                        const PathDiagnosticPiece &P,
1982042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek                        const FIDMap& FM, const SourceManager &SM,
1992042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek                        const LangOptions &LangOpts,
2002042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek                        unsigned indent,
201e881efe78596a6ce9219237b737ced4adb1f8251Ted Kremenek                        unsigned depth,
202d95b70175646829c26344d5f0bda1ec3009f2a5bAnna Zaks                        bool includeControlFlow,
203d95b70175646829c26344d5f0bda1ec3009f2a5bAnna Zaks                        bool isKeyEvent = false);
2042042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek
2052042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenekstatic void ReportCall(raw_ostream &o,
2062042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek                       const PathDiagnosticCallPiece &P,
2072042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek                       const FIDMap& FM, const SourceManager &SM,
2082042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek                       const LangOptions &LangOpts,
209e881efe78596a6ce9219237b737ced4adb1f8251Ted Kremenek                       unsigned indent,
210e881efe78596a6ce9219237b737ced4adb1f8251Ted Kremenek                       unsigned depth) {
2112042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek
2122042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek  IntrusiveRefCntPtr<PathDiagnosticEventPiece> callEnter =
2132042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek    P.getCallEnterEvent();
214097ebb3d8ce55d1f78a3f1e7a0978dbde5ee2898Ted Kremenek
2152042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek  if (callEnter)
216d95b70175646829c26344d5f0bda1ec3009f2a5bAnna Zaks    ReportPiece(o, *callEnter, FM, SM, LangOpts, indent, depth, true,
217d95b70175646829c26344d5f0bda1ec3009f2a5bAnna Zaks                P.isLastInMainSourceFile());
2182042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek
219097ebb3d8ce55d1f78a3f1e7a0978dbde5ee2898Ted Kremenek  IntrusiveRefCntPtr<PathDiagnosticEventPiece> callEnterWithinCaller =
220097ebb3d8ce55d1f78a3f1e7a0978dbde5ee2898Ted Kremenek    P.getCallEnterWithinCallerEvent();
221097ebb3d8ce55d1f78a3f1e7a0978dbde5ee2898Ted Kremenek
222e881efe78596a6ce9219237b737ced4adb1f8251Ted Kremenek  ++depth;
223e881efe78596a6ce9219237b737ced4adb1f8251Ted Kremenek
224097ebb3d8ce55d1f78a3f1e7a0978dbde5ee2898Ted Kremenek  if (callEnterWithinCaller)
225e881efe78596a6ce9219237b737ced4adb1f8251Ted Kremenek    ReportPiece(o, *callEnterWithinCaller, FM, SM, LangOpts,
226e881efe78596a6ce9219237b737ced4adb1f8251Ted Kremenek                indent, depth, true);
227097ebb3d8ce55d1f78a3f1e7a0978dbde5ee2898Ted Kremenek
228ed866e73bab7733f5226f84c52edefe23d694b2fTed Kremenek  for (PathPieces::const_iterator I = P.path.begin(), E = P.path.end();I!=E;++I)
229ed866e73bab7733f5226f84c52edefe23d694b2fTed Kremenek    ReportPiece(o, **I, FM, SM, LangOpts, indent, depth, true);
2307be2245487f9cd7d04f013db92280d9ccd323586Jordan Rose
2317be2245487f9cd7d04f013db92280d9ccd323586Jordan Rose  --depth;
2322042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek
2332042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek  IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit =
2342042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek    P.getCallExitEvent();
235097ebb3d8ce55d1f78a3f1e7a0978dbde5ee2898Ted Kremenek
236097ebb3d8ce55d1f78a3f1e7a0978dbde5ee2898Ted Kremenek  if (callExit)
237e881efe78596a6ce9219237b737ced4adb1f8251Ted Kremenek    ReportPiece(o, *callExit, FM, SM, LangOpts, indent, depth, true);
2382042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek}
2392042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek
2409c378f705405d37f49795d5e915989de774fe11fTed Kremenekstatic void ReportMacro(raw_ostream &o,
241082cb8d7bd9bdb3fe58e8e1a2897c79c4ebcc3a7Ted Kremenek                        const PathDiagnosticMacroPiece& P,
2422c78b873f4f3823ae859c15674cb3d76c8554113Chris Lattner                        const FIDMap& FM, const SourceManager &SM,
2432c78b873f4f3823ae859c15674cb3d76c8554113Chris Lattner                        const LangOptions &LangOpts,
244e881efe78596a6ce9219237b737ced4adb1f8251Ted Kremenek                        unsigned indent,
245e881efe78596a6ce9219237b737ced4adb1f8251Ted Kremenek                        unsigned depth) {
2461eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
247ed866e73bab7733f5226f84c52edefe23d694b2fTed Kremenek  for (PathPieces::const_iterator I = P.subPieces.begin(), E=P.subPieces.end();
248082cb8d7bd9bdb3fe58e8e1a2897c79c4ebcc3a7Ted Kremenek       I!=E; ++I) {
249ed866e73bab7733f5226f84c52edefe23d694b2fTed Kremenek    ReportPiece(o, **I, FM, SM, LangOpts, indent, depth, false);
25068fbb3ee8ae374b6505885e907af92b30eef707fChad Rosier  }
25168fbb3ee8ae374b6505885e907af92b30eef707fChad Rosier}
25268fbb3ee8ae374b6505885e907af92b30eef707fChad Rosier
25368fbb3ee8ae374b6505885e907af92b30eef707fChad Rosierstatic void ReportDiag(raw_ostream &o, const PathDiagnosticPiece& P,
25468fbb3ee8ae374b6505885e907af92b30eef707fChad Rosier                       const FIDMap& FM, const SourceManager &SM,
25568fbb3ee8ae374b6505885e907af92b30eef707fChad Rosier                       const LangOptions &LangOpts) {
256e881efe78596a6ce9219237b737ced4adb1f8251Ted Kremenek  ReportPiece(o, P, FM, SM, LangOpts, 4, 0, true);
2572042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek}
25868fbb3ee8ae374b6505885e907af92b30eef707fChad Rosier
2592042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenekstatic void ReportPiece(raw_ostream &o,
2602042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek                        const PathDiagnosticPiece &P,
2612042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek                        const FIDMap& FM, const SourceManager &SM,
2622042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek                        const LangOptions &LangOpts,
2632042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek                        unsigned indent,
264e881efe78596a6ce9219237b737ced4adb1f8251Ted Kremenek                        unsigned depth,
265d95b70175646829c26344d5f0bda1ec3009f2a5bAnna Zaks                        bool includeControlFlow,
266d95b70175646829c26344d5f0bda1ec3009f2a5bAnna Zaks                        bool isKeyEvent) {
26768fbb3ee8ae374b6505885e907af92b30eef707fChad Rosier  switch (P.getKind()) {
2682042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek    case PathDiagnosticPiece::ControlFlow:
2692042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek      if (includeControlFlow)
2702042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek        ReportControlFlow(o, cast<PathDiagnosticControlFlowPiece>(P), FM, SM,
2712042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek                          LangOpts, indent);
2722042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek      break;
2732042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek    case PathDiagnosticPiece::Call:
2742042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek      ReportCall(o, cast<PathDiagnosticCallPiece>(P), FM, SM, LangOpts,
275e881efe78596a6ce9219237b737ced4adb1f8251Ted Kremenek                 indent, depth);
2762042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek      break;
2772042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek    case PathDiagnosticPiece::Event:
2782042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek      ReportEvent(o, cast<PathDiagnosticSpotPiece>(P), FM, SM, LangOpts,
279d95b70175646829c26344d5f0bda1ec3009f2a5bAnna Zaks                  indent, depth, isKeyEvent);
2802042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek      break;
2812042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek    case PathDiagnosticPiece::Macro:
2822042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek      ReportMacro(o, cast<PathDiagnosticMacroPiece>(P), FM, SM, LangOpts,
283e881efe78596a6ce9219237b737ced4adb1f8251Ted Kremenek                  indent, depth);
2842042fc1f36d471f437023e8899f0c4fadded2341Ted Kremenek      break;
2850008683bee5ab26c2a5a495adb2a894fc7e7c7c9Ted Kremenek  }
2865d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek}
2875d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek
288bac341346f3c8e713a8f165120fd54b500ee3189Ted Kremenekvoid PlistDiagnostics::FlushDiagnosticsImpl(
289bac341346f3c8e713a8f165120fd54b500ee3189Ted Kremenek                                    std::vector<const PathDiagnostic *> &Diags,
290c4bac8e376b98d633bb00ee5f510d5e58449753cTed Kremenek                                    FilesMade *filesMade) {
2915d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek  // Build up a set of FIDs that we use by scanning the locations and
2925d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek  // ranges of the diagnostics.
2935d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek  FIDMap FM;
2945f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner  SmallVector<FileID, 10> Fids;
2956bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  const SourceManager* SM = nullptr;
2961eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
297bac341346f3c8e713a8f165120fd54b500ee3189Ted Kremenek  if (!Diags.empty())
298ed866e73bab7733f5226f84c52edefe23d694b2fTed Kremenek    SM = &(*(*Diags.begin())->path.begin())->getLocation().getManager();
2995d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek
30062ff52868976a8494224a2914f1869329777944cTed Kremenek
301bac341346f3c8e713a8f165120fd54b500ee3189Ted Kremenek  for (std::vector<const PathDiagnostic*>::iterator DI = Diags.begin(),
302bac341346f3c8e713a8f165120fd54b500ee3189Ted Kremenek       DE = Diags.end(); DI != DE; ++DI) {
3031eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
304ddf32dabe71f00aa0943449f67201f587f0a04d6Ted Kremenek    const PathDiagnostic *D = *DI;
3051eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
306cfa88f893915ceb8ae4ce2f17c46c24a4d67502fDmitri Gribenko    SmallVector<const PathPieces *, 5> WorkList;
30762ff52868976a8494224a2914f1869329777944cTed Kremenek    WorkList.push_back(&D->path);
3081eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
30962ff52868976a8494224a2914f1869329777944cTed Kremenek    while (!WorkList.empty()) {
310344472ebeded2fca2ed5013b9e87f81d09bfa908Robert Wilhelm      const PathPieces &path = *WorkList.pop_back_val();
311344472ebeded2fca2ed5013b9e87f81d09bfa908Robert Wilhelm
312344472ebeded2fca2ed5013b9e87f81d09bfa908Robert Wilhelm      for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E;
313344472ebeded2fca2ed5013b9e87f81d09bfa908Robert Wilhelm           ++I) {
314ef8225444452a1486bd721f3285301fe84643b00Stephen Hines        const PathDiagnosticPiece *piece = I->get();
315651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        AddFID(FM, Fids, *SM, piece->getLocation().asLocation());
3162b2c49d2ac5adb34f900f7a854a3ad5a6b0dff3cTed Kremenek        ArrayRef<SourceRange> Ranges = piece->getRanges();
3172b2c49d2ac5adb34f900f7a854a3ad5a6b0dff3cTed Kremenek        for (ArrayRef<SourceRange>::iterator I = Ranges.begin(),
3182b2c49d2ac5adb34f900f7a854a3ad5a6b0dff3cTed Kremenek                                             E = Ranges.end(); I != E; ++I) {
319651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          AddFID(FM, Fids, *SM, I->getBegin());
320651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          AddFID(FM, Fids, *SM, I->getEnd());
32162ff52868976a8494224a2914f1869329777944cTed Kremenek        }
32262ff52868976a8494224a2914f1869329777944cTed Kremenek
32362ff52868976a8494224a2914f1869329777944cTed Kremenek        if (const PathDiagnosticCallPiece *call =
32462ff52868976a8494224a2914f1869329777944cTed Kremenek            dyn_cast<PathDiagnosticCallPiece>(piece)) {
3250344e5423db6dbb614f057887be714d2c0f7f0f6Anna Zaks          IntrusiveRefCntPtr<PathDiagnosticEventPiece>
3260344e5423db6dbb614f057887be714d2c0f7f0f6Anna Zaks            callEnterWithin = call->getCallEnterWithinCallerEvent();
3270344e5423db6dbb614f057887be714d2c0f7f0f6Anna Zaks          if (callEnterWithin)
328651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines            AddFID(FM, Fids, *SM, callEnterWithin->getLocation().asLocation());
3290344e5423db6dbb614f057887be714d2c0f7f0f6Anna Zaks
33062ff52868976a8494224a2914f1869329777944cTed Kremenek          WorkList.push_back(&call->path);
33162ff52868976a8494224a2914f1869329777944cTed Kremenek        }
33262ff52868976a8494224a2914f1869329777944cTed Kremenek        else if (const PathDiagnosticMacroPiece *macro =
33362ff52868976a8494224a2914f1869329777944cTed Kremenek                 dyn_cast<PathDiagnosticMacroPiece>(piece)) {
33462ff52868976a8494224a2914f1869329777944cTed Kremenek          WorkList.push_back(&macro->subPieces);
33562ff52868976a8494224a2914f1869329777944cTed Kremenek        }
336ddf32dabe71f00aa0943449f67201f587f0a04d6Ted Kremenek      }
3375d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek    }
3385d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek  }
3395d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek
340ddf32dabe71f00aa0943449f67201f587f0a04d6Ted Kremenek  // Open the file.
3415d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek  std::string ErrMsg;
342651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  llvm::raw_fd_ostream o(OutputFile.c_str(), ErrMsg, llvm::sys::fs::F_Text);
3435d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek  if (!ErrMsg.empty()) {
344dba241df071c4a15ac97e5cadd2d581998662809Anna Zaks    llvm::errs() << "warning: could not create file: " << OutputFile << '\n';
3455d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek    return;
3465d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek  }
3471eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
348ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EmitPlistHeader(o);
3491eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
3505d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek  // Write the root object: a <dict> containing...
351f238aa4f556c0aa3024abebaf3bdbf5f3f68fb94Anna Zaks  //  - "clang_version", the string representation of clang version
3525d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek  //  - "files", an <array> mapping from FIDs to file names
3531eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  //  - "diagnostics", an <array> containing the path diagnostics
354f238aa4f556c0aa3024abebaf3bdbf5f3f68fb94Anna Zaks  o << "<dict>\n" <<
355f238aa4f556c0aa3024abebaf3bdbf5f3f68fb94Anna Zaks       " <key>clang_version</key>\n";
356f238aa4f556c0aa3024abebaf3bdbf5f3f68fb94Anna Zaks  EmitString(o, getClangFullVersion()) << '\n';
357f238aa4f556c0aa3024abebaf3bdbf5f3f68fb94Anna Zaks  o << " <key>files</key>\n"
3585d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek       " <array>\n";
3591eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
360ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  for (FileID FID : Fids)
361ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    EmitString(o << "  ", SM->getFileEntryForID(FID)->getName()) << '\n';
3621eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
3635d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek  o << " </array>\n"
3645d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek       " <key>diagnostics</key>\n"
3655d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek       " <array>\n";
3661eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
367bac341346f3c8e713a8f165120fd54b500ee3189Ted Kremenek  for (std::vector<const PathDiagnostic*>::iterator DI=Diags.begin(),
368bac341346f3c8e713a8f165120fd54b500ee3189Ted Kremenek       DE = Diags.end(); DI!=DE; ++DI) {
3691eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
370ddf32dabe71f00aa0943449f67201f587f0a04d6Ted Kremenek    o << "  <dict>\n"
371ddf32dabe71f00aa0943449f67201f587f0a04d6Ted Kremenek         "   <key>path</key>\n";
3721eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
373ddf32dabe71f00aa0943449f67201f587f0a04d6Ted Kremenek    const PathDiagnostic *D = *DI;
3741eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
375ddf32dabe71f00aa0943449f67201f587f0a04d6Ted Kremenek    o << "   <array>\n";
376f75560670bcdd59b051149bdece3eac14e313853Ted Kremenek
377ed866e73bab7733f5226f84c52edefe23d694b2fTed Kremenek    for (PathPieces::const_iterator I = D->path.begin(), E = D->path.end();
378802e02463b880f53a6e645bde78cc412481ce9e0Ted Kremenek         I != E; ++I)
379ed866e73bab7733f5226f84c52edefe23d694b2fTed Kremenek      ReportDiag(o, **I, FM, *SM, LangOpts);
3801eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
381ddf32dabe71f00aa0943449f67201f587f0a04d6Ted Kremenek    o << "   </array>\n";
3821eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
3831eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump    // Output the bug type and bug category.
384b0b6f726ab78ca32d60c5970777ae1d383d047dfTed Kremenek    o << "   <key>description</key>";
3853a46f5fd1709f6df03bbb8b0abf84052dc0f39ffJordan Rose    EmitString(o, D->getShortDescription()) << '\n';
386b0b6f726ab78ca32d60c5970777ae1d383d047dfTed Kremenek    o << "   <key>category</key>";
387b0b6f726ab78ca32d60c5970777ae1d383d047dfTed Kremenek    EmitString(o, D->getCategory()) << '\n';
388b0b6f726ab78ca32d60c5970777ae1d383d047dfTed Kremenek    o << "   <key>type</key>";
389b0b6f726ab78ca32d60c5970777ae1d383d047dfTed Kremenek    EmitString(o, D->getBugType()) << '\n';
39007189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek
39107189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek    // Output information about the semantic context where
39207189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek    // the issue occurred.
39307189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek    if (const Decl *DeclWithIssue = D->getDeclWithIssue()) {
39407189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek      // FIXME: handle blocks, which have no name.
39507189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek      if (const NamedDecl *ND = dyn_cast<NamedDecl>(DeclWithIssue)) {
39607189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek        StringRef declKind;
39707189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek        switch (ND->getKind()) {
39807189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek          case Decl::CXXRecord:
39907189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek            declKind = "C++ class";
40007189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek            break;
40107189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek          case Decl::CXXMethod:
40207189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek            declKind = "C++ method";
40307189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek            break;
40407189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek          case Decl::ObjCMethod:
40507189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek            declKind = "Objective-C method";
40607189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek            break;
40707189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek          case Decl::Function:
40807189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek            declKind = "function";
40907189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek            break;
41007189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek          default:
41107189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek            break;
41207189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek        }
41307189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek        if (!declKind.empty()) {
41407189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek          const std::string &declName = ND->getDeclName().getAsString();
41507189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek          o << "  <key>issue_context_kind</key>";
41607189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek          EmitString(o, declKind) << '\n';
41707189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek          o << "  <key>issue_context</key>";
41807189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek          EmitString(o, declName) << '\n';
41907189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek        }
420a64fae162fd1ca9398f6f4ecb27648d965e01587Anna Zaks
421a64fae162fd1ca9398f6f4ecb27648d965e01587Anna Zaks        // Output the bug hash for issue unique-ing. Currently, it's just an
422a64fae162fd1ca9398f6f4ecb27648d965e01587Anna Zaks        // offset from the beginning of the function.
423a64fae162fd1ca9398f6f4ecb27648d965e01587Anna Zaks        if (const Stmt *Body = DeclWithIssue->getBody()) {
42497bfb558f69c09b01a5c1510f08dc91eb62329a7Anna Zaks
4256dfb96045bebe00212d251da1dad4660cb8652acAnna Zaks          // If the bug uniqueing location exists, use it for the hash.
4266dfb96045bebe00212d251da1dad4660cb8652acAnna Zaks          // For example, this ensures that two leaks reported on the same line
4276dfb96045bebe00212d251da1dad4660cb8652acAnna Zaks          // will have different issue_hashes and that the hash will identify
4286dfb96045bebe00212d251da1dad4660cb8652acAnna Zaks          // the leak location even after code is added between the allocation
4296dfb96045bebe00212d251da1dad4660cb8652acAnna Zaks          // site and the end of scope (leak report location).
43097bfb558f69c09b01a5c1510f08dc91eb62329a7Anna Zaks          PathDiagnosticLocation UPDLoc = D->getUniqueingLoc();
43197bfb558f69c09b01a5c1510f08dc91eb62329a7Anna Zaks          if (UPDLoc.isValid()) {
43297bfb558f69c09b01a5c1510f08dc91eb62329a7Anna Zaks            FullSourceLoc UL(SM->getExpansionLoc(UPDLoc.asLocation()),
43397bfb558f69c09b01a5c1510f08dc91eb62329a7Anna Zaks                             *SM);
43497bfb558f69c09b01a5c1510f08dc91eb62329a7Anna Zaks            FullSourceLoc UFunL(SM->getExpansionLoc(
43597bfb558f69c09b01a5c1510f08dc91eb62329a7Anna Zaks              D->getUniqueingDecl()->getBody()->getLocStart()), *SM);
4366dfb96045bebe00212d251da1dad4660cb8652acAnna Zaks            o << "  <key>issue_hash</key><string>"
4376dfb96045bebe00212d251da1dad4660cb8652acAnna Zaks              << UL.getExpansionLineNumber() - UFunL.getExpansionLineNumber()
4386dfb96045bebe00212d251da1dad4660cb8652acAnna Zaks              << "</string>\n";
4396dfb96045bebe00212d251da1dad4660cb8652acAnna Zaks
4406dfb96045bebe00212d251da1dad4660cb8652acAnna Zaks          // Otherwise, use the location on which the bug is reported.
4416dfb96045bebe00212d251da1dad4660cb8652acAnna Zaks          } else {
4426dfb96045bebe00212d251da1dad4660cb8652acAnna Zaks            FullSourceLoc L(SM->getExpansionLoc(D->getLocation().asLocation()),
4436dfb96045bebe00212d251da1dad4660cb8652acAnna Zaks                            *SM);
4446dfb96045bebe00212d251da1dad4660cb8652acAnna Zaks            FullSourceLoc FunL(SM->getExpansionLoc(Body->getLocStart()), *SM);
4456dfb96045bebe00212d251da1dad4660cb8652acAnna Zaks            o << "  <key>issue_hash</key><string>"
4466dfb96045bebe00212d251da1dad4660cb8652acAnna Zaks              << L.getExpansionLineNumber() - FunL.getExpansionLineNumber()
4476dfb96045bebe00212d251da1dad4660cb8652acAnna Zaks              << "</string>\n";
44897bfb558f69c09b01a5c1510f08dc91eb62329a7Anna Zaks          }
4496dfb96045bebe00212d251da1dad4660cb8652acAnna Zaks
450a64fae162fd1ca9398f6f4ecb27648d965e01587Anna Zaks        }
45107189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek      }
45207189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek    }
4531eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
454ca1bada92c6e95d7beed2afdde5eaf3759fa8607Ted Kremenek    // Output the location of the bug.
455ca1bada92c6e95d7beed2afdde5eaf3759fa8607Ted Kremenek    o << "  <key>location</key>\n";
456651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    EmitLocation(o, *SM, LangOpts, D->getLocation().asLocation(), FM, 2);
4571eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
458f75560670bcdd59b051149bdece3eac14e313853Ted Kremenek    // Output the diagnostic to the sub-diagnostic client, if any.
459c4bac8e376b98d633bb00ee5f510d5e58449753cTed Kremenek    if (!filesMade->empty()) {
460c4bac8e376b98d633bb00ee5f510d5e58449753cTed Kremenek      StringRef lastName;
461b75e2602e246b44bb285be8cc31166302d77998fTed Kremenek      PDFileEntry::ConsumerFiles *files = filesMade->getFiles(*D);
4628c916ee23c7c16e859eb55a907385f94039f8b27Jordan Rose      if (files) {
4638c916ee23c7c16e859eb55a907385f94039f8b27Jordan Rose        for (PDFileEntry::ConsumerFiles::const_iterator CI = files->begin(),
4648c916ee23c7c16e859eb55a907385f94039f8b27Jordan Rose                CE = files->end(); CI != CE; ++CI) {
4658c916ee23c7c16e859eb55a907385f94039f8b27Jordan Rose          StringRef newName = CI->first;
4668c916ee23c7c16e859eb55a907385f94039f8b27Jordan Rose          if (newName != lastName) {
4678c916ee23c7c16e859eb55a907385f94039f8b27Jordan Rose            if (!lastName.empty()) {
4688c916ee23c7c16e859eb55a907385f94039f8b27Jordan Rose              o << "  </array>\n";
4698c916ee23c7c16e859eb55a907385f94039f8b27Jordan Rose            }
4708c916ee23c7c16e859eb55a907385f94039f8b27Jordan Rose            lastName = newName;
4718c916ee23c7c16e859eb55a907385f94039f8b27Jordan Rose            o <<  "  <key>" << lastName << "_files</key>\n";
4728c916ee23c7c16e859eb55a907385f94039f8b27Jordan Rose            o << "  <array>\n";
473b75e2602e246b44bb285be8cc31166302d77998fTed Kremenek          }
4748c916ee23c7c16e859eb55a907385f94039f8b27Jordan Rose          o << "   <string>" << CI->second << "</string>\n";
475c4bac8e376b98d633bb00ee5f510d5e58449753cTed Kremenek        }
476f9f5fdbbeff3f60c5e8c0461df48d84365d56fd7Jordan Rose        o << "  </array>\n";
4778c916ee23c7c16e859eb55a907385f94039f8b27Jordan Rose      }
478f75560670bcdd59b051149bdece3eac14e313853Ted Kremenek    }
4791eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
480b0b6f726ab78ca32d60c5970777ae1d383d047dfTed Kremenek    // Close up the entry.
481ca1bada92c6e95d7beed2afdde5eaf3759fa8607Ted Kremenek    o << "  </dict>\n";
482ddf32dabe71f00aa0943449f67201f587f0a04d6Ted Kremenek  }
4835d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek
484ddf32dabe71f00aa0943449f67201f587f0a04d6Ted Kremenek  o << " </array>\n";
4851eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
4865d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek  // Finish.
487b75e2602e246b44bb285be8cc31166302d77998fTed Kremenek  o << "</dict>\n</plist>";
4885d866256333fb6115a8a86ac4f89b2ca36e20c70Ted Kremenek}
489