Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/LibreOffice/compilerplugins/clang/sharedvisitor/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 16 kB image not shown  

Quelle  generator.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */


#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstring>
#include <iostream>
#include <fstream>
#include <memory>
#include <set>
#include <vector>

// Info about a Visit* function in a plugin.
struct VisitFunctionInfo
{
    std::string name;
    std::string argument;
};


// Info about a Traverse* function in a plugin.
struct TraverseFunctionInfo
{
    std::string name;
    std::string argument;
    bool hasPre = false;
    bool hasPost = false;
};

struct VisitFunctionInfoLess
{
    bool operator()( const VisitFunctionInfo& l, const VisitFunctionInfo& r ) const
    {
        return l.name < r.name;
    }
};

struct TraverseFunctionInfoLess
{
    bool operator()( const TraverseFunctionInfo& l, const TraverseFunctionInfo& r ) const
    {
        return l.name < r.name;
    }
};


// Information about each LO plugin.
struct PluginInfo
{
    std::string className; // e.g. "BadStatics"
    std::string variableName; // e.g. "badStatics"
    std::string lowercaseName;
    bool shouldVisitTemplateInstantiations;
    bool shouldVisitImplicitCode;
    std::set< VisitFunctionInfo, VisitFunctionInfoLess > visitFunctions;
    std::set< TraverseFunctionInfo, TraverseFunctionInfoLess > traverseFunctions;
};

// We need separate visitors for shouldVisitTemplateInstantiations and shouldVisitImplicitCode,
// so split plugins into groups by what they should visit.
// It seems that trying to handle the shouldVisit* functionality with just one visitor
// is tricky.
enum PluginType
{
    PluginBasic,
    PluginVisitTemplates,
    PluginVisitImplicit,
    PluginVisitTemplatesImplicit,
};

const int Plugin_Begin = PluginBasic;
const int Plugin_End = PluginVisitTemplatesImplicit + 1;
static const charconst pluginTypeNames[ Plugin_End ]
    = { "Basic""VisitTemplates""VisitImplicit""VisitTemplatesImplicit" };

static std::vector< PluginInfo > plugins[ Plugin_End ];


void generateVisitor( PluginType type );

void generate()
{
    std::ostream& output = std::cout;
    output <<
"// This file is autogenerated. Do not modify.\n"
"// Generated by compilerplugins/clang/sharedvisitor/generator.cxx .\n"
"\n"
"#ifdef LO_CLANG_SHARED_PLUGINS\n"
"\n"
"#include \n"
"\n"
"#include \n"
"#include \n"
"\n"
"#include \"plugin.hxx\"\n"
"#include \"sharedvisitor/dummyplugin.hxx\"\n"
"\n";

    output << "#undef LO_CLANG_SHARED_PLUGINS // to get sources of individual plugins\n";
    output << "// make use of the dummy base classes\n";
    output << "#define RecursiveASTVisitor DummyRecursiveASTVisitor\n";
    output << "#define FilteringPlugin DummyFilteringPlugin\n";
    output << "#define FilteringRewritePlugin DummyFilteringRewritePlugin\n";
    output << "\n";
    forconst auto& pluginGroup : plugins )
        forconst PluginInfo& plugin : pluginGroup )
            output << "#include \"" << plugin.lowercaseName << ".cxx\"" << std::endl;
    output << "\n";
    output << "#undef RecursiveASTVisitor\n";
    output << "#undef FilteringPlugin\n";
    output << "#undef FilteringRewritePlugin\n";

    output <<
"\n"
"using namespace clang;\n"
"using namespace llvm;\n"
"\n"
"namespace loplugin\n"
"{\n";

    forint type = Plugin_Begin; type < Plugin_End; ++type )
        generateVisitor( static_cast< PluginType >( type ));

    output <<
"} // namespace loplugin\n"
"\n"
"#endif // LO_CLANG_SHARED_PLUGINS\n";
}

