[clang-tools-extra] r323448 - [clangd] Add ClangdUnit diagnostics tests using annotated code.
Sam McCall via cfe-commits
cfe-commits at lists.llvm.org
Thu Jan 25 09:29:18 PST 2018
Author: sammccall
Date: Thu Jan 25 09:29:17 2018
New Revision: 323448
URL: http://llvm.org/viewvc/llvm-project?rev=323448&view=rev
Log:
[clangd] Add ClangdUnit diagnostics tests using annotated code.
Summary:
This adds checks that our diagnostics emit correct ranges in a bunch of cases,
as promised in D41118.
The diagnostics-preamble test is also converted and extended to be a little more
precise.
diagnostics.test stays around as the smoke test for this feature.
Reviewers: ilya-biryukov
Subscribers: klimek, mgorny, cfe-commits
Differential Revision: https://reviews.llvm.org/D41454
Added:
clang-tools-extra/trunk/unittests/clangd/ClangdUnitTests.cpp
Removed:
clang-tools-extra/trunk/test/clangd/diagnostics-preamble.test
Modified:
clang-tools-extra/trunk/clangd/Protocol.cpp
clang-tools-extra/trunk/clangd/Protocol.h
clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt
Modified: clang-tools-extra/trunk/clangd/Protocol.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Protocol.cpp?rev=323448&r1=323447&r2=323448&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/Protocol.cpp (original)
+++ clang-tools-extra/trunk/clangd/Protocol.cpp Thu Jan 25 09:29:17 2018
@@ -137,6 +137,12 @@ json::Expr toJSON(const TextEdit &P) {
};
}
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const TextEdit &TE) {
+ OS << TE.range << " => \"";
+ PrintEscapedString(TE.newText, OS);
+ return OS << '"';
+}
+
bool fromJSON(const json::Expr &E, TraceLevel &Out) {
if (auto S = E.asString()) {
if (*S == "off") {
@@ -255,6 +261,28 @@ bool fromJSON(const json::Expr &Params,
return O && O.map("diagnostics", R.diagnostics);
}
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Diagnostic &D) {
+ OS << D.range << " [";
+ switch (D.severity) {
+ case 1:
+ OS << "error";
+ break;
+ case 2:
+ OS << "warning";
+ break;
+ case 3:
+ OS << "note";
+ break;
+ case 4:
+ OS << "remark";
+ break;
+ default:
+ OS << "diagnostic";
+ break;
+ }
+ return OS << '(' << D.severity << "): " << D.message << "]";
+}
+
bool fromJSON(const json::Expr &Params, CodeActionParams &R) {
json::ObjectMapper O(Params);
return O && O.map("textDocument", R.textDocument) &&
Modified: clang-tools-extra/trunk/clangd/Protocol.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Protocol.h?rev=323448&r1=323447&r2=323448&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/Protocol.h (original)
+++ clang-tools-extra/trunk/clangd/Protocol.h Thu Jan 25 09:29:17 2018
@@ -150,6 +150,7 @@ struct TextEdit {
};
bool fromJSON(const json::Expr &, TextEdit &);
json::Expr toJSON(const TextEdit &);
+llvm::raw_ostream &operator<<(llvm::raw_ostream &, const TextEdit &);
struct TextDocumentItem {
/// The text document's URI.
@@ -341,6 +342,7 @@ struct LSPDiagnosticCompare {
}
};
bool fromJSON(const json::Expr &, Diagnostic &);
+llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Diagnostic &);
struct CodeActionContext {
/// An array of diagnostics.
Removed: clang-tools-extra/trunk/test/clangd/diagnostics-preamble.test
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/diagnostics-preamble.test?rev=323447&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clangd/diagnostics-preamble.test (original)
+++ clang-tools-extra/trunk/test/clangd/diagnostics-preamble.test (removed)
@@ -1,22 +0,0 @@
-# RUN: clangd -pretty -run-synchronously < %s | FileCheck -strict-whitespace %s
-# RUN: clangd -pretty -run-synchronously -pch-storage=memory < %s | FileCheck -strict-whitespace %s
-# It is absolutely vital that this file has CRLF line endings.
-#
-Content-Length: 125
-
-{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
-
-Content-Length: 206
-
-{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///main.cpp","languageId":"cpp","version":1,"text":"#ifndef FOO\n#define FOO\nint a;\n#else\nint a = b;#endif\n\n\n"}}}
-# CHECK: "method": "textDocument/publishDiagnostics",
-# CHECK-NEXT: "params": {
-# CHECK-NEXT: "diagnostics": [],
-# CHECK-NEXT: "uri": "file:///{{([A-Z]:/)?}}main.cpp"
-# CHECK-NEXT: }
-Content-Length: 58
-
-{"jsonrpc":"2.0","id":2,"method":"shutdown","params":null}
-Content-Length: 33
-
-{"jsonrpc":"2.0":"method":"exit"}
Modified: clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt?rev=323448&r1=323447&r2=323448&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt Thu Jan 25 09:29:17 2018
@@ -11,6 +11,7 @@ include_directories(
add_extra_unittest(ClangdTests
Annotations.cpp
ClangdTests.cpp
+ ClangdUnitTests.cpp
CodeCompleteTests.cpp
CodeCompletionStringsTests.cpp
ContextTests.cpp
Added: clang-tools-extra/trunk/unittests/clangd/ClangdUnitTests.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/ClangdUnitTests.cpp?rev=323448&view=auto
==============================================================================
--- clang-tools-extra/trunk/unittests/clangd/ClangdUnitTests.cpp (added)
+++ clang-tools-extra/trunk/unittests/clangd/ClangdUnitTests.cpp Thu Jan 25 09:29:17 2018
@@ -0,0 +1,130 @@
+//===-- ClangdUnitTests.cpp - ClangdUnit tests ------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangdUnit.h"
+#include "Annotations.h"
+#include "TestFS.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/PCHContainerOperations.h"
+#include "clang/Frontend/Utils.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace clangd {
+using namespace llvm;
+void PrintTo(const DiagWithFixIts &D, std::ostream *O) {
+ llvm::raw_os_ostream OS(*O);
+ OS << D.Diag;
+ if (!D.FixIts.empty()) {
+ OS << " {";
+ const char *Sep = "";
+ for (const auto &F : D.FixIts) {
+ OS << Sep << F;
+ Sep = ", ";
+ }
+ OS << "}";
+ }
+}
+
+namespace {
+using testing::ElementsAre;
+
+// FIXME: this is duplicated with FileIndexTests. Share it.
+ParsedAST build(StringRef Code, std::vector<const char*> Flags = {}) {
+ std::vector<const char*> Cmd = {"clang", "main.cpp"};
+ Cmd.insert(Cmd.begin() + 1, Flags.begin(), Flags.end());
+ auto CI = createInvocationFromCommandLine(Cmd);
+ auto Buf = MemoryBuffer::getMemBuffer(Code);
+ auto AST = ParsedAST::Build(
+ Context::empty(), std::move(CI), nullptr, std::move(Buf),
+ std::make_shared<PCHContainerOperations>(), vfs::getRealFileSystem());
+ assert(AST.hasValue());
+ return std::move(*AST);
+}
+
+MATCHER_P2(Diag, Range, Message,
+ "Diagnostic at " + llvm::to_string(Range) + " = [" + Message + "]") {
+ return arg.Diag.range == Range && arg.Diag.message == Message &&
+ arg.FixIts.empty();
+}
+
+MATCHER_P3(Fix, Range, Replacement, Message,
+ "Fix " + llvm::to_string(Range) + " => " +
+ testing::PrintToString(Replacement) + " = [" + Message + "]") {
+ return arg.Diag.range == Range && arg.Diag.message == Message &&
+ arg.FixIts.size() == 1 && arg.FixIts[0].range == Range &&
+ arg.FixIts[0].newText == Replacement;
+}
+
+TEST(DiagnosticsTest, DiagnosticRanges) {
+ // Check we report correct ranges, including various edge-cases.
+ Annotations Test(R"cpp(
+ void $decl[[foo]]();
+ int main() {
+ $typo[[go\
+o]]();
+ foo()$semicolon[[]]
+ $unk[[unknown]]();
+ }
+ )cpp");
+ llvm::errs() << Test.code();
+ EXPECT_THAT(
+ build(Test.code()).getDiagnostics(),
+ ElementsAre(
+ // This range spans lines.
+ Fix(Test.range("typo"), "foo",
+ "use of undeclared identifier 'goo'; did you mean 'foo'?"),
+ // This is a pretty normal range.
+ Diag(Test.range("decl"), "'foo' declared here"),
+ // This range is zero-width, and at the end of a line.
+ Fix(Test.range("semicolon"), ";",
+ "expected ';' after expression"),
+ // This range isn't provided by clang, we expand to the token.
+ Diag(Test.range("unk"),
+ "use of undeclared identifier 'unknown'")));
+}
+
+TEST(DiagnosticsTest, FlagsMatter) {
+ Annotations Test("[[void]] main() {}");
+ EXPECT_THAT(
+ build(Test.code()).getDiagnostics(),
+ ElementsAre(Fix(Test.range(), "int", "'main' must return 'int'")));
+ // Same code built as C gets different diagnostics.
+ EXPECT_THAT(
+ build(Test.code(), {"-x", "c"}).getDiagnostics(),
+ ElementsAre(
+ // FIXME: ideally this would be one diagnostic with a named FixIt.
+ Diag(Test.range(), "return type of 'main' is not 'int'"),
+ Fix(Test.range(), "int", "change return type to 'int'")));
+}
+
+TEST(DiagnosticsTest, Preprocessor) {
+ // This looks like a preamble, but there's an #else in the middle!
+ // Check that:
+ // - the #else doesn't generate diagnostics (we had this bug)
+ // - we get diagnostics from the taken branch
+ // - we get no diagnostics from the not taken branch
+ Annotations Test(R"cpp(
+ #ifndef FOO
+ #define FOO
+ int a = [[b]];
+ #else
+ int x = y;
+ #endif
+ )cpp");
+ EXPECT_THAT(
+ build(Test.code()).getDiagnostics(),
+ ElementsAre(Diag(Test.range(), "use of undeclared identifier 'b'")));
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang
More information about the cfe-commits
mailing list