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 #2
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 close_file(Analyser& analyser,
                       SourceLocation where,
                       std::string const&,
                       std::string const& name)
{
    if (analyser.is_component_header(name))
    {
        analyser.attachment<data>().line_ =
            analyser.get_location(where).line();
    }
}
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())
                    ;
            }
        }
    }
}