void generateVisitor( PluginType type )
{
    if( plugins[ type ].empty())
        return;
    std::ostream& output = std::cout;
    output <<
"\n"
"class SharedRecursiveASTVisitor" << pluginTypeNames[ type ] << "\n"
" : public FilteringPlugin< SharedRecursiveASTVisitor" << pluginTypeNames[ type ] << ">\n"
"{\n"
"public:\n"
" explicit SharedRecursiveASTVisitor" << pluginTypeNames[ type ] << "(const InstantiationData& rData)\n"
" : FilteringPlugin(rData)\n";
    forconst PluginInfo& plugin : plugins[ type ] )
        output << " , " << plugin.variableName << "( nullptr )\n";
    output << " , activeRefCount( 0 )\n";
    output << " {}\n";

    output <<
" ~SharedRecursiveASTVisitor" << pluginTypeNames[ type ] << "()\n"
" {\n"
" if( activeRefCount != 0 )\n"
" abort();\n"
" }\n";

    output <<
" virtual bool preRun() override\n"
" {\n";
    forconst PluginInfo& plugin : plugins[ type ] )
    {
        output << " if( " << plugin.variableName << " && !" << plugin.variableName << "->preRun())\n";
        // This will disable the plugin for the rest of the run.
        output << " " << plugin.variableName << " = nullptr;\n";
    }
    output <<
" return anyPluginActive();\n"
" }\n";

    output <<
" virtual void postRun() override\n"
" {\n";
    forconst PluginInfo& plugin : plugins[ type ] )
    {
        output << " if( " << plugin.variableName << " )\n";
        output << " " << plugin.variableName << "->postRun();\n";
    }
    output <<
" }\n";

    output <<
" virtual void run() override {\n"
" if (preRun()) {\n"
" TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());\n"
" postRun();\n"
" }\n"
" }\n"
" enum { isSharedPlugin = true };\n";

    output <<
" virtual bool setSharedPlugin( Plugin* plugin, const char* name ) override\n"
" {\n";
    bool first = true;
    forconst PluginInfo& plugin : plugins[ type ] )
    {
        output << " ";
        if( !first )
            output << "else ";
        first = false;
        output << "if( strcmp( name, \"" << plugin.lowercaseName << "\" ) == 0 )\n";
        output << " " << plugin.variableName << " = static_cast< " << plugin.className << "* >( plugin );\n";
    }
    output <<
" else\n"
" return false;\n"
" return true;\n"
" }\n";

    if( type == PluginVisitTemplates || type == PluginVisitTemplatesImplicit )
        output << "bool shouldVisitTemplateInstantiations() const { return true; }\n";
    if( type == PluginVisitImplicit || type == PluginVisitTemplatesImplicit )
        output << "bool shouldVisitImplicitCode() const { return true; }\n";

    std::set< VisitFunctionInfo, VisitFunctionInfoLess > visitFunctions;
    forconst PluginInfo& plugin : plugins[ type ] )
        forconst VisitFunctionInfo& visit : plugin.visitFunctions )
            visitFunctions.insert( visit );
    forconst VisitFunctionInfo& visit : visitFunctions )
    {
        output << " bool " << visit.name << "(" << visit.argument << " arg)\n";
        output <<
" {\n"
" if( ignoreLocation( arg ))\n"
" return true;\n";
        forconst PluginInfo& plugin : plugins[ type ] )
        {
            if( plugin.visitFunctions.find( visit ) == plugin.visitFunctions.end())
                continue;
            output << " if( " << plugin.variableName << " != nullptr ";
            output << ")\n";
            output << " {\n";
            output << " if( !" << plugin.variableName << "->" << visit.name << "( arg ))\n";
            // This will disable the plugin for the rest of the run (as would returning false
            // from Visit* normally do in the non-shared case).
            output << " " << plugin.variableName << " = nullptr;\n";
            output << " }\n";
        }
        output <<
" return anyPluginActive();\n"
" }\n";
    }

    std::set< TraverseFunctionInfo, TraverseFunctionInfoLess > traverseFunctions;
    forconst PluginInfo& plugin : plugins[ type ] )
        forconst TraverseFunctionInfo& traverse : plugin.traverseFunctions )
            traverseFunctions.insert( traverse );
    forconst TraverseFunctionInfo& traverse : traverseFunctions )
    {
        output << " bool " << traverse.name << "(" << traverse.argument << " arg)\n";
        output << " {\n";
        forconst PluginInfo& plugin : plugins[ type ] )
        {
            auto pluginTraverse = plugin.traverseFunctions.find( traverse );
            if( pluginTraverse == plugin.traverseFunctions.end())
                continue;
            output << " " << plugin.className << "* save" << plugin.className << " = " << plugin.variableName << ";\n";
            if( pluginTraverse->hasPre )
            {
                output << " if( " << plugin.variableName << " != nullptr ";
                output << ")\n";
                output << " {\n";
                output << " if( !" << plugin.variableName << "->Pre" << traverse.name << "( arg ))\n";
                // This will disable the plugin for the time of the traverse, until restored later,
                // just like directly returning from Traverse* would skip that part.
                output << " {\n";
                output << " " << plugin.variableName << " = nullptr;\n";
                output << " ++activeRefCount;\n";
                output << " }\n";
                output << " }\n";
            }
        }
        output << " bool ret = RecursiveASTVisitor::" << traverse.name << "( arg );\n";
        forconst PluginInfo& plugin : plugins[ type ] )
        {
            auto pluginTraverse = plugin.traverseFunctions.find( traverse );
            if( pluginTraverse == plugin.traverseFunctions.end())
                continue;
            if( pluginTraverse->hasPost )
            {
                output << " if( " << plugin.variableName << " != nullptr ";
                output << ")\n";
                output << " {\n";
                output << " if( !" << plugin.variableName << "->Post" << traverse.name << "( arg, ret ))\n";
                // This will disable the plugin for the rest of the run.
                output << " save" << plugin.className << " = nullptr;\n";
                output << " }\n";
            }
            output << " if( " << plugin.variableName << " == nullptr && save" << plugin.className << " != nullptr )\n";
            output << " --activeRefCount;\n";
            output << " " << plugin.variableName << " = save" << plugin.className << ";\n";
        }
        output << " if( false ) // silence -Wunused-function warnings\n";
        output << " {\n";
        forconst PluginInfo& plugin : plugins[ type ] )
        {
            auto pluginTraverse = plugin.traverseFunctions.find( traverse );
            if( pluginTraverse == plugin.traverseFunctions.end())
                continue;
            output << " " << plugin.variableName << "->" << pluginTraverse->name << "( arg );\n";
        }
        output << " }\n";
        output << " return ret;\n";
        output << " }\n";
    }

    output <<
"private:\n";

    output <<
" bool anyPluginActive() const\n"
" {\n"
" return activeRefCount > 0";
    forconst PluginInfo& plugin : plugins[ type ] )
        output << "\n || " << plugin.variableName << " != nullptr";
    output << ";\n";
    output << " }\n";

    forconst PluginInfo& plugin : plugins[ type ] )
        output << " " << plugin.className << "* " << plugin.variableName << ";\n";
    output << " int activeRefCount;\n";

    output <<
"};\n"
"\n"
"loplugin::Plugin::Registration< SharedRecursiveASTVisitor" << pluginTypeNames[ type ]
    << " > registration" << pluginTypeNames[ type ] << "(\"sharedvisitor" << pluginTypeNames[ type ] << "\");\n"
"\n";
}

static std::string getValue( const std::string& line, const char* tag )
{
    size_t taglen = strlen( tag );
    if( line.size() < taglen + 2 )
        return std::string();
    if( line.compare( 0, taglen, tag ) != 0 )
        return std::string();
    if( line[ taglen ] != ':' )
        return std::string();
    return line.substr( taglen + 1 );
}

static bool readFile( const std::string& fileName )
{
    std::ifstream file( fileName );
    if( !file )
    {
        std::cerr << "Cannot open file " << fileName << std::endl;
        return false;
    }
    PluginInfo pluginInfo;
    std::string line;
    do
    {
        getline( file, line );
    } while( !line.empty() && line[ 0 ] == '#' );
    std::string version = getValue( line, "InfoVersion" );
    if( version != "1" )
    {
        std::cerr << "Incorrect version '" << version << "' in " << fileName << std::endl;
        return false;
    }
    getline( file, line );
    pluginInfo.className = getValue( line, "ClassName" );
    pluginInfo.variableName = pluginInfo.className;
    assert( pluginInfo.variableName.size() > 0 );
    pluginInfo.variableName[ 0 ] = tolower( pluginInfo.variableName[ 0 ] );
    pluginInfo.lowercaseName = pluginInfo.className;
    forchar& c : pluginInfo.lowercaseName )
        c = tolower( c );
    pluginInfo.shouldVisitTemplateInstantiations = false;
    pluginInfo.shouldVisitImplicitCode = false;
    bool endOk = false;
    for(;;)
    {
        std::string line;
        getline( file, line );
        if( file.eof() || !file )
        {
            std::cerr << "Unexpected end of file" << std::endl;
            return false;
        }
        if( line.empty())
            continue;
        if( line == "InfoEnd" )
        {
            endOk = true;
            break;
        }
        else if( line == "VisitFunctionStart" )
        {
            VisitFunctionInfo visitInfo;
            getline( file, line );
            visitInfo.name = getValue( line, "VisitFunctionName" );
            getline( file, line );
            visitInfo.argument = getValue( line, "VisitFunctionArgument" );
            getline( file, line );
            if( line != "VisitFunctionEnd" )
            {
                std::cerr << "Missing VisitFunctionEnd" << std::endl;
                return false;
            }
            pluginInfo.visitFunctions.insert( std::move( visitInfo ));
        }
        else if( line == "TraverseFunctionStart" )
        {
            TraverseFunctionInfo traverseInfo;
            getline( file, line );
            traverseInfo.name = getValue( line, "TraverseFunctionName" );
            getline( file, line );
            traverseInfo.argument = getValue( line, "TraverseFunctionArgument" );
            getline( file, line );
            traverseInfo.hasPre = getValue( line, "TraverseFunctionHasPre" ) == "1";
            getline( file, line );
            traverseInfo.hasPost = getValue( line, "TraverseFunctionHasPost" ) == "1";
            getline( file, line );
            if( line != "TraverseFunctionEnd" )
            {
                std::cerr << "Missing TraverseFunctionEnd" << std::endl;
                return false;
            }
            pluginInfo.traverseFunctions.insert( std::move( traverseInfo ));
        }
        else
        {
            std::string value;
            value = getValue( line, "ShouldVisitTemplateInstantiations" );
            if( value == "1" )
                pluginInfo.shouldVisitTemplateInstantiations = true;
            else
            {
                value = getValue( line, "ShouldVisitImplicitCode" );
                if( value == "1" )
                    pluginInfo.shouldVisitImplicitCode = true;
                else
                {
                    std::cerr << "Unknown line " << line << std::endl;
                    return false;
                }
            }
        }
    }

    assert( endOk );
    (void)endOk;

    if( pluginInfo.shouldVisitTemplateInstantiations && pluginInfo.shouldVisitImplicitCode )
        plugins[ PluginVisitTemplatesImplicit ].push_back( std::move( pluginInfo ));
    else if( pluginInfo.shouldVisitTemplateInstantiations )
        plugins[ PluginVisitTemplates ].push_back( std::move( pluginInfo ));
    else if( pluginInfo.shouldVisitImplicitCode )
        plugins[ PluginVisitImplicit ].push_back( std::move( pluginInfo ));
    else
        plugins[ PluginBasic ].push_back( std::move( pluginInfo ));

    return true;
}

int main(int argc, char** argv)
{
    forint i = 1 ; i < argc; ++i )
    {
        if( !readFile( argv[ i ] ))
        {
            std::cerr << "Error reading " << argv[ i ] << std::endl;
            return 1;
        }
    }
    forint type = Plugin_Begin; type < Plugin_End; ++type )
    {
        sort( plugins[ static_cast< PluginType >( type ) ].begin(), plugins[ static_cast< PluginType >( type ) ].end(),
            []( const PluginInfo& l, const PluginInfo& r ) { return l.className < r.className; } );
    }
    generate();
    return 0;
}

Messung V0.5
C=97 H=86 G=91

¤ Dauer der Verarbeitung: 0.33 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.