text: #include "ClassDumper.h"
  #include "CmsSupport.h"
  #include <iostream>
  #include <fstream>
  #include <iterator>
  #include <string>
  #include <algorithm>
  using namespace clang;
  using namespace clang::ento;
  using namespace llvm;
  
  namespace clangcms {
  
    void ClassDumper::checkASTDecl(const clang::CXXRecordDecl *RD,
                                   clang::ento::AnalysisManager &mgr,
                                   clang::ento::BugReporter &BR,
                                   std::string tname) const {
      const char *sfile = BR.getSourceManager().getPresumedLoc(RD->getLocation()).getFilename();
      if (!RD->hasDefinition())
        return;
      std::string rname = RD->getQualifiedNameAsString();
      support::fixAnonNS(rname, sfile);
      clang::LangOptions LangOpts;
      LangOpts.CPlusPlus = true;
      clang::PrintingPolicy Policy(LangOpts);
      std::string crname("class '");
      const ClassTemplateSpecializationDecl *SD = dyn_cast_or_null<ClassTemplateSpecializationDecl>(RD);
      if (SD) {
        std::string buf;
        llvm::raw_string_ostream os(buf);
        SD->getNameForDiagnostic(os, Policy, true);
        crname = crname + os.str() + "'";
        support::writeLog(crname, tname);
        for (unsigned J = 0, F = SD->getTemplateArgs().size(); J != F; ++J) {
          if (SD->getTemplateArgs().get(J).getKind() == clang::TemplateArgument::Type) {
            std::string taname;
            auto tt = SD->getTemplateArgs().get(J).getAsType().getTypePtr();
            if (tt->isRecordType()) {
              auto TAD = tt->getAsCXXRecordDecl();
              if (TAD)
                taname = TAD->getQualifiedNameAsString();
              support::fixAnonNS(taname, sfile);
              std::string sdname = SD->getQualifiedNameAsString();
              support::fixAnonNS(sdname, sfile);
              std::string cfname = "templated data class '" + sdname + "' template type class '" + taname + "'";
              support::writeLog(crname + " " + cfname, tname);
            }
            if (tt->isPointerType() || tt->isReferenceType()) {
              auto TAD = tt->getPointeeCXXRecordDecl();
              if (TAD)
                taname = TAD->getQualifiedNameAsString();
              support::fixAnonNS(taname, sfile);
              std::string sdname = SD->getQualifiedNameAsString();
              support::fixAnonNS(sdname, sfile);
              std::string cfname = "templated data class '" + sdname + "' template type class '" + taname + "'";
              std::string cbname = "templated data class 'bare_ptr' template type class '" + taname + "'";
              support::writeLog(crname + " " + cfname, tname);
              support::writeLog(crname + " " + cbname, tname);
            }
          }
        }
  
      } else {
        // Dump the class name
        crname = crname + rname + "'";
        support::writeLog(crname, tname);
      }
  
      // Dump the class member classes
      for (auto I = RD->field_begin(), E = RD->field_end(); I != E; ++I) {
        clang::QualType qual;
        clang::QualType type = I->getType();
        if (type.getTypePtr()->isAnyPointerType())
          qual = type.getTypePtr()->getPointeeType();
        else
          qual = type.getNonReferenceType();
        if (!qual.getTypePtr()->isRecordType())
          continue;
        if (const CXXRecordDecl *TRD = qual.getTypePtr()->getAsCXXRecordDecl()) {
          std::string fname = TRD->getQualifiedNameAsString();
          support::fixAnonNS(fname, sfile);
          const ClassTemplateSpecializationDecl *SD = dyn_cast_or_null<ClassTemplateSpecializationDecl>(TRD);
          if (SD) {
            std::string buf;
            llvm::raw_string_ostream os(buf);
            SD->getNameForDiagnostic(os, Policy, true);
            std::string cfname = "member data class '" + os.str() + "'";
            support::writeLog(crname + " " + cfname, tname);
            // Recurse the template args
            for (unsigned J = 0, F = SD->getTemplateArgs().size(); J != F; ++J) {
              if (SD->getTemplateArgs().get(J).getKind() == clang::TemplateArgument::Type) {
                std::string taname;
                const clang::Type *tt = SD->getTemplateArgs().get(J).getAsType().getTypePtr();
                if (tt->isRecordType()) {
                  const clang::CXXRecordDecl *TAD = tt->getAsCXXRecordDecl();
                  if (TAD)
                    taname = TAD->getQualifiedNameAsString();
                  support::fixAnonNS(taname, sfile);
                  std::string sdname = SD->getQualifiedNameAsString();
                  support::fixAnonNS(sdname, sfile);
                  std::string cfname =
                      "templated member data class '" + sdname + "' template type class '" + taname + "'";
                  support::writeLog(crname + " " + cfname, tname);
                }
                if (tt->isPointerType() || tt->isReferenceType()) {
                  const clang::CXXRecordDecl *TAD = tt->getPointeeCXXRecordDecl();
                  if (TAD)
                    taname = TAD->getQualifiedNameAsString();
                  support::fixAnonNS(taname, sfile);
                  std::string sdname = SD->getQualifiedNameAsString();
                  support::fixAnonNS(sdname, sfile);
                  std::string cfname =
                      "templated member data class '" + sdname + "' template type class '" + taname + "'";
                  std::string cbname = "templated member data class 'bare_ptr' template type class '" + taname + "'";
                  support::writeLog(crname + " " + cfname, tname);
                  support::writeLog(crname + " " + cbname, tname);
                }
              }
            }
          } else {
            if (type.getTypePtr()->isRecordType()) {
              std::string cfname = "member data class '" + fname + "' ";
              support::writeLog(crname + " " + cfname, tname);
            }
            if (type.getTypePtr()->isAnyPointerType()) {
              std::string cfname = "templated member data class 'bare_ptr' template type class '" + fname + "'";
              support::writeLog(crname + " " + cfname, tname);
            }
          }
        }
      }
  
      // Dump the base classes
  
      for (auto J = RD->bases_begin(), F = RD->bases_end(); J != F; ++J) {
        auto BRD = J->getType()->getAsCXXRecordDecl();
        if (!BRD)
          continue;
        std::string bname = BRD->getQualifiedNameAsString();
        support::fixAnonNS(bname, sfile);
        std::string cbname = "base class '" + bname + "'";
        support::writeLog(crname + " " + cbname, tname);
      }
  
    }  //end class
  
    void ClassDumperCT::checkASTDecl(const clang::ClassTemplateDecl *TD,
                                     clang::ento::AnalysisManager &mgr,
                                     clang::ento::BugReporter &BR) const {
      const char *sfile = BR.getSourceManager().getPresumedLoc(TD->getLocation()).getFilename();
      if (!support::isCmsLocalFile(sfile))
        return;
      std::string crname("class '");
      std::string pname = "classes.txt.dumperct.unsorted";
      std::string tname = TD->getTemplatedDecl()->getQualifiedNameAsString();
  
      if (tname == "edm::Wrapper" || tname == "edm::RunCache" || tname == "edm::LuminosityBlockCache" ||
          tname == "edm::GlobalCache") {
        for (auto I = TD->spec_begin(), E = TD->spec_end(); I != E; ++I) {
          for (unsigned J = 0, F = I->getTemplateArgs().size(); J != F; ++J) {
            auto D = I->getTemplateArgs().get(J).getAsType()->getAsCXXRecordDecl();
            if (D) {
              ClassDumper dumper;
              dumper.checkASTDecl(D, mgr, BR, pname);
              std::string taname = D->getQualifiedNameAsString();
              support::fixAnonNS(taname, sfile);
              std::string tdname = TD->getQualifiedNameAsString();
              support::fixAnonNS(tdname, sfile);
              std::string cfname = "templated class '" + tdname + "' template type class '" + taname + "'";
              support::writeLog(cfname, pname);
            }
            auto E = I->getTemplateArgs().get(J).getAsType()->getPointeeCXXRecordDecl();
            if (E) {
              ClassDumper dumper;
              dumper.checkASTDecl(E, mgr, BR, pname);
              std::string taname = E->getQualifiedNameAsString();
              support::fixAnonNS(taname, sfile);
              std::string tdname = TD->getQualifiedNameAsString();
              support::fixAnonNS(tdname, sfile);
              std::string cfname = "templated class '" + tdname + "' template type class '" + taname + "'";
              support::writeLog(cfname, pname);
              std::string cbname = "templated class 'bare_ptr' template type class '" + taname + "'";
              support::writeLog(crname + " " + cbname, pname);
            }
          }
        }
      }
    }  //end class
  
    void ClassDumperFT::checkASTDecl(const clang::FunctionTemplateDecl *TD,
                                     clang::ento::AnalysisManager &mgr,
                                     clang::ento::BugReporter &BR) const {
      const char *sfile = BR.getSourceManager().getPresumedLoc(TD->getLocation()).getFilename();
      if (!support::isCmsLocalFile(sfile))
        return;
      std::string crname("class '");
      std::string pname = "classes.txt.dumperft.unsorted";
      if (TD->getTemplatedDecl()->getQualifiedNameAsString().find("typelookup::className") != std::string::npos) {
        for (auto I = TD->spec_begin(), E = TD->spec_end(); I != E; ++I) {
          auto *SD = (*I);
          for (unsigned J = 0, F = SD->getTemplateSpecializationArgs()->size(); J != F; ++J) {
            auto D = SD->getTemplateSpecializationArgs()->get(J).getAsType()->getAsCXXRecordDecl();
            if (D) {
              ClassDumper dumper;
              dumper.checkASTDecl(D, mgr, BR, pname);
              std::string taname = D->getQualifiedNameAsString();
              support::fixAnonNS(taname, sfile);
              std::string sdname = SD->getQualifiedNameAsString();
              support::fixAnonNS(sdname, sfile);
              std::string cfname = "templated function '" + sdname + "' template type class '" + taname + "'";
              support::writeLog(cfname, pname);
            }
            auto E = SD->getTemplateSpecializationArgs()->get(J).getAsType()->getPointeeCXXRecordDecl();
            if (E) {
              ClassDumper dumper;
              dumper.checkASTDecl(E, mgr, BR, pname);
              std::string taname = E->getQualifiedNameAsString();
              support::fixAnonNS(taname, sfile);
              std::string sdname = SD->getQualifiedNameAsString();
              support::fixAnonNS(sdname, sfile);
              std::string cfname = "templated function '" + sdname + "' template type class '" + taname + "'";
              support::writeLog(cfname, pname);
              std::string cbname = "templated function 'bare_ptr' template type class '" + taname + "'";
              support::writeLog(crname + " " + cbname, pname);
            }
          }
        }
      }
    }  //end class
  
    void ClassDumperInherit::checkASTDecl(const clang::CXXRecordDecl *RD,
                                          clang::ento::AnalysisManager &mgr,
                                          clang::ento::BugReporter &BR) const {
      return;
    }  //end of class
  
  }  // namespace clangcms
  