bool VisitCXXDestructorDecl(CXXDestructorDecl *D) {
    if (doIgnore(D->getLocStart())) {
      return true;
    }
    if (!D->isThisDeclarationADefinition()) {
      return true;
    }

    Stmt *t{nullptr}, *p{nullptr};

    p = D->getBody();

    if (p) {
      if (Stmt *throwStmt = searchStmt<CXXThrowExpr>(p)) {
        t = throwStmt;
      }
    }
    // dctor throws, check if there's a catch block
    if (t && p) {
      auto g = searchStmt<CXXCatchStmt>(p);
      if (!g) {
        reportError(t->getLocStart());
      }
    }

    return true;
  };
  bool VisitCXXRecordDecl(const CXXRecordDecl *decl) {
    if (doIgnore(decl->getLocStart())) {
      return true;
    }

    // Sort out any non-class or struct declarations
    if ((decl->isClass() || decl->isStruct()) == false) {
      return true;
    }
    // We can only judge classes with a visible definition
    if (decl->hasDefinition() == false) {
      return true;
    }
    // Rule applies to non-POD classes only
    // Note: POD definition from C++11, not 03. Problem?
    if (decl->isPOD()) {
      return true;
    }

    // Report all non-private members
    for (const FieldDecl *fieldDecl : decl->fields()) {
      if (fieldDecl->getAccess() != AS_private) {
        reportError(fieldDecl->getLocStart());
      }
    }
    return true;
  }
  bool VisitCXXRecordDecl(CXXRecordDecl *decl) {
    if (doIgnore(decl->getLocStart())) {
      return true;
    }

    // Forward declarations can not violate this rule
    if (!decl->hasDefinition()) {
      return true;
    }

    // If a class is not abstract skip it
    if (!decl->isAbstract()) {
      return true;
    }

    // If abstract class doesn't have user declared
    // operator= skip it
    if (!decl->hasUserDeclaredCopyAssignment()) {
      return true;
    }

    for (CXXMethodDecl *method : decl->methods()) {
      if (method->isCopyAssignmentOperator() &&
          method->getAccess() == clang::AS_public) {
        reportError(method->getLocStart());
      }
    }

    return true;
  }
  bool VisitDeclRefExpr(DeclRefExpr *expr) {
    if (doIgnore(expr->getLocation())) {
      return true;
    }

    std::string funName = expr->getNameInfo().getAsString();
    if (illegalFunctions.count(funName)) {
      reportError(expr->getLocStart());
    }
    return true;
  }
Пример #5
0
  bool rightHandOperatorHasSideEffect(const BinaryOperator *S) {
    if (doIgnore(S->getLocStart())) {
      return true;
    }

    Expr *rightHandExpr = S->getRHS();
    if (rightHandExpr->HasSideEffects(*context)) {
      reportError(rightHandExpr->getLocStart());
    }
    return true;
  }
Пример #6
0
  // errno is a macro.
  virtual void MacroExpands(const Token &MacroNameTok, const MacroDirective *MD,
                            SourceRange Range, const MacroArgs *Args) override {
    const std::string &name = MacroNameTok.getIdentifierInfo()->getName();
    if (name == illegalMacroName) {
      if (doIgnore(MacroNameTok.getLastLoc())) {
        return;
      }

      reportError(Range.getBegin());
    }
  }
  bool VisitNullStmt(NullStmt *stmt) {
    if (doIgnore(stmt->getLocStart())) {
      return true;
    }

    if (hasNonWhitespaceBeforeNullStmt(stmt) ||
        hasNonWhitespaceAfterNullStmt(stmt)) {
      reportError(stmt->getLocStart());
    }
    return true;
  }
Пример #8
0
 virtual void InclusionDirective(SourceLocation HashLoc,
                                 const Token &IncludeTok, StringRef FileName,
                                 bool IsAngled, CharSourceRange FilenameRange,
                                 const FileEntry *File, StringRef SearchPath,
                                 StringRef RelativePath,
                                 const Module *Imported) override {
   if (illegalIncludes.count(FileName)) {
     if (doIgnore(HashLoc)) {
       return;
     }
     reportError(HashLoc);
   }
 }
Пример #9
0
  bool VisitCXXRecordDecl(CXXRecordDecl *decl) {
    if (doIgnore(decl->getLocStart())) {
      return true;
    }

    for (const auto B : decl->methods()) {
      if (!B->isImplicit() && B->isVirtual() && !B->isVirtualAsWritten()) {
        reportError(B->getLocation());
        break;
      }
    }
    return true;
  }
Пример #10
0
  bool VisitVarDecl(VarDecl *D) {
    if (doIgnore(D->getLocStart())) {
      return true;
    }

    const QualType declType = D->getType();

    // Report error if this is an array type of unknown length
    if (isa<ArrayType>(declType) && !isa<ConstantArrayType>(declType)) {
      reportError(D->getLocation());
    }

    return true;
  }
