File indexing completed on 2023-03-17 11:26:52
0001 #include <clang/AST/DeclCXX.h>
0002 #include <clang/AST/ExprCXX.h>
0003 #include <clang/AST/Decl.h>
0004 #include <clang/AST/DeclTemplate.h>
0005 #include <clang/AST/StmtVisitor.h>
0006 #include <clang/AST/ParentMap.h>
0007 #include <clang/Analysis/CFGStmtMap.h>
0008 #include <clang/Analysis/CallGraph.h>
0009 #include <llvm/Support/SaveAndRestore.h>
0010 #include <clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h>
0011 #include <clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h>
0012 #include <clang/StaticAnalyzer/Core/Checker.h>
0013 #include <clang/StaticAnalyzer/Core/BugReporter/BugReporter.h>
0014 #include <clang/StaticAnalyzer/Core/BugReporter/BugType.h>
0015 #include <llvm/ADT/SmallString.h>
0016 #include <clang/AST/DeclTemplate.h>
0017 #include <iostream>
0018 #include <fstream>
0019 #include <iterator>
0020 #include <string>
0021 #include <algorithm>
0022 #include "CmsException.h"
0023 #include "CmsSupport.h"
0024 #include "FunctionDumper.h"
0025
0026 using namespace clang;
0027 using namespace ento;
0028 using namespace llvm;
0029
0030 namespace clangcms {
0031
0032 class FDumper : public clang::StmtVisitor<FDumper> {
0033 clang::ento::BugReporter &BR;
0034 clang::AnalysisDeclContext *AC;
0035 const FunctionDecl *AD;
0036
0037 enum Kind { NotVisited, Visited };
0038
0039
0040 llvm::DenseMap<const clang::Expr *, Kind> VisitedExpr;
0041
0042 public:
0043 FDumper(clang::ento::BugReporter &br, clang::AnalysisDeclContext *ac, const FunctionDecl *fd)
0044 : BR(br), AC(ac), AD(fd) {}
0045
0046
0047 void setVisited(Expr *E) {
0048 Kind &K = VisitedExpr[E];
0049 if (K = NotVisited) {
0050 VisitedExpr[E] = Visited;
0051 return;
0052 }
0053 }
0054
0055 bool wasVisited(Expr *E) {
0056 Kind &K = VisitedExpr[E];
0057 if (K = Visited)
0058 return true;
0059 return false;
0060 }
0061
0062 const clang::Stmt *ParentStmt(const Stmt *S) {
0063 const Stmt *P = AC->getParentMap().getParentIgnoreParens(S);
0064 if (!P)
0065 return nullptr;
0066 return P;
0067 }
0068
0069 void fixAnonNS(std::string &name) {
0070 const std::string anon_ns = "(anonymous namespace)";
0071 if (name.substr(0, anon_ns.size()) == anon_ns) {
0072 const char *fname = BR.getSourceManager().getPresumedLoc(AD->getLocation()).getFilename();
0073 const char *sname = "/src/";
0074 const char *filename = std::strstr(fname, sname);
0075 if (filename != nullptr)
0076 name = name.substr(0, anon_ns.size() - 1) + " in " + filename + ")" + name.substr(anon_ns.size());
0077 }
0078 return;
0079 }
0080
0081 void VisitChildren(clang::Stmt *S);
0082 void VisitStmt(clang::Stmt *S) { VisitChildren(S); }
0083 void VisitCallExpr(CallExpr *CE);
0084 void VisitCXXMemberCallExpr(CXXMemberCallExpr *CXE);
0085 void VisitCXXConstructExpr(CXXConstructExpr *CCE);
0086 };
0087
0088 void FDumper::VisitChildren(clang::Stmt *S) {
0089 for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I != E; ++I)
0090 if (clang::Stmt *child = *I) {
0091 Visit(child);
0092 }
0093 }
0094
0095 void FDumper::VisitCXXConstructExpr(CXXConstructExpr *CCE) {
0096 std::string buf;
0097 llvm::raw_string_ostream os(buf);
0098 LangOptions LangOpts;
0099 LangOpts.CPlusPlus = true;
0100 PrintingPolicy Policy(LangOpts);
0101 std::string mdname = support::getQualifiedName(*AD);
0102 fixAnonNS(mdname);
0103 CXXConstructorDecl *CCD = CCE->getConstructor();
0104 if (!CCD)
0105 return;
0106 const char *sfile = BR.getSourceManager().getPresumedLoc(CCE->getExprLoc()).getFilename();
0107 std::string sname(sfile);
0108 if (!support::isInterestingLocation(sname))
0109 return;
0110 std::string mname;
0111 mname = support::getQualifiedName(*CCD);
0112 fixAnonNS(mname);
0113 std::string tname = "function-dumper.txt.unsorted";
0114 std::string ostring = "function '" + mdname + "' " + "calls function '" + mname + "'\n";
0115 support::writeLog(ostring, tname);
0116
0117 VisitChildren(CCE);
0118 }
0119
0120 void FDumper::VisitCXXMemberCallExpr(CXXMemberCallExpr *CXE) {
0121 std::string buf;
0122 llvm::raw_string_ostream os(buf);
0123 LangOptions LangOpts;
0124 LangOpts.CPlusPlus = true;
0125 PrintingPolicy Policy(LangOpts);
0126 std::string mdname = support::getQualifiedName(*AD);
0127 fixAnonNS(mdname);
0128 CXXMethodDecl *MD = CXE->getMethodDecl();
0129 if (!MD)
0130 return;
0131 const char *sfile = BR.getSourceManager().getPresumedLoc(CXE->getExprLoc()).getFilename();
0132 std::string sname(sfile);
0133 if (!support::isInterestingLocation(sname))
0134 return;
0135 std::string mname;
0136 mname = support::getQualifiedName(*MD);
0137 fixAnonNS(mname);
0138 std::string tname = "function-dumper.txt.unsorted";
0139 std::string ostring;
0140 ostring = "function '" + mdname + "' " + "calls function '" + mname + "'\n";
0141 support::writeLog(ostring, tname);
0142
0143 VisitChildren(CXE);
0144 }
0145
0146 void FDumper::VisitCallExpr(CallExpr *CE) {
0147 std::string buf;
0148 llvm::raw_string_ostream os(buf);
0149 LangOptions LangOpts;
0150 LangOpts.CPlusPlus = true;
0151 PrintingPolicy Policy(LangOpts);
0152 std::string mdname = support::getQualifiedName(*AD);
0153 fixAnonNS(mdname);
0154 FunctionDecl *FD = CE->getDirectCallee();
0155 if (!FD)
0156 return;
0157 const char *sfile = BR.getSourceManager().getPresumedLoc(CE->getExprLoc()).getFilename();
0158 std::string sname(sfile);
0159 if (!support::isInterestingLocation(sname))
0160 return;
0161 std::string mname;
0162 mname = support::getQualifiedName(*FD);
0163 fixAnonNS(mname);
0164 std::string tname = "function-dumper.txt.unsorted";
0165 std::string ostring;
0166 ostring = "function '" + mdname + "' " + "calls function '" + mname + "'\n";
0167 support::writeLog(ostring, tname);
0168
0169 VisitChildren(CE);
0170 }
0171
0172 void FunctionDumper::checkASTDecl(const CXXMethodDecl *MD, AnalysisManager &mgr, BugReporter &BR) const {
0173 if (MD->getLocation().isInvalid())
0174 return;
0175 const char *sfile = BR.getSourceManager().getPresumedLoc(MD->getLocation()).getFilename();
0176 std::string sname(sfile);
0177 if (!support::isInterestingLocation(sname))
0178 return;
0179 if (!support::isCmsLocalFile(sfile))
0180 return;
0181 if (!MD->doesThisDeclarationHaveABody())
0182 return;
0183 FDumper walker(BR, mgr.getAnalysisDeclContext(MD), MD);
0184 walker.Visit(MD->getBody());
0185 std::string mname = support::getQualifiedName(*MD);
0186 walker.fixAnonNS(mname);
0187 std::string tname = "function-dumper.txt.unsorted";
0188 for (auto I = MD->begin_overridden_methods(), E = MD->end_overridden_methods(); I != E; ++I) {
0189 std::string oname = support::getQualifiedName(*(*I));
0190 walker.fixAnonNS(oname);
0191 std::string ostring = "function '" + mname + "' " + "overrides function '" + oname + "'\n";
0192 support::writeLog(ostring, tname);
0193 }
0194 return;
0195 }
0196
0197 void FunctionDumper::checkASTDecl(const FunctionDecl *MD, AnalysisManager &mgr, BugReporter &BR) const {
0198 if (MD->getLocation().isInvalid())
0199 return;
0200 const char *sfile = BR.getSourceManager().getPresumedLoc(MD->getLocation()).getFilename();
0201 std::string sname(sfile);
0202 if (!support::isInterestingLocation(sname))
0203 return;
0204 if (!support::isCmsLocalFile(sfile))
0205 return;
0206 if (!MD->doesThisDeclarationHaveABody())
0207 return;
0208 FDumper walker(BR, mgr.getAnalysisDeclContext(MD), MD);
0209 walker.Visit(MD->getBody());
0210 return;
0211 }
0212
0213 void FunctionDumper::checkASTDecl(const FunctionTemplateDecl *TD, AnalysisManager &mgr, BugReporter &BR) const {
0214 if (TD->getLocation().isInvalid())
0215 return;
0216 const char *sfile = BR.getSourceManager().getPresumedLoc(TD->getLocation()).getFilename();
0217 std::string sname(sfile);
0218 if (!support::isInterestingLocation(sname))
0219 return;
0220 if (!support::isCmsLocalFile(sfile))
0221 return;
0222 for (auto I = TD->spec_begin(), E = TD->spec_end(); I != E; ++I) {
0223 if (I->doesThisDeclarationHaveABody()) {
0224 FDumper walker(BR, mgr.getAnalysisDeclContext(*I), (*I));
0225 walker.Visit(I->getBody());
0226 }
0227 }
0228 return;
0229 }
0230
0231 }