brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.1 KiB · 9e1205c Raw
361 lines · cpp
1//==- ProgramPoint.cpp - Program Points for Path-Sensitive Analysis -*- C++ -*-/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 interface ProgramPoint, which identifies a10//  distinct location in a function.11//12//===----------------------------------------------------------------------===//13 14#include "clang/Analysis/ProgramPoint.h"15#include "clang/AST/ASTContext.h"16#include "clang/Analysis/AnalysisDeclContext.h"17#include "clang/Basic/JsonSupport.h"18 19using namespace clang;20 21ProgramPointTag::~ProgramPointTag() {}22 23ProgramPoint ProgramPoint::getProgramPoint(const Stmt *S, ProgramPoint::Kind K,24                                           const LocationContext *LC,25                                           const ProgramPointTag *tag){26  switch (K) {27    default:28      llvm_unreachable("Unhandled ProgramPoint kind");29    case ProgramPoint::PreStmtKind:30      return PreStmt(S, LC, tag);31    case ProgramPoint::PostStmtKind:32      return PostStmt(S, LC, tag);33    case ProgramPoint::PreLoadKind:34      return PreLoad(S, LC, tag);35    case ProgramPoint::PostLoadKind:36      return PostLoad(S, LC, tag);37    case ProgramPoint::PreStoreKind:38      return PreStore(S, LC, tag);39    case ProgramPoint::PostLValueKind:40      return PostLValue(S, LC, tag);41    case ProgramPoint::PostStmtPurgeDeadSymbolsKind:42      return PostStmtPurgeDeadSymbols(S, LC, tag);43    case ProgramPoint::PreStmtPurgeDeadSymbolsKind:44      return PreStmtPurgeDeadSymbols(S, LC, tag);45  }46}47 48LLVM_DUMP_METHOD void ProgramPoint::dump() const {49  return printJson(llvm::errs());50}51 52StringRef ProgramPoint::getProgramPointKindName(Kind K) {53  switch (K) {54  case BlockEdgeKind:55    return "BlockEdge";56  case BlockEntranceKind:57    return "BlockEntrance";58  case BlockExitKind:59    return "BlockExit";60  case PreStmtKind:61    return "PreStmt";62  case PreStmtPurgeDeadSymbolsKind:63    return "PreStmtPurgeDeadSymbols";64  case PostStmtPurgeDeadSymbolsKind:65    return "PostStmtPurgeDeadSymbols";66  case PostStmtKind:67    return "PostStmt";68  case PreLoadKind:69    return "PreLoad";70  case PostLoadKind:71    return "PostLoad";72  case PreStoreKind:73    return "PreStore";74  case PostStoreKind:75    return "PostStore";76  case PostConditionKind:77    return "PostCondition";78  case PostLValueKind:79    return "PostLValue";80  case PostAllocatorCallKind:81    return "PostAllocatorCall";82  case PostInitializerKind:83    return "PostInitializer";84  case CallEnterKind:85    return "CallEnter";86  case CallExitBeginKind:87    return "CallExitBegin";88  case CallExitEndKind:89    return "CallExitEnd";90  case FunctionExitKind:91    return "FunctionExit";92  case PreImplicitCallKind:93    return "PreImplicitCall";94  case PostImplicitCallKind:95    return "PostImplicitCall";96  case LoopExitKind:97    return "LoopExit";98  case EpsilonKind:99    return "Epsilon";100  }101  llvm_unreachable("Unknown ProgramPoint kind");102}103 104std::optional<SourceLocation> ProgramPoint::getSourceLocation() const {105  switch (getKind()) {106  case BlockEdgeKind:107    // If needed, the source and or destination beginning can be used to get108    // source location.109    return std::nullopt;110  case BlockEntranceKind:111    // If needed, first statement of the block can be used.112    return std::nullopt;113  case BlockExitKind:114    if (const auto *B = castAs<BlockExit>().getBlock()) {115      if (const auto *T = B->getTerminatorStmt()) {116        return T->getBeginLoc();117      }118    }119    return std::nullopt;120  case PreStmtKind:121  case PreStmtPurgeDeadSymbolsKind:122  case PostStmtPurgeDeadSymbolsKind:123  case PostStmtKind:124  case PreLoadKind:125  case PostLoadKind:126  case PreStoreKind:127  case PostStoreKind:128  case PostConditionKind:129  case PostLValueKind:130  case PostAllocatorCallKind:131    if (const Stmt *S = castAs<StmtPoint>().getStmt())132      return S->getBeginLoc();133    return std::nullopt;134  case PostInitializerKind:135    if (const auto *Init = castAs<PostInitializer>().getInitializer())136      return Init->getSourceLocation();137    return std::nullopt;138  case CallEnterKind:139    if (const Stmt *S = castAs<CallEnter>().getCallExpr())140      return S->getBeginLoc();141    return std::nullopt;142  case CallExitBeginKind:143    if (const Stmt *S = castAs<CallExitBegin>().getReturnStmt())144      return S->getBeginLoc();145    return std::nullopt;146  case CallExitEndKind:147    return std::nullopt;148  case FunctionExitKind:149    if (const auto *B = castAs<FunctionExitPoint>().getBlock();150        B && B->getTerminatorStmt())151      return B->getTerminatorStmt()->getBeginLoc();152    return std::nullopt;153  case PreImplicitCallKind:154    return castAs<ImplicitCallPoint>().getLocation();155  case PostImplicitCallKind:156    return castAs<ImplicitCallPoint>().getLocation();157  case LoopExitKind:158    if (const Stmt *S = castAs<LoopExit>().getLoopStmt())159      return S->getBeginLoc();160    return std::nullopt;161  case EpsilonKind:162    return std::nullopt;163  }164  llvm_unreachable("Unknown ProgramPoint kind");165}166 167void ProgramPoint::printJson(llvm::raw_ostream &Out, const char *NL) const {168  const ASTContext &Context =169      getLocationContext()->getAnalysisDeclContext()->getASTContext();170  const SourceManager &SM = Context.getSourceManager();171  const PrintingPolicy &PP = Context.getPrintingPolicy();172  const bool AddQuotes = true;173 174  Out << "\"kind\": \"";175  switch (getKind()) {176  case ProgramPoint::BlockEntranceKind:177    Out << "BlockEntrance\""178        << ", \"block_id\": "179        << castAs<BlockEntrance>().getBlock()->getBlockID();180    break;181 182  case ProgramPoint::FunctionExitKind: {183    auto FEP = getAs<FunctionExitPoint>();184    Out << "FunctionExit\""185        << ", \"block_id\": " << FEP->getBlock()->getBlockID()186        << ", \"stmt_id\": ";187 188    if (const ReturnStmt *RS = FEP->getStmt()) {189      Out << RS->getID(Context) << ", \"stmt\": ";190      RS->printJson(Out, nullptr, PP, AddQuotes);191    } else {192      Out << "null, \"stmt\": null";193    }194    break;195  }196  case ProgramPoint::BlockExitKind:197    llvm_unreachable("BlockExitKind");198    break;199  case ProgramPoint::CallEnterKind:200    Out << "CallEnter\", \"callee_decl\": \"";201    Out << AnalysisDeclContext::getFunctionName(202               castAs<CallEnter>().getCalleeContext()->getDecl())203        << '\"';204    break;205  case ProgramPoint::CallExitBeginKind:206    Out << "CallExitBegin\"";207    break;208  case ProgramPoint::CallExitEndKind:209    Out << "CallExitEnd\"";210    break;211  case ProgramPoint::EpsilonKind:212    Out << "EpsilonPoint\"";213    break;214 215  case ProgramPoint::LoopExitKind:216    Out << "LoopExit\", \"stmt\": \""217        << castAs<LoopExit>().getLoopStmt()->getStmtClassName() << '\"';218    break;219 220  case ProgramPoint::PreImplicitCallKind: {221    ImplicitCallPoint PC = castAs<ImplicitCallPoint>();222    Out << "PreCall\", \"decl\": \""223        << PC.getDecl()->getAsFunction()->getQualifiedNameAsString()224        << "\", \"location\": ";225    printSourceLocationAsJson(Out, PC.getLocation(), SM);226    break;227  }228 229  case ProgramPoint::PostImplicitCallKind: {230    ImplicitCallPoint PC = castAs<ImplicitCallPoint>();231    Out << "PostCall\", \"decl\": \""232        << PC.getDecl()->getAsFunction()->getQualifiedNameAsString()233        << "\", \"location\": ";234    printSourceLocationAsJson(Out, PC.getLocation(), SM);235    break;236  }237 238  case ProgramPoint::PostInitializerKind: {239    Out << "PostInitializer\", ";240    const CXXCtorInitializer *Init = castAs<PostInitializer>().getInitializer();241    if (const FieldDecl *FD = Init->getAnyMember()) {242      Out << "\"field_decl\": \"" << *FD << '\"';243    } else {244      Out << "\"type\": \"";245      QualType Ty = Init->getTypeSourceInfo()->getType();246      Ty = Ty.getLocalUnqualifiedType();247      Ty.print(Out, Context.getLangOpts());248      Out << '\"';249    }250    break;251  }252 253  case ProgramPoint::BlockEdgeKind: {254    const BlockEdge &E = castAs<BlockEdge>();255    const Stmt *T = E.getSrc()->getTerminatorStmt();256    Out << "Edge\", \"src_id\": " << E.getSrc()->getBlockID()257        << ", \"dst_id\": " << E.getDst()->getBlockID() << ", \"terminator\": ";258 259    if (!T) {260      Out << "null, \"term_kind\": null";261      break;262    }263 264    E.getSrc()->printTerminatorJson(Out, Context.getLangOpts(),265                                    /*AddQuotes=*/true);266    Out << ", \"location\": ";267    printSourceLocationAsJson(Out, T->getBeginLoc(), SM);268 269    Out << ", \"term_kind\": \"";270    if (isa<SwitchStmt>(T)) {271      Out << "SwitchStmt\", \"case\": ";272      if (const Stmt *Label = E.getDst()->getLabel()) {273        if (const auto *C = dyn_cast<CaseStmt>(Label)) {274          Out << "{ \"lhs\": ";275          if (const Stmt *LHS = C->getLHS()) {276            LHS->printJson(Out, nullptr, PP, AddQuotes);277          } else {278            Out << "null";279          }280 281          Out << ", \"rhs\": ";282          if (const Stmt *RHS = C->getRHS()) {283            RHS->printJson(Out, nullptr, PP, AddQuotes);284          } else {285            Out << "null";286          }287          Out << " }";288        } else {289          assert(isa<DefaultStmt>(Label));290          Out << "\"default\"";291        }292      } else {293        Out << "\"implicit default\"";294      }295    } else if (isa<IndirectGotoStmt>(T)) {296      // FIXME: More info.297      Out << "IndirectGotoStmt\"";298    } else {299      Out << "Condition\", \"value\": "300          << (*E.getSrc()->succ_begin() == E.getDst() ? "true" : "false");301    }302    break;303  }304 305  default: {306    const Stmt *S = castAs<StmtPoint>().getStmt();307    assert(S != nullptr && "Expecting non-null Stmt");308 309    Out << "Statement\", \"stmt_kind\": \"" << S->getStmtClassName()310        << "\", \"stmt_id\": " << S->getID(Context)311        << ", \"pointer\": \"" << (const void *)S << "\", ";312    if (const auto *CS = dyn_cast<CastExpr>(S))313      Out << "\"cast_kind\": \"" << CS->getCastKindName() << "\", ";314 315    Out << "\"pretty\": ";316 317    S->printJson(Out, nullptr, PP, AddQuotes);318 319    Out << ", \"location\": ";320    printSourceLocationAsJson(Out, S->getBeginLoc(), SM);321 322    Out << ", \"stmt_point_kind\": \"";323    if (getAs<PreLoad>())324      Out << "PreLoad";325    else if (getAs<PreStore>())326      Out << "PreStore";327    else if (getAs<PostAllocatorCall>())328      Out << "PostAllocatorCall";329    else if (getAs<PostCondition>())330      Out << "PostCondition";331    else if (getAs<PostLoad>())332      Out << "PostLoad";333    else if (getAs<PostLValue>())334      Out << "PostLValue";335    else if (getAs<PostStore>())336      Out << "PostStore";337    else if (getAs<PostStmt>())338      Out << "PostStmt";339    else if (getAs<PostStmtPurgeDeadSymbols>())340      Out << "PostStmtPurgeDeadSymbols";341    else if (getAs<PreStmtPurgeDeadSymbols>())342      Out << "PreStmtPurgeDeadSymbols";343    else if (getAs<PreStmt>())344      Out << "PreStmt";345    else {346      Out << "\nKind: '" << getKind();347      llvm_unreachable("' is unhandled StmtPoint kind!");348    }349 350    Out << '\"';351    break;352  }353  }354}355 356SimpleProgramPointTag::SimpleProgramPointTag(StringRef MsgProvider,357                                             StringRef Msg)358  : Desc((MsgProvider + " : " + Msg).str()) {}359 360StringRef SimpleProgramPointTag::getDebugTag() const { return Desc; }361