Home | History | Annotate | Line # | Download | only in Analysis
      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-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 //
      9 //  This file defines the interface ProgramPoint, which identifies a
     10 //  distinct location in a function.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "clang/Analysis/ProgramPoint.h"
     15 #include "clang/AST/ASTContext.h"
     16 #include "clang/Basic/JsonSupport.h"
     17 
     18 using namespace clang;
     19 
     20 ProgramPointTag::~ProgramPointTag() {}
     21 
     22 ProgramPoint ProgramPoint::getProgramPoint(const Stmt *S, ProgramPoint::Kind K,
     23                                            const LocationContext *LC,
     24                                            const ProgramPointTag *tag){
     25   switch (K) {
     26     default:
     27       llvm_unreachable("Unhandled ProgramPoint kind");
     28     case ProgramPoint::PreStmtKind:
     29       return PreStmt(S, LC, tag);
     30     case ProgramPoint::PostStmtKind:
     31       return PostStmt(S, LC, tag);
     32     case ProgramPoint::PreLoadKind:
     33       return PreLoad(S, LC, tag);
     34     case ProgramPoint::PostLoadKind:
     35       return PostLoad(S, LC, tag);
     36     case ProgramPoint::PreStoreKind:
     37       return PreStore(S, LC, tag);
     38     case ProgramPoint::PostLValueKind:
     39       return PostLValue(S, LC, tag);
     40     case ProgramPoint::PostStmtPurgeDeadSymbolsKind:
     41       return PostStmtPurgeDeadSymbols(S, LC, tag);
     42     case ProgramPoint::PreStmtPurgeDeadSymbolsKind:
     43       return PreStmtPurgeDeadSymbols(S, LC, tag);
     44   }
     45 }
     46 
     47 LLVM_DUMP_METHOD void ProgramPoint::dump() const {
     48   return printJson(llvm::errs());
     49 }
     50 
     51 void ProgramPoint::printJson(llvm::raw_ostream &Out, const char *NL) const {
     52   const ASTContext &Context =
     53       getLocationContext()->getAnalysisDeclContext()->getASTContext();
     54   const SourceManager &SM = Context.getSourceManager();
     55   const PrintingPolicy &PP = Context.getPrintingPolicy();
     56   const bool AddQuotes = true;
     57 
     58   Out << "\"kind\": \"";
     59   switch (getKind()) {
     60   case ProgramPoint::BlockEntranceKind:
     61     Out << "BlockEntrance\""
     62         << ", \"block_id\": "
     63         << castAs<BlockEntrance>().getBlock()->getBlockID();
     64     break;
     65 
     66   case ProgramPoint::FunctionExitKind: {
     67     auto FEP = getAs<FunctionExitPoint>();
     68     Out << "FunctionExit\""
     69         << ", \"block_id\": " << FEP->getBlock()->getBlockID()
     70         << ", \"stmt_id\": ";
     71 
     72     if (const ReturnStmt *RS = FEP->getStmt()) {
     73       Out << RS->getID(Context) << ", \"stmt\": ";
     74       RS->printJson(Out, nullptr, PP, AddQuotes);
     75     } else {
     76       Out << "null, \"stmt\": null";
     77     }
     78     break;
     79   }
     80   case ProgramPoint::BlockExitKind:
     81     llvm_unreachable("BlockExitKind");
     82     break;
     83   case ProgramPoint::CallEnterKind:
     84     Out << "CallEnter\"";
     85     break;
     86   case ProgramPoint::CallExitBeginKind:
     87     Out << "CallExitBegin\"";
     88     break;
     89   case ProgramPoint::CallExitEndKind:
     90     Out << "CallExitEnd\"";
     91     break;
     92   case ProgramPoint::EpsilonKind:
     93     Out << "EpsilonPoint\"";
     94     break;
     95 
     96   case ProgramPoint::LoopExitKind:
     97     Out << "LoopExit\", \"stmt\": \""
     98         << castAs<LoopExit>().getLoopStmt()->getStmtClassName() << '\"';
     99     break;
    100 
    101   case ProgramPoint::PreImplicitCallKind: {
    102     ImplicitCallPoint PC = castAs<ImplicitCallPoint>();
    103     Out << "PreCall\", \"decl\": \""
    104         << PC.getDecl()->getAsFunction()->getQualifiedNameAsString()
    105         << "\", \"location\": ";
    106     printSourceLocationAsJson(Out, PC.getLocation(), SM);
    107     break;
    108   }
    109 
    110   case ProgramPoint::PostImplicitCallKind: {
    111     ImplicitCallPoint PC = castAs<ImplicitCallPoint>();
    112     Out << "PostCall\", \"decl\": \""
    113         << PC.getDecl()->getAsFunction()->getQualifiedNameAsString()
    114         << "\", \"location\": ";
    115     printSourceLocationAsJson(Out, PC.getLocation(), SM);
    116     break;
    117   }
    118 
    119   case ProgramPoint::PostInitializerKind: {
    120     Out << "PostInitializer\", ";
    121     const CXXCtorInitializer *Init = castAs<PostInitializer>().getInitializer();
    122     if (const FieldDecl *FD = Init->getAnyMember()) {
    123       Out << "\"field_decl\": \"" << *FD << '\"';
    124     } else {
    125       Out << "\"type\": \"";
    126       QualType Ty = Init->getTypeSourceInfo()->getType();
    127       Ty = Ty.getLocalUnqualifiedType();
    128       Ty.print(Out, Context.getLangOpts());
    129       Out << '\"';
    130     }
    131     break;
    132   }
    133 
    134   case ProgramPoint::BlockEdgeKind: {
    135     const BlockEdge &E = castAs<BlockEdge>();
    136     const Stmt *T = E.getSrc()->getTerminatorStmt();
    137     Out << "Edge\", \"src_id\": " << E.getSrc()->getBlockID()
    138         << ", \"dst_id\": " << E.getDst()->getBlockID() << ", \"terminator\": ";
    139 
    140     if (!T) {
    141       Out << "null, \"term_kind\": null";
    142       break;
    143     }
    144 
    145     E.getSrc()->printTerminatorJson(Out, Context.getLangOpts(),
    146                                     /*AddQuotes=*/true);
    147     Out << ", \"location\": ";
    148     printSourceLocationAsJson(Out, T->getBeginLoc(), SM);
    149 
    150     Out << ", \"term_kind\": \"";
    151     if (isa<SwitchStmt>(T)) {
    152       Out << "SwitchStmt\", \"case\": ";
    153       if (const Stmt *Label = E.getDst()->getLabel()) {
    154         if (const auto *C = dyn_cast<CaseStmt>(Label)) {
    155           Out << "{ \"lhs\": ";
    156           if (const Stmt *LHS = C->getLHS()) {
    157             LHS->printJson(Out, nullptr, PP, AddQuotes);
    158           } else {
    159             Out << "null";
    160 	  }
    161 
    162           Out << ", \"rhs\": ";
    163           if (const Stmt *RHS = C->getRHS()) {
    164             RHS->printJson(Out, nullptr, PP, AddQuotes);
    165           } else {
    166             Out << "null";
    167           }
    168           Out << " }";
    169         } else {
    170           assert(isa<DefaultStmt>(Label));
    171           Out << "\"default\"";
    172         }
    173       } else {
    174         Out << "\"implicit default\"";
    175       }
    176     } else if (isa<IndirectGotoStmt>(T)) {
    177       // FIXME: More info.
    178       Out << "IndirectGotoStmt\"";
    179     } else {
    180       Out << "Condition\", \"value\": "
    181           << (*E.getSrc()->succ_begin() == E.getDst() ? "true" : "false");
    182     }
    183     break;
    184   }
    185 
    186   default: {
    187     const Stmt *S = castAs<StmtPoint>().getStmt();
    188     assert(S != nullptr && "Expecting non-null Stmt");
    189 
    190     Out << "Statement\", \"stmt_kind\": \"" << S->getStmtClassName()
    191         << "\", \"stmt_id\": " << S->getID(Context)
    192         << ", \"pointer\": \"" << (const void *)S << "\", ";
    193     if (const auto *CS = dyn_cast<CastExpr>(S))
    194       Out << "\"cast_kind\": \"" << CS->getCastKindName() << "\", ";
    195 
    196     Out << "\"pretty\": ";
    197 
    198     S->printJson(Out, nullptr, PP, AddQuotes);
    199 
    200     Out << ", \"location\": ";
    201     printSourceLocationAsJson(Out, S->getBeginLoc(), SM);
    202 
    203     Out << ", \"stmt_point_kind\": \"";
    204     if (getAs<PreLoad>())
    205       Out << "PreLoad";
    206     else if (getAs<PreStore>())
    207       Out << "PreStore";
    208     else if (getAs<PostAllocatorCall>())
    209       Out << "PostAllocatorCall";
    210     else if (getAs<PostCondition>())
    211       Out << "PostCondition";
    212     else if (getAs<PostLoad>())
    213       Out << "PostLoad";
    214     else if (getAs<PostLValue>())
    215       Out << "PostLValue";
    216     else if (getAs<PostStore>())
    217       Out << "PostStore";
    218     else if (getAs<PostStmt>())
    219       Out << "PostStmt";
    220     else if (getAs<PostStmtPurgeDeadSymbols>())
    221       Out << "PostStmtPurgeDeadSymbols";
    222     else if (getAs<PreStmtPurgeDeadSymbols>())
    223       Out << "PreStmtPurgeDeadSymbols";
    224     else if (getAs<PreStmt>())
    225       Out << "PreStmt";
    226     else {
    227       Out << "\nKind: '" << getKind();
    228       llvm_unreachable("' is unhandled StmtPoint kind!");
    229     }
    230 
    231     Out << '\"';
    232     break;
    233   }
    234   }
    235 }
    236 
    237 SimpleProgramPointTag::SimpleProgramPointTag(StringRef MsgProvider,
    238                                              StringRef Msg)
    239   : Desc((MsgProvider + " : " + Msg).str()) {}
    240 
    241 StringRef SimpleProgramPointTag::getTagDescription() const {
    242   return Desc;
    243 }
    244