Beispiel #1
0
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;
        }
    }
}
Beispiel #5
0
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())
                    ;
            }
        }
    }
}