Skip to content

Commit 3b4936b

Browse files
committed
[clangd] Add --check-lines to restrict --check to specific lines
This will allow us to add code completion, which is too expensive at every token, to --check too. Differential Revision: https://reviews.llvm.org/D98970
1 parent 494ba60 commit 3b4936b

File tree

3 files changed

+65
-9
lines changed

3 files changed

+65
-9
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: cp %s %t.cpp
2+
// RUN: not clangd -check=%t.cpp -check-lines=6-14 2>&1 | FileCheck -strict-whitespace %s
3+
// RUN: not clangd -check=%t.cpp -check-lines=14 2>&1 | FileCheck -strict-whitespace %s
4+
5+
// CHECK: Testing on source file {{.*}}check-lines.test
6+
// CHECK: internal (cc1) args are: -cc1
7+
// CHECK: Building preamble...
8+
// CHECK: Building AST...
9+
// CHECK: Testing features at each token
10+
// CHECK: tweak: ExpandAutoType ==> FAIL
11+
// CHECK: All checks completed, 1 errors
12+
13+
void fun();
14+
auto x = fun; // This line is tested
15+
auto y = fun; // This line is not tested

clang-tools-extra/clangd/tool/Check.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -192,14 +192,19 @@ class Checker {
192192
}
193193

194194
// Run AST-based features at each token in the file.
195-
void testLocationFeatures() {
195+
void testLocationFeatures(
196+
llvm::function_ref<bool(const Position &)> ShouldCheckLine) {
196197
log("Testing features at each token (may be slow in large files)");
197-
auto SpelledTokens =
198-
AST->getTokens().spelledTokens(AST->getSourceManager().getMainFileID());
198+
auto &SM = AST->getSourceManager();
199+
auto SpelledTokens = AST->getTokens().spelledTokens(SM.getMainFileID());
199200
for (const auto &Tok : SpelledTokens) {
200201
unsigned Start = AST->getSourceManager().getFileOffset(Tok.location());
201202
unsigned End = Start + Tok.length();
202203
Position Pos = offsetToPosition(Inputs.Contents, Start);
204+
205+
if (!ShouldCheckLine(Pos))
206+
continue;
207+
203208
// FIXME: dumping the tokens may leak sensitive code into bug reports.
204209
// Add an option to turn this off, once we decide how options work.
205210
vlog(" {0} {1}", Pos, Tok.text(AST->getSourceManager()));
@@ -229,8 +234,9 @@ class Checker {
229234

230235
} // namespace
231236

232-
bool check(llvm::StringRef File, const ThreadsafeFS &TFS,
233-
const ClangdLSPServer::Options &Opts) {
237+
bool check(llvm::StringRef File,
238+
llvm::function_ref<bool(const Position &)> ShouldCheckLine,
239+
const ThreadsafeFS &TFS, const ClangdLSPServer::Options &Opts) {
234240
llvm::SmallString<0> FakeFile;
235241
llvm::Optional<std::string> Contents;
236242
if (File.empty()) {
@@ -254,7 +260,7 @@ bool check(llvm::StringRef File, const ThreadsafeFS &TFS,
254260
if (!C.buildCommand(TFS) || !C.buildInvocation(TFS, Contents) ||
255261
!C.buildAST())
256262
return false;
257-
C.testLocationFeatures();
263+
C.testLocationFeatures(ShouldCheckLine);
258264

259265
log("All checks completed, {0} errors", C.ErrCount);
260266
return C.ErrCount == 0;

clang-tools-extra/clangd/tool/ClangdMain.cpp

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,9 @@ namespace clang {
6060
namespace clangd {
6161

6262
// Implemented in Check.cpp.
63-
bool check(const llvm::StringRef File, const ThreadsafeFS &TFS,
64-
const ClangdLSPServer::Options &Opts);
63+
bool check(const llvm::StringRef File,
64+
llvm::function_ref<bool(const Position &)> ShouldCheckLine,
65+
const ThreadsafeFS &TFS, const ClangdLSPServer::Options &Opts);
6566

6667
namespace {
6768

@@ -347,6 +348,17 @@ opt<Path> CheckFile{
347348
ValueOptional,
348349
};
349350

351+
opt<std::string> CheckFileLines{
352+
"check-lines",
353+
cat(Misc),
354+
desc("If specified, limits the range of tokens in -check file on which "
355+
"various features are tested. Example --check-lines=3-7 restricts "
356+
"testing to lines 3 to 7 (inclusive) or --check-lines=5 to restrict "
357+
"to one line. Default is testing entire file."),
358+
init(""),
359+
ValueOptional,
360+
};
361+
350362
enum PCHStorageFlag { Disk, Memory };
351363
opt<PCHStorageFlag> PCHStorage{
352364
"pch-storage",
@@ -883,10 +895,33 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var
883895
llvm::SmallString<256> Path;
884896
llvm::sys::fs::real_path(CheckFile, Path, /*expand_tilde=*/true);
885897
log("Entering check mode (no LSP server)");
886-
return check(Path, TFS, Opts)
898+
uint32_t Begin = 0, End = std::numeric_limits<uint32_t>::max();
899+
if (!CheckFileLines.empty()) {
900+
StringRef RangeStr(CheckFileLines);
901+
bool ParseError = RangeStr.consumeInteger(0, Begin);
902+
if (RangeStr.empty()) {
903+
End = Begin;
904+
} else {
905+
ParseError |= !RangeStr.consume_front("-");
906+
ParseError |= RangeStr.consumeInteger(0, End);
907+
}
908+
if (ParseError || !RangeStr.empty()) {
909+
elog("Invalid --check-line specified. Use Begin-End format, e.g. 3-17");
910+
return 1;
911+
}
912+
}
913+
auto ShouldCheckLine = [&](const Position &Pos) {
914+
uint32_t Line = Pos.line + 1; // Position::line is 0-based.
915+
return Line >= Begin && Line <= End;
916+
};
917+
return check(Path, ShouldCheckLine, TFS, Opts)
887918
? 0
888919
: static_cast<int>(ErrorResultCode::CheckFailed);
889920
}
921+
if (!CheckFileLines.empty()) {
922+
elog("--check-lines requires --check");
923+
return 1;
924+
}
890925

891926
// Initialize and run ClangdLSPServer.
892927
// Change stdin to binary to not lose \r\n on windows.

0 commit comments

Comments
 (0)