llvm/clang/lib/StaticAnalyzer/Core/BugReporter.cpp

//===- BugReporter.cpp - Generate PathDiagnostics for bugs ----------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
//  This file defines BugReporter, a utility class for generating
//  PathDiagnostics.
//
//===----------------------------------------------------------------------===//

#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/AST/ASTTypeTraits.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/ParentMapContext.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/CFGStmtMap.h"
#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Analysis/ProgramPoint.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/BugReporter/Z3CrosscheckVisitor.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/CheckerRegistryData.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <iterator>
#include <memory>
#include <optional>
#include <queue>
#include <string>
#include <tuple>
#include <utility>
#include <vector>

usingnamespaceclang;
usingnamespaceento;
usingnamespacellvm;

#define DEBUG_TYPE

STATISTIC(MaxBugClassSize,
          "The maximum number of bug reports in the same equivalence class");
STATISTIC(MaxValidBugClassSize,
          "The maximum number of bug reports in the same equivalence class "
          "where at least one report is valid (not suppressed)");

STATISTIC(NumTimesReportPassesZ3, "Number of reports passed Z3");
STATISTIC(NumTimesReportRefuted, "Number of reports refuted by Z3");
STATISTIC(NumTimesReportEQClassAborted,
          "Number of times a report equivalence class was aborted by the Z3 "
          "oracle heuristic");
STATISTIC(NumTimesReportEQClassWasExhausted,
          "Number of times all reports of an equivalence class was refuted");

BugReporterVisitor::~BugReporterVisitor() = default;

void BugReporterContext::anchor() {}

//===----------------------------------------------------------------------===//
// PathDiagnosticBuilder and its associated routines and helper objects.
//===----------------------------------------------------------------------===//

namespace {

/// A (CallPiece, node assiciated with its CallEnter) pair.
CallWithEntry;
CallWithEntryStack;

/// Map from each node to the diagnostic pieces visitors emit for them.
VisitorsDiagnosticsTy;

/// A map from PathDiagnosticPiece to the LocationContext of the inlined
/// function call it represents.
LocationContextMap;

/// A helper class that contains everything needed to construct a
/// PathDiagnostic object. It does no much more then providing convenient
/// getters and some well placed asserts for extra security.
class PathDiagnosticConstruct {};

/// Contains every contextual information needed for constructing a
/// PathDiagnostic object for a given bug report. This class and its fields are
/// immutable, and passes a BugReportConstruct object around during the
/// construction.
class PathDiagnosticBuilder : public BugReporterContext {};

} // namespace

//===----------------------------------------------------------------------===//
// Base implementation of stack hint generators.
//===----------------------------------------------------------------------===//

StackHintGenerator::~StackHintGenerator() = default;

std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){}

std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE,
                                                          unsigned ArgIndex) {}

//===----------------------------------------------------------------------===//
// Diagnostic cleanup.
//===----------------------------------------------------------------------===//

static PathDiagnosticEventPiece *
eventsDescribeSameCondition(PathDiagnosticEventPiece *X,
                            PathDiagnosticEventPiece *Y) {}

/// An optimization pass over PathPieces that removes redundant diagnostics
/// generated by both ConditionBRVisitor and TrackConstraintBRVisitor.  Both
/// BugReporterVisitors use different methods to generate diagnostics, with
/// one capable of emitting diagnostics in some cases but not in others.  This
/// can lead to redundant diagnostic pieces at the same point in a path.
static void removeRedundantMsgs(PathPieces &path) {}

/// Recursively scan through a path and prune out calls and macros pieces
/// that aren't needed.  Return true if afterwards the path contains
/// "interesting stuff" which means it shouldn't be pruned from the parent path.
static bool removeUnneededCalls(const PathDiagnosticConstruct &C,
                                PathPieces &pieces,
                                const PathSensitiveBugReport *R,
                                bool IsInteresting = false) {}

/// Same logic as above to remove extra pieces.
static void removePopUpNotes(PathPieces &Path) {}

/// Returns true if the given decl has been implicitly given a body, either by
/// the analyzer or by the compiler proper.
static bool hasImplicitBody(const Decl *D) {}

/// Recursively scan through a path and make sure that all call pieces have
/// valid locations.
static void
adjustCallLocations(PathPieces &Pieces,
                    PathDiagnosticLocation *LastCallLocation = nullptr) {}

