From f5d2328fc849288c3a62e43d065685f516d57091 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Tue, 17 Feb 2009 06:49:55 +0000 Subject: [PATCH] fix notes so that they are always filtered with the same logic as the last non-note diagnostic that preceeded them. This ensures that diagnostics in main files which have notes with locations in system headers get all the bits and pieces emitted or not in a unit. This fixes PR3215. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64746 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/Diagnostic.h | 25 +++++-- lib/Basic/Diagnostic.cpp | 124 ++++++++++++++++++++----------- 2 files changed, 96 insertions(+), 53 deletions(-) diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index 4ab47d0be0..c6e91a9a46 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -106,6 +106,11 @@ private: /// fatal error is emitted, and is sticky. bool ErrorOccurred; bool FatalErrorOccurred; + + /// LastDiagLevel - This is the level of the last diagnostic emitted. This is + /// used to emit continuation diagnostics with the same level as the + /// diagnostic that they follow. + Diagnostic::Level LastDiagLevel; unsigned NumDiagnostics; // Number of diagnostics reported unsigned NumErrors; // Number of diagnostics that are errors @@ -161,11 +166,11 @@ public: bool getSuppressSystemWarnings() const { return SuppressSystemWarnings; } /// setDiagnosticMapping - This allows the client to specify that certain - /// warnings are ignored. Only NOTEs, WARNINGs, and EXTENSIONs can be mapped. + /// warnings are ignored. Only WARNINGs and EXTENSIONs can be mapped. void setDiagnosticMapping(diag::kind Diag, diag::Mapping Map) { assert(Diag < diag::DIAG_UPPER_LIMIT && "Can only map builtin diagnostics"); - assert((isBuiltinNoteWarningOrExtension(Diag) || Map == diag::MAP_FATAL) && + assert((isBuiltinWarningOrExtension(Diag) || Map == diag::MAP_FATAL) && "Cannot map errors!"); unsigned char &Slot = DiagMappings[Diag/2]; unsigned Bits = (Diag & 1)*4; @@ -212,16 +217,16 @@ public: /// issue. const char *getDescription(unsigned DiagID) const; - /// isBuiltinNoteWarningOrExtension - Return true if the unmapped diagnostic - /// level of the specified diagnostic ID is a Note, Warning, or Extension. - /// Note that this only works on builtin diagnostics, not custom ones. - static bool isBuiltinNoteWarningOrExtension(unsigned DiagID); + /// isNoteWarningOrExtension - Return true if the unmapped diagnostic + /// level of the specified diagnostic ID is a Warning or Extension. + /// This only works on builtin diagnostics, not custom ones, and is not legal to + /// call on NOTEs. + static bool isBuiltinWarningOrExtension(unsigned DiagID); /// getDiagnosticLevel - Based on the way the client configured the Diagnostic /// object, classify the specified diagnostic ID into a Level, consumable by /// the DiagnosticClient. - Level getDiagnosticLevel(unsigned DiagID) const; - + Level getDiagnosticLevel(unsigned DiagID) const; /// Report - Issue the message to the client. @c DiagID is a member of the /// @c diag::kind enum. This actually returns aninstance of DiagnosticBuilder @@ -231,6 +236,10 @@ public: inline DiagnosticBuilder Report(FullSourceLoc Pos, unsigned DiagID); private: + /// getDiagnosticLevel - This is an internal implementation helper used when + /// DiagClass is already known. + Level getDiagnosticLevel(unsigned DiagID, unsigned DiagClass) const; + // This is private state used by DiagnosticBuilder. We put it here instead of // in DiagnosticBuilder in order to keep DiagnosticBuilder a small lightweight // object. This implementation choice means that we can only have one diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index ff110711f5..3ccaebf2b7 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -196,6 +196,7 @@ Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) { NumErrors = 0; CustomDiagInfo = 0; CurDiagID = ~0U; + LastDiagLevel = Fatal; ArgToStringFn = DummyArgToStringFn; } @@ -214,10 +215,11 @@ unsigned Diagnostic::getCustomDiagID(Level L, const char *Message) { } -/// isBuiltinNoteWarningOrExtension - Return true if the unmapped diagnostic -/// level of the specified diagnostic ID is a Note, Warning, or Extension. -/// Note that this only works on builtin diagnostics, not custom ones. -bool Diagnostic::isBuiltinNoteWarningOrExtension(unsigned DiagID) { +/// isBuiltinWarningOrExtension - Return true if the unmapped diagnostic +/// level of the specified diagnostic ID is a Warning or Extension. +/// This only works on builtin diagnostics, not custom ones, and is not legal to +/// call on NOTEs. +bool Diagnostic::isBuiltinWarningOrExtension(unsigned DiagID) { return DiagID < diag::DIAG_UPPER_LIMIT && getBuiltinDiagClass(DiagID) < ERROR; } @@ -225,21 +227,18 @@ bool Diagnostic::isBuiltinNoteWarningOrExtension(unsigned DiagID) { /// getDescription - Given a diagnostic ID, return a description of the /// issue. const char *Diagnostic::getDescription(unsigned DiagID) const { - if (DiagID < diag::DIAG_UPPER_LIMIT) { - if (DiagID < diag::DIAG_START_LEX) - return DiagnosticTextCommon[DiagID]; - else if (DiagID < diag::DIAG_START_PARSE) - return DiagnosticTextLex[DiagID - diag::DIAG_START_LEX - 1]; - else if (DiagID < diag::DIAG_START_AST) - return DiagnosticTextParse[DiagID - diag::DIAG_START_PARSE - 1]; - else if (DiagID < diag::DIAG_START_SEMA) - return DiagnosticTextAST[DiagID - diag::DIAG_START_AST - 1]; - else if (DiagID < diag::DIAG_START_ANALYSIS) - return DiagnosticTextSema[DiagID - diag::DIAG_START_SEMA - 1]; - else if (DiagID < diag::DIAG_UPPER_LIMIT) - return DiagnosticTextAnalysis[DiagID - diag::DIAG_START_ANALYSIS - 1]; - } - + if (DiagID < diag::DIAG_START_LEX) + return DiagnosticTextCommon[DiagID]; + else if (DiagID < diag::DIAG_START_PARSE) + return DiagnosticTextLex[DiagID - diag::DIAG_START_LEX - 1]; + else if (DiagID < diag::DIAG_START_AST) + return DiagnosticTextParse[DiagID - diag::DIAG_START_PARSE - 1]; + else if (DiagID < diag::DIAG_START_SEMA) + return DiagnosticTextAST[DiagID - diag::DIAG_START_AST - 1]; + else if (DiagID < diag::DIAG_START_ANALYSIS) + return DiagnosticTextSema[DiagID - diag::DIAG_START_SEMA - 1]; + else if (DiagID < diag::DIAG_UPPER_LIMIT) + return DiagnosticTextAnalysis[DiagID - diag::DIAG_START_ANALYSIS - 1]; return CustomDiagInfo->getDescription(DiagID); } @@ -252,19 +251,23 @@ Diagnostic::Level Diagnostic::getDiagnosticLevel(unsigned DiagID) const { return CustomDiagInfo->getLevel(DiagID); unsigned DiagClass = getBuiltinDiagClass(DiagID); - + assert(DiagClass != NOTE && "Cannot get the diagnostic level of a note!"); + return getDiagnosticLevel(DiagID, DiagClass); +} + +/// getDiagnosticLevel - Based on the way the client configured the Diagnostic +/// object, classify the specified diagnostic ID into a Level, consumable by +/// the DiagnosticClient. +Diagnostic::Level +Diagnostic::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass) const { // Specific non-error diagnostics may be mapped to various levels from ignored - // to error. - if (DiagClass < ERROR) { - switch (getDiagnosticMapping((diag::kind)DiagID)) { - case diag::MAP_DEFAULT: break; - case diag::MAP_IGNORE: return Diagnostic::Ignored; - case diag::MAP_WARNING: DiagClass = WARNING; break; - case diag::MAP_ERROR: DiagClass = ERROR; break; - case diag::MAP_FATAL: DiagClass = FATAL; break; - } - } else if (getDiagnosticMapping((diag::kind)DiagID) == diag::MAP_FATAL) { - DiagClass = FATAL; + // to error. Errors can only be mapped to fatal. + switch (getDiagnosticMapping((diag::kind)DiagID)) { + case diag::MAP_DEFAULT: break; + case diag::MAP_IGNORE: return Diagnostic::Ignored; + case diag::MAP_WARNING: DiagClass = WARNING; break; + case diag::MAP_ERROR: DiagClass = ERROR; break; + case diag::MAP_FATAL: DiagClass = FATAL; break; } // Map diagnostic classes based on command line argument settings. @@ -289,7 +292,6 @@ Diagnostic::Level Diagnostic::getDiagnosticLevel(unsigned DiagID) const { switch (DiagClass) { default: assert(0 && "Unknown diagnostic class!"); - case NOTE: return Diagnostic::Note; case WARNING: return Diagnostic::Warning; case ERROR: return Diagnostic::Error; case FATAL: return Diagnostic::Fatal; @@ -307,23 +309,55 @@ void Diagnostic::ProcessDiag() { return; // Figure out the diagnostic level of this message. - Diagnostic::Level DiagLevel = getDiagnosticLevel(Info.getID()); + Diagnostic::Level DiagLevel; + unsigned DiagID = Info.getID(); - // If the client doesn't care about this message, don't issue it. - if (DiagLevel == Diagnostic::Ignored) + // ShouldEmitInSystemHeader - True if this diagnostic should be produced even + // in a system header. + bool ShouldEmitInSystemHeader; + + if (DiagID >= diag::DIAG_UPPER_LIMIT) { + // Handle custom diagnostics, which cannot be mapped. + DiagLevel = CustomDiagInfo->getLevel(DiagID); + + // Custom diagnostics always are emitted in system headers. + ShouldEmitInSystemHeader = true; + } else { + // Get the class of the diagnostic. If this is a NOTE, map it onto whatever + // the diagnostic level was for the previous diagnostic so that it is + // filtered the same as the previous diagnostic. + unsigned DiagClass = getBuiltinDiagClass(DiagID); + if (DiagClass == NOTE) { + DiagLevel = Diagnostic::Note; + ShouldEmitInSystemHeader = false; // extra consideration is needed + } else { + // If this is not an error and we are in a system header, we ignore it. + // Check the original Diag ID here, because we also want to ignore + // extensions and warnings in -Werror and -pedantic-errors modes, which + // *map* warnings/extensions to errors. + ShouldEmitInSystemHeader = DiagClass == ERROR; + + DiagLevel = getDiagnosticLevel(DiagID, DiagClass); + } + } + + if (DiagLevel != Diagnostic::Note) + LastDiagLevel = DiagLevel; + + // If the client doesn't care about this message, don't issue it. If this is + // a note and the last real diagnostic was ignored, ignore it too. + if (DiagLevel == Diagnostic::Ignored || + (DiagLevel == Diagnostic::Note && LastDiagLevel == Diagnostic::Ignored)) return; - // If this is not an error and we are in a system header, ignore it. We - // have to check on the original Diag ID here, because we also want to - // ignore extensions and warnings in -Werror and -pedantic-errors modes, - // which *map* warnings/extensions to errors. - if (SuppressSystemWarnings && - Info.getID() < diag::DIAG_UPPER_LIMIT && - getBuiltinDiagClass(Info.getID()) != ERROR && + // If this diagnostic is in a system header and is not a clang error, suppress + // it. + if (SuppressSystemWarnings && !ShouldEmitInSystemHeader && Info.getLocation().isValid() && - Info.getLocation().getSpellingLoc().isInSystemHeader()) + Info.getLocation().getSpellingLoc().isInSystemHeader() && + (DiagLevel != Diagnostic::Note || LastDiagLevel == Diagnostic::Ignored)) return; - + if (DiagLevel >= Diagnostic::Error) { ErrorOccurred = true; ++NumErrors; @@ -331,7 +365,7 @@ void Diagnostic::ProcessDiag() { if (DiagLevel == Diagnostic::Fatal) FatalErrorOccurred = true; } - + // Finally, report it. Client->HandleDiagnostic(DiagLevel, Info); if (Client->IncludeInDiagnosticCounts()) ++NumDiagnostics; -- 2.40.0