/* Support for suggestions about missing #include directives.
Copyright (C) 2017-2020 Free Software Foundation, Inc.
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
. */
#include "config.h"
#define INCLUDE_UNIQUE_PTR
#include "system.h"
#include "coretypes.h"
#include "c-family/c-common.h"
#include "c-family/name-hint.h"
#include "c-family/known-headers.h"
#include "gcc-rich-location.h"
/* An enum for distinguishing between the C and C++ stdlibs. */
enum stdlib
{
STDLIB_C,
STDLIB_CPLUSPLUS,
NUM_STDLIBS
};
/* A struct for associating names in a standard library with the header
that should be included to locate them, for each of the C and C++ stdlibs
(or NULL, for names that aren't in a header for a particular stdlib). */
struct stdlib_hint
{
const char *name;
const char *header[NUM_STDLIBS];
};
/* Given non-NULL NAME, return the header name defining it within either
the standard library (with '<' and '>'), or NULL.
Only handles a subset of the most common names within the stdlibs. */
static const char *
get_stdlib_header_for_name (const char *name, enum stdlib lib)
{
gcc_assert (name);
gcc_assert (lib < NUM_STDLIBS);
static const stdlib_hint hints[] = {
/* and . */
{"assert", {"", ""} },
/* and . */
{"errno", {"", ""} },
/* and . */
{"CHAR_BIT", {"", ""} },
{"CHAR_MAX", {"", ""} },
{"CHAR_MIN", {"", ""} },
{"INT_MAX", {"", ""} },
{"INT_MIN", {"", ""} },
{"LLONG_MAX", {"", ""} },
{"LLONG_MIN", {"", ""} },
{"LONG_MAX", {"", ""} },
{"LONG_MIN", {"", ""} },
{"MB_LEN_MAX", {"", ""} },
{"SCHAR_MAX", {"", ""} },
{"SCHAR_MIN", {"", ""} },
{"SHRT_MAX", {"", ""} },
{"SHRT_MIN", {"", ""} },
{"UCHAR_MAX", {"", ""} },
{"UINT_MAX", {"", ""} },
{"ULLONG_MAX", {"", ""} },
{"ULONG_MAX", {"", ""} },
{"USHRT_MAX", {"", ""} },
/* and . */
{"DBL_MAX", {"", ""} },
{"DBL_MIN", {"", ""} },
{"FLT_MAX", {"", ""} },
{"FLT_MIN", {"", ""} },
{"LDBL_MAX", {"", ""} },
{"LDBL_MIN", {"", ""} },
/* and . */
{"va_list", {"", ""} },
/* and . */
{"NULL", {"", ""} },
{"nullptr_t", {NULL, ""} },
{"offsetof", {"", ""} },
{"ptrdiff_t", {"", ""} },
{"size_t", {"", ""} },
{"wchar_t", {"", NULL /* a keyword in C++ */} },
/* and . */
{"BUFSIZ", {"", ""} },
{"EOF", {"", ""} },
{"FILE", {"", ""} },
{"FILENAME_MAX", {"", ""} },
{"fopen", {"", ""} },
{"fpos_t", {"", ""} },
{"getchar", {"", ""} },
{"printf", {"", ""} },
{"snprintf", {"", ""} },
{"sprintf", {"", ""} },
{"stderr", {"", ""} },
{"stdin", {"", ""} },
{"stdout", {"", ""} },
/* and . */
{"free", {"", ""} },
{"malloc", {"", ""} },
{"realloc", {"", ""} },
/* and . */
{"memchr", {"", ""} },
{"memcmp", {"", ""} },
{"memcpy", {"", ""} },
{"memmove", {"", ""} },
{"memset", {"", ""} },
{"strcat", {"", ""} },
{"strchr", {"", ""} },
{"strcmp", {"", ""} },
{"strcpy", {"", ""} },
{"strlen", {"", ""} },
{"strncat", {"", ""} },
{"strncmp", {"", ""} },
{"strncpy", {"", ""} },
{"strrchr", {"", ""} },
{"strspn", {"", ""} },
{"strstr", {"", ""} },
/* . */
{"PTRDIFF_MAX", {"", ""} },
{"PTRDIFF_MIN", {"", ""} },
{"SIG_ATOMIC_MAX", {"", ""} },
{"SIG_ATOMIC_MIN", {"", ""} },
{"SIZE_MAX", {"", ""} },
{"WINT_MAX", {"", ""} },
{"WINT_MIN", {"", ""} },
/* . */
{"WCHAR_MAX", {"", ""} },
{"WCHAR_MIN", {"", ""} }
};
const size_t num_hints = sizeof (hints) / sizeof (hints[0]);
for (size_t i = 0; i < num_hints; i++)
if (strcmp (name, hints[i].name) == 0)
return hints[i].header[lib];
return NULL;
}
/* Given non-NULL NAME, return the header name defining it within the C
standard library (with '<' and '>'), or NULL. */
const char *
get_c_stdlib_header_for_name (const char *name)
{
return get_stdlib_header_for_name (name, STDLIB_C);
}
/* Given non-NULL NAME, return the header name defining it within the C++
standard library (with '<' and '>'), or NULL. */
const char *
get_cp_stdlib_header_for_name (const char *name)
{
return get_stdlib_header_for_name (name, STDLIB_CPLUSPLUS);
}
/* Implementation of class suggest_missing_header. */
/* suggest_missing_header's ctor. */
suggest_missing_header::suggest_missing_header (location_t loc,
const char *name,
const char *header_hint)
: deferred_diagnostic (loc), m_name_str (name), m_header_hint (header_hint)
{
gcc_assert (name);
gcc_assert (header_hint);
}
/* suggest_missing_header's dtor. */
suggest_missing_header::~suggest_missing_header ()
{
if (is_suppressed_p ())
return;
gcc_rich_location richloc (get_location ());
maybe_add_include_fixit (&richloc, m_header_hint, true);
inform (&richloc,
"%qs is defined in header %qs;"
" did you forget to %<#include %s%>?",
m_name_str, m_header_hint, m_header_hint);
}