/* 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); }