/// Remove edges in and out of C++ default initializer expressions. These are
/// for fields that have in-class initializers, as opposed to being initialized
/// explicitly in a constructor or braced list.
static void removeEdgesToDefaultInitializers(PathPieces &Pieces) {}

/// Remove all pieces with invalid locations as these cannot be serialized.
/// We might have pieces with invalid locations as a result of inlining Body
/// Farm generated functions.
static void removePiecesWithInvalidLocations(PathPieces &Pieces) {}

PathDiagnosticLocation PathDiagnosticBuilder::ExecutionContinues(
    const PathDiagnosticConstruct &C) const {}

PathDiagnosticLocation PathDiagnosticBuilder::ExecutionContinues(
    llvm::raw_string_ostream &os, const PathDiagnosticConstruct &C) const {}

static const Stmt *getEnclosingParent(const Stmt *S, const ParentMap &PM) {}

static PathDiagnosticLocation
getEnclosingStmtLocation(const Stmt *S, const LocationContext *LC,
                         bool allowNestedContexts = false) {}

//===----------------------------------------------------------------------===//
// "Minimal" path diagnostic generation algorithm.
//===----------------------------------------------------------------------===//

/// If the piece contains a special message, add it to all the call pieces on
/// the active stack. For example, my_malloc allocated memory, so MallocChecker
/// will construct an event at the call to malloc(), and add a stack hint that
/// an allocated memory was returned. We'll use this hint to construct a message
/// when returning from the call to my_malloc
///
///   void *my_malloc() { return malloc(sizeof(int)); }
///   void fishy() {
///     void *ptr = my_malloc(); // returned allocated memory
///   } // leak
void PathDiagnosticBuilder::updateStackPiecesWithMessage(
    PathDiagnosticPieceRef P, const CallWithEntryStack &CallStack) const {}

static void CompactMacroExpandedPieces(PathPieces &path,
                                       const SourceManager& SM);

PathDiagnosticPieceRef PathDiagnosticBuilder::generateDiagForSwitchOP(
    const PathDiagnosticConstruct &C, const CFGBlock *Dst,
    PathDiagnosticLocation &Start) const {}

PathDiagnosticPieceRef PathDiagnosticBuilder::generateDiagForGotoOP(
    const PathDiagnosticConstruct &C, const Stmt *S,
    PathDiagnosticLocation &Start) const {}

PathDiagnosticPieceRef PathDiagnosticBuilder::generateDiagForBinaryOP(
    const PathDiagnosticConstruct &C, const Stmt *T, const CFGBlock *Src,
    const CFGBlock *Dst) const {}

void PathDiagnosticBuilder::generateMinimalDiagForBlockEdge(
    PathDiagnosticConstruct &C, BlockEdge BE) const {}

//===----------------------------------------------------------------------===//
// Functions for determining if a loop was executed 0 times.
//===----------------------------------------------------------------------===//

static bool isLoop(const Stmt *Term) {}

static bool isJumpToFalseBranch(const BlockEdge *BE) {}

static bool isContainedByStmt(const ParentMap &PM, const Stmt *S,
                              const Stmt *SubS) {}

static const Stmt *getStmtBeforeCond(const ParentMap &PM, const Stmt *Term,
                                     const ExplodedNode *N) {}

static bool isInLoopBody(const ParentMap &PM, const Stmt *S, const Stmt *Term) {}

/// Adds a sanitized control-flow diagnostic edge to a path.
static void addEdgeToPath(PathPieces &path,
                          PathDiagnosticLocation &PrevLoc,
                          PathDiagnosticLocation NewLoc) {}

/// A customized wrapper for CFGBlock::getTerminatorCondition()
/// which returns the element for ObjCForCollectionStmts.
static const Stmt *getTerminatorCondition(const CFGBlock *B) {}

constexpr llvm::StringLiteral StrEnteringLoop =;
constexpr llvm::StringLiteral StrLoopBodyZero =;
constexpr llvm::StringLiteral StrLoopRangeEmpty =;
constexpr llvm::StringLiteral StrLoopCollectionEmpty =;

static std::unique_ptr<FilesToLineNumsMap>
findExecutedLines(const SourceManager &SM, const ExplodedNode *N);

