xaizek / gcc-plugins (License: GPLv3+) (since 2018-12-07)
Some GCC plugins (actually only one was uploaded so far, and its functionality is not unique).
<root> / inc-tree / inc-tree.cpp (d90a0d1201a354e23e4370535955ec92965a0256) (3,636B) (mode 100644) [raw]
// Copyright (C) 2015 xaizek <xaizek@openmailbox.org>
//
// This plugin is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The plugin is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with the plugin.  If not, see <http://www.gnu.org/licenses/>.

#include <cstring>

#include <iostream>
#include <string>
#include <vector>

#include <gcc-plugin.h>

#include <input.h>
#include <c-family/c-pragma.h>

#include "IncTree.hpp"

static void includeCallback(void *includeName, void *userData);
static void finishCallback(void *gccData, void *userData);

extern "C"
{
    /**
     * @brief Confirms GCC that we comply to GPL.
     */
    int plugin_is_GPL_compatible = 1;
}

/**
 * @brief Name of the plugin.
 */
static const char *const PLUGIN_NAME = "inc-tree";

/**
 * @brief Generic information about the plugin.
 */
static plugin_info helpInfo = {
    .version = "0.1",
    .help = "Prints tree of includes",
};

/**
 * @brief Plugin version requirements.
 */
static plugin_gcc_version pluginVer = {
    .basever = "4.9",
};

/**
 * @brief Object that builds the tree.
 */
static IncTree incTree;

/**
 * @brief Plugin entry point.
 *
 * @param info Argument information.
 * @param ver Version info of GCC.
 *
 * @returns @c 0 on success or error code on failure.
 */
int
plugin_init(struct plugin_name_args *info, struct plugin_gcc_version *ver)
{
    // Validate the version information without plugin_default_version_check().
    if (std::strncmp(ver->basever, pluginVer.basever,
                     std::strlen(pluginVer.basever)) < 0) {
        // Incorrect version of GCC.
        return -1;
    }

    // Provide plugin information for --help and --version.
    register_callback(PLUGIN_NAME, PLUGIN_INFO, nullptr, &helpInfo);

    // Setup callback for each #include (and #line) directive.
    register_callback(PLUGIN_NAME, PLUGIN_INCLUDE_FILE, &includeCallback,
                      nullptr);

    // Setup callback that will print out results.
    register_callback(PLUGIN_NAME, PLUGIN_FINISH, &finishCallback, &helpInfo);

    return 0;
}

/**
 * @brief Callback which is called for @c #include and @c #line directives.
 *
 * @param includeName Name of include.
 * @param userData User-provided data.
 */
static void
includeCallback(void */*includeName*/, void */*userData*/)
{
    cpp_buffer *curr = cpp_get_buffer(parse_in);

    // Register root source files as no other files include them, but we want
    // to have them in the output even in the absence on any includes.
    if (cpp_get_prev(curr) == nullptr) {
        incTree.addUnit(cpp_get_path(cpp_get_file(curr)));
        return;
    }

    std::vector<std::string> includeTrail;

    do {
        includeTrail.push_back(cpp_get_path(cpp_get_file(curr)));
        curr = cpp_get_prev(curr);
    } while (curr != nullptr);

    // Not using std::reverse() as there are poisoned symbols.
    incTree.addIncludeTrail({ includeTrail.rbegin(), includeTrail.rend() });
}

/**
 * @brief Callback which is called before GCC quits.
 *
 * @param gccData Unused GCC-provided data.
 * @param userData User-provided data.
 */
static void
finishCallback(void */*gccData*/, void */*userData*/)
{
    std::cout << incTree;
}
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/gcc-plugins

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/gcc-plugins

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master