Пример #11
0
  bool VisitCXXDestructorDecl(clang::CXXDestructorDecl *decl) {
    if (doIgnore(decl->getLocStart())) {
      return true;
    }

    // Definitions outside of the class body do not have the virtual keyword
    if (decl->isThisDeclarationADefinition()) {
      return true;
    }

    if (decl->isVirtual() && !decl->isVirtualAsWritten()) {
      reportError(decl->getLocation());
    }
    return true;
  }
Пример #12
0
  void detectViolation(const Token &MacroNameTok) {
    const std::string &name = MacroNameTok.getIdentifierInfo()->getName();
    const SourceLocation &loc = MacroNameTok.getLocation();

    if (doIgnore(loc)) {
      return;
    }

    // A few specific macros with two leading underscores are valid
    if (explicitlyLegalMacroNames.count(name)) {
      return;
    }
    // All other, whether exlicitly banned or starting with a leading underscore
    // constitute a violation of this rule.
    if (explicitlyIllegalMacroNames.count(name) || (name.find('_') == 0)) {
      reportError(loc);
    }
  }
Пример #13
0
  bool VisitDecl(Decl *D) {
    if (doIgnore(D->getLocStart())) {
      return true;
    }

    // Declarations in headers are always accepted
    if (isInMainFile(D->getLocation()) == false) {
      return true;
    }

    // C++ methods can not violate this rule
    if (isa<CXXMethodDecl>(D)) {
      return true;
    }

    // The main function is allowed to be in global namespace and not having an
    // external declaration
    if (isa<FunctionDecl>(D) && static_cast<FunctionDecl *>(D)->isMain()) {
      return true;
    }

    // If linkage is strictly internal, this rule simply can not be
    // violated
    if (const VarDecl *varDecl = dyn_cast<const VarDecl>(D)) {
      if (varDecl->getFormalLinkage() <= UniqueExternalLinkage) {
        return true;
      }
    }

    // Declarations declared auto, static or in an anonymous namespace can not
    // violate this rule
    if (D->isInAnonymousNamespace() || isStorageClass<VarDecl>(D, SC_Static) ||
        isStorageClass<VarDecl>(D, SC_Auto) ||
        isStorageClass<FunctionDecl>(D, SC_Static)) {
      return true;
    }

    if (hasExternalStorageClass<FunctionDecl>(D) ||
        hasExternalStorageClass<VarDecl>(D)) {
      D->dump();
      reportError(D->getLocation());
    }
    return true;
  }
Пример #14
0
  bool VisitVarDecl(const VarDecl *D) {
    // Bail out early if this location should not be checked.
    if (doIgnore(D->getLocation())) {
      return true;
    }

    const QualType qualType = D->getType();
    // Bail out if this type is either an enum or does not look like a real
    // value.
    if (qualType->isEnumeralType() || qualType->isBooleanType() ||
        qualType->isArithmeticType() == false) {
      return true;
    }

    const Type *t = qualType.getTypePtrOrNull();
    assert(t && "Type of arithmetic types has to be available.");
    const std::string typeName = qualType.getAsString();
    // If it is of the same type as "size_t" and does have "size_t" somewhere in
    // its name we can go with it.
    // Please note: This also allows a typedef for "unsigned long" to be named
    // e.g. "size_type" without any size indicator - which may or may not be a
    // good thing.
    if (context->hasSameUnqualifiedType(qualType, context->getSizeType()) &&
        typeName.find("size_t") != std::string::npos) {
      return true;
    }

    // char_t and wchar_t are not subject to this rule.
    const std::string needle = "char_t";
    if (std::equal(needle.rbegin(), needle.rend(), typeName.rbegin())) {
      return true;
    }

    const uint64_t typeSize = context->getTypeSize(t);
    const std::string sizeStr = llvm::utostr(typeSize);
    // For all remaining types, the number of occupied bits must be embedded in
    // the typename.
    if (typeName.rfind(sizeStr) == std::string::npos) {
      reportError(D->getLocation());
    }

    return true;
  }
  virtual void MacroDefined(const Token &MacroNameTok,
                            const MacroDirective *MD) override {
    const MacroInfo *macroInfo = MD->getMacroInfo();

    if (doIgnore(MD->getLocation())) {
      return;
    }

    for (MacroInfo::tokens_iterator I = macroInfo->tokens_begin(),
                                    E = macroInfo->tokens_end();
         I != E; ++I) {
      const std::string tokenType = I->getName();
      // Count occurrences of "hash" and "hashhash"
      if (tokenType.find("hash") == 0) {
        reportError(I->getLocation());
        break;
      }
    }
  }
Пример #16
0
  bool VisitCXXNewExpr(CXXNewExpr *decl) {
    if (doIgnore(decl->getStartLoc())) {
      return true;
    }

    bool doesNotThrow = decl->shouldNullCheckAllocation(*context);
    if (doesNotThrow) {
      // Iterate over children and try to figure out if this new expr
      // looks like a placement new which can be used legally.
      for (const auto it : decl->children()) {
        if (const auto *castExpr = dyn_cast<CastExpr>(it)) {
          if (castExpr->getCastKind() == CK_BitCast) {
            // Looks legit. Bail out without generating an error.
            return true;
          }
        }
      }
    }

    // This new expr does not look like a placement new. Generate an error.
    reportError(decl->getLocStart());
    return true;
  }