brintos

brintos / llvm-project-archived public Read only

0
0
Text · 43.2 KiB · e42731b Raw
1248 lines · cpp
1//===- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9//  This file defines the PathDiagnostic-related interfaces.10//11//===----------------------------------------------------------------------===//12 13#include "clang/Analysis/PathDiagnostic.h"14#include "clang/AST/Decl.h"15#include "clang/AST/DeclBase.h"16#include "clang/AST/DeclCXX.h"17#include "clang/AST/DeclObjC.h"18#include "clang/AST/DeclTemplate.h"19#include "clang/AST/Expr.h"20#include "clang/AST/ExprCXX.h"21#include "clang/AST/ParentMap.h"22#include "clang/AST/PrettyPrinter.h"23#include "clang/AST/Stmt.h"24#include "clang/AST/Type.h"25#include "clang/Analysis/AnalysisDeclContext.h"26#include "clang/Analysis/CFG.h"27#include "clang/Analysis/IssueHash.h"28#include "clang/Analysis/ProgramPoint.h"29#include "clang/Basic/LLVM.h"30#include "clang/Basic/SourceLocation.h"31#include "clang/Basic/SourceManager.h"32#include "llvm/ADT/ArrayRef.h"33#include "llvm/ADT/FoldingSet.h"34#include "llvm/ADT/STLExtras.h"35#include "llvm/ADT/StringExtras.h"36#include "llvm/ADT/StringRef.h"37#include "llvm/Support/ErrorHandling.h"38#include "llvm/Support/raw_ostream.h"39#include <cassert>40#include <cstring>41#include <memory>42#include <optional>43#include <utility>44#include <vector>45 46using namespace clang;47using namespace ento;48 49static StringRef StripTrailingDots(StringRef s) { return s.rtrim('.'); }50 51PathDiagnosticPiece::PathDiagnosticPiece(StringRef s,52                                         Kind k, DisplayHint hint)53    : str(StripTrailingDots(s)), kind(k), Hint(hint) {}54 55PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)56    : kind(k), Hint(hint) {}57 58PathDiagnosticPiece::~PathDiagnosticPiece() = default;59 60PathDiagnosticEventPiece::~PathDiagnosticEventPiece() = default;61 62PathDiagnosticCallPiece::~PathDiagnosticCallPiece() = default;63 64PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() = default;65 66PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() = default;67 68PathDiagnosticNotePiece::~PathDiagnosticNotePiece() = default;69 70PathDiagnosticPopUpPiece::~PathDiagnosticPopUpPiece() = default;71 72void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current,73                           bool ShouldFlattenMacros) const {74  for (auto &Piece : *this) {75    switch (Piece->getKind()) {76    case PathDiagnosticPiece::Call: {77      auto &Call = cast<PathDiagnosticCallPiece>(*Piece);78      if (auto CallEnter = Call.getCallEnterEvent())79        Current.push_back(std::move(CallEnter));80      Call.path.flattenTo(Primary, Primary, ShouldFlattenMacros);81      if (auto callExit = Call.getCallExitEvent())82        Current.push_back(std::move(callExit));83      break;84    }85    case PathDiagnosticPiece::Macro: {86      auto &Macro = cast<PathDiagnosticMacroPiece>(*Piece);87      if (ShouldFlattenMacros) {88        Macro.subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros);89      } else {90        Current.push_back(Piece);91        PathPieces NewPath;92        Macro.subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros);93        // FIXME: This probably shouldn't mutate the original path piece.94        Macro.subPieces = NewPath;95      }96      break;97    }98    case PathDiagnosticPiece::Event:99    case PathDiagnosticPiece::ControlFlow:100    case PathDiagnosticPiece::Note:101    case PathDiagnosticPiece::PopUp:102      Current.push_back(Piece);103      break;104    }105  }106}107 108PathDiagnostic::~PathDiagnostic() = default;109 110PathDiagnostic::PathDiagnostic(111    StringRef CheckerName, const Decl *declWithIssue, StringRef bugtype,112    StringRef verboseDesc, StringRef shortDesc, StringRef category,113    PathDiagnosticLocation LocationToUnique, const Decl *DeclToUnique,114    const Decl *AnalysisEntryPoint,115    std::unique_ptr<FilesToLineNumsMap> ExecutedLines)116    : CheckerName(CheckerName), DeclWithIssue(declWithIssue),117      BugType(StripTrailingDots(bugtype)),118      VerboseDesc(StripTrailingDots(verboseDesc)),119      ShortDesc(StripTrailingDots(shortDesc)),120      Category(StripTrailingDots(category)), UniqueingLoc(LocationToUnique),121      UniqueingDecl(DeclToUnique), AnalysisEntryPoint(AnalysisEntryPoint),122      ExecutedLines(std::move(ExecutedLines)), path(pathImpl) {123  assert(AnalysisEntryPoint);124}125 126void PathDiagnosticConsumer::anchor() {}127 128PathDiagnosticConsumer::~PathDiagnosticConsumer() {129  // Delete the contents of the FoldingSet if it isn't empty already.130  for (auto &Diag : Diags)131    delete &Diag;132}133 134void PathDiagnosticConsumer::HandlePathDiagnostic(135    std::unique_ptr<PathDiagnostic> D) {136  if (!D || D->path.empty())137    return;138 139  // We need to flatten the locations (convert Stmt* to locations) because140  // the referenced statements may be freed by the time the diagnostics141  // are emitted.142  D->flattenLocations();143 144  // If the PathDiagnosticConsumer does not support diagnostics that145  // cross file boundaries, prune out such diagnostics now.146  if (!supportsCrossFileDiagnostics()) {147    // Verify that the entire path is from the same FileID.148    FileID FID;149    const SourceManager &SMgr = D->path.front()->getLocation().getManager();150    SmallVector<const PathPieces *, 5> WorkList;151    WorkList.push_back(&D->path);152    SmallString<128> buf;153    llvm::raw_svector_ostream warning(buf);154    warning << "warning: Path diagnostic report is not generated. Current "155            << "output format does not support diagnostics that cross file "156            << "boundaries. Refer to --analyzer-output for valid output "157            << "formats\n";158 159    while (!WorkList.empty()) {160      const PathPieces &path = *WorkList.pop_back_val();161 162      for (const auto &I : path) {163        const PathDiagnosticPiece *piece = I.get();164        FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc();165 166        if (FID.isInvalid()) {167          FID = SMgr.getFileID(L);168        } else if (SMgr.getFileID(L) != FID) {169          llvm::errs() << warning.str();170          return;171        }172 173        // Check the source ranges.174        ArrayRef<SourceRange> Ranges = piece->getRanges();175        for (const auto &I : Ranges) {176          SourceLocation L = SMgr.getExpansionLoc(I.getBegin());177          if (!L.isFileID() || SMgr.getFileID(L) != FID) {178            llvm::errs() << warning.str();179            return;180          }181          L = SMgr.getExpansionLoc(I.getEnd());182          if (!L.isFileID() || SMgr.getFileID(L) != FID) {183            llvm::errs() << warning.str();184            return;185          }186        }187 188        if (const auto *call = dyn_cast<PathDiagnosticCallPiece>(piece))189          WorkList.push_back(&call->path);190        else if (const auto *macro = dyn_cast<PathDiagnosticMacroPiece>(piece))191          WorkList.push_back(&macro->subPieces);192      }193    }194 195    if (FID.isInvalid())196      return; // FIXME: Emit a warning?197  }198 199  // Profile the node to see if we already have something matching it200  llvm::FoldingSetNodeID profile;201  D->Profile(profile);202  void *InsertPos = nullptr;203 204  if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) {205    // Keep the PathDiagnostic with the shorter path.206    // Note, the enclosing routine is called in deterministic order, so the207    // results will be consistent between runs (no reason to break ties if the208    // size is the same).209    const unsigned orig_size = orig->full_size();210    const unsigned new_size = D->full_size();211    if (orig_size <= new_size)212      return;213 214    assert(orig != D.get());215    Diags.RemoveNode(orig);216    delete orig;217  }218 219  Diags.InsertNode(D.release());220}221 222static std::optional<bool> comparePath(const PathPieces &X,223                                       const PathPieces &Y);224 225static std::optional<bool>226compareControlFlow(const PathDiagnosticControlFlowPiece &X,227                   const PathDiagnosticControlFlowPiece &Y) {228  FullSourceLoc XSL = X.getStartLocation().asLocation();229  FullSourceLoc YSL = Y.getStartLocation().asLocation();230  if (XSL != YSL)231    return XSL.isBeforeInTranslationUnitThan(YSL);232  FullSourceLoc XEL = X.getEndLocation().asLocation();233  FullSourceLoc YEL = Y.getEndLocation().asLocation();234  if (XEL != YEL)235    return XEL.isBeforeInTranslationUnitThan(YEL);236  return std::nullopt;237}238 239static std::optional<bool> compareMacro(const PathDiagnosticMacroPiece &X,240                                        const PathDiagnosticMacroPiece &Y) {241  return comparePath(X.subPieces, Y.subPieces);242}243 244static std::optional<bool> compareCall(const PathDiagnosticCallPiece &X,245                                       const PathDiagnosticCallPiece &Y) {246  FullSourceLoc X_CEL = X.callEnter.asLocation();247  FullSourceLoc Y_CEL = Y.callEnter.asLocation();248  if (X_CEL != Y_CEL)249    return X_CEL.isBeforeInTranslationUnitThan(Y_CEL);250  FullSourceLoc X_CEWL = X.callEnterWithin.asLocation();251  FullSourceLoc Y_CEWL = Y.callEnterWithin.asLocation();252  if (X_CEWL != Y_CEWL)253    return X_CEWL.isBeforeInTranslationUnitThan(Y_CEWL);254  FullSourceLoc X_CRL = X.callReturn.asLocation();255  FullSourceLoc Y_CRL = Y.callReturn.asLocation();256  if (X_CRL != Y_CRL)257    return X_CRL.isBeforeInTranslationUnitThan(Y_CRL);258  return comparePath(X.path, Y.path);259}260 261static std::optional<bool> comparePiece(const PathDiagnosticPiece &X,262                                        const PathDiagnosticPiece &Y) {263  if (X.getKind() != Y.getKind())264    return X.getKind() < Y.getKind();265 266  FullSourceLoc XL = X.getLocation().asLocation();267  FullSourceLoc YL = Y.getLocation().asLocation();268  if (XL != YL)269    return XL.isBeforeInTranslationUnitThan(YL);270 271  if (X.getString() != Y.getString())272    return X.getString() < Y.getString();273 274  if (X.getRanges().size() != Y.getRanges().size())275    return X.getRanges().size() < Y.getRanges().size();276 277  const SourceManager &SM = XL.getManager();278 279  for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) {280    SourceRange XR = X.getRanges()[i];281    SourceRange YR = Y.getRanges()[i];282    if (XR != YR) {283      if (XR.getBegin() != YR.getBegin())284        return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin());285      return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd());286    }287  }288 289  switch (X.getKind()) {290    case PathDiagnosticPiece::ControlFlow:291      return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X),292                                cast<PathDiagnosticControlFlowPiece>(Y));293    case PathDiagnosticPiece::Macro:294      return compareMacro(cast<PathDiagnosticMacroPiece>(X),295                          cast<PathDiagnosticMacroPiece>(Y));296    case PathDiagnosticPiece::Call:297      return compareCall(cast<PathDiagnosticCallPiece>(X),298                         cast<PathDiagnosticCallPiece>(Y));299    case PathDiagnosticPiece::Event:300    case PathDiagnosticPiece::Note:301    case PathDiagnosticPiece::PopUp:302      return std::nullopt;303  }304  llvm_unreachable("all cases handled");305}306 307static std::optional<bool> comparePath(const PathPieces &X,308                                       const PathPieces &Y) {309  if (X.size() != Y.size())310    return X.size() < Y.size();311 312  PathPieces::const_iterator X_I = X.begin(), X_end = X.end();313  PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end();314 315  for (; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I)316    if (std::optional<bool> b = comparePiece(**X_I, **Y_I))317      return *b;318 319  return std::nullopt;320}321 322static bool compareCrossTUSourceLocs(FullSourceLoc XL, FullSourceLoc YL) {323  if (XL.isInvalid() && YL.isValid())324    return true;325  if (XL.isValid() && YL.isInvalid())326    return false;327  FileIDAndOffset XOffs = XL.getDecomposedLoc();328  FileIDAndOffset YOffs = YL.getDecomposedLoc();329  const SourceManager &SM = XL.getManager();330  std::pair<bool, bool> InSameTU = SM.isInTheSameTranslationUnit(XOffs, YOffs);331  if (InSameTU.first)332    return XL.isBeforeInTranslationUnitThan(YL);333  OptionalFileEntryRef XFE =334      SM.getFileEntryRefForID(XL.getSpellingLoc().getFileID());335  OptionalFileEntryRef YFE =336      SM.getFileEntryRefForID(YL.getSpellingLoc().getFileID());337  if (!XFE || !YFE)338    return XFE && !YFE;339  int NameCmp = XFE->getName().compare(YFE->getName());340  if (NameCmp != 0)341    return NameCmp < 0;342  // Last resort: Compare raw file IDs that are possibly expansions.343  return XL.getFileID() < YL.getFileID();344}345 346static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) {347  FullSourceLoc XL = X.getLocation().asLocation();348  FullSourceLoc YL = Y.getLocation().asLocation();349  if (XL != YL)350    return compareCrossTUSourceLocs(XL, YL);351  FullSourceLoc XUL = X.getUniqueingLoc().asLocation();352  FullSourceLoc YUL = Y.getUniqueingLoc().asLocation();353  if (XUL != YUL)354    return compareCrossTUSourceLocs(XUL, YUL);355  if (X.getBugType() != Y.getBugType())356    return X.getBugType() < Y.getBugType();357  if (X.getCategory() != Y.getCategory())358    return X.getCategory() < Y.getCategory();359  if (X.getVerboseDescription() != Y.getVerboseDescription())360    return X.getVerboseDescription() < Y.getVerboseDescription();361  if (X.getShortDescription() != Y.getShortDescription())362    return X.getShortDescription() < Y.getShortDescription();363  auto CompareDecls = [&XL](const Decl *D1,364                            const Decl *D2) -> std::optional<bool> {365    if (D1 == D2)366      return std::nullopt;367    if (!D1)368      return true;369    if (!D2)370      return false;371    SourceLocation D1L = D1->getLocation();372    SourceLocation D2L = D2->getLocation();373    if (D1L != D2L) {374      const SourceManager &SM = XL.getManager();375      return compareCrossTUSourceLocs(FullSourceLoc(D1L, SM),376                                      FullSourceLoc(D2L, SM));377    }378    return std::nullopt;379  };380  if (auto Result = CompareDecls(X.getDeclWithIssue(), Y.getDeclWithIssue()))381    return *Result;382  if (XUL.isValid()) {383    if (auto Result = CompareDecls(X.getUniqueingDecl(), Y.getUniqueingDecl()))384      return *Result;385  }386  PathDiagnostic::meta_iterator XI = X.meta_begin(), XE = X.meta_end();387  PathDiagnostic::meta_iterator YI = Y.meta_begin(), YE = Y.meta_end();388  if (XE - XI != YE - YI)389    return (XE - XI) < (YE - YI);390  for ( ; XI != XE ; ++XI, ++YI) {391    if (*XI != *YI)392      return (*XI) < (*YI);393  }394  return *comparePath(X.path, Y.path);395}396 397void PathDiagnosticConsumer::FlushDiagnostics(398                                     PathDiagnosticConsumer::FilesMade *Files) {399  if (flushed)400    return;401 402  flushed = true;403 404  std::vector<const PathDiagnostic *> BatchDiags;405  for (const auto &D : Diags)406    BatchDiags.push_back(&D);407 408  // Sort the diagnostics so that they are always emitted in a deterministic409  // order.410  int (*Comp)(const PathDiagnostic *const *, const PathDiagnostic *const *) =411      [](const PathDiagnostic *const *X, const PathDiagnostic *const *Y) {412        assert(*X != *Y && "PathDiagnostics not uniqued!");413        if (compare(**X, **Y))414          return -1;415        assert(compare(**Y, **X) && "Not a total order!");416        return 1;417      };418  array_pod_sort(BatchDiags.begin(), BatchDiags.end(), Comp);419 420  FlushDiagnosticsImpl(BatchDiags, Files);421 422  // Delete the flushed diagnostics.423  for (const auto D : BatchDiags)424    delete D;425 426  // Clear out the FoldingSet.427  Diags.clear();428}429 430PathDiagnosticConsumer::FilesMade::~FilesMade() {431  for (auto It = Set.begin(); It != Set.end();)432    (It++)->~PDFileEntry();433}434 435void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD,436                                                      StringRef ConsumerName,437                                                      StringRef FileName) {438  llvm::FoldingSetNodeID NodeID;439  NodeID.Add(PD);440  void *InsertPos;441  PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos);442  if (!Entry) {443    Entry = Alloc.Allocate<PDFileEntry>();444    Entry = new (Entry) PDFileEntry(NodeID);445    Set.InsertNode(Entry, InsertPos);446  }447 448  // Allocate persistent storage for the file name.449  char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1);450  memcpy(FileName_cstr, FileName.data(), FileName.size());451 452  Entry->files.push_back(std::make_pair(ConsumerName,453                                        StringRef(FileName_cstr,454                                                  FileName.size())));455}456 457PathDiagnosticConsumer::PDFileEntry::ConsumerFiles *458PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) {459  llvm::FoldingSetNodeID NodeID;460  NodeID.Add(PD);461  void *InsertPos;462  PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos);463  if (!Entry)464    return nullptr;465  return &Entry->files;466}467 468//===----------------------------------------------------------------------===//469// PathDiagnosticLocation methods.470//===----------------------------------------------------------------------===//471 472SourceLocation PathDiagnosticLocation::getValidSourceLocation(473    const Stmt *S, LocationOrAnalysisDeclContext LAC, bool UseEndOfStatement) {474  SourceLocation L = UseEndOfStatement ? S->getEndLoc() : S->getBeginLoc();475  assert(!LAC.isNull() &&476         "A valid LocationContext or AnalysisDeclContext should be passed to "477         "PathDiagnosticLocation upon creation.");478 479  // S might be a temporary statement that does not have a location in the480  // source code, so find an enclosing statement and use its location.481  if (!L.isValid()) {482    AnalysisDeclContext *ADC;483    if (auto *LC = dyn_cast<const LocationContext *>(LAC))484      ADC = LC->getAnalysisDeclContext();485    else486      ADC = cast<AnalysisDeclContext *>(LAC);487 488    ParentMap &PM = ADC->getParentMap();489 490    const Stmt *Parent = S;491    do {492      Parent = PM.getParent(Parent);493 494      // In rare cases, we have implicit top-level expressions,495      // such as arguments for implicit member initializers.496      // In this case, fall back to the start of the body (even if we were497      // asked for the statement end location).498      if (!Parent) {499        const Stmt *Body = ADC->getBody();500        if (Body)501          L = Body->getBeginLoc();502        else503          L = ADC->getDecl()->getEndLoc();504        break;505      }506 507      L = UseEndOfStatement ? Parent->getEndLoc() : Parent->getBeginLoc();508    } while (!L.isValid());509  }510 511  // FIXME: Ironically, this assert actually fails in some cases.512  //assert(L.isValid());513  return L;514}515 516static PathDiagnosticLocation517getLocationForCaller(const StackFrameContext *SFC,518                     const LocationContext *CallerCtx,519                     const SourceManager &SM) {520  const CFGBlock &Block = *SFC->getCallSiteBlock();521  CFGElement Source = Block[SFC->getIndex()];522 523  switch (Source.getKind()) {524  case CFGElement::Statement:525  case CFGElement::Constructor:526  case CFGElement::CXXRecordTypedCall:527    return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(),528                                  SM, CallerCtx);529  case CFGElement::Initializer: {530    const CFGInitializer &Init = Source.castAs<CFGInitializer>();531    return PathDiagnosticLocation(Init.getInitializer()->getInit(),532                                  SM, CallerCtx);533  }534  case CFGElement::AutomaticObjectDtor: {535    const CFGAutomaticObjDtor &Dtor = Source.castAs<CFGAutomaticObjDtor>();536    return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(),537                                             SM, CallerCtx);538  }539  case CFGElement::DeleteDtor: {540    const CFGDeleteDtor &Dtor = Source.castAs<CFGDeleteDtor>();541    return PathDiagnosticLocation(Dtor.getDeleteExpr(), SM, CallerCtx);542  }543  case CFGElement::BaseDtor:544  case CFGElement::MemberDtor: {545    const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext();546    if (const Stmt *CallerBody = CallerInfo->getBody())547      return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx);548    return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM);549  }550  case CFGElement::NewAllocator: {551    const CFGNewAllocator &Alloc = Source.castAs<CFGNewAllocator>();552    return PathDiagnosticLocation(Alloc.getAllocatorExpr(), SM, CallerCtx);553  }554  case CFGElement::TemporaryDtor: {555    // Temporary destructors are for temporaries. They die immediately at around556    // the location of CXXBindTemporaryExpr. If they are lifetime-extended,557    // they'd be dealt with via an AutomaticObjectDtor instead.558    const auto &Dtor = Source.castAs<CFGTemporaryDtor>();559    return PathDiagnosticLocation::createEnd(Dtor.getBindTemporaryExpr(), SM,560                                             CallerCtx);561  }562  case CFGElement::ScopeBegin:563  case CFGElement::ScopeEnd:564  case CFGElement::CleanupFunction:565    llvm_unreachable("not yet implemented!");566  case CFGElement::LifetimeEnds:567  case CFGElement::LoopExit:568    llvm_unreachable("CFGElement kind should not be on callsite!");569  }570 571  llvm_unreachable("Unknown CFGElement kind");572}573 574PathDiagnosticLocation575PathDiagnosticLocation::createBegin(const Decl *D,576                                    const SourceManager &SM) {577  return PathDiagnosticLocation(D->getBeginLoc(), SM, SingleLocK);578}579 580PathDiagnosticLocation581PathDiagnosticLocation::createBegin(const Stmt *S,582                                    const SourceManager &SM,583                                    LocationOrAnalysisDeclContext LAC) {584  assert(S && "Statement cannot be null");585  return PathDiagnosticLocation(getValidSourceLocation(S, LAC),586                                SM, SingleLocK);587}588 589PathDiagnosticLocation590PathDiagnosticLocation::createEnd(const Stmt *S,591                                  const SourceManager &SM,592                                  LocationOrAnalysisDeclContext LAC) {593  if (const auto *CS = dyn_cast<CompoundStmt>(S))594    return createEndBrace(CS, SM);595  return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true),596                                SM, SingleLocK);597}598 599PathDiagnosticLocation600PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO,601                                          const SourceManager &SM) {602  return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK);603}604 605PathDiagnosticLocation606PathDiagnosticLocation::createConditionalColonLoc(607                                            const ConditionalOperator *CO,608                                            const SourceManager &SM) {609  return PathDiagnosticLocation(CO->getColonLoc(), SM, SingleLocK);610}611 612PathDiagnosticLocation613PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME,614                                        const SourceManager &SM) {615 616  assert(ME->getMemberLoc().isValid() || ME->getBeginLoc().isValid());617 618  // In some cases, getMemberLoc isn't valid -- in this case we'll return with619  // some other related valid SourceLocation.620  if (ME->getMemberLoc().isValid())621    return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK);622 623  return PathDiagnosticLocation(ME->getBeginLoc(), SM, SingleLocK);624}625 626PathDiagnosticLocation627PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS,628                                         const SourceManager &SM) {629  SourceLocation L = CS->getLBracLoc();630  return PathDiagnosticLocation(L, SM, SingleLocK);631}632 633PathDiagnosticLocation634PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS,635                                       const SourceManager &SM) {636  SourceLocation L = CS->getRBracLoc();637  return PathDiagnosticLocation(L, SM, SingleLocK);638}639 640PathDiagnosticLocation641PathDiagnosticLocation::createDeclBegin(const LocationContext *LC,642                                        const SourceManager &SM) {643  // FIXME: Should handle CXXTryStmt if analyser starts supporting C++.644  if (const auto *CS = dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody()))645    if (!CS->body_empty()) {646      SourceLocation Loc = (*CS->body_begin())->getBeginLoc();647      return PathDiagnosticLocation(Loc, SM, SingleLocK);648    }649 650  return PathDiagnosticLocation();651}652 653PathDiagnosticLocation654PathDiagnosticLocation::createDeclEnd(const LocationContext *LC,655                                      const SourceManager &SM) {656  SourceLocation L = LC->getDecl()->getBodyRBrace();657  return PathDiagnosticLocation(L, SM, SingleLocK);658}659 660PathDiagnosticLocation661PathDiagnosticLocation::create(const ProgramPoint& P,662                               const SourceManager &SMng) {663  const Stmt* S = nullptr;664  if (std::optional<BlockEdge> BE = P.getAs<BlockEdge>()) {665    const CFGBlock *BSrc = BE->getSrc();666    if (BSrc->getTerminator().isVirtualBaseBranch()) {667      // TODO: VirtualBaseBranches should also appear for destructors.668      // In this case we should put the diagnostic at the end of decl.669      return PathDiagnosticLocation::createBegin(670          P.getLocationContext()->getDecl(), SMng);671 672    } else {673      S = BSrc->getTerminatorCondition();674      if (!S) {675        // If the BlockEdge has no terminator condition statement but its676        // source is the entry of the CFG (e.g. a checker crated the branch at677        // the beginning of a function), use the function's declaration instead.678        assert(BSrc == &BSrc->getParent()->getEntry() && "CFGBlock has no "679               "TerminatorCondition and is not the enrty block of the CFG");680        return PathDiagnosticLocation::createBegin(681            P.getLocationContext()->getDecl(), SMng);682      }683    }684  } else if (std::optional<StmtPoint> SP = P.getAs<StmtPoint>()) {685    S = SP->getStmt();686    if (P.getAs<PostStmtPurgeDeadSymbols>())687      return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext());688  } else if (std::optional<PostInitializer> PIP = P.getAs<PostInitializer>()) {689    return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(),690                                  SMng);691  } else if (std::optional<PreImplicitCall> PIC = P.getAs<PreImplicitCall>()) {692    return PathDiagnosticLocation(PIC->getLocation(), SMng);693  } else if (std::optional<PostImplicitCall> PIE =694                 P.getAs<PostImplicitCall>()) {695    return PathDiagnosticLocation(PIE->getLocation(), SMng);696  } else if (std::optional<CallEnter> CE = P.getAs<CallEnter>()) {697    return getLocationForCaller(CE->getCalleeContext(),698                                CE->getLocationContext(),699                                SMng);700  } else if (std::optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) {701    return getLocationForCaller(CEE->getCalleeContext(),702                                CEE->getLocationContext(),703                                SMng);704  } else if (auto CEB = P.getAs<CallExitBegin>()) {705    if (const ReturnStmt *RS = CEB->getReturnStmt())706      return PathDiagnosticLocation::createBegin(RS, SMng,707                                                 CEB->getLocationContext());708    return PathDiagnosticLocation(709        CEB->getLocationContext()->getDecl()->getSourceRange().getEnd(), SMng);710  } else if (std::optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {711    if (std::optional<CFGElement> BlockFront = BE->getFirstElement()) {712      if (auto StmtElt = BlockFront->getAs<CFGStmt>()) {713        return PathDiagnosticLocation(StmtElt->getStmt()->getBeginLoc(), SMng);714      } else if (auto NewAllocElt = BlockFront->getAs<CFGNewAllocator>()) {715        return PathDiagnosticLocation(716            NewAllocElt->getAllocatorExpr()->getBeginLoc(), SMng);717      }718      llvm_unreachable("Unexpected CFG element at front of block");719    }720 721    return PathDiagnosticLocation(722        BE->getBlock()->getTerminatorStmt()->getBeginLoc(), SMng);723  } else if (std::optional<FunctionExitPoint> FE =724                 P.getAs<FunctionExitPoint>()) {725    return PathDiagnosticLocation(FE->getStmt(), SMng,726                                  FE->getLocationContext());727  } else {728    llvm_unreachable("Unexpected ProgramPoint");729  }730 731  return PathDiagnosticLocation(S, SMng, P.getLocationContext());732}733 734PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation(735                                           const PathDiagnosticLocation &PDL) {736  FullSourceLoc L = PDL.asLocation();737  return PathDiagnosticLocation(L, L.getManager(), SingleLocK);738}739 740FullSourceLoc741  PathDiagnosticLocation::genLocation(SourceLocation L,742                                      LocationOrAnalysisDeclContext LAC) const {743  assert(isValid());744  // Note that we want a 'switch' here so that the compiler can warn us in745  // case we add more cases.746  switch (K) {747    case SingleLocK:748    case RangeK:749      break;750    case StmtK:751      // Defensive checking.752      if (!S)753        break;754      return FullSourceLoc(getValidSourceLocation(S, LAC),755                           const_cast<SourceManager&>(*SM));756    case DeclK:757      // Defensive checking.758      if (!D)759        break;760      return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));761  }762 763  return FullSourceLoc(L, const_cast<SourceManager&>(*SM));764}765 766PathDiagnosticRange767  PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const {768  assert(isValid());769  // Note that we want a 'switch' here so that the compiler can warn us in770  // case we add more cases.771  switch (K) {772    case SingleLocK:773      return PathDiagnosticRange(SourceRange(Loc,Loc), true);774    case RangeK:775      break;776    case StmtK: {777      const Stmt *S = asStmt();778      switch (S->getStmtClass()) {779        default:780          break;781        case Stmt::DeclStmtClass: {782          const auto *DS = cast<DeclStmt>(S);783          if (DS->isSingleDecl()) {784            // Should always be the case, but we'll be defensive.785            return SourceRange(DS->getBeginLoc(),786                               DS->getSingleDecl()->getLocation());787          }788          break;789        }790          // FIXME: Provide better range information for different791          //  terminators.792        case Stmt::IfStmtClass:793        case Stmt::WhileStmtClass:794        case Stmt::DoStmtClass:795        case Stmt::ForStmtClass:796        case Stmt::ChooseExprClass:797        case Stmt::IndirectGotoStmtClass:798        case Stmt::SwitchStmtClass:799        case Stmt::BinaryConditionalOperatorClass:800        case Stmt::ConditionalOperatorClass:801        case Stmt::ObjCForCollectionStmtClass: {802          SourceLocation L = getValidSourceLocation(S, LAC);803          return SourceRange(L, L);804        }805      }806      SourceRange R = S->getSourceRange();807      if (R.isValid())808        return R;809      break;810    }811    case DeclK:812      if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))813        return MD->getSourceRange();814      if (const auto *FD = dyn_cast<FunctionDecl>(D)) {815        if (Stmt *Body = FD->getBody())816          return Body->getSourceRange();817      }818      else {819        SourceLocation L = D->getLocation();820        return PathDiagnosticRange(SourceRange(L, L), true);821      }822  }823 824  return SourceRange(Loc, Loc);825}826 827void PathDiagnosticLocation::flatten() {828  if (K == StmtK) {829    K = RangeK;830    S = nullptr;831    D = nullptr;832  }833  else if (K == DeclK) {834    K = SingleLocK;835    S = nullptr;836    D = nullptr;837  }838}839 840//===----------------------------------------------------------------------===//841// Manipulation of PathDiagnosticCallPieces.842//===----------------------------------------------------------------------===//843 844std::shared_ptr<PathDiagnosticCallPiece>845PathDiagnosticCallPiece::construct(const CallExitEnd &CE,846                                   const SourceManager &SM) {847  const Decl *caller = CE.getLocationContext()->getDecl();848  PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(),849                                                    CE.getLocationContext(),850                                                    SM);851  return std::shared_ptr<PathDiagnosticCallPiece>(852      new PathDiagnosticCallPiece(caller, pos));853}854 855PathDiagnosticCallPiece *856PathDiagnosticCallPiece::construct(PathPieces &path,857                                   const Decl *caller) {858  std::shared_ptr<PathDiagnosticCallPiece> C(859      new PathDiagnosticCallPiece(path, caller));860  path.clear();861  auto *R = C.get();862  path.push_front(std::move(C));863  return R;864}865 866void PathDiagnosticCallPiece::setCallee(const CallEnter &CE,867                                        const SourceManager &SM) {868  const StackFrameContext *CalleeCtx = CE.getCalleeContext();869  Callee = CalleeCtx->getDecl();870 871  callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM);872  callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM);873 874  // Autosynthesized property accessors are special because we'd never875  // pop back up to non-autosynthesized code until we leave them.876  // This is not generally true for autosynthesized callees, which may call877  // non-autosynthesized callbacks.878  // Unless set here, the IsCalleeAnAutosynthesizedPropertyAccessor flag879  // defaults to false.880  if (const auto *MD = dyn_cast<ObjCMethodDecl>(Callee))881    IsCalleeAnAutosynthesizedPropertyAccessor = (882        MD->isPropertyAccessor() &&883        CalleeCtx->getAnalysisDeclContext()->isBodyAutosynthesized());884}885 886static void describeTemplateParameters(raw_ostream &Out,887                                       const ArrayRef<TemplateArgument> TAList,888                                       const LangOptions &LO,889                                       StringRef Prefix = StringRef(),890                                       StringRef Postfix = StringRef());891 892static void describeTemplateParameter(raw_ostream &Out,893                                      const TemplateArgument &TArg,894                                      const LangOptions &LO) {895 896  if (TArg.getKind() == TemplateArgument::ArgKind::Pack) {897    describeTemplateParameters(Out, TArg.getPackAsArray(), LO);898  } else {899    TArg.print(PrintingPolicy(LO), Out, /*IncludeType*/ true);900  }901}902 903static void describeTemplateParameters(raw_ostream &Out,904                                       const ArrayRef<TemplateArgument> TAList,905                                       const LangOptions &LO,906                                       StringRef Prefix, StringRef Postfix) {907  if (TAList.empty())908    return;909 910  Out << Prefix;911  for (int I = 0, Last = TAList.size() - 1; I != Last; ++I) {912    describeTemplateParameter(Out, TAList[I], LO);913    Out << ", ";914  }915  describeTemplateParameter(Out, TAList[TAList.size() - 1], LO);916  Out << Postfix;917}918 919static void describeClass(raw_ostream &Out, const CXXRecordDecl *D,920                          StringRef Prefix = StringRef()) {921  if (!D->getIdentifier())922    return;923  Out << Prefix << '\'' << *D;924  if (const auto T = dyn_cast<ClassTemplateSpecializationDecl>(D))925    describeTemplateParameters(Out, T->getTemplateArgs().asArray(),926                               D->getLangOpts(), "<", ">");927 928  Out << '\'';929}930 931static bool describeCodeDecl(raw_ostream &Out, const Decl *D,932                             bool ExtendedDescription,933                             StringRef Prefix = StringRef()) {934  if (!D)935    return false;936 937  if (isa<BlockDecl>(D)) {938    if (ExtendedDescription)939      Out << Prefix << "anonymous block";940    return ExtendedDescription;941  }942 943  if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {944    Out << Prefix;945    if (ExtendedDescription && !MD->isUserProvided()) {946      if (MD->isExplicitlyDefaulted())947        Out << "defaulted ";948      else949        Out << "implicit ";950    }951 952    if (const auto *CD = dyn_cast<CXXConstructorDecl>(MD)) {953      if (CD->isDefaultConstructor())954        Out << "default ";955      else if (CD->isCopyConstructor())956        Out << "copy ";957      else if (CD->isMoveConstructor())958        Out << "move ";959 960      Out << "constructor";961      describeClass(Out, MD->getParent(), " for ");962    } else if (isa<CXXDestructorDecl>(MD)) {963      if (!MD->isUserProvided()) {964        Out << "destructor";965        describeClass(Out, MD->getParent(), " for ");966      } else {967        // Use ~Foo for explicitly-written destructors.968        Out << "'" << *MD << "'";969      }970    } else if (MD->isCopyAssignmentOperator()) {971        Out << "copy assignment operator";972        describeClass(Out, MD->getParent(), " for ");973    } else if (MD->isMoveAssignmentOperator()) {974        Out << "move assignment operator";975        describeClass(Out, MD->getParent(), " for ");976    } else {977      if (MD->getParent()->getIdentifier())978        Out << "'" << *MD->getParent() << "::" << *MD << "'";979      else980        Out << "'" << *MD << "'";981    }982 983    return true;984  }985 986  Out << Prefix << '\'' << cast<NamedDecl>(*D);987 988  // Adding template parameters.989  if (const auto FD = dyn_cast<FunctionDecl>(D))990    if (const TemplateArgumentList *TAList =991                                    FD->getTemplateSpecializationArgs())992      describeTemplateParameters(Out, TAList->asArray(), FD->getLangOpts(), "<",993                                 ">");994 995  Out << '\'';996  return true;997}998 999std::shared_ptr<PathDiagnosticEventPiece>1000PathDiagnosticCallPiece::getCallEnterEvent() const {1001  // We do not produce call enters and call exits for autosynthesized property1002  // accessors. We do generally produce them for other functions coming from1003  // the body farm because they may call callbacks that bring us back into1004  // visible code.1005  if (!Callee || IsCalleeAnAutosynthesizedPropertyAccessor)1006    return nullptr;1007 1008  SmallString<256> buf;1009  llvm::raw_svector_ostream Out(buf);1010 1011  Out << "Calling ";1012  describeCodeDecl(Out, Callee, /*ExtendedDescription=*/true);1013 1014  assert(callEnter.asLocation().isValid());1015  return std::make_shared<PathDiagnosticEventPiece>(callEnter, Out.str());1016}1017 1018std::shared_ptr<PathDiagnosticEventPiece>1019PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {1020  if (!callEnterWithin.asLocation().isValid())1021    return nullptr;1022  if (Callee->isImplicit() || !Callee->hasBody())1023    return nullptr;1024  if (const auto *MD = dyn_cast<CXXMethodDecl>(Callee))1025    if (MD->isDefaulted())1026      return nullptr;1027 1028  SmallString<256> buf;1029  llvm::raw_svector_ostream Out(buf);1030 1031  Out << "Entered call";1032  describeCodeDecl(Out, Caller, /*ExtendedDescription=*/false, " from ");1033 1034  return std::make_shared<PathDiagnosticEventPiece>(callEnterWithin, Out.str());1035}1036 1037std::shared_ptr<PathDiagnosticEventPiece>1038PathDiagnosticCallPiece::getCallExitEvent() const {1039  // We do not produce call enters and call exits for autosynthesized property1040  // accessors. We do generally produce them for other functions coming from1041  // the body farm because they may call callbacks that bring us back into1042  // visible code.1043  if (NoExit || IsCalleeAnAutosynthesizedPropertyAccessor)1044    return nullptr;1045 1046  SmallString<256> buf;1047  llvm::raw_svector_ostream Out(buf);1048 1049  if (!CallStackMessage.empty()) {1050    Out << CallStackMessage;1051  } else {1052    bool DidDescribe = describeCodeDecl(Out, Callee,1053                                        /*ExtendedDescription=*/false,1054                                        "Returning from ");1055    if (!DidDescribe)1056      Out << "Returning to caller";1057  }1058 1059  assert(callReturn.asLocation().isValid());1060  return std::make_shared<PathDiagnosticEventPiece>(callReturn, Out.str());1061}1062 1063static void compute_path_size(const PathPieces &pieces, unsigned &size) {1064  for (const auto &I : pieces) {1065    const PathDiagnosticPiece *piece = I.get();1066    if (const auto *cp = dyn_cast<PathDiagnosticCallPiece>(piece))1067      compute_path_size(cp->path, size);1068    else1069      ++size;1070  }1071}1072 1073unsigned PathDiagnostic::full_size() {1074  unsigned size = 0;1075  compute_path_size(path, size);1076  return size;1077}1078 1079SmallString<32>1080PathDiagnostic::getIssueHash(const SourceManager &SrcMgr,1081                             const LangOptions &LangOpts) const {1082  PathDiagnosticLocation UPDLoc = getUniqueingLoc();1083  FullSourceLoc FullLoc(1084      SrcMgr.getExpansionLoc(UPDLoc.isValid() ? UPDLoc.asLocation()1085                                              : getLocation().asLocation()),1086      SrcMgr);1087 1088  return clang::getIssueHash(FullLoc, getCheckerName(), getBugType(),1089                             getDeclWithIssue(), LangOpts);1090}1091 1092//===----------------------------------------------------------------------===//1093// FoldingSet profiling methods.1094//===----------------------------------------------------------------------===//1095 1096void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {1097  ID.Add(Range.getBegin());1098  ID.Add(Range.getEnd());1099  ID.Add(static_cast<const SourceLocation &>(Loc));1100}1101 1102void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {1103  ID.AddInteger((unsigned) getKind());1104  ID.AddString(str);1105  // FIXME: Add profiling support for code hints.1106  ID.AddInteger((unsigned) getDisplayHint());1107  ArrayRef<SourceRange> Ranges = getRanges();1108  for (const auto &I : Ranges) {1109    ID.Add(I.getBegin());1110    ID.Add(I.getEnd());1111  }1112}1113 1114void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const {1115  PathDiagnosticPiece::Profile(ID);1116  for (const auto &I : path)1117    ID.Add(*I);1118}1119 1120void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {1121  PathDiagnosticPiece::Profile(ID);1122  ID.Add(Pos);1123}1124 1125void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {1126  PathDiagnosticPiece::Profile(ID);1127  for (const auto &I : *this)1128    ID.Add(I);1129}1130 1131void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {1132  PathDiagnosticSpotPiece::Profile(ID);1133  for (const auto &I : subPieces)1134    ID.Add(*I);1135}1136 1137void PathDiagnosticNotePiece::Profile(llvm::FoldingSetNodeID &ID) const {1138  PathDiagnosticSpotPiece::Profile(ID);1139}1140 1141void PathDiagnosticPopUpPiece::Profile(llvm::FoldingSetNodeID &ID) const {1142  PathDiagnosticSpotPiece::Profile(ID);1143}1144 1145void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {1146  ID.Add(getLocation());1147  ID.Add(getUniqueingLoc());1148  ID.AddString(BugType);1149  ID.AddString(VerboseDesc);1150  ID.AddString(Category);1151}1152 1153void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const {1154  Profile(ID);1155  for (const auto &I : path)1156    ID.Add(*I);1157  for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)1158    ID.AddString(*I);1159}1160 1161LLVM_DUMP_METHOD void PathPieces::dump() const {1162  unsigned index = 0;1163  for (const PathDiagnosticPieceRef &Piece : *this) {1164    llvm::errs() << "[" << index++ << "]  ";1165    Piece->dump();1166    llvm::errs() << "\n";1167  }1168}1169 1170LLVM_DUMP_METHOD void PathDiagnosticCallPiece::dump() const {1171  llvm::errs() << "CALL\n--------------\n";1172 1173  if (const Stmt *SLoc = getLocation().getStmtOrNull())1174    SLoc->dump();1175  else if (const auto *ND = dyn_cast_or_null<NamedDecl>(getCallee()))1176    llvm::errs() << *ND << "\n";1177  else1178    getLocation().dump();1179}1180 1181LLVM_DUMP_METHOD void PathDiagnosticEventPiece::dump() const {1182  llvm::errs() << "EVENT\n--------------\n";1183  llvm::errs() << getString() << "\n";1184  llvm::errs() << " ---- at ----\n";1185  getLocation().dump();1186}1187 1188LLVM_DUMP_METHOD void PathDiagnosticControlFlowPiece::dump() const {1189  llvm::errs() << "CONTROL\n--------------\n";1190  getStartLocation().dump();1191  llvm::errs() << " ---- to ----\n";1192  getEndLocation().dump();1193}1194 1195LLVM_DUMP_METHOD void PathDiagnosticMacroPiece::dump() const {1196  llvm::errs() << "MACRO\n--------------\n";1197  // FIXME: Print which macro is being invoked.1198}1199 1200LLVM_DUMP_METHOD void PathDiagnosticNotePiece::dump() const {1201  llvm::errs() << "NOTE\n--------------\n";1202  llvm::errs() << getString() << "\n";1203  llvm::errs() << " ---- at ----\n";1204  getLocation().dump();1205}1206 1207LLVM_DUMP_METHOD void PathDiagnosticPopUpPiece::dump() const {1208  llvm::errs() << "POP-UP\n--------------\n";1209  llvm::errs() << getString() << "\n";1210  llvm::errs() << " ---- at ----\n";1211  getLocation().dump();1212}1213 1214LLVM_DUMP_METHOD void PathDiagnosticLocation::dump() const {1215  if (!isValid()) {1216    llvm::errs() << "<INVALID>\n";1217    return;1218  }1219 1220  switch (K) {1221  case RangeK:1222    // FIXME: actually print the range.1223    llvm::errs() << "<range>\n";1224    break;1225  case SingleLocK:1226    asLocation().dump();1227    llvm::errs() << "\n";1228    break;1229  case StmtK:1230    if (S)1231      S->dump();1232    else1233      llvm::errs() << "<NULL STMT>\n";1234    break;1235  case DeclK:1236    if (const auto *ND = dyn_cast_or_null<NamedDecl>(D))1237      llvm::errs() << *ND << "\n";1238    else if (isa<BlockDecl>(D))1239      // FIXME: Make this nicer.1240      llvm::errs() << "<block>\n";1241    else if (D)1242      llvm::errs() << "<unknown decl>\n";1243    else1244      llvm::errs() << "<NULL DECL>\n";1245    break;1246  }1247}1248