Hi,
A couple of days ago i was asking:
does any frontend support some sort of noting that a user-header was
included but no decl of it was ever referenced (i.e. superfluous
#include) ?
I could not find an appropriate tool to diagnose them, so i was thinking
about a gcc plugin to do that.
Would some plugin like the attached be suitable to put into svn if
cleaned up a bit?
If so, where would they live?
Observations while thinking about all this:
- libcpp does not record LC_PSEUDO_ENTER (or something like that),
so pristine libcpp cannot detect duplicate includes, like iostream
in attached sample input.cc
- should figure out how to print a help-text for the plugin
Hints?
- should handle structs.
Thanks in advance for hints on the help-text printing or comments about
the overall idea of such a facility.
/* Dump superfluous, missing or duplicate includes.
*
* Copyright (C) 2010 Bernhard Reutner-Fischer
*/
/*
This file is part of GCC.
GCC 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, or (at your option) any later
version.
GCC 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 GCC; see the file COPYING3. If not see
http://www.gnu.org/licenses/. */
#include config.h
#include system.h
#include gcc-plugin.h
#include coretypes.h
#include tree.h
#include tree-iterator.h
#include tree-pass.h
#include intl.h
#include line-map.h
#include langhooks.h
#include target.h
#include toplev.h /* warning_at */
//#define info warning
#define info(...) /**/
typedef struct include_t {
struct include_t *next;
const char *filename;
source_location location;
} include_t;
static include_t *incs = NULL, *referenced = NULL;
static bool warn_missing;
static bool warn_surplus;
/* Add filename to the end of the include list. */
static void __attribute__ ((__nonnull__ (2)))
add_include (include_t **head, const char *filename, const source_location loc,
const bool mainfile)
{
include_t *tail, *elt;
if (filename == NULL)
gcc_unreachable ();
tail = *head;
while (1)
{
if (tail strcmp (tail-filename, filename) == 0)
{
const bool old_warn_system_headers = warn_system_headers;
warn_system_headers = 1; /* to please warning_at */
if (tail-location != loc mainfile warn_surplus)
warning_at (loc, 0, Duplicate include %s, filename);
warn_system_headers = old_warn_system_headers;
return; /* don't enter duplicate */
}
if (tail tail-next)
tail = tail-next;
else
break;
}
info (0, ADDING %s, filename);
elt = XNEW (include_t);
elt-filename = filename;
elt-location = loc;
elt-next = NULL;
if (tail)
tail-next = elt;
else
*head = elt;
}
/* Remove filename from the include list. */
static void __attribute__ ((__nonnull__ (2)))
remove_include (include_t **head, const char *filename)
{
bool seen;
if (filename == NULL)
gcc_unreachable ();
seen = false;
while (*head)
{
if (strcmp ((*head)-filename, filename) == 0)
{
include_t *delete = *head;
info (0, REMOVE %s, filename);
*head = (*head)-next;
XDELETE (delete);
seen = true;
break;
}
head = (*head)-next;
}
if (!seen warn_missing)
warning (0, Missing include %s, filename);
}
/* Callback function to invoke after GCC finishes parsing a struct. */
void
handle_struct (void *event_data, void *user_data)
{
tree type = (tree) event_data;
if (type == error_mark_node)
return;
warning (0, G_(Process struct %s),
IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type;
}
static void
fn_add_includes (tree fndecl, const bool mainfile)
{
tree decl, type;
const struct line_map *map;
map = linemap_lookup (line_table, DECL_SOURCE_LOCATION (fndecl));
if (!MAIN_FILE_P (map))
{
source_location loc = DECL_SOURCE_LOCATION (fndecl);
info (0,fn %s: %s, lang_hooks.decl_printable_name (fndecl, 3), LOCATION_FILE (DECL_SOURCE_LOCATION (fndecl)));
add_include (referenced, LOCATION_FILE (loc), loc, mainfile);
}
for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl))
{
map = linemap_lookup (line_table, DECL_SOURCE_LOCATION (decl));
if (!MAIN_FILE_P (map))
{
source_location loc = DECL_SOURCE_LOCATION (decl);
info (0,fn arg %s: %s, lang_hooks.decl_printable_name (decl, 3), LOCATION_FILE (DECL_SOURCE_LOCATION (decl)));
add_include (referenced,
LOCATION_FILE (loc),
loc,
false);
}
}
}
static void debug_location (location_t l)
{
fprintf (stderr, LOCATION_FILE=%s\n, LOCATION_FILE (l));
}
static void
operands_add_includes (tree decl, location_t decl_loc, const bool mainfile)
{