Clang – 获取SubstTemplateTypeParm的完整模板信息

原创 287865  2019-07-09 20:00 

我正在遍历一个clang ast,但是在遍历包含clang :: substtemplatetypeparmtype的[...]

的ast声明的类型信息时,我无法获得所需的信息。给出以下最小输入代码clang tooling

   #include <map>

template <typename k, typename v> using map = std::map<k, v>;
using string = std::string;
using parametermap = map<string, string>;

parametermap somefunc();
   

当通过

parametermap 的类型递归时,clang说第一个 map 参数arg, string ,是 clang::substtemplatetypeparmtype 。如果我试图进一步递增以获得更多关于 string 的信息,通过去贬值或获得替换类型(下面的代码),基础类型是 type::record ,并且是 std::basic_string 。这对我来说是意想不到的,因为我希望底层类型是模板特化,类似于 basic_string<const char*, std::char_traits<const char*>, std::allocator<const char*>> 。自从没有de是一个记录,我可以得到地图包含 std::basic_string ,但无法获取 basic_string 的模板信息。在这种情况下如何获得 basic_string 的模板专业化信息?

   case type::substtemplatetypeparm:
{
    auto substtemplatetype = qualtype->getas<substtemplatetypeparmtype>();
    walktype(substtemplatetype->getreplacementtype());
    return;
}
   

我理解发布的要求最小的可运行代码示例,如下所示。但是这需要一个clang工具依赖,没有预建,所以这不是很容易插拔。

路径是硬编码的,所以需要根据你的本地设置进行更新。这是compile_commands文件,它还有3个要更新的路径。编译器路径和末尾的文件路径两次。

   [
{"directory":"f:/git/minrepro/","command":"\"c:/program files (x86)/compilers/clang.exe\" -wall -isystem -g -std=c++14 -wno-format -wno-unneeded-internal-declaration -werror f:/git/minrepro/examplesource.cpp","file":"f:/git/minrepro/examplesource.cpp"}
]
   

代码:

  [123 ]  #pragma comment(lib,"version.lib")

#include <clang/tooling/jsoncompilationdatabase.h>
#include <clang/tooling/tooling.h>
#include <clang/frontend/frontendaction.h>
#include <clang/sema/semaconsumer.h>
#include <clang/ast/type.h>
#include <clang/ast/templatename.h>
#include <clang/ast/decl.h>
#include <clang/ast/decltemplate.h>
#include <clang/frontend/compilerinstance.h>

#include <iostream>
#include <cstdlib>
#include <cassert>
#include <vector>
#include <string>

class astwalker : public clang::semaconsumer
{
public:
    astwalker(clang::astcontext& context)
        : m_context(context)
    {}

    virtual void handletranslationunit(clang::astcontext& context)
    {
        using namespace clang;

        for (auto declaration : context.gettranslationunitdecl()->decls())
        {
            const auto&sm = m_context.getsourcemanager();

            if (!declaration->getbeginloc().isvalid())
                continue;

            // only walk declarations from our file.
            if (!sm.isinmainfile(sm.getspellingloc(declaration->getbeginloc())))
                continue;

            // find functions, and inspect their return type.
            auto nodekind = declaration->getkind();
            if (nodekind == decl::function)
            {
                auto funcdecl = cast<functiondecl>(declaration);

                // check for and ignore built-in functions.
                if (funcdecl->getbuiltinid() != 0)
                    break;

                walktype(funcdecl->getreturntype());
                break;
            }
        }
    }

    void walktype(const clang::qualtype& qualtype)
    {
        using namespace clang;

        auto classtype = qualtype->gettypeclass();
        switch (classtype)
        {
        case type::typedef:
        {
            auto typedeftype = qualtype->getas<typedeftype>();
            walktype(typedeftype->desugar());
            return;
        }
        case type::templatespecialization:
        {
            auto templatespecialization = qualtype->getas<templatespecializationtype>();
            if (templatespecialization->istypealias())
            {
                walktype(templatespecialization->getaliasedtype());
                return;
            }

            std::string templatetype = templatespecialization->gettemplatename().getastemplatedecl()->getqualifiednameasstring();
            std::cout << templatetype << "<";

            auto numargs = templatespecialization->getnumargs();
            for (unsigned int i = 0; i < numargs; ++i)
            {
                if (i > 0)
                    std::cout << ", ";

                const clang::templateargument& templatearg = templatespecialization->getarg(i);
                if (templatearg.getkind() == clang::templateargument::argkind::type)
                {
                    walktype(templatearg.getastype());
                }
            }

            std::cout << ">";
            return;
        }
        case type::record:
        {
            const auto record = qualtype->getas<recordtype>();
            std::string recordqualifiedname = record->getasrecorddecl()->getqualifiednameasstring();
            std::cout << recordqualifiedname;
            return;
        }
        case type::elaborated:
        {
            auto elaboratedtype = qualtype->getas<elaboratedtype>();
            walktype(elaboratedtype->desugar());
            return;
        }
        case type::substtemplatetypeparm:
        {
            auto substtemplatetype = qualtype->getas<substtemplatetypeparmtype>();
            walktype(substtemplatetype->desugar());
            //also tried getreplacementtype.
            //walktype(substtemplatetype->getreplacementtype());
            return;
        }
        }
    }

private:
    clang::astcontext& m_context;
};

class exampleaction : public clang::astfrontendaction
{
public:
    exampleaction() {}

    virtual std::unique_ptr<clang::astconsumer> createastconsumer(clang::compilerinstance& compiler, llvm::stringref infile)
    {
        return std::unique_ptr<clang::astconsumer>(new astwalker(compiler.getastcontext()));
    }
};

int main(int argc, char **argv)
{
    // create the compilation database.
    std::string errorout;
    std::unique_ptr<clang::tooling::jsoncompilationdatabase> compilationdatabase = clang::tooling::jsoncompilationdatabase::loadfromfile("f:/git/minrepro/compile_commands.json", errorout, clang::tooling::jsoncommandlinesyntax::autodetect);

    if (compilationdatabase == nullptr || !errorout.empty())
    {
        std::cout << "[error] failed to load compilation database. error=" << errorout.c_str() << std::endl;
        return false;
    }

    std::vector<std::string> headerfiles;
    headerfiles.push_back("f:/git/minrepro/examplesource.cpp");
    clang::tooling::clangtool tool(*compilationdatabase, llvm::arrayref<std::string>(headerfiles));

    auto toolresult = tool.run(clang::tooling::newfrontendactionfactory<exampleaction>().get());
    if (toolresult == 1)
    {
        std::cout << "[error] error occurred.  check log.  aborting.\n";
        assert(false);
        return false;
    }
}
   

最佳答案:

本文地址:https://www.hedasudi.com/2820.shtml
版权声明:本文为原创文章,版权归 287865 所有,欢迎分享本文,转载请保留出处!

发表评论


表情