Commit 7e506b30 authored by Sam McCall's avatar Sam McCall
Browse files

[clangd] Allow diagnostics to be suppressed with configuration

This has been specifically requested:
  https://github.com/clangd/vscode-clangd/issues/114
and various issues can be addressed with this as a workaround, e.g.:
  https://github.com/clangd/clangd/issues/662

Differential Revision: https://reviews.llvm.org/D95349
parent 00054382
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#include "llvm/ADT/FunctionExtras.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSet.h"
#include <string>
#include <vector>

@@ -77,6 +78,12 @@ struct Config {
    llvm::Optional<ExternalIndexSpec> External;
  } Index;

  /// Controls warnings and errors when parsing code.
  struct {
    bool SuppressAll = false;
    llvm::StringSet<> Suppress;
  } Diagnostics;

  /// Style of the codebase.
  struct {
    // Namespaces that should always be fully qualified, meaning no "using"
+23 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
#include "Config.h"
#include "ConfigFragment.h"
#include "ConfigProvider.h"
#include "Diagnostics.h"
#include "Features.inc"
#include "TidyProvider.h"
#include "support/Logger.h"
@@ -187,6 +188,7 @@ struct FragmentCompiler {
    compile(std::move(F.If));
    compile(std::move(F.CompileFlags));
    compile(std::move(F.Index));
    compile(std::move(F.Diagnostics));
    compile(std::move(F.ClangTidy));
  }

@@ -328,6 +330,27 @@ struct FragmentCompiler {
    });
  }

  void compile(Fragment::DiagnosticsBlock &&F) {
    std::vector<llvm::StringRef> Normalized;
    for (const auto &Suppressed : F.Suppress) {
      if (*Suppressed == "*") {
        Out.Apply.push_back([&](const Params &, Config &C) {
          C.Diagnostics.SuppressAll = true;
          C.Diagnostics.Suppress.clear();
        });
        return;
      }
      Normalized.push_back(normalizeSuppressedCode(*Suppressed));
    }
    if (!Normalized.empty())
      Out.Apply.push_back([Normalized](const Params &, Config &C) {
        if (C.Diagnostics.SuppressAll)
          return;
        for (llvm::StringRef N : Normalized)
          C.Diagnostics.Suppress.insert(N);
      });
  }

  void compile(Fragment::StyleBlock &&F) {
    if (!F.FullyQualifiedNamespaces.empty()) {
      std::vector<std::string> FullyQualifiedNamespaces;
+19 −0
Original line number Diff line number Diff line
@@ -181,6 +181,24 @@ struct Fragment {
  };
  IndexBlock Index;

  /// Controls behavior of diagnostics (errors and warnings).
  struct DiagnosticsBlock {
    /// Diagnostic codes that should be suppressed.
    ///
    /// Valid values are:
    /// - *, to disable all diagnostics
    /// - diagnostic codes exposed by clangd (e.g unknown_type, -Wunused-result)
    /// - clang internal diagnostic codes (e.g. err_unknown_type)
    /// - warning categories (e.g. unused-result)
    /// - clang-tidy check names (e.g. bugprone-narrowing-conversions)
    ///
    /// This is a simple filter. Diagnostics can be controlled in other ways
    /// (e.g. by disabling a clang-tidy check, or the -Wunused compile flag).
    /// This often has other advantages, such as skipping some analysis.
    std::vector<Located<std::string>> Suppress;
  };
  DiagnosticsBlock Diagnostics;

  // Describes the style of the codebase, beyond formatting.
  struct StyleBlock {
    // Namespaces that should always be fully qualified, meaning no "using"
@@ -195,6 +213,7 @@ struct Fragment {
  ///
  /// The settings are merged with any settings found in .clang-tidy
  /// configiration files with these ones taking precedence.
  // FIXME: move this to Diagnostics.Tidy.
  struct ClangTidyBlock {
    std::vector<Located<std::string>> Add;
    /// List of checks to disable.
+18 −0
Original line number Diff line number Diff line
@@ -801,5 +801,23 @@ void StoreDiags::flushLastDiag() {
  Output.push_back(std::move(*LastDiag));
}

bool isBuiltinDiagnosticSuppressed(unsigned ID,
                                   const llvm::StringSet<> &Suppress) {
  if (const char *CodePtr = getDiagnosticCode(ID)) {
    if (Suppress.contains(normalizeSuppressedCode(CodePtr)))
      return true;
  }
  StringRef Warning = DiagnosticIDs::getWarningOptionForDiag(ID);
  if (!Warning.empty() && Suppress.contains(Warning))
    return true;
  return false;
}

llvm::StringRef normalizeSuppressedCode(llvm::StringRef Code) {
  Code.consume_front("err_");
  Code.consume_front("-W");
  return Code;
}

} // namespace clangd
} // namespace clang
+9 −0
Original line number Diff line number Diff line
@@ -159,6 +159,15 @@ private:
  bool LastPrimaryDiagnosticWasSuppressed = false;
};

/// Determine whether a (non-clang-tidy) diagnostic is suppressed by config.
bool isBuiltinDiagnosticSuppressed(unsigned ID,
                                   const llvm::StringSet<> &Suppressed);
/// Take a user-specified diagnostic code, and convert it to a normalized form
/// stored in the config and consumed by isBuiltinDiagnosticsSuppressed.
///
/// (This strips err_ and -W prefix so we can match with or without them.)
llvm::StringRef normalizeSuppressedCode(llvm::StringRef);

} // namespace clangd
} // namespace clang

Loading