xref: /llvm-project/clang-tools-extra/clangd/unittests/ConfigTesting.h (revision f71ffd3b735b4d6ae3c12be1806cdd6205b3b378)
1 //===-- ConfigTesting.h - Helpers for configuration tests -------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_UNITTESTS_CONFIGTESTING_H
10 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_UNITTESTS_CONFIGTESTING_H
11 
12 #include "Protocol.h"
13 #include "llvm/Support/ScopedPrinter.h"
14 #include "llvm/Support/SourceMgr.h"
15 #include "gmock/gmock.h"
16 #include <functional>
17 #include <optional>
18 
19 namespace clang {
20 namespace clangd {
21 namespace config {
22 
23 // Provides a DiagnosticsCallback that records diganostics.
24 // Unlike just pushing them into a vector, underlying storage need not survive.
25 struct CapturedDiags {
callbackCapturedDiags26   std::function<void(const llvm::SMDiagnostic &)> callback() {
27     return [this](const llvm::SMDiagnostic &D) {
28       if (Files.empty() || Files.back() != D.getFilename())
29         Files.push_back(D.getFilename().str());
30 
31       if (D.getKind() > llvm::SourceMgr::DK_Warning)
32         return;
33 
34       Diagnostics.emplace_back();
35       Diag &Out = Diagnostics.back();
36       Out.Message = D.getMessage().str();
37       Out.Kind = D.getKind();
38       Out.Pos.line = D.getLineNo() - 1;
39       Out.Pos.character = D.getColumnNo(); // Zero-based - bug in SourceMgr?
40       if (!D.getRanges().empty()) {
41         const auto &R = D.getRanges().front();
42         Out.Rng.emplace();
43         Out.Rng->start.line = Out.Rng->end.line = Out.Pos.line;
44         Out.Rng->start.character = R.first;
45         Out.Rng->end.character = R.second;
46       }
47     };
48   }
49   struct Diag {
50     std::string Message;
51     llvm::SourceMgr::DiagKind Kind;
52     Position Pos;
53     std::optional<Range> Rng;
54 
PrintToCapturedDiags::Diag55     friend void PrintTo(const Diag &D, std::ostream *OS) {
56       *OS << (D.Kind == llvm::SourceMgr::DK_Error ? "error: " : "warning: ")
57           << D.Message << "@" << llvm::to_string(D.Pos);
58     }
59   };
60   std::vector<Diag> Diagnostics;  // Warning or higher.
61   std::vector<std::string> Files; // Filename from diagnostics including notes.
62 
clearCapturedDiags63   void clear() {
64     Diagnostics.clear();
65     Files.clear();
66   }
67 };
68 
69 MATCHER_P(diagMessage, M, "") { return arg.Message == M; }
70 MATCHER_P(diagKind, K, "") { return arg.Kind == K; }
71 MATCHER_P(diagPos, P, "") { return arg.Pos == P; }
72 MATCHER_P(diagRange, R, "") { return arg.Rng == R; }
73 
toPosition(llvm::SMLoc L,const llvm::SourceMgr & SM)74 inline Position toPosition(llvm::SMLoc L, const llvm::SourceMgr &SM) {
75   auto LineCol = SM.getLineAndColumn(L);
76   Position P;
77   P.line = LineCol.first - 1;
78   P.character = LineCol.second - 1;
79   return P;
80 }
81 
toRange(llvm::SMRange R,const llvm::SourceMgr & SM)82 inline Range toRange(llvm::SMRange R, const llvm::SourceMgr &SM) {
83   return Range{toPosition(R.Start, SM), toPosition(R.End, SM)};
84 }
85 
86 } // namespace config
87 } // namespace clangd
88 } // namespace clang
89 
90 #endif
91