diff --git a/clang-tools-extra/clangd/Protocol.h b/clang-tools-extra/clangd/Protocol.h --- a/clang-tools-extra/clangd/Protocol.h +++ b/clang-tools-extra/clangd/Protocol.h @@ -1579,6 +1579,7 @@ llvm::json::Value toJSON(const InlayHint &); bool operator==(const InlayHint &, const InlayHint &); bool operator<(const InlayHint &, const InlayHint &); +llvm::raw_ostream &operator<<(llvm::raw_ostream &, InlayHintKind); struct ReferenceContext { /// Include the declaration of the current symbol. diff --git a/clang-tools-extra/clangd/Protocol.cpp b/clang-tools-extra/clangd/Protocol.cpp --- a/clang-tools-extra/clangd/Protocol.cpp +++ b/clang-tools-extra/clangd/Protocol.cpp @@ -15,6 +15,7 @@ #include "support/Logger.h" #include "clang/Basic/LLVM.h" #include "clang/Index/IndexSymbol.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/JSON.h" @@ -1318,7 +1319,7 @@ return O && O.map("textDocument", R.textDocument) && O.map("range", R.range); } -llvm::json::Value toJSON(InlayHintKind K) { +static llvm::StringLiteral toString(InlayHintKind K) { switch (K) { case InlayHintKind::ParameterHint: return "parameter"; @@ -1330,6 +1331,8 @@ llvm_unreachable("Unknown clang.clangd.InlayHintKind"); } +llvm::json::Value toJSON(InlayHintKind K) { return toString(K); } + llvm::json::Value toJSON(const InlayHint &H) { return llvm::json::Object{{"position", H.position}, {"range", H.range}, @@ -1345,6 +1348,10 @@ std::tie(B.position, B.range, B.kind, B.label); } +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, InlayHintKind Kind) { + return OS << toString(Kind); +} + static const char *toString(OffsetEncoding OE) { switch (OE) { case OffsetEncoding::UTF8: diff --git a/clang-tools-extra/clangd/tool/Check.cpp b/clang-tools-extra/clangd/tool/Check.cpp --- a/clang-tools-extra/clangd/tool/Check.cpp +++ b/clang-tools-extra/clangd/tool/Check.cpp @@ -30,8 +30,10 @@ #include "Config.h" #include "GlobalCompilationDatabase.h" #include "Hover.h" +#include "InlayHints.h" #include "ParsedAST.h" #include "Preamble.h" +#include "Protocol.h" #include "SourceCode.h" #include "XRefs.h" #include "index/CanonicalIncludes.h" @@ -190,10 +192,19 @@ return true; } + // Build Inlay Hints for the entire AST or the specified range + void buildInlayHints(llvm::Optional LineRange) { + log("Building inlay hints"); + auto Hints = inlayHints(*AST, LineRange); + + for (const auto &Hint : Hints) { + vlog(" {0} {1} {2}", Hint.kind, Hint.position, Hint.label); + } + } + // Run AST-based features at each token in the file. - void testLocationFeatures( - llvm::function_ref ShouldCheckLine, - const bool EnableCodeCompletion) { + void testLocationFeatures(llvm::Optional LineRange, + const bool EnableCodeCompletion) { trace::Span Trace("testLocationFeatures"); log("Testing features at each token (may be slow in large files)"); auto &SM = AST->getSourceManager(); @@ -207,7 +218,7 @@ unsigned End = Start + Tok.length(); Position Pos = offsetToPosition(Inputs.Contents, Start); - if (!ShouldCheckLine(Pos)) + if (LineRange && !LineRange->contains(Pos)) continue; trace::Span Trace("Token"); @@ -254,8 +265,7 @@ } // namespace -bool check(llvm::StringRef File, - llvm::function_ref ShouldCheckLine, +bool check(llvm::StringRef File, llvm::Optional LineRange, const ThreadsafeFS &TFS, const ClangdLSPServer::Options &Opts, bool EnableCodeCompletion) { llvm::SmallString<0> FakeFile; @@ -284,7 +294,8 @@ if (!C.buildCommand(TFS) || !C.buildInvocation(TFS, Contents) || !C.buildAST()) return false; - C.testLocationFeatures(ShouldCheckLine, EnableCodeCompletion); + C.buildInlayHints(LineRange); + C.testLocationFeatures(LineRange, EnableCodeCompletion); log("All checks completed, {0} errors", C.ErrCount); return C.ErrCount == 0; diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp --- a/clang-tools-extra/clangd/tool/ClangdMain.cpp +++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp @@ -61,8 +61,7 @@ namespace clangd { // Implemented in Check.cpp. -bool check(const llvm::StringRef File, - llvm::function_ref ShouldCheckLine, +bool check(const llvm::StringRef File, llvm::Optional LineRange, const ThreadsafeFS &TFS, const ClangdLSPServer::Options &Opts, bool EnableCodeCompletion); @@ -955,8 +954,9 @@ return 1; } log("Entering check mode (no LSP server)"); - uint32_t Begin = 0, End = std::numeric_limits::max(); + llvm::Optional CheckLineRange; if (!CheckFileLines.empty()) { + uint32_t Begin = 0, End = std::numeric_limits::max(); StringRef RangeStr(CheckFileLines); bool ParseError = RangeStr.consumeInteger(0, Begin); if (RangeStr.empty()) { @@ -965,19 +965,18 @@ ParseError |= !RangeStr.consume_front("-"); ParseError |= RangeStr.consumeInteger(0, End); } - if (ParseError || !RangeStr.empty()) { - elog("Invalid --check-line specified. Use Begin-End format, e.g. 3-17"); + if (ParseError || !RangeStr.empty() || Begin <= 0 || End < Begin) { + elog( + "Invalid --check-lines specified. Use Begin-End format, e.g. 3-17"); return 1; } + CheckLineRange = Range{Position{static_cast(Begin - 1), 0}, + Position{static_cast(End), 0}}; } - auto ShouldCheckLine = [&](const Position &Pos) { - uint32_t Line = Pos.line + 1; // Position::line is 0-based. - return Line >= Begin && Line <= End; - }; // For now code completion is enabled any time the range is limited via // --check-lines. If it turns out to be to slow, we can introduce a // dedicated flag for that instead. - return check(Path, ShouldCheckLine, TFS, Opts, + return check(Path, CheckLineRange, TFS, Opts, /*EnableCodeCompletion=*/!CheckFileLines.empty()) ? 0 : static_cast(ErrorResultCode::CheckFailed);