static void open_file(Analyser& analyser, SourceLocation where, const std::string&, const std::string& name) { FileName fn(name); std::string filename = fn.name(); if (analyser.is_component_header(filename) || name == analyser.toplevel()) { const SourceManager &m = analyser.manager(); llvm::StringRef buf = m.getBuffer(m.getFileID(where))->getBuffer(); if (buf.size() == 0) { return; } buf = buf.substr(0, buf.find('\n')).rtrim(); std::string expectcpp("// " + filename); expectcpp.resize(70, ' '); expectcpp += "-*-C++-*-"; std::string expectc("/* " + filename); expectc.resize(69, ' '); expectc += "-*-C-*- */"; if ( !buf.equals(expectcpp) && !buf.equals(expectc) && buf.find("GENERATED") == buf.npos) { std::pair<size_t, size_t> mcpp = mid_mismatch(buf, expectcpp); std::pair<size_t, size_t> mc = mid_mismatch(buf, expectc); std::pair<size_t, size_t> m; std::string expect; if (mcpp.first >= mc.first || mcpp.second >= mc.second) { m = mcpp; expect = expectcpp; } else { m = mc; expect = expectc; } analyser.report(where.getLocWithOffset(m.first), check_name, "HL01", "File headline incorrect", true); analyser.report(where.getLocWithOffset(m.first), check_name, "HL01", "Correct format is\n%0", true, DiagnosticIDs::Note) << expect; if (m.first == 0) { analyser.InsertTextAfter( where.getLocWithOffset(m.first), expect + "\n"); } else { analyser.ReplaceText(analyser.get_line_range(where), expect); } } } }
static void member_definition_in_class_definition(Analyser& analyser, CXXMethodDecl const* decl) { member_definition& data = analyser.attachment<member_definition>(); if (decl->isTemplateInstantiation()) { if (CXXMethodDecl const* tplt = llvm::dyn_cast<CXXMethodDecl>( decl->getTemplateInstantiationPattern())) { decl = tplt; } } if (decl->getLexicalDeclContext() == decl->getDeclContext() && decl->hasInlineBody() && !decl->getParent()->isLocalClass() && !decl->isImplicit() && !data.reported_[decl->getCanonicalDecl()] && !analyser.is_test_driver() && !decl->getLocStart().isMacroID()) { analyser.report(decl, check_name, "CD01", "Member function '%0' is defined in the class definition.") << decl->getQualifiedNameAsString(); data.reported_[decl->getCanonicalDecl()] = true; } }
static void check(Analyser& analyser, CastExpr const *expr) { if (expr->getSubExpr()->isNullPointerConstant( *analyser.context(), Expr::NPC_ValueDependentIsNotNull)) { return; // RETURN } if (expr->getCastKind() != CK_BitCast && expr->getCastKind() != CK_LValueBitCast && expr->getCastKind() != CK_IntegralToPointer) { return; // RETURN } CanQualType source(getType(expr->getSubExpr()->getType())); CanQualType target(getType(expr->getType())); std::string tt = static_cast<QualType>(target).getAsString(); if ((source != target && tt != "char" && tt != "unsigned char" && tt != "signed char" && tt != "void") || (expr->getType()->isPointerType() != expr->getSubExpr()->getType()->isPointerType())) { analyser.report(expr, check_name, "AL01", "Possible strict-aliasing violation") << expr->getSourceRange(); } }
static void include_file(Analyser& analyser, SourceLocation where, bool, std::string const& name) { data& status(analyser.attachment<data>()); if (status.check_) { if (analyser.is_component_header(name) || analyser.is_component_header(analyser.toplevel())) { status.header_seen_ = true; } else if (!status.header_seen_ && analyser.toplevel() != name && builtin != name && command_line != name && "bdes_ident.h" != name && !analyser.is_main()) { analyser.report(where, check_name, "TR09", "Include files precede component header", true); status.check_ = false; } } }
static void process(Analyser& analyser, Expr const* expr, Decl const* decl) { if (const FunctionDecl* function = decl ? llvm::dyn_cast<FunctionDecl>(decl) : 0) { function = function->getCanonicalDecl(); std::string name; PrintingPolicy policy(analyser.context()->getLangOpts()); function->getNameForDiagnostic(name, policy, true); std::ostringstream out; out << name << "("; for (FunctionDecl::param_const_iterator it(function->param_begin()), end(function->param_end()); it != end; ++it) { if (it != function->param_begin()) { out << ", "; } ParmVarDecl const* param(*it); out << param->getType().getAsString(); if (param->isParameterPack()) { out << "..."; } } out << ")"; CXXMethodDecl const* method(llvm::dyn_cast<CXXMethodDecl>(function)); if (method && !method->isStatic()) { if (method->getTypeQualifiers() & Qualifiers::Const) { out << " const"; } if (method->getTypeQualifiers() & Qualifiers::Volatile) { out << " volatile"; } if (method->getTypeQualifiers() & Qualifiers::Restrict) { out << " restrict"; } } name += out.str(); //-dk:TODO analyser.report(expr, check_name, "function decl: '%0'") //-dk:TODO << expr->getSourceRange() //-dk:TODO << out.str() ; } else { analyser.report(expr, check_name, "UF01", "Unresolved function call") << expr->getSourceRange(); } }
static void check(Analyser& analyser, BinaryOperator const* expr) { if ((expr->getOpcode() == BO_Add || expr->getOpcode() == BO_Sub) && (is_addition( analyser, expr->getLHS(), expr->getRHS(), expr->getOpcode()) || is_addition( analyser, expr->getRHS(), expr->getLHS(), expr->getOpcode()))) { analyser.report(expr->getOperatorLoc(), check_name, "SA01", "%0 integer %1 string literal") << expr->getSourceRange() << (expr->getOpcode() == BO_Add? "Adding": "Subtracting") << (expr->getOpcode() == BO_Add? "to": "from"); } }
static void check(Analyser& analyser, CXXThrowExpr const* expr) { const TypeDecl *e = analyser.lookup_type("::std::exception"); Expr *object(const_cast<Expr*>(expr->getSubExpr())); if (e && e->getTypeForDecl() && object) // else it is a rethrow... { QualType t = e->getTypeForDecl()->getCanonicalTypeInternal(); QualType ot = object->getType()->getCanonicalTypeInternal(); if (ot != t && !analyser.sema().IsDerivedFrom(ot, t)) { analyser.report(expr, check_name, "FE01", "Object of type %0 not derived from " "std::exception is thrown.") << ot; } } }
static void declaration(Analyser& analyser, Decl const* decl) { data& status(analyser.attachment<data>()); if (status.check_) { if (!status.header_seen_ || analyser.is_component_header(analyser.toplevel())) { status.header_seen_ = true; status.line_ = 0; } Location loc(analyser.get_location(decl)); if ((analyser.toplevel() != loc.file() && status.header_seen_) || (analyser.toplevel() == loc.file() && status.line_ < loc.line())) { status.check_ = false; } else if (((analyser.toplevel() != loc.file() && !status.header_seen_) || loc.line() < status.line_) && builtin != loc.file() && command_line != loc.file() && (llvm::dyn_cast<NamedDecl>(decl) == 0 || utils::end(id_names) == std::find(utils::begin(id_names), utils::end(id_names), llvm::dyn_cast<NamedDecl>(decl) ->getNameAsString())) && !analyser.is_main()) { analyser.report(decl, check_name, "TR09", "Declarations precede component header", true); status.check_ = false; } } }
static void check(Analyser& analyser, Decl const* decl) { if (analyser.is_main() && analyser.config()->value("main_namespace_check") == "off") { return; // RETURN } if (analyser.is_global_package()) { return; // RETURN } Location location(analyser.get_location(decl)); NamedDecl const* named(llvm::dyn_cast<NamedDecl>(decl)); if (analyser.is_component(location.file()) && named) { if (llvm::dyn_cast<NamespaceDecl>(decl) || llvm::dyn_cast<UsingDirectiveDecl>(decl)) { // namespace declarations are permissible e.g. for forward declarations. return; // RETURN } else if (TagDecl const* tag = llvm::dyn_cast<TagDecl>(decl)) { // Forward declarations are always permissible but definitions are not. if (!tag->isThisDeclarationADefinition() && analyser.is_component_header(location.file())) { return; // RETURN } } else if (llvm::dyn_cast<NamespaceAliasDecl>(decl) && analyser.is_component_source(decl)) { return; // RETURN } DeclContext const* context(decl->getDeclContext()); std::string name = named->getNameAsString(); if (llvm::dyn_cast<TranslationUnitDecl>(context)) { if (name != "main" && name != "RCSId" && !llvm::dyn_cast<ClassTemplateSpecializationDecl>(decl) && !llvm::dyn_cast<ClassTemplatePartialSpecializationDecl>(decl) && name.find("operator new") == std::string::npos && name.find("operator delete") == std::string::npos ) { analyser.report(decl, check_name, "TR04", "Declaration of '%0' at global scope", true) << decl->getSourceRange() << name; } return; // RETURN } NamespaceDecl const* space = llvm::dyn_cast<NamespaceDecl>(context); if (!space) { return; // RETURN } std::string pkgns = analyser.package(); if ( space->isAnonymousNamespace() && llvm::dyn_cast<NamespaceDecl>(space->getDeclContext())) { space = llvm::dyn_cast<NamespaceDecl>(space->getDeclContext()); } if (space->getNameAsString() == analyser.config()->toplevel_namespace()) { // No package namespace. This is OK if no package namespace has // been seen, for the sake of legacy "package_name" components. DeclContext::decl_iterator b = space->decls_begin(); DeclContext::decl_iterator e = space->decls_end(); bool found = false; while (!found && b != e) { const NamespaceDecl *ns = llvm::dyn_cast<NamespaceDecl>(*b++); found = ns && ns->getNameAsString() == analyser.package(); } if (!found) { pkgns = analyser.config()->toplevel_namespace(); } } if (name.length() > 0) { std::string spname = space->getNameAsString(); NamespaceDecl const* outer = space; if (pkgns == analyser.package()) { outer = llvm::dyn_cast<NamespaceDecl>( space->getDeclContext()); } if ((spname != pkgns || !outer || outer->getNameAsString() != analyser.config()->toplevel_namespace()) && ( spname != analyser.config()->toplevel_namespace() || name.find(analyser.package() + '_') != 0 ) && to_lower(spname) != to_lower(analyser.component()) && !llvm::dyn_cast<ClassTemplateSpecializationDecl>(decl) && !llvm::dyn_cast<ClassTemplatePartialSpecializationDecl>(decl) && name.find("operator new") == std::string::npos && name.find("operator delete") == std::string::npos && !isSpecialFunction(named) && ( analyser.is_component_header(named) || named->hasLinkage() ) && !analyser.is_ADL_candidate(decl) ) { //-dk:TODO check if this happens in the correct namespace analyser.report(decl, check_name, "TR04", "Declaration of '%0' not within package namespace '%1'", true) << decl->getSourceRange() << name << (analyser.config()->toplevel_namespace() + "::" + analyser.package()) ; } } } }