Szelethus updated this revision to Diff 170509. Szelethus added a comment. Added a new `macro_expansions` key on the same level at `path` and `notes`, under which the macro expansions are listed, as suggested by @NoQ.
There were a couple ways to make this happen. I could've changed how macro pieces are made in `BugReporter`, so that they are created but the path isn't compacted, but then the `BugReporter`'s implementation would be complicated by doing specific things specific output formats. I instead decided to manually flatten macro pieces in `PlistDiagnostics`. Since `FlushDiagnosticsImpl` was already super long, I decided to move both the logic of this patch and the logic for `notes` into a separate function. https://reviews.llvm.org/D52742 Files: include/clang/StaticAnalyzer/Core/AnalyzerOptions.h lib/StaticAnalyzer/Core/AnalyzerOptions.cpp lib/StaticAnalyzer/Core/BugReporter.cpp lib/StaticAnalyzer/Core/PlistDiagnostics.cpp test/Analysis/Inputs/expected-plists/plist-macros-with-expansion.cpp.plist test/Analysis/plist-macros-with-expansion.cpp
Index: test/Analysis/plist-macros-with-expansion.cpp =================================================================== --- /dev/null +++ test/Analysis/plist-macros-with-expansion.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s +// +// RUN: %clang_analyze_cc1 -analyzer-checker=core %s \ +// RUN: -analyzer-output=plist -o %t.plist \ +// RUN: -analyzer-config expand-macros=true +// +// Check the actual plist output. +// RUN: cat %t.plist | %diff_plist \ +// RUN: %S/Inputs/expected-plists/plist-macros-with-expansion.cpp.plist +// +// Check the macro expansions from the plist output here, to make the test more +// understandable. +// RUN: FileCheck --input-file=%t.plist %s + +void print(const void*); + +//===----------------------------------------------------------------------===// +// Tests for non-function-like macro expansions. +//===----------------------------------------------------------------------===// + +#define SET_PTR_VAR_TO_NULL \ + ptr = 0 + +void nonFunctionLikeMacroTest() { + int *ptr; + SET_PTR_VAR_TO_NULL; + *ptr = 5; // expected-warning{{Dereference of null pointer}} +} + +// CHECK: <key>name</key><string></string> +// CHECK-NEXT: <key>expansion</key><string></string> + +#define NULL 0 +#define SET_PTR_VAR_TO_NULL_WITH_NESTED_MACRO \ + ptr = NULL + +void nonFunctionLikeNestedMacroTest() { + int *ptr; + SET_PTR_VAR_TO_NULL_WITH_NESTED_MACRO; + *ptr = 5; // expected-warning{{Dereference of null pointer}} +} + +// CHECK: <key>name</key><string></string> +// CHECK-NEXT: <key>expansion</key><string></string> Index: test/Analysis/Inputs/expected-plists/plist-macros-with-expansion.cpp.plist =================================================================== --- /dev/null +++ test/Analysis/Inputs/expected-plists/plist-macros-with-expansion.cpp.plist @@ -0,0 +1,419 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>diagnostics</key> + <array> + <dict> + <key>macro_expansions</key> + <array> + <dict> + <key>location</key> + <dict> + <key>line</key><integer>26</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <key>name</key><string></string> + <key>expansion</key><string></string> + </dict> + </array> + <key>path</key> + <array> + <dict> + <key>kind</key><string>control</string> + <key>edges</key> + <array> + <dict> + <key>start</key> + <array> + <dict> + <key>line</key><integer>25</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>25</integer> + <key>col</key><integer>5</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + <key>end</key> + <array> + <dict> + <key>line</key><integer>26</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>26</integer> + <key>col</key><integer>21</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + </dict> + </array> + </dict> + <dict> + <key>kind</key><string>event</string> + <key>location</key> + <dict> + <key>line</key><integer>26</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ranges</key> + <array> + <array> + <dict> + <key>line</key><integer>26</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>26</integer> + <key>col</key><integer>21</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + </array> + <key>depth</key><integer>0</integer> + <key>extended_message</key> + <string>Null pointer value stored to 'ptr'</string> + <key>message</key> + <string>Null pointer value stored to 'ptr'</string> + </dict> + <dict> + <key>kind</key><string>control</string> + <key>edges</key> + <array> + <dict> + <key>start</key> + <array> + <dict> + <key>line</key><integer>26</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>26</integer> + <key>col</key><integer>21</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + <key>end</key> + <array> + <dict> + <key>line</key><integer>27</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>27</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + </dict> + </array> + </dict> + <dict> + <key>kind</key><string>control</string> + <key>edges</key> + <array> + <dict> + <key>start</key> + <array> + <dict> + <key>line</key><integer>27</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>27</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + <key>end</key> + <array> + <dict> + <key>line</key><integer>27</integer> + <key>col</key><integer>8</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>27</integer> + <key>col</key><integer>8</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + </dict> + </array> + </dict> + <dict> + <key>kind</key><string>event</string> + <key>location</key> + <dict> + <key>line</key><integer>27</integer> + <key>col</key><integer>8</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ranges</key> + <array> + <array> + <dict> + <key>line</key><integer>27</integer> + <key>col</key><integer>4</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>27</integer> + <key>col</key><integer>6</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + </array> + <key>depth</key><integer>0</integer> + <key>extended_message</key> + <string>Dereference of null pointer (loaded from variable 'ptr')</string> + <key>message</key> + <string>Dereference of null pointer (loaded from variable 'ptr')</string> + </dict> + </array> + <key>description</key><string>Dereference of null pointer (loaded from variable 'ptr')</string> + <key>category</key><string>Logic error</string> + <key>type</key><string>Dereference of null pointer</string> + <key>check_name</key><string>core.NullDereference</string> + <!-- This hash is experimental and going to change! --> + <key>issue_hash_content_of_line_in_context</key><string>f8fbc46cc5afbb056d92bd3d3d702781</string> + <key>issue_context_kind</key><string>function</string> + <key>issue_context</key><string>nonFunctionLikeMacroTest</string> + <key>issue_hash_function_offset</key><string>3</string> + <key>location</key> + <dict> + <key>line</key><integer>27</integer> + <key>col</key><integer>8</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ExecutedLines</key> + <dict> + <key>0</key> + <array> + <integer>24</integer> + <integer>25</integer> + <integer>26</integer> + <integer>27</integer> + </array> + </dict> + </dict> + <dict> + <key>macro_expansions</key> + <array> + <dict> + <key>location</key> + <dict> + <key>line</key><integer>39</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <key>name</key><string></string> + <key>expansion</key><string></string> + </dict> + </array> + <key>path</key> + <array> + <dict> + <key>kind</key><string>control</string> + <key>edges</key> + <array> + <dict> + <key>start</key> + <array> + <dict> + <key>line</key><integer>38</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>38</integer> + <key>col</key><integer>5</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + <key>end</key> + <array> + <dict> + <key>line</key><integer>39</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>39</integer> + <key>col</key><integer>39</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + </dict> + </array> + </dict> + <dict> + <key>kind</key><string>event</string> + <key>location</key> + <dict> + <key>line</key><integer>39</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ranges</key> + <array> + <array> + <dict> + <key>line</key><integer>39</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>39</integer> + <key>col</key><integer>39</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + </array> + <key>depth</key><integer>0</integer> + <key>extended_message</key> + <string>Null pointer value stored to 'ptr'</string> + <key>message</key> + <string>Null pointer value stored to 'ptr'</string> + </dict> + <dict> + <key>kind</key><string>control</string> + <key>edges</key> + <array> + <dict> + <key>start</key> + <array> + <dict> + <key>line</key><integer>39</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>39</integer> + <key>col</key><integer>39</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + <key>end</key> + <array> + <dict> + <key>line</key><integer>40</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>40</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + </dict> + </array> + </dict> + <dict> + <key>kind</key><string>control</string> + <key>edges</key> + <array> + <dict> + <key>start</key> + <array> + <dict> + <key>line</key><integer>40</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>40</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + <key>end</key> + <array> + <dict> + <key>line</key><integer>40</integer> + <key>col</key><integer>8</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>40</integer> + <key>col</key><integer>8</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + </dict> + </array> + </dict> + <dict> + <key>kind</key><string>event</string> + <key>location</key> + <dict> + <key>line</key><integer>40</integer> + <key>col</key><integer>8</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ranges</key> + <array> + <array> + <dict> + <key>line</key><integer>40</integer> + <key>col</key><integer>4</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>40</integer> + <key>col</key><integer>6</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + </array> + <key>depth</key><integer>0</integer> + <key>extended_message</key> + <string>Dereference of null pointer (loaded from variable 'ptr')</string> + <key>message</key> + <string>Dereference of null pointer (loaded from variable 'ptr')</string> + </dict> + </array> + <key>description</key><string>Dereference of null pointer (loaded from variable 'ptr')</string> + <key>category</key><string>Logic error</string> + <key>type</key><string>Dereference of null pointer</string> + <key>check_name</key><string>core.NullDereference</string> + <!-- This hash is experimental and going to change! --> + <key>issue_hash_content_of_line_in_context</key><string>d5eba61193b41c27fc7b2705cbd607ba</string> + <key>issue_context_kind</key><string>function</string> + <key>issue_context</key><string>nonFunctionLikeNestedMacroTest</string> + <key>issue_hash_function_offset</key><string>3</string> + <key>location</key> + <dict> + <key>line</key><integer>40</integer> + <key>col</key><integer>8</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ExecutedLines</key> + <dict> + <key>0</key> + <array> + <integer>37</integer> + <integer>38</integer> + <integer>39</integer> + <integer>40</integer> + </array> + </dict> + </dict> + </array> + <key>files</key> + <array> + <string>/home/szelethus/Documents/macro_expansion/clang/test/Analysis/plist-macros-with-expansion.cpp</string> + </array> +</dict> +</plist> Index: lib/StaticAnalyzer/Core/PlistDiagnostics.cpp =================================================================== --- lib/StaticAnalyzer/Core/PlistDiagnostics.cpp +++ lib/StaticAnalyzer/Core/PlistDiagnostics.cpp @@ -246,7 +246,7 @@ ReportPiece(o, *callEnterWithinCaller, FM, PP, AnOpts, indent, depth, /*includeControlFlow*/ true); - for (PathPieces::const_iterator I = P.path.begin(), E = P.path.end();I!=E;++I) + for (auto I = P.path.begin(), E = P.path.end(); I!= E; ++I) ReportPiece(o, **I, FM, PP, AnOpts, indent, depth, /*includeControlFlow*/ true); @@ -257,19 +257,58 @@ /*includeControlFlow*/ true); } +namespace { + +struct ExpansionInfo { + std::string MacroName; + std::string Expansion; + ExpansionInfo(std::string N, std::string E) + : MacroName(std::move(N)), Expansion(std::move(E)) {} +}; + +} // end of anonymous namespace + +static ExpansionInfo getExpandedMacro(SourceLocation MacroLoc, + const Preprocessor &PP) { + // TODO: Implement macro expansion. + return { "", "" }; +} + static void ReportMacro(raw_ostream &o, const PathDiagnosticMacroPiece& P, const FIDMap& FM, const Preprocessor &PP, AnalyzerOptions &AnOpts, unsigned indent, unsigned depth) { + const SourceManager &SM = PP.getSourceManager(); + ExpansionInfo EI = getExpandedMacro(P.getLocation().asLocation(), PP); - for (PathPieces::const_iterator I = P.subPieces.begin(), E=P.subPieces.end(); - I!=E; ++I) { - ReportPiece(o, **I, FM, PP, AnOpts, indent, depth, - /*includeControlFlow*/ false); - } + 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, PP, indent); + + // Output the macro name. + Indent(o, indent) << "<key>name</key>"; + EmitString(o, EI.MacroName) << '\n'; + + // Output what it expands into. + Indent(o, indent) << "<key>expansion</key>"; + EmitString(o, EI.Expansion) << '\n'; + + // Finish up. + --indent; + Indent(o, indent); + o << "</dict>\n"; } static void ReportNote(raw_ostream &o, const PathDiagnosticNotePiece& P, @@ -309,6 +348,89 @@ /*includeControlFlow*/ true); } +/// The bugpath we can access is const, but we need to modify the bugpath +/// in order to flatten macros. Because copying shared_ptrs isn't cheap, we'll +/// store raw pointers to the Pieces, as their lifetime will be at least as long +/// as the PlistDiagnostics object. +using MutablePathPieces = std::list<const PathDiagnosticPiece *>; + +/// Converts a const PathPieces object to a mutable, raw pointer storing +/// containter. +MutablePathPieces getMutablePathPieces(const PathPieces &Path) { + auto RetrievePrt = [] (const std::shared_ptr<PathDiagnosticPiece> &Piece) { + return Piece.get(); + }; + + MutablePathPieces Ret(Path.size()); + std::transform(Path.begin(), Path.end(), Ret.begin(), RetrievePrt); + return Ret; +} + +/// Returns an iterator to the first non-note element in Path. +MutablePathPieces::const_iterator +getFirstNonNotePiece(const MutablePathPieces &Path) { + + auto IsNote = [](const PathDiagnosticPiece *E) { + return E->getKind() == PathDiagnosticPiece::Note; + }; + + assert(std::is_partitioned(Path.begin(), Path.end(), IsNote) && + "PathDiagnostic is not partitioned so that notes precede the rest"); + + return std::partition_point(Path.begin(), Path.end(), IsNote); +} + +/// Report the note pieces in Path. +static void ReportNotes(raw_ostream &o, + const MutablePathPieces& Path, + const FIDMap& FM, + const Preprocessor &PP, + AnalyzerOptions &AnOpts) { + auto FirstNonNote = getFirstNonNotePiece(Path); + + if (FirstNonNote != Path.begin()) { + o << " <key>notes</key>\n" + " <array>\n"; + + for (auto NoteIt = Path.begin(); NoteIt != FirstNonNote; ++NoteIt) + ReportDiag(o, **NoteIt, FM, PP, AnOpts); + + o << " </array>\n"; + } +} + +/// Report macro pieces in Path, then replace them with their subpieces. +static void ReportAndFlattenMacros(raw_ostream &o, + MutablePathPieces& Path, + const FIDMap& FM, + const Preprocessor &PP, + AnalyzerOptions &AnOpts) { + MutablePathPieces MacroPieces; + for (auto It = getFirstNonNotePiece(Path); It != Path.end();) { + + const auto *MacroPiece = dyn_cast<PathDiagnosticMacroPiece>(*It); + if (!MacroPiece) { + ++It; + continue; + } + + Path.splice(It, getMutablePathPieces(MacroPiece->subPieces)); + const auto MacroIt = It++; + MacroPieces.splice(MacroPieces.end(), Path, MacroIt); + } + + if (MacroPieces.empty()) + return; + + o << " <key>macro_expansions</key>\n" + " <array>\n"; + + for (const PathDiagnosticPiece *MacroPiece : MacroPieces) + ReportDiag(o, *MacroPiece, FM, PP, AnOpts); + + o << " </array>\n"; +} + static void ReportPiece(raw_ostream &o, const PathDiagnosticPiece &P, const FIDMap& FM, @@ -443,42 +565,23 @@ o << " <key>diagnostics</key>\n" " <array>\n"; - for (std::vector<const PathDiagnostic*>::iterator DI=Diags.begin(), - DE = Diags.end(); DI!=DE; ++DI) { + for (std::vector<const PathDiagnostic*>::iterator DI = Diags.begin(), + DE = Diags.end(); DI != DE; ++DI) { o << " <dict>\n"; const PathDiagnostic *D = *DI; - const PathPieces &Path = D->path; - - assert(std::is_partitioned( - Path.begin(), Path.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( - Path.begin(), Path.end(), - [](const std::shared_ptr<PathDiagnosticPiece> &E) - { return E->getKind() == PathDiagnosticPiece::Note; }); + MutablePathPieces Path = getMutablePathPieces(D->path); - PathPieces::const_iterator I = Path.begin(); + ReportNotes(o, Path, FM, PP, AnOpts); + ReportAndFlattenMacros(o, Path, FM, PP, AnOpts); - if (FirstNonNote != Path.begin()) { - o << " <key>notes</key>\n" - " <array>\n"; - - for (; I != FirstNonNote; ++I) - ReportDiag(o, **I, FM, PP, AnOpts); - - o << " </array>\n"; - } + auto I = getFirstNonNotePiece(Path); o << " <key>path</key>\n"; - o << " <array>\n"; - for (PathPieces::const_iterator E = Path.end(); I != E; ++I) + for (auto E = Path.end(); I != E; ++I) ReportDiag(o, **I, FM, PP, AnOpts); o << " </array>\n"; Index: lib/StaticAnalyzer/Core/BugReporter.cpp =================================================================== --- lib/StaticAnalyzer/Core/BugReporter.cpp +++ lib/StaticAnalyzer/Core/BugReporter.cpp @@ -546,7 +546,8 @@ } } -static void CompactPathDiagnostic(PathPieces &path, const SourceManager& SM); +static void CompactMacroExpandedPieces(PathPieces &path, + const SourceManager& SM); std::shared_ptr<PathDiagnosticControlFlowPiece> generateDiagForSwitchOP( @@ -1972,8 +1973,6 @@ PathDiagnosticLocation::createBegin(D, SM)); } - if (!AddPathEdges && GenerateDiagnostics) - CompactPathDiagnostic(PD->getMutablePieces(), SM); // Finally, prune the diagnostic path of uninteresting stuff. if (!PD->path.empty()) { @@ -2007,6 +2006,10 @@ removeRedundantMsgs(PD->getMutablePieces()); removeEdgesToDefaultInitializers(PD->getMutablePieces()); } + + if (GenerateDiagnostics && Opts.shouldDisplayMacroExpansions()) + CompactMacroExpandedPieces(PD->getMutablePieces(), SM); + return PD; } @@ -2436,9 +2439,10 @@ return true; } -/// CompactPathDiagnostic - This function postprocesses a PathDiagnostic object -/// and collapses PathDiagosticPieces that are expanded by macros. -static void CompactPathDiagnostic(PathPieces &path, const SourceManager& SM) { +/// CompactMacroExpandedPieces - This function postprocesses a PathDiagnostic +/// object and collapses PathDiagosticPieces that are expanded by macros. +static void CompactMacroExpandedPieces(PathPieces &path, + const SourceManager& SM) { using MacroStackTy = std::vector< std::pair<std::shared_ptr<PathDiagnosticMacroPiece>, SourceLocation>>; @@ -2454,7 +2458,7 @@ // Recursively compact calls. if (auto *call = dyn_cast<PathDiagnosticCallPiece>(&*piece)) { - CompactPathDiagnostic(call->path, SM); + CompactMacroExpandedPieces(call->path, SM); } // Get the location of the PathDiagnosticPiece. Index: lib/StaticAnalyzer/Core/AnalyzerOptions.cpp =================================================================== --- lib/StaticAnalyzer/Core/AnalyzerOptions.cpp +++ lib/StaticAnalyzer/Core/AnalyzerOptions.cpp @@ -465,6 +465,13 @@ return DisplayNotesAsEvents.getValue(); } +bool AnalyzerOptions::shouldDisplayMacroExpansions() { + if (!DisplayMacroExpansions.hasValue()) + DisplayMacroExpansions = + getBooleanOption("expand-macros", /*Default=*/false); + return DisplayMacroExpansions.getValue(); +} + bool AnalyzerOptions::shouldAggressivelySimplifyBinaryOperation() { if (!AggressiveBinaryOperationSimplification.hasValue()) AggressiveBinaryOperationSimplification = Index: include/clang/StaticAnalyzer/Core/AnalyzerOptions.h =================================================================== --- include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -312,6 +312,9 @@ /// \sa shouldDisplayNotesAsEvents Optional<bool> DisplayNotesAsEvents; + /// \sa shouldDisplayMacroExpansions + Optional<bool> DisplayMacroExpansions; + /// \sa shouldAggressivelySimplifyBinaryOperation Optional<bool> AggressiveBinaryOperationSimplification; @@ -687,6 +690,13 @@ /// to false when unset. bool shouldDisplayNotesAsEvents(); + /// Returns true if macros related to the bugpath should be expanded and + /// included in the plist output. + /// + /// This is controlled by the 'expand-macros' option, which defaults to false + /// when unset. + bool shouldDisplayMacroExpansions(); + /// Returns true if SValBuilder should rearrange comparisons and additive /// operations of symbolic expressions which consist of a sum of a symbol and /// a concrete integer into the format where symbols are on the left-hand
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits