// BugReporterVisitors.cpp - Helpers for reporting bugs -----------*- C++ -*--//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines a set of BugReporter "visitors" which can be used to
// enhance the diagnostics reported for a bug.
//
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "llvm/ADT/SmallString.h"
using namespace clang;
using namespace ento;
//===----------------------------------------------------------------------===//
// Utility functions.
//===----------------------------------------------------------------------===//
bool bugreporter::isDeclRefExprToReference(const Expr *E) {
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
return DRE->getDecl()->getType()->isReferenceType();
}
return false;
}
const Stmt *bugreporter::GetDerefExpr(const ExplodedNode *N) {
// Pattern match for a few useful cases (do something smarter later):
// a[0], p->f, *p
const PostStmt *Loc = N->getLocationAs<PostStmt>();
if (!Loc)
return 0;
const Expr *S = dyn_cast<Expr>(Loc->getStmt());
if (!S)
return 0;
S = S->IgnoreParenCasts();
while (true) {
if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) {
assert(B->isAssignmentOp());
S = B->getLHS()->IgnoreParenCasts();
continue;
}
else if (const UnaryOperator *U = dyn_cast<UnaryOperator>(S)) {
if (U->getOpcode() == UO_Deref)
return U->getSubExpr()->IgnoreParenCasts();
}
else if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) {
if (ME->isArrow() || isDeclRefExprToReference(ME->getBase())) {
return ME->getBase()->IgnoreParenCasts();
}
}
else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(S)) {
return AE->getBase();
}
break;
}
return NULL;
}
const Stmt *bugreporter::GetDenomExpr(const ExplodedNode *N) {
const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(S))
return BE->getRHS();
return NULL;
}
const Stmt *bugreporter::GetRetValExpr(const ExplodedNode *N) {
const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
if (const ReturnStmt *RS = dyn_cast<ReturnStmt>(S))
return RS->getRetValue();
return NULL;
}
//===----------------------------------------------------------------------===//
// Definitions for bug reporter visitors.
//===----------------------------------------------------------------------===//
PathDiagnosticPiece*
BugReporterVisitor::getEndPath(BugReporterContext &BRC,
const ExplodedNode *EndPathNode,
BugReport &BR) {
return 0;
}
PathDiagnosticPiece*
BugReporterVisitor::getDefaultEndPath(BugReporterContext &BRC,
const ExplodedNode *EndPathNode,
BugReport &BR) {
PathDiagnosticLocation L =
PathDiagnosticLocation::createEndOfPath(EndPathNode,BRC.getSourceManager());
BugReport::ranges_iterator Beg, End;
llvm::tie(Beg, End) = BR.getRanges();
// Only add the statement itself as a range if we didn't specify any
// special ranges for this report.
PathDiagnosticPiece *P = new PathDiagnosticEventPiece(L,
BR.getDescription(),
Beg == End);
for (; Beg != End; ++Beg)
P->addRange(*Beg);
return P;
}
namespace {
/// Emits an extra note at the return statement of an interesting stack frame.
///
/// The returned value is marked as an interesting value, and if it's null,
/// adds a visitor to track where it became null.
///
/// This visitor is intended to be used when another visitor discovers that an
/// interesting value comes from an inlined function call.
class ReturnVisitor : public BugReporterVisitorImpl<ReturnVisitor> {
const StackFrameContext *StackFrame;
bool