void PathDiagnosticBuilder::generatePathDiagnosticsForNode(
    PathDiagnosticConstruct &C, PathDiagnosticLocation &PrevLoc) const {}

static std::unique_ptr<PathDiagnostic>
generateDiagnosticForBasicReport(const BasicBugReport *R,
                                 const Decl *AnalysisEntryPoint) {}

static std::unique_ptr<PathDiagnostic>
generateEmptyDiagnosticForReport(const PathSensitiveBugReport *R,
                                 const SourceManager &SM,
                                 const Decl *AnalysisEntryPoint) {}

static const Stmt *getStmtParent(const Stmt *S, const ParentMap &PM) {}

static bool isConditionForTerminator(const Stmt *S, const Stmt *Cond) {}

static bool isIncrementOrInitInForLoop(const Stmt *S, const Stmt *FL) {}

OptimizedCallsSet;

/// Adds synthetic edges from top-level statements to their subexpressions.
///
/// This avoids a "swoosh" effect, where an edge from a top-level statement A
/// points to a sub-expression B.1 that's not at the start of B. In these cases,
/// we'd like to see an edge from A to B, then another one from B to B.1.
static void addContextEdges(PathPieces &pieces, const LocationContext *LC) {}

/// Move edges from a branch condition to a branch target
///        when the condition is simple.
///
/// This restructures some of the work of addContextEdges.  That function
/// creates edges this may destroy, but they work together to create a more
/// aesthetically set of edges around branches.  After the call to
/// addContextEdges, we may have (1) an edge to the branch, (2) an edge from
/// the branch to the branch condition, and (3) an edge from the branch
/// condition to the branch target.  We keep (1), but may wish to remove (2)
/// and move the source of (3) to the branch if the branch condition is simple.
static void simplifySimpleBranches(PathPieces &pieces) {}

/// Returns the number of bytes in the given (character-based) SourceRange.
///
/// If the locations in the range are not on the same line, returns
/// std::nullopt.
///
/// Note that this does not do a precise user-visible character or column count.
static std::optional<size_t> getLengthOnSingleLine(const SourceManager &SM,
                                                   SourceRange Range) {}

/// \sa getLengthOnSingleLine(SourceManager, SourceRange)
static std::optional<size_t> getLengthOnSingleLine(const SourceManager &SM,
                                                   const Stmt *S) {}

/// Eliminate two-edge cycles created by addContextEdges().
///
/// Once all the context edges are in place, there are plenty of cases where
/// there's a single edge from a top-level statement to a subexpression,
/// followed by a single path note, and then a reverse edge to get back out to
/// the top level. If the statement is simple enough, the subexpression edges
/// just add noise and make it harder to understand what's going on.
///
/// This function only removes edges in pairs, because removing only one edge
/// might leave other edges dangling.
///
/// This will not remove edges in more complicated situations:
/// - if there is more than one "hop" leading to or from a subexpression.
/// - if there is an inlined call between the edges instead of a single event.
/// - if the whole statement is large enough that having subexpression arrows
///   might be helpful.
static void removeContextCycles(PathPieces &Path, const SourceManager &SM) {}

/// Return true if X is contained by Y.
static bool lexicalContains(const ParentMap &PM, const Stmt *X, const Stmt *Y) {}

// Remove short edges on the same line less than 3 columns in difference.
static void removePunyEdges(PathPieces &path, const SourceManager &SM,
                            const ParentMap &PM) {}

static void removeIdenticalEvents(PathPieces &path) {}

static bool optimizeEdges(const PathDiagnosticConstruct &C, PathPieces &path,
                          OptimizedCallsSet &OCS) {}

/// Drop the very first edge in a path, which should be a function entry edge.
///
/// If the first edge is not a function entry edge (say, because the first
/// statement had an invalid source location), this function does nothing.
// FIXME: We should just generate invalid edges anyway and have the optimizer
// deal with them.
static void dropFunctionEntryEdge(const PathDiagnosticConstruct &C,
                                  PathPieces &Path) {}

/// Populate executes lines with lines containing at least one diagnostics.
static void updateExecutedLinesWithDiagnosticPieces(PathDiagnostic &PD) {}

PathDiagnosticConstruct::PathDiagnosticConstruct(
    const PathDiagnosticConsumer *PDC, const ExplodedNode *ErrorNode,
    const PathSensitiveBugReport *R, const Decl *AnalysisEntryPoint)
    :{}

