Author: dergachev Date: Tue Apr 24 13:45:48 2018 New Revision: 330766 URL: http://llvm.org/viewvc/llvm-project?rev=330766&view=rev Log: [analyzer] Add support for the note diagnostic pieces to plist output format.
Note diagnostic pieces are an additional way of highlighting code sections to the user. They aren't part of the normal path diagnostic sequence. They can also be attached to path-insensitive reports. Notes are already supported by the text output and scan-build. Expanding our machine-readable plist output format to be able to represent notes opens up the possibility for various analyzer GUIs to pick them up. Patch by Umann Kristóf! Differential Revision: https://reviews.llvm.org/D45407 Modified: cfe/trunk/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp cfe/trunk/test/Analysis/copypaste/plist-diagnostics.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp?rev=330766&r1=330765&r2=330766&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp Tue Apr 24 13:45:48 2018 @@ -84,6 +84,41 @@ void ento::createPlistMultiFileDiagnosti PP.getLangOpts(), true)); } +static void EmitRanges(raw_ostream &o, + const ArrayRef<SourceRange> Ranges, + const FIDMap& FM, + const SourceManager &SM, + const LangOptions &LangOpts, + unsigned indent) { + + if (Ranges.empty()) + return; + + Indent(o, indent) << "<key>ranges</key>\n"; + Indent(o, indent) << "<array>\n"; + ++indent; + for (auto &R : Ranges) + EmitRange(o, SM, + Lexer::getAsCharRange(SM.getExpansionRange(R), SM, LangOpts), + FM, indent + 1); + --indent; + Indent(o, indent) << "</array>\n"; +} + +static void EmitMessage(raw_ostream &o, StringRef Message, unsigned indent) { + // Output the text. + assert(!Message.empty()); + Indent(o, indent) << "<key>extended_message</key>\n"; + Indent(o, indent); + EmitString(o, Message) << '\n'; + + // Output the short text. + // FIXME: Really use a short string. + Indent(o, indent) << "<key>message</key>\n"; + Indent(o, indent); + EmitString(o, Message) << '\n'; +} + static void ReportControlFlow(raw_ostream &o, const PathDiagnosticControlFlowPiece& P, const FIDMap& FM, @@ -138,7 +173,7 @@ static void ReportControlFlow(raw_ostrea Indent(o, indent) << "</dict>\n"; } -static void ReportEvent(raw_ostream &o, const PathDiagnosticPiece& P, +static void ReportEvent(raw_ostream &o, const PathDiagnosticEventPiece& P, const FIDMap& FM, const SourceManager &SM, const LangOptions &LangOpts, @@ -163,34 +198,14 @@ static void ReportEvent(raw_ostream &o, // Output the ranges (if any). ArrayRef<SourceRange> Ranges = P.getRanges(); - - if (!Ranges.empty()) { - Indent(o, indent) << "<key>ranges</key>\n"; - Indent(o, indent) << "<array>\n"; - ++indent; - for (auto &R : Ranges) - EmitRange(o, SM, - Lexer::getAsCharRange(SM.getExpansionRange(R), SM, LangOpts), - FM, indent + 1); - --indent; - Indent(o, indent) << "</array>\n"; - } + EmitRanges(o, Ranges, FM, SM, LangOpts, indent); // Output the call depth. Indent(o, indent) << "<key>depth</key>"; EmitInteger(o, depth) << '\n'; // Output the text. - assert(!P.getString().empty()); - Indent(o, indent) << "<key>extended_message</key>\n"; - Indent(o, indent); - EmitString(o, P.getString()) << '\n'; - - // Output the short text. - // FIXME: Really use a short string. - Indent(o, indent) << "<key>message</key>\n"; - Indent(o, indent); - EmitString(o, P.getString()) << '\n'; + EmitMessage(o, P.getString(), indent); // Finish up. --indent; @@ -246,6 +261,34 @@ static void ReportMacro(raw_ostream &o, } } +static void ReportNote(raw_ostream &o, const PathDiagnosticNotePiece& P, + const FIDMap& FM, + const SourceManager &SM, + const LangOptions &LangOpts, + unsigned indent, + unsigned depth) { + + Indent(o, indent) << "<dict>\n"; + ++indent; + + // Output the location. + FullSourceLoc L = P.getLocation().asLocation(); + + Indent(o, indent) << "<key>location</key>\n"; + EmitLocation(o, SM, L, FM, indent); + + // Output the ranges (if any). + ArrayRef<SourceRange> Ranges = P.getRanges(); + EmitRanges(o, Ranges, FM, SM, LangOpts, indent); + + // Output the text. + EmitMessage(o, P.getString(), indent); + + // Finish up. + --indent; + Indent(o, indent); o << "</dict>\n"; +} + static void ReportDiag(raw_ostream &o, const PathDiagnosticPiece& P, const FIDMap& FM, const SourceManager &SM, const LangOptions &LangOpts) { @@ -271,7 +314,7 @@ static void ReportPiece(raw_ostream &o, indent, depth); break; case PathDiagnosticPiece::Event: - ReportEvent(o, cast<PathDiagnosticSpotPiece>(P), FM, SM, LangOpts, + ReportEvent(o, cast<PathDiagnosticEventPiece>(P), FM, SM, LangOpts, indent, depth, isKeyEvent); break; case PathDiagnosticPiece::Macro: @@ -279,7 +322,8 @@ static void ReportPiece(raw_ostream &o, indent, depth); break; case PathDiagnosticPiece::Note: - // FIXME: Extend the plist format to support those. + ReportNote(o, cast<PathDiagnosticNotePiece>(P), FM, SM, LangOpts, + indent, depth); break; } } @@ -364,15 +408,39 @@ void PlistDiagnostics::FlushDiagnosticsI for (std::vector<const PathDiagnostic*>::iterator DI=Diags.begin(), DE = Diags.end(); DI!=DE; ++DI) { - o << " <dict>\n" - " <key>path</key>\n"; + o << " <dict>\n"; const PathDiagnostic *D = *DI; + const PathPieces &PP = D->path; + + assert(std::is_partitioned( + PP.begin(), PP.end(), + [](const std::shared_ptr<PathDiagnosticPiece> &E) + { return E->getKind() == PathDiagnosticPiece::Note; }) && + "PathDiagnostic is not partitioned so that notes precede the rest"); + + PathPieces::const_iterator FirstNonNote = std::partition_point( + PP.begin(), PP.end(), + [](const std::shared_ptr<PathDiagnosticPiece> &E) + { return E->getKind() == PathDiagnosticPiece::Note; }); + + PathPieces::const_iterator I = PP.begin(); + + if (FirstNonNote != PP.begin()) { + o << " <key>notes</key>\n" + " <array>\n"; + + for (; I != FirstNonNote; ++I) + ReportDiag(o, **I, FM, *SM, LangOpts); + + o << " </array>\n"; + } + + o << " <key>path</key>\n"; o << " <array>\n"; - for (PathPieces::const_iterator I = D->path.begin(), E = D->path.end(); - I != E; ++I) + for (PathPieces::const_iterator E = PP.end(); I != E; ++I) ReportDiag(o, **I, FM, *SM, LangOpts); o << " </array>\n"; Modified: cfe/trunk/test/Analysis/copypaste/plist-diagnostics.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/copypaste/plist-diagnostics.cpp?rev=330766&r1=330765&r2=330766&view=diff ============================================================================== --- cfe/trunk/test/Analysis/copypaste/plist-diagnostics.cpp (original) +++ cfe/trunk/test/Analysis/copypaste/plist-diagnostics.cpp Tue Apr 24 13:45:48 2018 @@ -17,12 +17,39 @@ int maxClone(int a, int b) { // expected return b; } -// FIXME: This plist output doesn't include the extra note on line 13. -// It should be updated once the format for extra notes in plists is defined. - // CHECK: <key>diagnostics</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> +// CHECK-NEXT: <key>notes</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>location</key> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>13</integer> +// CHECK-NEXT: <key>col</key><integer>28</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <key>ranges</key> +// CHECK-NEXT: <array> +// CHECK-NEXT: <array> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>13</integer> +// CHECK-NEXT: <key>col</key><integer>28</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: <dict> +// CHECK-NEXT: <key>line</key><integer>18</integer> +// CHECK-NEXT: <key>col</key><integer>1</integer> +// CHECK-NEXT: <key>file</key><integer>0</integer> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> +// CHECK-NEXT: </array> +// CHECK-NEXT: <key>extended_message</key> +// CHECK-NEXT: <string>Similar code here</string> +// CHECK-NEXT: <key>message</key> +// CHECK-NEXT: <string>Similar code here</string> +// CHECK-NEXT: </dict> +// CHECK-NEXT: </array> // CHECK-NEXT: <key>path</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits