<commit_before>// csaaq_freefunctionsdepend.cpp                                      -*-C++-*-

#include <csabase_analyser.h>
#include <csabase_clang.h>
#include <csabase_config.h>
#include <csabase_debug.h>
#include <csabase_format.h>
#include <csabase_registercheck.h>
#include <csabase_report.h>
#include <csabase_visitor.h>
#include <map>

using namespace csabase;
using namespace clang;

// ----------------------------------------------------------------------------

static std::string const check_name("free-functions-depend");

// ----------------------------------------------------------------------------

namespace
{

struct data
    // Data attached to analyzer for this check.
{
};

struct report : Report<data>
{
    using Report<data>::Report;

    bool depends(SourceLocation sl, QualType type);

    bool isFree(const FunctionDecl *decl);

    void operator()(const FunctionDecl *decl);

    void operator()(const FunctionTemplateDecl *decl);
};

bool report::isFree(const FunctionDecl *decl)
{
    const DeclContext *dc = decl->getDeclContext();
    while (dc->getDeclKind() == Decl::LinkageSpec) {
        dc = dc->getParent();
    }
    return dc->isFileContext();
}

bool report::depends(SourceLocation sl, QualType type)
{
    type = type.getDesugaredType(*a.context());

    QualType sub;
    while (!(sub = type->getPointeeType()).isNull()) {
        type = sub.getDesugaredType(*a.context());
    }
    if (type->isBuiltinType()) {
        return false;
    }
    if (type->getAs<TemplateTypeParmType>()) {
        return false;
    }
    if (auto dnt = type->getAs<DependentNameType>()) {
        if (auto nns = dnt->getQualifier()) {
            if (auto t = nns->getAsType()) {
                if (depends(sl, QualType(t, 0))) {
                    return true;
                }
            }
        }
        return false;
    }
    if (auto ft = type->getAs<FunctionProtoType>()) {
        unsigned n = ft->getNumParams();
        for (unsigned i = 0; i < n; ++i) {
            if (depends(sl, ft->getParamType(i))) {
                return true;
            }
        }
        return false;
    }
    auto rd = type->getAsCXXRecordDecl();
    if (auto tspt = type->getAs<TemplateSpecializationType>()) {
        if (auto td = tspt->getTemplateName().getAsTemplateDecl()) {
            unsigned n = tspt->getNumArgs();<commit_msg>Free functions can depend on locally-defined enums.<commit_after>// csaaq_freefunctionsdepend.cpp                                      -*-C++-*-

#include <csabase_analyser.h>
#include <csabase_clang.h>
#include <csabase_config.h>
#include <csabase_debug.h>
#include <csabase_format.h>
#include <csabase_registercheck.h>
#include <csabase_report.h>
#include <csabase_visitor.h>
#include <map>

using namespace csabase;
using namespace clang;

// ----------------------------------------------------------------------------

static std::string const check_name("free-functions-depend");

// ----------------------------------------------------------------------------

namespace
{

struct data
    // Data attached to analyzer for this check.
{
};

struct report : Report<data>
{
    using Report<data>::Report;

    bool depends(SourceLocation sl, QualType type);

    bool isFree(const FunctionDecl *decl);

    void operator()(const FunctionDecl *decl);

    void operator()(const FunctionTemplateDecl *decl);
};

bool report::isFree(const FunctionDecl *decl)
{
    const DeclContext *dc = decl->getDeclContext();
    while (dc->getDeclKind() == Decl::LinkageSpec) {
        dc = dc->getParent();
    }
    return dc->isFileContext();
}

bool report::depends(SourceLocation sl, QualType type)
{
    type = type.getDesugaredType(*a.context());

    QualType sub;
    while (!(sub = type->getPointeeType()).isNull()) {
        type = sub.getDesugaredType(*a.context());
    }
    if (type->isBuiltinType()) {
        return false;
    }
    if (type->getAs<TemplateTypeParmType>()) {
        return false;
    }
    if (auto dnt = type->getAs<DependentNameType>()) {
        if (auto nns = dnt->getQualifier()) {
            if (auto t = nns->getAsType()) {
                if (depends(sl, QualType(t, 0))) {
                    return true;
                }
            }
        }
        return false;
    }
    if (auto ft = type->getAs<FunctionProtoType>()) {
        unsigned n = ft->getNumParams();
        for (unsigned i = 0; i < n; ++i) {
            if (depends(sl, ft->getParamType(i))) {
                return true;
            }
        }
        return false;
    }
    //auto rd = type->getAsCXXRecordDecl();
    auto rd = type->getAsTagDecl();
    if (auto tspt = type->getAs<TemplateSpecializationType>()) {
        if (auto td = tspt->getTemplateName().getAsTemplateDecl()) {
            unsigned n = tspt->getNumArgs();
{'fraction_non_alphanumeric': 0.19558884727424053, 'fraction_numerical': 0.0008322929671244278, 'mean_word_length': 2.042405063291139, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 68, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5928019', 'n_tokens_mistral': 1434, 'n_tokens_neox': 1404, 'n_words': 318}