Path: blob/main/contrib/llvm-project/clang/lib/Basic/DiagnosticIDs.cpp
35233 views
//===--- DiagnosticIDs.cpp - Diagnostic IDs Handling ----------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements the Diagnostic IDs-related interfaces.9//10//===----------------------------------------------------------------------===//1112#include "clang/Basic/DiagnosticIDs.h"13#include "clang/Basic/AllDiagnostics.h"14#include "clang/Basic/DiagnosticCategories.h"15#include "clang/Basic/SourceManager.h"16#include "llvm/ADT/STLExtras.h"17#include "llvm/ADT/SmallVector.h"18#include "llvm/Support/ErrorHandling.h"19#include <map>20#include <optional>21using namespace clang;2223//===----------------------------------------------------------------------===//24// Builtin Diagnostic information25//===----------------------------------------------------------------------===//2627namespace {2829struct StaticDiagInfoRec;3031// Store the descriptions in a separate table to avoid pointers that need to32// be relocated, and also decrease the amount of data needed on 64-bit33// platforms. See "How To Write Shared Libraries" by Ulrich Drepper.34struct StaticDiagInfoDescriptionStringTable {35#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \36SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \37char ENUM##_desc[sizeof(DESC)];38// clang-format off39#include "clang/Basic/DiagnosticCommonKinds.inc"40#include "clang/Basic/DiagnosticDriverKinds.inc"41#include "clang/Basic/DiagnosticFrontendKinds.inc"42#include "clang/Basic/DiagnosticSerializationKinds.inc"43#include "clang/Basic/DiagnosticLexKinds.inc"44#include "clang/Basic/DiagnosticParseKinds.inc"45#include "clang/Basic/DiagnosticASTKinds.inc"46#include "clang/Basic/DiagnosticCommentKinds.inc"47#include "clang/Basic/DiagnosticCrossTUKinds.inc"48#include "clang/Basic/DiagnosticSemaKinds.inc"49#include "clang/Basic/DiagnosticAnalysisKinds.inc"50#include "clang/Basic/DiagnosticRefactoringKinds.inc"51#include "clang/Basic/DiagnosticInstallAPIKinds.inc"52// clang-format on53#undef DIAG54};5556const StaticDiagInfoDescriptionStringTable StaticDiagInfoDescriptions = {57#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \58SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \59DESC,60// clang-format off61#include "clang/Basic/DiagnosticCommonKinds.inc"62#include "clang/Basic/DiagnosticDriverKinds.inc"63#include "clang/Basic/DiagnosticFrontendKinds.inc"64#include "clang/Basic/DiagnosticSerializationKinds.inc"65#include "clang/Basic/DiagnosticLexKinds.inc"66#include "clang/Basic/DiagnosticParseKinds.inc"67#include "clang/Basic/DiagnosticASTKinds.inc"68#include "clang/Basic/DiagnosticCommentKinds.inc"69#include "clang/Basic/DiagnosticCrossTUKinds.inc"70#include "clang/Basic/DiagnosticSemaKinds.inc"71#include "clang/Basic/DiagnosticAnalysisKinds.inc"72#include "clang/Basic/DiagnosticRefactoringKinds.inc"73#include "clang/Basic/DiagnosticInstallAPIKinds.inc"74// clang-format on75#undef DIAG76};7778extern const StaticDiagInfoRec StaticDiagInfo[];7980// Stored separately from StaticDiagInfoRec to pack better. Otherwise,81// StaticDiagInfoRec would have extra padding on 64-bit platforms.82const uint32_t StaticDiagInfoDescriptionOffsets[] = {83#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \84SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \85offsetof(StaticDiagInfoDescriptionStringTable, ENUM##_desc),86// clang-format off87#include "clang/Basic/DiagnosticCommonKinds.inc"88#include "clang/Basic/DiagnosticDriverKinds.inc"89#include "clang/Basic/DiagnosticFrontendKinds.inc"90#include "clang/Basic/DiagnosticSerializationKinds.inc"91#include "clang/Basic/DiagnosticLexKinds.inc"92#include "clang/Basic/DiagnosticParseKinds.inc"93#include "clang/Basic/DiagnosticASTKinds.inc"94#include "clang/Basic/DiagnosticCommentKinds.inc"95#include "clang/Basic/DiagnosticCrossTUKinds.inc"96#include "clang/Basic/DiagnosticSemaKinds.inc"97#include "clang/Basic/DiagnosticAnalysisKinds.inc"98#include "clang/Basic/DiagnosticRefactoringKinds.inc"99#include "clang/Basic/DiagnosticInstallAPIKinds.inc"100// clang-format on101#undef DIAG102};103104// Diagnostic classes.105enum DiagnosticClass {106CLASS_NOTE = 0x01,107CLASS_REMARK = 0x02,108CLASS_WARNING = 0x03,109CLASS_EXTENSION = 0x04,110CLASS_ERROR = 0x05111};112113struct StaticDiagInfoRec {114uint16_t DiagID;115LLVM_PREFERRED_TYPE(diag::Severity)116uint8_t DefaultSeverity : 3;117LLVM_PREFERRED_TYPE(DiagnosticClass)118uint8_t Class : 3;119LLVM_PREFERRED_TYPE(DiagnosticIDs::SFINAEResponse)120uint8_t SFINAE : 2;121uint8_t Category : 6;122LLVM_PREFERRED_TYPE(bool)123uint8_t WarnNoWerror : 1;124LLVM_PREFERRED_TYPE(bool)125uint8_t WarnShowInSystemHeader : 1;126LLVM_PREFERRED_TYPE(bool)127uint8_t WarnShowInSystemMacro : 1;128129uint16_t OptionGroupIndex : 15;130LLVM_PREFERRED_TYPE(bool)131uint16_t Deferrable : 1;132133uint16_t DescriptionLen;134135unsigned getOptionGroupIndex() const {136return OptionGroupIndex;137}138139StringRef getDescription() const {140size_t MyIndex = this - &StaticDiagInfo[0];141uint32_t StringOffset = StaticDiagInfoDescriptionOffsets[MyIndex];142const char* Table = reinterpret_cast<const char*>(&StaticDiagInfoDescriptions);143return StringRef(&Table[StringOffset], DescriptionLen);144}145146diag::Flavor getFlavor() const {147return Class == CLASS_REMARK ? diag::Flavor::Remark148: diag::Flavor::WarningOrError;149}150151bool operator<(const StaticDiagInfoRec &RHS) const {152return DiagID < RHS.DiagID;153}154};155156#define STRINGIFY_NAME(NAME) #NAME157#define VALIDATE_DIAG_SIZE(NAME) \158static_assert( \159static_cast<unsigned>(diag::NUM_BUILTIN_##NAME##_DIAGNOSTICS) < \160static_cast<unsigned>(diag::DIAG_START_##NAME) + \161static_cast<unsigned>(diag::DIAG_SIZE_##NAME), \162STRINGIFY_NAME( \163DIAG_SIZE_##NAME) " is insufficient to contain all " \164"diagnostics, it may need to be made larger in " \165"DiagnosticIDs.h.");166VALIDATE_DIAG_SIZE(COMMON)167VALIDATE_DIAG_SIZE(DRIVER)168VALIDATE_DIAG_SIZE(FRONTEND)169VALIDATE_DIAG_SIZE(SERIALIZATION)170VALIDATE_DIAG_SIZE(LEX)171VALIDATE_DIAG_SIZE(PARSE)172VALIDATE_DIAG_SIZE(AST)173VALIDATE_DIAG_SIZE(COMMENT)174VALIDATE_DIAG_SIZE(CROSSTU)175VALIDATE_DIAG_SIZE(SEMA)176VALIDATE_DIAG_SIZE(ANALYSIS)177VALIDATE_DIAG_SIZE(REFACTORING)178VALIDATE_DIAG_SIZE(INSTALLAPI)179#undef VALIDATE_DIAG_SIZE180#undef STRINGIFY_NAME181182const StaticDiagInfoRec StaticDiagInfo[] = {183// clang-format off184#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \185SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \186{ \187diag::ENUM, \188DEFAULT_SEVERITY, \189CLASS, \190DiagnosticIDs::SFINAE, \191CATEGORY, \192NOWERROR, \193SHOWINSYSHEADER, \194SHOWINSYSMACRO, \195GROUP, \196DEFERRABLE, \197STR_SIZE(DESC, uint16_t)},198#include "clang/Basic/DiagnosticCommonKinds.inc"199#include "clang/Basic/DiagnosticDriverKinds.inc"200#include "clang/Basic/DiagnosticFrontendKinds.inc"201#include "clang/Basic/DiagnosticSerializationKinds.inc"202#include "clang/Basic/DiagnosticLexKinds.inc"203#include "clang/Basic/DiagnosticParseKinds.inc"204#include "clang/Basic/DiagnosticASTKinds.inc"205#include "clang/Basic/DiagnosticCommentKinds.inc"206#include "clang/Basic/DiagnosticCrossTUKinds.inc"207#include "clang/Basic/DiagnosticSemaKinds.inc"208#include "clang/Basic/DiagnosticAnalysisKinds.inc"209#include "clang/Basic/DiagnosticRefactoringKinds.inc"210#include "clang/Basic/DiagnosticInstallAPIKinds.inc"211// clang-format on212#undef DIAG213};214215} // namespace216217static const unsigned StaticDiagInfoSize = std::size(StaticDiagInfo);218219/// GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID,220/// or null if the ID is invalid.221static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {222// Out of bounds diag. Can't be in the table.223using namespace diag;224if (DiagID >= DIAG_UPPER_LIMIT || DiagID <= DIAG_START_COMMON)225return nullptr;226227// Compute the index of the requested diagnostic in the static table.228// 1. Add the number of diagnostics in each category preceding the229// diagnostic and of the category the diagnostic is in. This gives us230// the offset of the category in the table.231// 2. Subtract the number of IDs in each category from our ID. This gives us232// the offset of the diagnostic in the category.233// This is cheaper than a binary search on the table as it doesn't touch234// memory at all.235unsigned Offset = 0;236unsigned ID = DiagID - DIAG_START_COMMON - 1;237#define CATEGORY(NAME, PREV) \238if (DiagID > DIAG_START_##NAME) { \239Offset += NUM_BUILTIN_##PREV##_DIAGNOSTICS - DIAG_START_##PREV - 1; \240ID -= DIAG_START_##NAME - DIAG_START_##PREV; \241}242CATEGORY(DRIVER, COMMON)243CATEGORY(FRONTEND, DRIVER)244CATEGORY(SERIALIZATION, FRONTEND)245CATEGORY(LEX, SERIALIZATION)246CATEGORY(PARSE, LEX)247CATEGORY(AST, PARSE)248CATEGORY(COMMENT, AST)249CATEGORY(CROSSTU, COMMENT)250CATEGORY(SEMA, CROSSTU)251CATEGORY(ANALYSIS, SEMA)252CATEGORY(REFACTORING, ANALYSIS)253CATEGORY(INSTALLAPI, REFACTORING)254#undef CATEGORY255256// Avoid out of bounds reads.257if (ID + Offset >= StaticDiagInfoSize)258return nullptr;259260assert(ID < StaticDiagInfoSize && Offset < StaticDiagInfoSize);261262const StaticDiagInfoRec *Found = &StaticDiagInfo[ID + Offset];263// If the diag id doesn't match we found a different diag, abort. This can264// happen when this function is called with an ID that points into a hole in265// the diagID space.266if (Found->DiagID != DiagID)267return nullptr;268return Found;269}270271DiagnosticMapping DiagnosticIDs::getDefaultMapping(unsigned DiagID) {272DiagnosticMapping Info = DiagnosticMapping::Make(273diag::Severity::Fatal, /*IsUser=*/false, /*IsPragma=*/false);274275if (const StaticDiagInfoRec *StaticInfo = GetDiagInfo(DiagID)) {276Info.setSeverity((diag::Severity)StaticInfo->DefaultSeverity);277278if (StaticInfo->WarnNoWerror) {279assert(Info.getSeverity() == diag::Severity::Warning &&280"Unexpected mapping with no-Werror bit!");281Info.setNoWarningAsError(true);282}283}284285return Info;286}287288/// getCategoryNumberForDiag - Return the category number that a specified289/// DiagID belongs to, or 0 if no category.290unsigned DiagnosticIDs::getCategoryNumberForDiag(unsigned DiagID) {291if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))292return Info->Category;293return 0;294}295296namespace {297// The diagnostic category names.298struct StaticDiagCategoryRec {299const char *NameStr;300uint8_t NameLen;301302StringRef getName() const {303return StringRef(NameStr, NameLen);304}305};306}307308static const StaticDiagCategoryRec CategoryNameTable[] = {309#define GET_CATEGORY_TABLE310#define CATEGORY(X, ENUM) { X, STR_SIZE(X, uint8_t) },311#include "clang/Basic/DiagnosticGroups.inc"312#undef GET_CATEGORY_TABLE313{ nullptr, 0 }314};315316/// getNumberOfCategories - Return the number of categories317unsigned DiagnosticIDs::getNumberOfCategories() {318return std::size(CategoryNameTable) - 1;319}320321/// getCategoryNameFromID - Given a category ID, return the name of the322/// category, an empty string if CategoryID is zero, or null if CategoryID is323/// invalid.324StringRef DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) {325if (CategoryID >= getNumberOfCategories())326return StringRef();327return CategoryNameTable[CategoryID].getName();328}329330331332DiagnosticIDs::SFINAEResponse333DiagnosticIDs::getDiagnosticSFINAEResponse(unsigned DiagID) {334if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))335return static_cast<DiagnosticIDs::SFINAEResponse>(Info->SFINAE);336return SFINAE_Report;337}338339bool DiagnosticIDs::isDeferrable(unsigned DiagID) {340if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))341return Info->Deferrable;342return false;343}344345/// getBuiltinDiagClass - Return the class field of the diagnostic.346///347static unsigned getBuiltinDiagClass(unsigned DiagID) {348if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))349return Info->Class;350return ~0U;351}352353//===----------------------------------------------------------------------===//354// Custom Diagnostic information355//===----------------------------------------------------------------------===//356357namespace clang {358namespace diag {359class CustomDiagInfo {360typedef std::pair<DiagnosticIDs::Level, std::string> DiagDesc;361std::vector<DiagDesc> DiagInfo;362std::map<DiagDesc, unsigned> DiagIDs;363public:364365/// getDescription - Return the description of the specified custom366/// diagnostic.367StringRef getDescription(unsigned DiagID) const {368assert(DiagID - DIAG_UPPER_LIMIT < DiagInfo.size() &&369"Invalid diagnostic ID");370return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second;371}372373/// getLevel - Return the level of the specified custom diagnostic.374DiagnosticIDs::Level getLevel(unsigned DiagID) const {375assert(DiagID - DIAG_UPPER_LIMIT < DiagInfo.size() &&376"Invalid diagnostic ID");377return DiagInfo[DiagID-DIAG_UPPER_LIMIT].first;378}379380unsigned getOrCreateDiagID(DiagnosticIDs::Level L, StringRef Message,381DiagnosticIDs &Diags) {382DiagDesc D(L, std::string(Message));383// Check to see if it already exists.384std::map<DiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D);385if (I != DiagIDs.end() && I->first == D)386return I->second;387388// If not, assign a new ID.389unsigned ID = DiagInfo.size()+DIAG_UPPER_LIMIT;390DiagIDs.insert(std::make_pair(D, ID));391DiagInfo.push_back(D);392return ID;393}394};395396} // end diag namespace397} // end clang namespace398399400//===----------------------------------------------------------------------===//401// Common Diagnostic implementation402//===----------------------------------------------------------------------===//403404DiagnosticIDs::DiagnosticIDs() {}405406DiagnosticIDs::~DiagnosticIDs() {}407408/// getCustomDiagID - Return an ID for a diagnostic with the specified message409/// and level. If this is the first request for this diagnostic, it is410/// registered and created, otherwise the existing ID is returned.411///412/// \param FormatString A fixed diagnostic format string that will be hashed and413/// mapped to a unique DiagID.414unsigned DiagnosticIDs::getCustomDiagID(Level L, StringRef FormatString) {415if (!CustomDiagInfo)416CustomDiagInfo.reset(new diag::CustomDiagInfo());417return CustomDiagInfo->getOrCreateDiagID(L, FormatString, *this);418}419420421/// isBuiltinWarningOrExtension - Return true if the unmapped diagnostic422/// level of the specified diagnostic ID is a Warning or Extension.423/// This only works on builtin diagnostics, not custom ones, and is not legal to424/// call on NOTEs.425bool DiagnosticIDs::isBuiltinWarningOrExtension(unsigned DiagID) {426return DiagID < diag::DIAG_UPPER_LIMIT &&427getBuiltinDiagClass(DiagID) != CLASS_ERROR;428}429430/// Determine whether the given built-in diagnostic ID is a431/// Note.432bool DiagnosticIDs::isBuiltinNote(unsigned DiagID) {433return DiagID < diag::DIAG_UPPER_LIMIT &&434getBuiltinDiagClass(DiagID) == CLASS_NOTE;435}436437/// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic438/// ID is for an extension of some sort. This also returns EnabledByDefault,439/// which is set to indicate whether the diagnostic is ignored by default (in440/// which case -pedantic enables it) or treated as a warning/error by default.441///442bool DiagnosticIDs::isBuiltinExtensionDiag(unsigned DiagID,443bool &EnabledByDefault) {444if (DiagID >= diag::DIAG_UPPER_LIMIT ||445getBuiltinDiagClass(DiagID) != CLASS_EXTENSION)446return false;447448EnabledByDefault =449getDefaultMapping(DiagID).getSeverity() != diag::Severity::Ignored;450return true;451}452453bool DiagnosticIDs::isDefaultMappingAsError(unsigned DiagID) {454if (DiagID >= diag::DIAG_UPPER_LIMIT)455return false;456457return getDefaultMapping(DiagID).getSeverity() >= diag::Severity::Error;458}459460/// getDescription - Given a diagnostic ID, return a description of the461/// issue.462StringRef DiagnosticIDs::getDescription(unsigned DiagID) const {463if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))464return Info->getDescription();465assert(CustomDiagInfo && "Invalid CustomDiagInfo");466return CustomDiagInfo->getDescription(DiagID);467}468469static DiagnosticIDs::Level toLevel(diag::Severity SV) {470switch (SV) {471case diag::Severity::Ignored:472return DiagnosticIDs::Ignored;473case diag::Severity::Remark:474return DiagnosticIDs::Remark;475case diag::Severity::Warning:476return DiagnosticIDs::Warning;477case diag::Severity::Error:478return DiagnosticIDs::Error;479case diag::Severity::Fatal:480return DiagnosticIDs::Fatal;481}482llvm_unreachable("unexpected severity");483}484485/// getDiagnosticLevel - Based on the way the client configured the486/// DiagnosticsEngine object, classify the specified diagnostic ID into a Level,487/// by consumable the DiagnosticClient.488DiagnosticIDs::Level489DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,490const DiagnosticsEngine &Diag) const {491// Handle custom diagnostics, which cannot be mapped.492if (DiagID >= diag::DIAG_UPPER_LIMIT) {493assert(CustomDiagInfo && "Invalid CustomDiagInfo");494return CustomDiagInfo->getLevel(DiagID);495}496497unsigned DiagClass = getBuiltinDiagClass(DiagID);498if (DiagClass == CLASS_NOTE) return DiagnosticIDs::Note;499return toLevel(getDiagnosticSeverity(DiagID, Loc, Diag));500}501502/// Based on the way the client configured the Diagnostic503/// object, classify the specified diagnostic ID into a Level, consumable by504/// the DiagnosticClient.505///506/// \param Loc The source location we are interested in finding out the507/// diagnostic state. Can be null in order to query the latest state.508diag::Severity509DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,510const DiagnosticsEngine &Diag) const {511assert(getBuiltinDiagClass(DiagID) != CLASS_NOTE);512513// Specific non-error diagnostics may be mapped to various levels from ignored514// to error. Errors can only be mapped to fatal.515diag::Severity Result = diag::Severity::Fatal;516517// Get the mapping information, or compute it lazily.518DiagnosticsEngine::DiagState *State = Diag.GetDiagStateForLoc(Loc);519DiagnosticMapping &Mapping = State->getOrAddMapping((diag::kind)DiagID);520521// TODO: Can a null severity really get here?522if (Mapping.getSeverity() != diag::Severity())523Result = Mapping.getSeverity();524525// Upgrade ignored diagnostics if -Weverything is enabled.526if (State->EnableAllWarnings && Result == diag::Severity::Ignored &&527!Mapping.isUser() && getBuiltinDiagClass(DiagID) != CLASS_REMARK)528Result = diag::Severity::Warning;529530// Ignore -pedantic diagnostics inside __extension__ blocks.531// (The diagnostics controlled by -pedantic are the extension diagnostics532// that are not enabled by default.)533bool EnabledByDefault = false;534bool IsExtensionDiag = isBuiltinExtensionDiag(DiagID, EnabledByDefault);535if (Diag.AllExtensionsSilenced && IsExtensionDiag && !EnabledByDefault)536return diag::Severity::Ignored;537538// For extension diagnostics that haven't been explicitly mapped, check if we539// should upgrade the diagnostic.540if (IsExtensionDiag && !Mapping.isUser())541Result = std::max(Result, State->ExtBehavior);542543// At this point, ignored errors can no longer be upgraded.544if (Result == diag::Severity::Ignored)545return Result;546547// Honor -w: this disables all messages which are not Error/Fatal by548// default (disregarding attempts to upgrade severity from Warning to Error),549// as well as disabling all messages which are currently mapped to Warning550// (whether by default or downgraded from Error via e.g. -Wno-error or #pragma551// diagnostic.)552if (State->IgnoreAllWarnings) {553if (Result == diag::Severity::Warning ||554(Result >= diag::Severity::Error &&555!isDefaultMappingAsError((diag::kind)DiagID)))556return diag::Severity::Ignored;557}558559// If -Werror is enabled, map warnings to errors unless explicitly disabled.560if (Result == diag::Severity::Warning) {561if (State->WarningsAsErrors && !Mapping.hasNoWarningAsError())562Result = diag::Severity::Error;563}564565// If -Wfatal-errors is enabled, map errors to fatal unless explicitly566// disabled.567if (Result == diag::Severity::Error) {568if (State->ErrorsAsFatal && !Mapping.hasNoErrorAsFatal())569Result = diag::Severity::Fatal;570}571572// If explicitly requested, map fatal errors to errors.573if (Result == diag::Severity::Fatal &&574Diag.CurDiagID != diag::fatal_too_many_errors && Diag.FatalsAsError)575Result = diag::Severity::Error;576577// Custom diagnostics always are emitted in system headers.578bool ShowInSystemHeader =579!GetDiagInfo(DiagID) || GetDiagInfo(DiagID)->WarnShowInSystemHeader;580581// If we are in a system header, we ignore it. We look at the diagnostic class582// because we also want to ignore extensions and warnings in -Werror and583// -pedantic-errors modes, which *map* warnings/extensions to errors.584if (State->SuppressSystemWarnings && !ShowInSystemHeader && Loc.isValid() &&585Diag.getSourceManager().isInSystemHeader(586Diag.getSourceManager().getExpansionLoc(Loc)))587return diag::Severity::Ignored;588589// We also ignore warnings due to system macros590bool ShowInSystemMacro =591!GetDiagInfo(DiagID) || GetDiagInfo(DiagID)->WarnShowInSystemMacro;592if (State->SuppressSystemWarnings && !ShowInSystemMacro && Loc.isValid() &&593Diag.getSourceManager().isInSystemMacro(Loc))594return diag::Severity::Ignored;595596return Result;597}598599#define GET_DIAG_ARRAYS600#include "clang/Basic/DiagnosticGroups.inc"601#undef GET_DIAG_ARRAYS602603namespace {604struct WarningOption {605uint16_t NameOffset;606uint16_t Members;607uint16_t SubGroups;608StringRef Documentation;609610// String is stored with a pascal-style length byte.611StringRef getName() const {612return StringRef(DiagGroupNames + NameOffset + 1,613DiagGroupNames[NameOffset]);614}615};616}617618// Second the table of options, sorted by name for fast binary lookup.619static const WarningOption OptionTable[] = {620#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups, Docs) \621{FlagNameOffset, Members, SubGroups, Docs},622#include "clang/Basic/DiagnosticGroups.inc"623#undef DIAG_ENTRY624};625626/// Given a diagnostic group ID, return its documentation.627StringRef DiagnosticIDs::getWarningOptionDocumentation(diag::Group Group) {628return OptionTable[static_cast<int>(Group)].Documentation;629}630631StringRef DiagnosticIDs::getWarningOptionForGroup(diag::Group Group) {632return OptionTable[static_cast<int>(Group)].getName();633}634635std::optional<diag::Group>636DiagnosticIDs::getGroupForWarningOption(StringRef Name) {637const auto *Found = llvm::partition_point(638OptionTable, [=](const WarningOption &O) { return O.getName() < Name; });639if (Found == std::end(OptionTable) || Found->getName() != Name)640return std::nullopt;641return static_cast<diag::Group>(Found - OptionTable);642}643644std::optional<diag::Group> DiagnosticIDs::getGroupForDiag(unsigned DiagID) {645if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))646return static_cast<diag::Group>(Info->getOptionGroupIndex());647return std::nullopt;648}649650/// getWarningOptionForDiag - Return the lowest-level warning option that651/// enables the specified diagnostic. If there is no -Wfoo flag that controls652/// the diagnostic, this returns null.653StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {654if (auto G = getGroupForDiag(DiagID))655return getWarningOptionForGroup(*G);656return StringRef();657}658659std::vector<std::string> DiagnosticIDs::getDiagnosticFlags() {660std::vector<std::string> Res{"-W", "-Wno-"};661for (size_t I = 1; DiagGroupNames[I] != '\0';) {662std::string Diag(DiagGroupNames + I + 1, DiagGroupNames[I]);663I += DiagGroupNames[I] + 1;664Res.push_back("-W" + Diag);665Res.push_back("-Wno-" + Diag);666}667668return Res;669}670671/// Return \c true if any diagnostics were found in this group, even if they672/// were filtered out due to having the wrong flavor.673static bool getDiagnosticsInGroup(diag::Flavor Flavor,674const WarningOption *Group,675SmallVectorImpl<diag::kind> &Diags) {676// An empty group is considered to be a warning group: we have empty groups677// for GCC compatibility, and GCC does not have remarks.678if (!Group->Members && !Group->SubGroups)679return Flavor == diag::Flavor::Remark;680681bool NotFound = true;682683// Add the members of the option diagnostic set.684const int16_t *Member = DiagArrays + Group->Members;685for (; *Member != -1; ++Member) {686if (GetDiagInfo(*Member)->getFlavor() == Flavor) {687NotFound = false;688Diags.push_back(*Member);689}690}691692// Add the members of the subgroups.693const int16_t *SubGroups = DiagSubGroups + Group->SubGroups;694for (; *SubGroups != (int16_t)-1; ++SubGroups)695NotFound &= getDiagnosticsInGroup(Flavor, &OptionTable[(short)*SubGroups],696Diags);697698return NotFound;699}700701bool702DiagnosticIDs::getDiagnosticsInGroup(diag::Flavor Flavor, StringRef Group,703SmallVectorImpl<diag::kind> &Diags) const {704if (std::optional<diag::Group> G = getGroupForWarningOption(Group))705return ::getDiagnosticsInGroup(706Flavor, &OptionTable[static_cast<unsigned>(*G)], Diags);707return true;708}709710void DiagnosticIDs::getAllDiagnostics(diag::Flavor Flavor,711std::vector<diag::kind> &Diags) {712for (unsigned i = 0; i != StaticDiagInfoSize; ++i)713if (StaticDiagInfo[i].getFlavor() == Flavor)714Diags.push_back(StaticDiagInfo[i].DiagID);715}716717StringRef DiagnosticIDs::getNearestOption(diag::Flavor Flavor,718StringRef Group) {719StringRef Best;720unsigned BestDistance = Group.size() + 1; // Maximum threshold.721for (const WarningOption &O : OptionTable) {722// Don't suggest ignored warning flags.723if (!O.Members && !O.SubGroups)724continue;725726unsigned Distance = O.getName().edit_distance(Group, true, BestDistance);727if (Distance > BestDistance)728continue;729730// Don't suggest groups that are not of this kind.731llvm::SmallVector<diag::kind, 8> Diags;732if (::getDiagnosticsInGroup(Flavor, &O, Diags) || Diags.empty())733continue;734735if (Distance == BestDistance) {736// Two matches with the same distance, don't prefer one over the other.737Best = "";738} else if (Distance < BestDistance) {739// This is a better match.740Best = O.getName();741BestDistance = Distance;742}743}744745return Best;746}747748/// ProcessDiag - This is the method used to report a diagnostic that is749/// finally fully formed.750bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const {751Diagnostic Info(&Diag);752753assert(Diag.getClient() && "DiagnosticClient not set!");754755// Figure out the diagnostic level of this message.756unsigned DiagID = Info.getID();757DiagnosticIDs::Level DiagLevel758= getDiagnosticLevel(DiagID, Info.getLocation(), Diag);759760// Update counts for DiagnosticErrorTrap even if a fatal error occurred761// or diagnostics are suppressed.762if (DiagLevel >= DiagnosticIDs::Error) {763++Diag.TrapNumErrorsOccurred;764if (isUnrecoverable(DiagID))765++Diag.TrapNumUnrecoverableErrorsOccurred;766}767768if (Diag.SuppressAllDiagnostics)769return false;770771if (DiagLevel != DiagnosticIDs::Note) {772// Record that a fatal error occurred only when we see a second773// non-note diagnostic. This allows notes to be attached to the774// fatal error, but suppresses any diagnostics that follow those775// notes.776if (Diag.LastDiagLevel == DiagnosticIDs::Fatal)777Diag.FatalErrorOccurred = true;778779Diag.LastDiagLevel = DiagLevel;780}781782// If a fatal error has already been emitted, silence all subsequent783// diagnostics.784if (Diag.FatalErrorOccurred) {785if (DiagLevel >= DiagnosticIDs::Error &&786Diag.Client->IncludeInDiagnosticCounts()) {787++Diag.NumErrors;788}789790return false;791}792793// If the client doesn't care about this message, don't issue it. If this is794// a note and the last real diagnostic was ignored, ignore it too.795if (DiagLevel == DiagnosticIDs::Ignored ||796(DiagLevel == DiagnosticIDs::Note &&797Diag.LastDiagLevel == DiagnosticIDs::Ignored))798return false;799800if (DiagLevel >= DiagnosticIDs::Error) {801if (isUnrecoverable(DiagID))802Diag.UnrecoverableErrorOccurred = true;803804// Warnings which have been upgraded to errors do not prevent compilation.805if (isDefaultMappingAsError(DiagID))806Diag.UncompilableErrorOccurred = true;807808Diag.ErrorOccurred = true;809if (Diag.Client->IncludeInDiagnosticCounts()) {810++Diag.NumErrors;811}812813// If we've emitted a lot of errors, emit a fatal error instead of it to814// stop a flood of bogus errors.815if (Diag.ErrorLimit && Diag.NumErrors > Diag.ErrorLimit &&816DiagLevel == DiagnosticIDs::Error) {817Diag.SetDelayedDiagnostic(diag::fatal_too_many_errors);818return false;819}820}821822// Make sure we set FatalErrorOccurred to ensure that the notes from the823// diagnostic that caused `fatal_too_many_errors` won't be emitted.824if (Diag.CurDiagID == diag::fatal_too_many_errors)825Diag.FatalErrorOccurred = true;826// Finally, report it.827EmitDiag(Diag, DiagLevel);828return true;829}830831void DiagnosticIDs::EmitDiag(DiagnosticsEngine &Diag, Level DiagLevel) const {832Diagnostic Info(&Diag);833assert(DiagLevel != DiagnosticIDs::Ignored && "Cannot emit ignored diagnostics!");834835Diag.Client->HandleDiagnostic((DiagnosticsEngine::Level)DiagLevel, Info);836if (Diag.Client->IncludeInDiagnosticCounts()) {837if (DiagLevel == DiagnosticIDs::Warning)838++Diag.NumWarnings;839}840841Diag.CurDiagID = ~0U;842}843844bool DiagnosticIDs::isUnrecoverable(unsigned DiagID) const {845if (DiagID >= diag::DIAG_UPPER_LIMIT) {846assert(CustomDiagInfo && "Invalid CustomDiagInfo");847// Custom diagnostics.848return CustomDiagInfo->getLevel(DiagID) >= DiagnosticIDs::Error;849}850851// Only errors may be unrecoverable.852if (getBuiltinDiagClass(DiagID) < CLASS_ERROR)853return false;854855if (DiagID == diag::err_unavailable ||856DiagID == diag::err_unavailable_message)857return false;858859// Currently we consider all ARC errors as recoverable.860if (isARCDiagnostic(DiagID))861return false;862863if (isCodegenABICheckDiagnostic(DiagID))864return false;865866return true;867}868869bool DiagnosticIDs::isARCDiagnostic(unsigned DiagID) {870unsigned cat = getCategoryNumberForDiag(DiagID);871return DiagnosticIDs::getCategoryNameFromID(cat).starts_with("ARC ");872}873874bool DiagnosticIDs::isCodegenABICheckDiagnostic(unsigned DiagID) {875unsigned cat = getCategoryNumberForDiag(DiagID);876return DiagnosticIDs::getCategoryNameFromID(cat) == "Codegen ABI Check";877}878879880