Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  analyzer.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 "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/StringExtras.h"

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

#include "config_clang.h"
#include "../check.hxx"
#include "../check.cxx"
#include "../compat.hxx"

using namespace clang;
using namespace llvm;

using namespace loplugin;

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

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

static std::set< TraverseFunctionInfo, TraverseFunctionInfoLess > traverseFunctions;

class CheckFileVisitor
    : public RecursiveASTVisitor< CheckFileVisitor >
{
public:
    void setContext(ASTContext const& context) { context_ = &context; }

    bool VisitCXXRecordDecl(CXXRecordDecl *Declaration);

    bool TraverseNamespaceDecl(NamespaceDecl * decl)
    {
        // Skip non-LO namespaces the same way FilteringPlugin does.
        if( !ContextCheck( decl ).Namespace"loplugin" ).GlobalNamespace()
            && !ContextCheck( decl ).AnonymousNamespace())
        {
            return true;
        }
        return RecursiveASTVisitor<CheckFileVisitor>::TraverseNamespaceDecl(decl);
    }

private:
    ASTContext const* context_ = nullptr;

    QualType unqualifyPointeeType(QualType type)
    {
        assert(context_ != nullptr);
        if (auto const t = type->getAs<clang::PointerType>())
        {
            return context_->getQualifiedType(
                context_->getPointerType(t->getPointeeType().getUnqualifiedType()),
                type.getQualifiers());
        }
        return type;
    }
};

static bool inheritsPluginClassCheck( const Decl* decl )
{
    return bool( DeclCheck( decl ).Class"FilteringPlugin" ).Namespace"loplugin" ).GlobalNamespace())
        || bool( DeclCheck( decl ).Class"FilteringRewritePlugin" ).Namespace"loplugin" ).GlobalNamespace());
}

static TraverseFunctionInfo findOrCreateTraverseFunctionInfo( StringRef name )
{
    TraverseFunctionInfo info;
    info.name = name.str();
    auto foundInfo = traverseFunctions.find( info );
    if( foundInfo != traverseFunctions.end())
    {
        info = std::move( *foundInfo );
        traverseFunctions.erase( foundInfo );
    }
    return info;
}

static bool foundSomething;

bool CheckFileVisitor::VisitCXXRecordDecl( CXXRecordDecl* decl )
{
    if( !isDerivedFrom( decl, inheritsPluginClassCheck ))
        return true;

    if( decl->getName() == "FilteringPlugin" || decl->getName() == "FilteringRewritePlugin" )
        return true;

    std::cout << "# This file is autogenerated. Do not modify." << std::endl;
    std::cout << "# Generated by compilerplugins/clang/sharedvisitor/analyzer.cxx ." << std::endl;
    std::cout << "InfoVersion:1" << std::endl;
    std::cout << "ClassName:" << decl->getName().str() << std::endl;
    traverseFunctions.clear();
    forconst CXXMethodDecl* method : decl->methods())
    {
        if( !method->getDeclName().isIdentifier())
            continue;
        if( method->isStatic() || method->getAccess() != AS_public )
            continue;
        if( compat::starts_with(method->getName(), "Visit" ))
        {
            if( method->getNumParams() == 1 )
            {
                std::cout << "VisitFunctionStart" << std::endl;
                std::cout << "VisitFunctionName:" << method->getName().str() << std::endl;
                std::cout << "VisitFunctionArgument:"
                    << unqualifyPointeeType(
                        method->getParamDecl( 0 )->getTypeSourceInfo()->getType()).getAsString()
                    << std::endl;
                std::cout << "VisitFunctionEnd" << std::endl;
            }
            else
            {
                std::cerr << "Unhandled Visit* function: " << decl->getName().str()
                     << "::" << method->getName().str() << std::endl;
                abort();
            }
        }
        else if( compat::starts_with(method->getName(), "Traverse" ))
        {
            if( method->getNumParams() == 1 )
            {
                TraverseFunctionInfo traverseInfo = findOrCreateTraverseFunctionInfo( method->getName());
                traverseInfo.argument = method->getParamDecl( 0 )->getTypeSourceInfo()->getType().getAsString();
                traverseFunctions.insert( std::move( traverseInfo ));
            }
            else
            {
                std::cerr << "Unhandled Traverse* function: " << decl->getName().str()
                     << "::" << method->getName().str() << std::endl;
                abort();
            }
        }
        else if( compat::starts_with(method->getName(), "PreTraverse" ))
        {
            TraverseFunctionInfo traverseInfo = findOrCreateTraverseFunctionInfo( method->getName().substr( 3 ));
            traverseInfo.hasPre = true;
            traverseFunctions.insert( std::move( traverseInfo ));
        }
        else if( compat::starts_with(method->getName(), "PostTraverse" ))
        {
                TraverseFunctionInfo traverseInfo = findOrCreateTraverseFunctionInfo( method->getName().substr( 4 ));
                traverseInfo.hasPost = true;
                traverseFunctions.insert( std::move( traverseInfo ));
        }
        else if( method->getName() == "shouldVisitTemplateInstantiations" )
            std::cout << "ShouldVisitTemplateInstantiations:1" << std::endl;
        else if (method->getName() == "shouldVisitImplicitCode")
            std::cout << "ShouldVisitImplicitCode:1" << std::endl;
        else if( compat::starts_with(method->getName(), "WalkUp" ))
        {
            std::cerr << "WalkUp function not supported for shared visitor: " << decl->getName().str()
                 << "::" << method->getName().str() << std::endl;
            abort();
        }
    }

    forconst auto& traverseFunction : traverseFunctions )
    {
        std::cout << "TraverseFunctionStart" << std::endl;
        std::cout << "TraverseFunctionName:" << traverseFunction.name << std::endl;
        std::cout << "TraverseFunctionArgument:" << traverseFunction.argument << std::endl;
        std::cout << "TraverseFunctionHasPre:" << traverseFunction.hasPre << std::endl;
        std::cout << "TraverseFunctionHasPost:" << traverseFunction.hasPost << std::endl;
        std::cout << "TraverseFunctionEnd" << std::endl;
    }

    std::cout << "InfoEnd" << std::endl;
    foundSomething = true;
    return true;
}

class FindNamedClassConsumer
    : public ASTConsumer
{
public:
    void Initialize(ASTContext& context) override
    {
        visitor.setContext(context);
    }
    virtual void HandleTranslationUnit(ASTContext& context) override
    {
        visitor.TraverseDecl( context.getTranslationUnitDecl());
    }
private:
    CheckFileVisitor visitor;
};

class FindNamedClassAction
    : public ASTFrontendAction
    {
public:
    virtual std::unique_ptr<ASTConsumer> CreateASTConsumer( CompilerInstance&, StringRef ) override
    {
        return std::unique_ptr<ASTConsumer>( new FindNamedClassConsumer );
    }
};


std::string readSourceFile( const char* filename )
{
    std::string contents;
    std::ifstream stream( filename );
    if( !stream )
    {
        std::cerr << "Failed to open: " << filename << std::endl;
        exit( 1 );
    }
    std::string line;
    bool hasIfdef = false;
    while( getline( stream, line ))
    {
        // TODO add checks that it's e.g. not "#ifdef" ?
        if( line.find( "#ifndef LO_CLANG_SHARED_PLUGINS" ) == 0 )
            hasIfdef = true;
        contents += line;
        contents += '\n';
    }
    if( stream.eof() && hasIfdef )
        return contents;
    return "";
}

int main(int argc, char** argv)
{
    std::vector< std::string > args;
    int i = 1;
    for( ; i < argc; ++ i )
    {
        constexpr std::size_t prefixlen = 5; // strlen("-arg=");
        if (std::strncmp(argv[i], "-arg=", prefixlen) != 0)
        {
            break;
        }
        args.push_back(argv[i] + prefixlen);
    }
    SmallVector< StringRef, 20 > clangflags;
    SplitString( CLANGFLAGS, clangflags );
    for (auto const & i: clangflags) {
        args.push_back(i.str());
    }
    args.insert(
        args.end(),
        {   // These must match LO_CLANG_ANALYZER_PCH_CXXFLAGS in Makefile-clang.mk .
            "-I" BUILDDIR "/config_host" // plugin sources use e.g. config_global.h
#if LO_CLANG_USE_ANALYZER_PCH
            ,
            "-include-pch"// use PCH with Clang headers to speed up parsing/analysing
            BUILDDIR "/compilerplugins/clang/sharedvisitor/clang.pch"
#endif
        });
    for( ; i < argc; ++ i )
    {
        std::string contents = readSourceFile(argv[i]);
        if( contents.empty())
            continue;
        foundSomething = false;
        if( !tooling::runToolOnCodeWithArgs( std::unique_ptr<FindNamedClassAction>(new FindNamedClassAction), contents, args, argv[ i ] ))
        {
            std::cerr << "Failed to analyze: " << argv[ i ] << std::endl;
            return 2;
        }
        if( !foundSomething )
        {
            // there's #ifndef LO_CLANG_SHARED_PLUGINS in the source, but no class matched
            std::cerr << "Failed to find code: " << argv[ i ] << std::endl;
            return 2;
        }
    }
    return 0;
}

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

¤ Dauer der Verarbeitung: 0.12 Sekunden  (vorverarbeitet)  ¤

*© 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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge