From 182745ae7892bca0842d9c023370ade5f8d1c6e8 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sun, 2 Dec 2007 01:09:57 +0000 Subject: [PATCH] add support for custom client-specific diagnostics. As a testcase, make the rewriter emit this error if it fails to rewrite an @encode: t.m:17:9: error: rewriter could not replace sub-expression due to macros c = ENC(char *)[2] + 4; ^~~~~~~~~~~ ... where ENC is: #define ENC @encode git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@44498 91177308-0d34-0410-b5e6-96231b3b80d8 --- Basic/Diagnostic.cpp | 80 ++++++++++++++++++++++++++++++-- Driver/RewriteTest.cpp | 5 ++ include/clang/Basic/Diagnostic.h | 23 +++++++-- 3 files changed, 98 insertions(+), 10 deletions(-) diff --git a/Basic/Diagnostic.cpp b/Basic/Diagnostic.cpp index 239211bcd4..b5853a2531 100644 --- a/Basic/Diagnostic.cpp +++ b/Basic/Diagnostic.cpp @@ -14,8 +14,14 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceLocation.h" #include +#include +#include using namespace clang; +//===----------------------------------------------------------------------===// +// Builtin Diagnostic information +//===----------------------------------------------------------------------===// + /// Flag values for diagnostics. enum { // Diagnostic classes. @@ -50,6 +56,56 @@ static const char * const DiagnosticText[] = { 0 }; +//===----------------------------------------------------------------------===// +// Custom Diagnostic information +//===----------------------------------------------------------------------===// + +namespace clang { + namespace diag { + class CustomDiagInfo { + typedef std::pair DiagDesc; + std::vector DiagInfo; + std::map DiagIDs; + public: + + /// getDescription - Return the description of the specified custom + /// diagnostic. + const char *getDescription(unsigned DiagID) const { + assert(this && DiagID-diag::NUM_BUILTIN_DIAGNOSTICS < DiagInfo.size() && + "Invalid diagnosic ID"); + return DiagInfo[DiagID-diag::NUM_BUILTIN_DIAGNOSTICS].second.c_str(); + } + + /// getLevel - Return the level of the specified custom diagnostic. + Diagnostic::Level getLevel(unsigned DiagID) const { + assert(this && DiagID-diag::NUM_BUILTIN_DIAGNOSTICS < DiagInfo.size() && + "Invalid diagnosic ID"); + return DiagInfo[DiagID-diag::NUM_BUILTIN_DIAGNOSTICS].first; + } + + unsigned getOrCreateDiagID(Diagnostic::Level L, const char *Message) { + DiagDesc D(L, Message); + // Check to see if it already exists. + std::map::iterator I = DiagIDs.lower_bound(D); + if (I != DiagIDs.end() && I->first == D) + return I->second; + + // If not, assign a new ID. + unsigned ID = DiagInfo.size()+diag::NUM_BUILTIN_DIAGNOSTICS; + DiagIDs.insert(std::make_pair(D, ID)); + DiagInfo.push_back(D); + return ID; + } + }; + + } // end diag namespace +} // end clang namespace + + +//===----------------------------------------------------------------------===// +// Common Diagnostic implementation +//===----------------------------------------------------------------------===// + Diagnostic::Diagnostic(DiagnosticClient &client) : Client(client) { WarningsAsErrors = false; WarnOnExtensions = false; @@ -60,8 +116,23 @@ Diagnostic::Diagnostic(DiagnosticClient &client) : Client(client) { ErrorOccurred = false; NumDiagnostics = 0; NumErrors = 0; + CustomDiagInfo = 0; +} + +Diagnostic::~Diagnostic() { + delete CustomDiagInfo; } +/// getCustomDiagID - Return an ID for a diagnostic with the specified message +/// and level. If this is the first request for this diagnosic, it is +/// registered and created, otherwise the existing ID is returned. +unsigned Diagnostic::getCustomDiagID(Level L, const char *Message) { + if (CustomDiagInfo == 0) + CustomDiagInfo = new diag::CustomDiagInfo(); + return CustomDiagInfo->getOrCreateDiagID(L, 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. @@ -77,17 +148,16 @@ const char *Diagnostic::getDescription(unsigned DiagID) { if (DiagID < diag::NUM_BUILTIN_DIAGNOSTICS) return DiagnosticText[DiagID]; else - assert(0 && "FIXME: IMPLEMENT"); + return CustomDiagInfo->getDescription(DiagID); } /// 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) const { - if (DiagID >= diag::NUM_BUILTIN_DIAGNOSTICS) { - // FIXME: HAndle custom here. - assert(0 && "unimp"); - } + // Handle custom diagnostics, which cannot be mapped. + if (DiagID >= diag::NUM_BUILTIN_DIAGNOSTICS) + return CustomDiagInfo->getLevel(DiagID); unsigned DiagClass = getBuiltinDiagClass(DiagID); diff --git a/Driver/RewriteTest.cpp b/Driver/RewriteTest.cpp index 808fe98798..2073f7e391 100644 --- a/Driver/RewriteTest.cpp +++ b/Driver/RewriteTest.cpp @@ -867,6 +867,11 @@ Stmt *RewriteTest::RewriteAtEncode(ObjCEncodeExpr *Exp) { SourceLocation(), SourceLocation()); if (Rewrite.ReplaceStmt(Exp, Replacement)) { // replacement failed. + unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error, + "rewriter could not replace sub-expression due to macros"); + SourceRange Range = Exp->getSourceRange(); + Diags.Report(Exp->getAtLoc(), DiagID, 0, 0, &Range, 1); + delete Replacement; return Exp; } diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index 2d2fffad37..b9029d9bca 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -24,6 +24,8 @@ namespace clang { // Import the diagnostic enums themselves. namespace diag { + class CustomDiagInfo; + /// diag::kind - All of the diagnostics that can be emitted by the frontend. enum kind { #define DIAG(ENUM,FLAGS,DESC) ENUM, @@ -47,6 +49,13 @@ namespace clang { /// "report warnings as errors" and passes them off to the DiagnosticClient for /// reporting to the user. class Diagnostic { +public: + /// Level - The level of the diagnostic, after it has been through mapping. + enum Level { + Ignored, Note, Warning, Error, Fatal + }; + +private: bool WarningsAsErrors; // Treat warnings like errors: bool WarnOnExtensions; // Enables warnings for gcc extensions: -pedantic. bool ErrorOnExtensions; // Error on extensions: -pedantic-errors. @@ -62,8 +71,12 @@ class Diagnostic { unsigned NumDiagnostics; // Number of diagnostics reported unsigned NumErrors; // Number of diagnostics that are errors + + /// CustomDiagInfo - Information for uniquing and looking up custom diags. + diag::CustomDiagInfo *CustomDiagInfo; public: explicit Diagnostic(DiagnosticClient &client); + ~Diagnostic(); //===--------------------------------------------------------------------===// // Diagnostic characterization methods, used by a client to customize how @@ -108,6 +121,11 @@ public: unsigned getNumErrors() const { return NumErrors; } unsigned getNumDiagnostics() const { return NumDiagnostics; } + /// getCustomDiagID - Return an ID for a diagnostic with the specified message + /// and level. If this is the first request for this diagnosic, it is + /// registered and created, otherwise the existing ID is returned. + unsigned getCustomDiagID(Level L, const char *Message); + //===--------------------------------------------------------------------===// // Diagnostic classification and reporting interfaces. // @@ -116,11 +134,6 @@ public: /// issue. const char *getDescription(unsigned DiagID); - /// Level - The level of the diagnostic, after it has been through mapping. - enum Level { - Ignored, Note, Warning, Error, Fatal - }; - /// 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. -- 2.40.0