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; }
bool rightHandOperatorHasSideEffect(const BinaryOperator *S) { if (doIgnore(S->getLocStart())) { return true; } Expr *rightHandExpr = S->getRHS(); if (rightHandExpr->HasSideEffects(*context)) { reportError(rightHandExpr->getLocStart()); } return true; }
// 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; }
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); } }
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; }
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; }
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; }
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); } }
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; }
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; } } }
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; }