PathDiagnosticBuilder::PathDiagnosticBuilder(
    BugReporterContext BRC, std::unique_ptr<ExplodedGraph> BugPath,
    PathSensitiveBugReport *r, const ExplodedNode *ErrorNode,
    std::unique_ptr<VisitorsDiagnosticsTy> VisitorsDiagnostics)
    :{}

std::unique_ptr<PathDiagnostic>
PathDiagnosticBuilder::generate(const PathDiagnosticConsumer *PDC) const {}

//===----------------------------------------------------------------------===//
// Methods for BugType and subclasses.
//===----------------------------------------------------------------------===//

void BugType::anchor() {}

//===----------------------------------------------------------------------===//
// Methods for BugReport and subclasses.
//===----------------------------------------------------------------------===//

LLVM_ATTRIBUTE_USED static bool
isDependency(const CheckerRegistryData &Registry, StringRef CheckerName) {}

LLVM_ATTRIBUTE_USED static bool isHidden(const CheckerRegistryData &Registry,
                                         StringRef CheckerName) {}

PathSensitiveBugReport::PathSensitiveBugReport(
    const BugType &bt, StringRef shortDesc, StringRef desc,
    const ExplodedNode *errorNode, PathDiagnosticLocation LocationToUnique,
    const Decl *DeclToUnique)
    :{}

void PathSensitiveBugReport::addVisitor(
    std::unique_ptr<BugReporterVisitor> visitor) {}

void PathSensitiveBugReport::clearVisitors() {}

const Decl *PathSensitiveBugReport::getDeclWithIssue() const {}

void BasicBugReport::Profile(llvm::FoldingSetNodeID& hash) const {}

void PathSensitiveBugReport::Profile(llvm::FoldingSetNodeID &hash) const {}

template <class T>
static void insertToInterestingnessMap(
    llvm::DenseMap<T, bugreporter::TrackingKind> &InterestingnessMap, T Val,
    bugreporter::TrackingKind TKind) {}

void PathSensitiveBugReport::markInteresting(SymbolRef sym,
                                             bugreporter::TrackingKind TKind) {}

void PathSensitiveBugReport::markNotInteresting(SymbolRef sym) {}

void PathSensitiveBugReport::markInteresting(const MemRegion *R,
                                             bugreporter::TrackingKind TKind) {}

void PathSensitiveBugReport::markNotInteresting(const MemRegion *R) {}

void PathSensitiveBugReport::markInteresting(SVal V,
                                             bugreporter::TrackingKind TKind) {}

void PathSensitiveBugReport::markInteresting(const LocationContext *LC) {}

std::optional<bugreporter::TrackingKind>
PathSensitiveBugReport::getInterestingnessKind(SVal V) const {}

std::optional<bugreporter::TrackingKind>
PathSensitiveBugReport::getInterestingnessKind(SymbolRef sym) const {}

std::optional<bugreporter::TrackingKind>
PathSensitiveBugReport::getInterestingnessKind(const MemRegion *R) const {}

bool PathSensitiveBugReport::isInteresting(SVal V) const {}

bool PathSensitiveBugReport::isInteresting(SymbolRef sym) const {}

bool PathSensitiveBugReport::isInteresting(const MemRegion *R) const {}

bool PathSensitiveBugReport::isInteresting(const LocationContext *LC)  const {}

const Stmt *PathSensitiveBugReport::getStmt() const {}

ArrayRef<SourceRange>
PathSensitiveBugReport::getRanges() const {}

PathDiagnosticLocation
PathSensitiveBugReport::getLocation() const {}

//===----------------------------------------------------------------------===//
// Methods for BugReporter and subclasses.
//===----------------------------------------------------------------------===//

const ExplodedGraph &PathSensitiveBugReporter::getGraph() const {}

ProgramStateManager &PathSensitiveBugReporter::getStateManager() const {}

BugReporter::BugReporter(BugReporterData &D)
    :{}

BugReporter::~BugReporter() {}

void BugReporter::FlushReports() {}

//===----------------------------------------------------------------------===//
// PathDiagnostics generation.
//===----------------------------------------------------------------------===//

namespace {

/// A wrapper around an ExplodedGraph that contains a single path from the root
/// to the error node.
class BugPathInfo {};

/// A wrapper around an ExplodedGraph whose leafs are all error nodes. Can
/// conveniently retrieve bug paths from a single error node to the root.
class BugPathGetter {};

} // namespace

