From 76dbe8c800c818d4ebe414999cf9e44834bb31a7 Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Mon, 3 Jan 2011 19:44:02 +0000 Subject: [PATCH] Speed up code-completion by skipping function bodies. When we are in code-completion mode, skip parsing of all function bodies except the one where the code-completion point resides. For big .cpp files like 'SemaExpr.cpp' the improvement makes a huge difference, in some cases cutting down code-completion time -62% ! We don't get diagnostics for the bodies though, so modify the code-completion tests that check for errors. See rdar://8814203. llvm-svn: 122765 --- clang/include/clang/Lex/Preprocessor.h | 3 +++ clang/include/clang/Parse/Parser.h | 11 ++++++----- clang/lib/Parse/ParseStmt.cpp | 13 +++++++++++++ clang/lib/Parse/Parser.cpp | 12 +++++++----- clang/test/Index/code-complete-errors.c | 25 ------------------------- clang/test/Index/remap-complete.c | 5 +---- 6 files changed, 30 insertions(+), 39 deletions(-) delete mode 100644 clang/test/Index/code-complete-errors.c diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index ca4b9fddabbf..df3a5b234bc9 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -618,6 +618,9 @@ public: /// for which we are performing code completion. bool isCodeCompletionFile(SourceLocation FileLoc) const; + /// \brief Determine if we are performing code completion. + bool isCodeCompletionEnabled() const { return CodeCompletionFile != 0; } + /// \brief Instruct the preprocessor to skip part of the main /// the main source file. /// diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index db4d1b7a4b77..f523bed9761a 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -553,16 +553,17 @@ private: /// If SkipUntil finds the specified token, it returns true, otherwise it /// returns false. bool SkipUntil(tok::TokenKind T, bool StopAtSemi = true, - bool DontConsume = false) { - return SkipUntil(&T, 1, StopAtSemi, DontConsume); + bool DontConsume = false, bool StopAtCodeCompletion = false) { + return SkipUntil(&T, 1, StopAtSemi, DontConsume, StopAtCodeCompletion); } bool SkipUntil(tok::TokenKind T1, tok::TokenKind T2, bool StopAtSemi = true, - bool DontConsume = false) { + bool DontConsume = false, bool StopAtCodeCompletion = false) { tok::TokenKind TokArray[] = {T1, T2}; - return SkipUntil(TokArray, 2, StopAtSemi, DontConsume); + return SkipUntil(TokArray, 2, StopAtSemi, DontConsume,StopAtCodeCompletion); } bool SkipUntil(const tok::TokenKind *Toks, unsigned NumToks, - bool StopAtSemi = true, bool DontConsume = false); + bool StopAtSemi = true, bool DontConsume = false, + bool StopAtCodeCompletion = false); //===--------------------------------------------------------------------===// // Lexing and parsing of C++ inline methods. diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index dafe37377835..d25cc110a8a8 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -1466,6 +1466,19 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl) { assert(Tok.is(tok::l_brace)); SourceLocation LBraceLoc = Tok.getLocation(); + // When in code-completion, skip parsing for all function bodies unless + // the body contains the code-completion point. + if (PP.isCodeCompletionEnabled()) { + TentativeParsingAction PA(*this); + ConsumeBrace(); + if (SkipUntil(tok::r_brace, /*StopAtSemi=*/false, /*DontConsume=*/false, + /*StopAtCodeCompletion=*/true)) { + PA.Commit(); + return Actions.ActOnFinishFunctionBody(Decl, 0); + } + PA.Revert(); + } + PrettyDeclStackTraceEntry CrashInfo(Actions, Decl, LBraceLoc, "parsing function body"); diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 2a569b58d8c4..aa0ad795cab7 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -214,7 +214,8 @@ bool Parser::ExpectAndConsumeSemi(unsigned DiagID) { /// If SkipUntil finds the specified token, it returns true, otherwise it /// returns false. bool Parser::SkipUntil(const tok::TokenKind *Toks, unsigned NumToks, - bool StopAtSemi, bool DontConsume) { + bool StopAtSemi, bool DontConsume, + bool StopAtCodeCompletion) { // We always want this function to skip at least one token if the first token // isn't T and if not at EOF. bool isFirstTokenSkipped = true; @@ -237,23 +238,24 @@ bool Parser::SkipUntil(const tok::TokenKind *Toks, unsigned NumToks, return false; case tok::code_completion: - ConsumeToken(); + if (!StopAtCodeCompletion) + ConsumeToken(); return false; case tok::l_paren: // Recursively skip properly-nested parens. ConsumeParen(); - SkipUntil(tok::r_paren, false); + SkipUntil(tok::r_paren, false, false, StopAtCodeCompletion); break; case tok::l_square: // Recursively skip properly-nested square brackets. ConsumeBracket(); - SkipUntil(tok::r_square, false); + SkipUntil(tok::r_square, false, false, StopAtCodeCompletion); break; case tok::l_brace: // Recursively skip properly-nested braces. ConsumeBrace(); - SkipUntil(tok::r_brace, false); + SkipUntil(tok::r_brace, false, false, StopAtCodeCompletion); break; // Okay, we found a ']' or '}' or ')', which we think should be balanced. diff --git a/clang/test/Index/code-complete-errors.c b/clang/test/Index/code-complete-errors.c deleted file mode 100644 index 51cfb895e2bd..000000000000 --- a/clang/test/Index/code-complete-errors.c +++ /dev/null @@ -1,25 +0,0 @@ -_Complex cd; // CHECK: code-complete-errors.c:1:1: warning: plain '_Complex' requires a type specifier; assuming '_Complex double' -// CHECK: FIX-IT: Insert " double" at 1:9 -struct s { - int x, y;; // CHECK: code-complete-errors.c:4:12: warning: extra ';' inside a struct -}; // CHECK: FIX-IT: Remove [4:12 - 4:13] - -struct s s0 = { y: 5 }; // CHECK: code-complete-errors.c:7:20: warning: use of GNU old-style field designator extension -// CHECK: FIX-IT: Replace [7:17 - 7:19] with ".y = " -int f(int *ptr1, float *ptr2) { - return ptr1 != ptr2; // CHECK: code-complete-errors.c:10:15:{10:10-10:14}{10:18-10:22}: warning: comparison of distinct pointer types ('int *' and 'float *') -} - -#define expand_to_binary_function(ret, name, parm1, parm2, code) ret name(parm1, parm2) code - -expand_to_binary_function(int, g, int *ip, float *fp, { - // CHECK: code-complete-errors.c:17:12:{17:9-17:24}: warning: using the result of an assignment as a condition without parentheses [-Wparentheses] - if (ip = (float*)fp) ; -// CHECK: code-complete-errors.c:19:15:{19:12-19:14}{19:18-19:20}: warning: comparison of distinct pointer types ('int *' and 'float *') - return ip == fp; - }) - -void g() { } - -// RUN: c-index-test -code-completion-at=%s:21:12 -pedantic %s 2> %t -// RUN: FileCheck -check-prefix=CHECK %s < %t diff --git a/clang/test/Index/remap-complete.c b/clang/test/Index/remap-complete.c index e5b782930db6..93fb6236c243 100644 --- a/clang/test/Index/remap-complete.c +++ b/clang/test/Index/remap-complete.c @@ -1,7 +1,4 @@ -// RUN: c-index-test -code-completion-at=%s:6:2 -remap-file="%s;%S/Inputs/remap-complete-to.c" %s 2> %t.err | FileCheck %s -// RUN: FileCheck -check-prefix=CHECK-DIAGS %s < %t.err +// RUN: c-index-test -code-completion-at=%s:6:2 -remap-file="%s;%S/Inputs/remap-complete-to.c" %s | FileCheck %s // CHECK: FunctionDecl:{ResultType int}{TypedText f0}{LeftParen (} void f() { } - -// CHECK-DIAGS: remap-complete.c:2:19