From: Douglas Gregor Date: Fri, 19 Nov 2010 16:18:16 +0000 (+0000) Subject: Extend the libclang diagnostic API to provide information about the X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=aa5f135f8db82b5e5fb1640fd51f8078e0b2d82d;p=clang Extend the libclang diagnostic API to provide information about the option name, category ID, and category name corresponding to a diagnostic. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@119802 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index e4edf3b944..2fc4089735 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -499,7 +499,34 @@ enum CXDiagnosticDisplayOptions { * This option corresponds to the clang flag * \c -fdiagnostics-print-source-range-info. */ - CXDiagnostic_DisplaySourceRanges = 0x04 + CXDiagnostic_DisplaySourceRanges = 0x04, + + /** + * \brief Display the option name associated with this diagnostic, if any. + * + * The option name displayed (e.g., -Wconversion) will be placed in brackets + * after the diagnostic text. This option corresponds to the clang flag + * \c -fdiagnostics-show-option. + */ + CXDiagnostic_DisplayOption = 0x08, + + /** + * \brief Display the category number associated with this diagnostic, if any. + * + * The category number is displayed within brackets after the diagnostic text. + * This option corresponds to the clang flag + * \c -fdiagnostics-show-category=id. + */ + CXDiagnostic_DisplayCategoryId = 0x10, + + /** + * \brief Display the category name associated with this diagnostic, if any. + * + * The category name is displayed within brackets after the diagnostic text. + * This option corresponds to the clang flag + * \c -fdiagnostics-show-category=name. + */ + CXDiagnostic_DisplayCategoryName = 0x20 }; /** @@ -529,10 +556,6 @@ CINDEX_LINKAGE CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, */ CINDEX_LINKAGE unsigned clang_defaultDiagnosticDisplayOptions(void); -/** - * \brief Print a diagnostic to the given file. - */ - /** * \brief Determine the severity of the given diagnostic. */ @@ -552,6 +575,43 @@ CINDEX_LINKAGE CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic); */ CINDEX_LINKAGE CXString clang_getDiagnosticSpelling(CXDiagnostic); +/** + * \brief Retrieve the name of the command-line option that enabled this + * diagnostic. + * + * \param Diag The diagnostic to be queried. + * + * \param Disable If non-NULL, will be set to the option that disables this + * diagnostic (if any). + * + * \returns A string that contains the command-line option used to enable this + * warning, such as "-Wconversion" or "-pedantic". + */ +CINDEX_LINKAGE CXString clang_getDiagnosticOption(CXDiagnostic Diag, + CXString *Disable); + +/** + * \brief Retrieve the category number for this diagnostic. + * + * Diagnostics can be categorized into groups along with other, related + * diagnostics (e.g., diagnostics under the same warning flag). This routine + * retrieves the category number for the given diagnostic. + * + * \returns The number of the category that contains this diagnostic, or zero + * if this diagnostic is uncategorized. + */ +CINDEX_LINKAGE unsigned clang_getDiagnosticCategory(CXDiagnostic); + +/** + * \brief Retrieve the name of a particular diagnostic category. + * + * \param Category A diagnostic category number, as returned by + * \c clang_getDiagnosticCategory(). + * + * \returns The name of the given diagnostic category. + */ +CINDEX_LINKAGE CXString clang_getDiagnosticCategoryName(unsigned Category); + /** * \brief Determine the number of source ranges associated with the given * diagnostic. diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index c4988e417d..b0ed3e1a17 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -876,6 +876,7 @@ public: * corresponding source manager is destroyed. */ class StoredDiagnostic { + unsigned ID; Diagnostic::Level Level; FullSourceLoc Loc; std::string Message; @@ -885,12 +886,14 @@ class StoredDiagnostic { public: StoredDiagnostic(); StoredDiagnostic(Diagnostic::Level Level, const DiagnosticInfo &Info); - StoredDiagnostic(Diagnostic::Level Level, llvm::StringRef Message); + StoredDiagnostic(Diagnostic::Level Level, unsigned ID, + llvm::StringRef Message); ~StoredDiagnostic(); /// \brief Evaluates true when this object stores a diagnostic. operator bool() const { return Message.size() > 0; } + unsigned getID() const { return ID; } Diagnostic::Level getLevel() const { return Level; } const FullSourceLoc &getLocation() const { return Loc; } llvm::StringRef getMessage() const { return Message; } diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index 858b70a712..83ae2c5187 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -547,13 +547,14 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd, StoredDiagnostic::StoredDiagnostic() { } -StoredDiagnostic::StoredDiagnostic(Diagnostic::Level Level, +StoredDiagnostic::StoredDiagnostic(Diagnostic::Level Level, unsigned ID, llvm::StringRef Message) - : Level(Level), Loc(), Message(Message) { } + : Level(Level), ID(ID), Loc(), Message(Message) { } StoredDiagnostic::StoredDiagnostic(Diagnostic::Level Level, const DiagnosticInfo &Info) - : Level(Level) { + : ID(Info.getID()), Level(Level) +{ assert((Info.getLocation().isInvalid() || Info.hasSourceManager()) && "Valid source location without setting a source manager for diagnostic"); if (Info.getLocation().isValid()) diff --git a/test/Index/code-complete-errors.c b/test/Index/code-complete-errors.c index 4fe213eca6..51cfb895e2 100644 --- a/test/Index/code-complete-errors.c +++ b/test/Index/code-complete-errors.c @@ -13,11 +13,13 @@ int f(int *ptr1, float *ptr2) { #define expand_to_binary_function(ret, name, parm1, parm2, code) ret name(parm1, parm2) code expand_to_binary_function(int, g, int *ip, float *fp, { -// CHECK: code-complete-errors.c:17:15:{17:12-17:14}{17:18-17:20}: warning: comparison of distinct pointer types ('int *' and 'float *') + // CHECK: code-complete-errors.c:17:12:{17:9-17:24}: warning: using the result of an assignment as a condition without parentheses [-Wparentheses] + if (ip = (float*)fp) ; +// CHECK: code-complete-errors.c:19:15:{19:12-19:14}{19:18-19:20}: warning: comparison of distinct pointer types ('int *' and 'float *') return ip == fp; }) void g() { } -// RUN: c-index-test -code-completion-at=%s:19:12 -pedantic %s 2> %t +// RUN: c-index-test -code-completion-at=%s:21:12 -pedantic %s 2> %t // RUN: FileCheck -check-prefix=CHECK %s < %t diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index c13f0313f2..8e76dc0b8b 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -309,7 +309,8 @@ void PrintDiagnostic(CXDiagnostic Diagnostic) { CXFile file; CXString Msg; unsigned display_opts = CXDiagnostic_DisplaySourceLocation - | CXDiagnostic_DisplayColumn | CXDiagnostic_DisplaySourceRanges; + | CXDiagnostic_DisplayColumn | CXDiagnostic_DisplaySourceRanges + | CXDiagnostic_DisplayOption; unsigned i, num_fixits; if (clang_getDiagnosticSeverity(Diagnostic) == CXDiagnostic_Ignored) diff --git a/tools/libclang/CIndexDiagnostic.cpp b/tools/libclang/CIndexDiagnostic.cpp index 35acd0da00..fa3b1cec7f 100644 --- a/tools/libclang/CIndexDiagnostic.cpp +++ b/tools/libclang/CIndexDiagnostic.cpp @@ -119,11 +119,61 @@ CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) { else Out << ""; clang_disposeString(Text); + + if (Options & (CXDiagnostic_DisplayOption | CXDiagnostic_DisplayCategoryId | + CXDiagnostic_DisplayCategoryName)) { + bool NeedBracket = true; + bool NeedComma = false; + + if (Options & CXDiagnostic_DisplayOption) { + CXString OptionName = clang_getDiagnosticOption(Diagnostic, 0); + if (const char *OptionText = clang_getCString(OptionName)) { + if (OptionText[0]) { + Out << " [" << OptionText; + NeedBracket = false; + NeedComma = true; + } + } + clang_disposeString(OptionName); + } + + if (Options & (CXDiagnostic_DisplayCategoryId | + CXDiagnostic_DisplayCategoryName)) { + if (unsigned CategoryID = clang_getDiagnosticCategory(Diagnostic)) { + if (Options & CXDiagnostic_DisplayCategoryId) { + if (NeedBracket) + Out << " ["; + if (NeedComma) + Out << ", "; + Out << CategoryID; + NeedBracket = false; + NeedComma = true; + } + + if (Options & CXDiagnostic_DisplayCategoryName) { + CXString CategoryName = clang_getDiagnosticCategoryName(CategoryID); + if (NeedBracket) + Out << " ["; + if (NeedComma) + Out << ", "; + Out << clang_getCString(CategoryName); + NeedBracket = false; + NeedComma = true; + clang_disposeString(CategoryName); + } + } + } + + if (!NeedBracket) + Out << "]"; + } + return createCXString(Out.str(), true); } unsigned clang_defaultDiagnosticDisplayOptions() { - return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn; + return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn | + CXDiagnostic_DisplayOption; } enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) { @@ -161,6 +211,47 @@ CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) { return createCXString(StoredDiag->Diag.getMessage(), false); } +CXString clang_getDiagnosticOption(CXDiagnostic Diag, CXString *Disable) { + if (Disable) + *Disable = createCXString(""); + + CXStoredDiagnostic *StoredDiag = static_cast(Diag); + if (!StoredDiag) + return createCXString(""); + + unsigned ID = StoredDiag->Diag.getID(); + if (const char *Option = DiagnosticIDs::getWarningOptionForDiag(ID)) { + if (Disable) + *Disable = createCXString((llvm::Twine("-Wno-") + Option).str()); + return createCXString((llvm::Twine("-W") + Option).str()); + } + + if (ID == diag::fatal_too_many_errors) { + if (Disable) + *Disable = createCXString("-ferror-limit=0"); + return createCXString("-ferror-limit="); + } + + bool EnabledByDefault; + if (DiagnosticIDs::isBuiltinExtensionDiag(ID, EnabledByDefault) && + !EnabledByDefault) + return createCXString("-pedantic"); + + return createCXString(""); +} + +unsigned clang_getDiagnosticCategory(CXDiagnostic Diag) { + CXStoredDiagnostic *StoredDiag = static_cast(Diag); + if (!StoredDiag) + return 0; + + return DiagnosticIDs::getCategoryNumberForDiag(StoredDiag->Diag.getID()); +} + +CXString clang_getDiagnosticCategoryName(unsigned Category) { + return createCXString(DiagnosticIDs::getCategoryNameFromID(Category)); +} + unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) { CXStoredDiagnostic *StoredDiag = static_cast(Diag); if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid()) diff --git a/tools/libclang/libclang.darwin.exports b/tools/libclang/libclang.darwin.exports index 09f3cf7d21..5e8abf2533 100644 --- a/tools/libclang/libclang.darwin.exports +++ b/tools/libclang/libclang.darwin.exports @@ -58,10 +58,13 @@ _clang_getCursorType _clang_getCursorUSR _clang_getDefinitionSpellingAndExtent _clang_getDiagnostic +_clang_getDiagnosticCategory +_clang_getDiagnosticCategoryName _clang_getDiagnosticFixIt _clang_getDiagnosticLocation _clang_getDiagnosticNumFixIts _clang_getDiagnosticNumRanges +_clang_getDiagnosticOption _clang_getDiagnosticRange _clang_getDiagnosticSeverity _clang_getDiagnosticSpelling diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports index 6cbd2c63b7..ca9a9d1016 100644 --- a/tools/libclang/libclang.exports +++ b/tools/libclang/libclang.exports @@ -58,10 +58,13 @@ clang_getCursorType clang_getCursorUSR clang_getDefinitionSpellingAndExtent clang_getDiagnostic +clang_getDiagnosticCategory +clang_getDiagnosticCategoryName clang_getDiagnosticFixIt clang_getDiagnosticLocation clang_getDiagnosticNumFixIts clang_getDiagnosticNumRanges +clang_getDiagnosticOption clang_getDiagnosticRange clang_getDiagnosticSeverity clang_getDiagnosticSpelling