BugPathGetter::BugPathGetter(const ExplodedGraph *OriginalGraph,
                             ArrayRef<PathSensitiveBugReport *> &bugReports) {}

BugPathInfo *BugPathGetter::getNextBugPath() {}

/// CompactMacroExpandedPieces - This function postprocesses a PathDiagnostic
/// object and collapses PathDiagosticPieces that are expanded by macros.
static void CompactMacroExpandedPieces(PathPieces &path,
                                       const SourceManager& SM) {}

/// Generate notes from all visitors.
/// Notes associated with @c ErrorNode are generated using
/// @c getEndPath, and the rest are generated with @c VisitNode.
static std::unique_ptr<VisitorsDiagnosticsTy>
generateVisitorsDiagnostics(PathSensitiveBugReport *R,
                            const ExplodedNode *ErrorNode,
                            BugReporterContext &BRC) {}

std::optional<PathDiagnosticBuilder> PathDiagnosticBuilder::findValidReport(
    ArrayRef<PathSensitiveBugReport *> &bugReports,
    PathSensitiveBugReporter &Reporter) {}

std::unique_ptr<DiagnosticForConsumerMapTy>
PathSensitiveBugReporter::generatePathDiagnostics(
    ArrayRef<PathDiagnosticConsumer *> consumers,
    ArrayRef<PathSensitiveBugReport *> &bugReports) {}

void BugReporter::emitReport(std::unique_ptr<BugReport> R) {}

void PathSensitiveBugReporter::emitReport(std::unique_ptr<BugReport> R) {}

//===----------------------------------------------------------------------===//
// Emitting reports in equivalence classes.
//===----------------------------------------------------------------------===//

namespace {

struct FRIEC_WLItem {};

} // namespace

BugReport *PathSensitiveBugReporter::findReportInEquivalenceClass(
    BugReportEquivClass &EQ, SmallVectorImpl<BugReport *> &bugReports) {}

void BugReporter::FlushReport(BugReportEquivClass& EQ) {}

/// Insert all lines participating in the function signature \p Signature
/// into \p ExecutedLines.
static void populateExecutedLinesWithFunctionSignature(
    const Decl *Signature, const SourceManager &SM,
    FilesToLineNumsMap &ExecutedLines) {}

static void populateExecutedLinesWithStmt(
    const Stmt *S, const SourceManager &SM,
    FilesToLineNumsMap &ExecutedLines) {}

/// \return all executed lines including function signatures on the path
/// starting from \p N.
static std::unique_ptr<FilesToLineNumsMap>
findExecutedLines(const SourceManager &SM, const ExplodedNode *N) {}

std::unique_ptr<DiagnosticForConsumerMapTy>
BugReporter::generateDiagnosticForConsumerMap(
    BugReport *exampleReport, ArrayRef<PathDiagnosticConsumer *> consumers,
    ArrayRef<BugReport *> bugReports) {}

static PathDiagnosticCallPiece *
getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP,
                                const SourceManager &SMgr) {}

static void resetDiagnosticLocationToMainFile(PathDiagnostic &PD) {}



std::unique_ptr<DiagnosticForConsumerMapTy>
PathSensitiveBugReporter::generateDiagnosticForConsumerMap(
    BugReport *exampleReport, ArrayRef<PathDiagnosticConsumer *> consumers,
    ArrayRef<BugReport *> bugReports) {}

void BugReporter::EmitBasicReport(const Decl *DeclWithIssue,
                                  const CheckerBase *Checker, StringRef Name,
                                  StringRef Category, StringRef Str,
                                  PathDiagnosticLocation Loc,
                                  ArrayRef<SourceRange> Ranges,
                                  ArrayRef<FixItHint> Fixits) {}

void BugReporter::EmitBasicReport(const Decl *DeclWithIssue,
                                  CheckerNameRef CheckName,
                                  StringRef name, StringRef category,
                                  StringRef str, PathDiagnosticLocation Loc,
                                  ArrayRef<SourceRange> Ranges,
                                  ArrayRef<FixItHint> Fixits) {}

BugType *BugReporter::getBugTypeForName(CheckerNameRef CheckName,
                                        StringRef name, StringRef category) {}