Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-03-17 11:26:53

0001 #include <clang/AST/DeclCXX.h>
0002 #include <clang/AST/ExprCXX.h>
0003 #include <clang/AST/StmtCXX.h>
0004 #include <clang/AST/Decl.h>
0005 #include <clang/AST/DeclTemplate.h>
0006 #include <llvm/ADT/StringSwitch.h>
0007 #include <clang/AST/Decl.h>
0008 #include <clang/AST/Attr.h>
0009 #include <clang/AST/DeclTemplate.h>
0010 #include <clang/AST/DeclCXX.h>
0011 #include <clang/AST/StmtVisitor.h>
0012 #include <clang/AST/ParentMap.h>
0013 #include <clang/Analysis/CFGStmtMap.h>
0014 #include <clang/StaticAnalyzer/Core/Checker.h>
0015 #include <clang/StaticAnalyzer/Core/BugReporter/BugReporter.h>
0016 #include <clang/StaticAnalyzer/Core/BugReporter/BugType.h>
0017 #include <clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h>
0018 #include <llvm/Support/SaveAndRestore.h>
0019 #include <llvm/ADT/SmallString.h>
0020 #include <iostream>
0021 #include <fstream>
0022 #include <iterator>
0023 #include <string>
0024 #include <algorithm>
0025 
0026 #include "CmsException.h"
0027 #include "CmsSupport.h"
0028 #include "getParamDumper.h"
0029 
0030 using namespace clang;
0031 using namespace ento;
0032 using namespace llvm;
0033 
0034 namespace clangcms {
0035 
0036   void getParamDumper::analyzerEval(const clang::CallExpr *CE, clang::ento::CheckerContext &C) const {
0037     if (!C.getSourceManager().isInMainFile(CE->getExprLoc()))
0038       return;
0039 
0040     const FunctionDecl *FD = CE->getDirectCallee();
0041 
0042     if (!FD)
0043       return;
0044 
0045     std::string mname = support::getQualifiedName(*FD);
0046     const char *sfile = C.getSourceManager().getPresumedLoc(CE->getExprLoc()).getFilename();
0047     std::string sname(sfile);
0048     if (!support::isInterestingLocation(sname))
0049       return;
0050     std::string mdname;
0051     const FunctionDecl *MD = C.getCurrentAnalysisDeclContext()->getDecl()->getAsFunction();
0052     if (!MD)
0053       return;
0054     mdname = MD->getQualifiedNameAsString();
0055     for (unsigned I = 0, E = MD->getNumParams(); I != E; ++I) {
0056       std::string ps = "const class edm::ParameterSet ";
0057       std::string ups = "const class edm::UntrackedParameterSet ";
0058       std::string pname = MD->getParamDecl(I)->getQualifiedNameAsString();
0059       std::string qname = MD->getParamDecl(I)->getType().getCanonicalType().getAsString();
0060       //             if (qname.substr(0,ps.length()) == ps || qname.substr(0,ups.length()) == ups) {
0061       std::string buf;
0062       llvm::raw_string_ostream os(buf);
0063       os << "in function decl '" << mdname << "' with parameter '" << qname << " " << pname << "'\n";
0064       //                 }
0065     }
0066     const CXXMemberCallExpr *CXE = llvm::dyn_cast_or_null<CXXMemberCallExpr>(CE);
0067     if (!CXE)
0068       return;
0069     const Expr *IOA = CXE->getImplicitObjectArgument();
0070     std::string tname = "getparam-dumper.txt.unsorted";
0071     std::string gp = "edm::ParameterSet::getParameter";
0072     std::string gup = "edm::ParameterSet::getUntrackedParameter";
0073     if (mname.substr(0, gp.length()) == gp || mname.substr(0, gup.length()) == gup) {
0074       std::string buf;
0075       llvm::raw_string_ostream os(buf);
0076       os << "in function decl '" << mdname << "' member function call '";
0077       clang::LangOptions LangOpts;
0078       LangOpts.CPlusPlus = true;
0079       clang::PrintingPolicy Policy(LangOpts);
0080       os << support::getQualifiedName(*(CXE->getMethodDecl()));
0081       os << "' with args '";
0082       for (unsigned I = 0, E = CE->getNumArgs(); I != E; ++I) {
0083         if (I)
0084           os << ", ";
0085         CE->getArg(I)->printPretty(os, nullptr, Policy);
0086       }
0087       os << "' with implicit object '";
0088       const Expr *E = IOA->IgnoreParenNoopCasts(C.getASTContext());
0089       QualType QE = E->getType().getCanonicalType();
0090       os << QE.getAsString() << " ";
0091       switch (E->getStmtClass()) {
0092         case Stmt::MemberExprClass:
0093           os << dyn_cast<MemberExpr>(E)->getMemberDecl()->getQualifiedNameAsString();
0094           break;
0095         case Stmt::DeclRefExprClass:
0096           os << dyn_cast<DeclRefExpr>(E)->getDecl()->getQualifiedNameAsString();
0097           break;
0098         case Stmt::CXXOperatorCallExprClass:
0099           dyn_cast<CXXOperatorCallExpr>(E)->printPretty(os, nullptr, Policy);
0100           break;
0101         case Stmt::CXXBindTemporaryExprClass:
0102           dyn_cast<CXXBindTemporaryExpr>(E)->printPretty(os, nullptr, Policy);
0103           break;
0104         case Stmt::CXXMemberCallExprClass:
0105           dyn_cast<CXXMemberCallExpr>(E)->printPretty(os, nullptr, Policy);
0106           break;
0107         case Stmt::UnaryOperatorClass:
0108           dyn_cast<UnaryOperator>(E)->printPretty(os, nullptr, Policy);
0109           break;
0110         default:
0111           E->printPretty(os, nullptr, Policy);
0112           os << " unhandled expr class " << E->getStmtClassName();
0113       }
0114       os << "'\n";
0115 
0116       support::writeLog(os.str(), tname);
0117     }
0118     return;
0119   }
0120 
0121   bool getParamDumper::evalCall(const CallEvent &Call, CheckerContext &C) const {
0122     const auto *CE = llvm::dyn_cast_or_null<clang::CallExpr>(Call.getOriginExpr());
0123     if (!CE)
0124       return false;
0125 
0126     FnCheck Handler = llvm::StringSwitch<FnCheck>(C.getCalleeName(CE))
0127                           .Case("getParameter", &getParamDumper::analyzerEval)
0128                           .Case("getUntrackedParameter", &getParamDumper::analyzerEval)
0129                           .Default(nullptr);
0130 
0131     if (!Handler)
0132       return false;
0133 
0134     (this->*Handler)(CE, C);
0135 
0136     return true;
0137   }
0138 
0139   class gpWalkAST : public clang::StmtVisitor<gpWalkAST> {
0140     const CheckerBase *Checker;
0141     clang::ento::BugReporter &BR;
0142     clang::AnalysisDeclContext *AC;
0143     const NamedDecl *ND;
0144 
0145   public:
0146     gpWalkAST(const CheckerBase *checker,
0147               clang::ento::BugReporter &br,
0148               clang::AnalysisDeclContext *ac,
0149               const NamedDecl *nd)
0150         : Checker(checker), BR(br), AC(ac), ND(nd) {}
0151 
0152     // Stmt visitor methods.
0153     void VisitChildren(clang::Stmt *S);
0154     void VisitStmt(clang::Stmt *S) { VisitChildren(S); }
0155     void VisitCXXMemberCallExpr(clang::CXXMemberCallExpr *CE);
0156   };
0157 
0158   void gpWalkAST::VisitChildren(clang::Stmt *S) {
0159     for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I != E; ++I)
0160       if (clang::Stmt *child = *I) {
0161         Visit(child);
0162       }
0163   }
0164 
0165   void gpWalkAST::VisitCXXMemberCallExpr(clang::CXXMemberCallExpr *CE) {
0166     const FunctionDecl *FD = CE->getMethodDecl();
0167     if (!FD)
0168       return;
0169 
0170     std::string mname = FD->getQualifiedNameAsString();
0171     const char *sfile = BR.getSourceManager().getPresumedLoc(CE->getExprLoc()).getFilename();
0172     std::string sname(sfile);
0173     if (!support::isInterestingLocation(sname))
0174       return;
0175     std::string mdname = ND->getQualifiedNameAsString();
0176     const Expr *IOA = CE->getImplicitObjectArgument();
0177     std::string tname = "getparam-dumper.txt.unsorted";
0178     std::string ps = "const class edm::ParameterSet ";
0179     std::string ups = "const class edm::UntrackedParameterSet ";
0180     std::string gp = "edm::ParameterSet::getParameter";
0181     std::string gup = "edm::ParameterSet::getUntrackedParameter";
0182     if (mname.substr(0, gp.length()) == gp || mname.substr(0, gup.length()) == gup) {
0183       std::string buf;
0184       llvm::raw_string_ostream os(buf);
0185       const NamedDecl *nd = llvm::dyn_cast<NamedDecl>(AC->getDecl());
0186       if (FunctionDecl::classof(ND)) {
0187         os << "function decl '" << nd->getQualifiedNameAsString();
0188         os << "' this '" << mdname;
0189       } else {
0190         os << "constructor decl '" << nd->getQualifiedNameAsString();
0191         os << "' initializer for member decl '" << mdname;
0192       }
0193       clang::LangOptions LangOpts;
0194       LangOpts.CPlusPlus = true;
0195       clang::PrintingPolicy Policy(LangOpts);
0196       os << "' with call args '";
0197       for (unsigned I = 0, E = CE->getNumArgs(); I != E; ++I) {
0198         if (I)
0199           os << ", ";
0200         os << CE->getType().getCanonicalType().getAsString() << " ";
0201         CE->getArg(I)->printPretty(os, nullptr, Policy);
0202       }
0203       os << "' with implicit object '";
0204       const Expr *E = IOA->IgnoreParenCasts();
0205       QualType QE = E->getType().getCanonicalType();
0206       os << QE.getAsString() << " ";
0207       switch (E->getStmtClass()) {
0208         case Stmt::MemberExprClass:
0209           os << dyn_cast<MemberExpr>(E)->getMemberDecl()->getQualifiedNameAsString();
0210           break;
0211         case Stmt::DeclRefExprClass:
0212           os << dyn_cast<DeclRefExpr>(E)->getDecl()->getQualifiedNameAsString();
0213           break;
0214         case Stmt::CXXOperatorCallExprClass:
0215           dyn_cast<CXXOperatorCallExpr>(E)->printPretty(os, nullptr, Policy);
0216           break;
0217         case Stmt::CXXBindTemporaryExprClass:
0218           dyn_cast<CXXBindTemporaryExpr>(E)->printPretty(os, nullptr, Policy);
0219           break;
0220         case Stmt::CXXMemberCallExprClass:
0221           dyn_cast<CXXMemberCallExpr>(E)->printPretty(os, nullptr, Policy);
0222           break;
0223         case Stmt::UnaryOperatorClass:
0224           dyn_cast<UnaryOperator>(E)->printPretty(os, nullptr, Policy);
0225           break;
0226         default:
0227           E->printPretty(os, nullptr, Policy);
0228           os << " unhandled expr class " << E->getStmtClassName();
0229       }
0230       os << "'\n";
0231 
0232       support::writeLog(os.str(), tname);
0233     }
0234     return;
0235   }
0236 
0237   void getParamDumper::checkASTDecl(const clang::CXXRecordDecl *RD,
0238                                     clang::ento::AnalysisManager &mgr,
0239                                     clang::ento::BugReporter &BR) const {
0240     const clang::SourceManager &SM = BR.getSourceManager();
0241     const char *sfile = SM.getPresumedLoc(RD->getLocation()).getFilename();
0242     if (!support::isCmsLocalFile(sfile))
0243       return;
0244 
0245     std::string tname = "getparam-dumper.txt.unsorted";
0246     std::string ps = "const class edm::ParameterSet ";
0247     std::string ups = "const class edm::UntrackedParameterSet ";
0248 
0249     for (clang::CXXRecordDecl::ctor_iterator I = RD->ctor_begin(), E = RD->ctor_end(); I != E; ++I) {
0250       clang::CXXConstructorDecl *CD = llvm::dyn_cast<clang::CXXConstructorDecl>((*I)->getMostRecentDecl());
0251       for (unsigned I = 0, E = CD->getNumParams(); I != E; ++I) {
0252         std::string pname = CD->getParamDecl(I)->getQualifiedNameAsString();
0253         std::string qname = CD->getParamDecl(I)->getType().getCanonicalType().getAsString();
0254         if (qname.substr(0, ps.length()) == ps || qname.substr(0, ups.length()) == ups) {
0255           std::string buf;
0256           llvm::raw_string_ostream os(buf);
0257           os << "constructor decl '" << CD->getQualifiedNameAsString() << "' with parameter '" << qname << " " << pname
0258              << "'\n";
0259           support::writeLog(os.str(), tname);
0260           for (CXXConstructorDecl::init_iterator J = CD->init_begin(), E = CD->init_end(); J != E; ++J) {
0261             if (FieldDecl *fd = (*J)->getAnyMember()) {
0262               std::string fname = fd->getQualifiedNameAsString();
0263               std::string fqname = fd->getType().getCanonicalType().getAsString();
0264               os << "constructor decl '" << CD->getQualifiedNameAsString() << "' initializer for member decl '" << fname
0265                  << "' of type '" << fqname << "'\n";
0266               Expr *e = (*J)->getInit();
0267               if (e) {
0268                 gpWalkAST walker(this, BR, mgr.getAnalysisDeclContext(CD), fd);
0269                 walker.Visit(e);
0270               }
0271             }
0272           }
0273           support::writeLog(os.str(), tname);
0274         }
0275       }
0276     }
0277 
0278     for (clang::CXXRecordDecl::method_iterator I = RD->method_begin(), E = RD->method_end(); I != E; ++I) {
0279       clang::CXXMethodDecl *MD = llvm::cast<clang::CXXMethodDecl>((*I)->getMostRecentDecl());
0280       for (unsigned I = 0, E = MD->getNumParams(); I != E; ++I) {
0281         std::string pname = MD->getParamDecl(I)->getQualifiedNameAsString();
0282         std::string qname = MD->getParamDecl(I)->getType().getCanonicalType().getAsString();
0283         if (qname.substr(0, ps.length()) == ps || qname.substr(0, ups.length()) == ups) {
0284           std::string buf;
0285           llvm::raw_string_ostream os(buf);
0286           clang::Stmt *Body = MD->getBody();
0287           if (Body) {
0288             os << "function decl '" << MD->getQualifiedNameAsString() << "' with parameter '" << qname << " " << pname
0289                << "'\n";
0290             gpWalkAST walker(this, BR, mgr.getAnalysisDeclContext(MD), MD);
0291             walker.Visit(Body);
0292           }
0293           support::writeLog(os.str(), tname);
0294         }
0295       }
0296     }
0297 
0298     return;
0299   }
0300 
0301 }  // namespace clangcms