forked from OSchip/llvm-project
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
This commit is contained in:
parent
968f23ab97
commit
76dbe8c800
|
@ -618,6 +618,9 @@ public:
|
||||||
/// for which we are performing code completion.
|
/// for which we are performing code completion.
|
||||||
bool isCodeCompletionFile(SourceLocation FileLoc) const;
|
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
|
/// \brief Instruct the preprocessor to skip part of the main
|
||||||
/// the main source file.
|
/// the main source file.
|
||||||
///
|
///
|
||||||
|
|
|
@ -553,16 +553,17 @@ private:
|
||||||
/// If SkipUntil finds the specified token, it returns true, otherwise it
|
/// If SkipUntil finds the specified token, it returns true, otherwise it
|
||||||
/// returns false.
|
/// returns false.
|
||||||
bool SkipUntil(tok::TokenKind T, bool StopAtSemi = true,
|
bool SkipUntil(tok::TokenKind T, bool StopAtSemi = true,
|
||||||
bool DontConsume = false) {
|
bool DontConsume = false, bool StopAtCodeCompletion = false) {
|
||||||
return SkipUntil(&T, 1, StopAtSemi, DontConsume);
|
return SkipUntil(&T, 1, StopAtSemi, DontConsume, StopAtCodeCompletion);
|
||||||
}
|
}
|
||||||
bool SkipUntil(tok::TokenKind T1, tok::TokenKind T2, bool StopAtSemi = true,
|
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};
|
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 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.
|
// Lexing and parsing of C++ inline methods.
|
||||||
|
|
|
@ -1466,6 +1466,19 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl) {
|
||||||
assert(Tok.is(tok::l_brace));
|
assert(Tok.is(tok::l_brace));
|
||||||
SourceLocation LBraceLoc = Tok.getLocation();
|
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,
|
PrettyDeclStackTraceEntry CrashInfo(Actions, Decl, LBraceLoc,
|
||||||
"parsing function body");
|
"parsing function body");
|
||||||
|
|
||||||
|
|
|
@ -214,7 +214,8 @@ bool Parser::ExpectAndConsumeSemi(unsigned DiagID) {
|
||||||
/// If SkipUntil finds the specified token, it returns true, otherwise it
|
/// If SkipUntil finds the specified token, it returns true, otherwise it
|
||||||
/// returns false.
|
/// returns false.
|
||||||
bool Parser::SkipUntil(const tok::TokenKind *Toks, unsigned NumToks,
|
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
|
// We always want this function to skip at least one token if the first token
|
||||||
// isn't T and if not at EOF.
|
// isn't T and if not at EOF.
|
||||||
bool isFirstTokenSkipped = true;
|
bool isFirstTokenSkipped = true;
|
||||||
|
@ -237,23 +238,24 @@ bool Parser::SkipUntil(const tok::TokenKind *Toks, unsigned NumToks,
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case tok::code_completion:
|
case tok::code_completion:
|
||||||
ConsumeToken();
|
if (!StopAtCodeCompletion)
|
||||||
|
ConsumeToken();
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case tok::l_paren:
|
case tok::l_paren:
|
||||||
// Recursively skip properly-nested parens.
|
// Recursively skip properly-nested parens.
|
||||||
ConsumeParen();
|
ConsumeParen();
|
||||||
SkipUntil(tok::r_paren, false);
|
SkipUntil(tok::r_paren, false, false, StopAtCodeCompletion);
|
||||||
break;
|
break;
|
||||||
case tok::l_square:
|
case tok::l_square:
|
||||||
// Recursively skip properly-nested square brackets.
|
// Recursively skip properly-nested square brackets.
|
||||||
ConsumeBracket();
|
ConsumeBracket();
|
||||||
SkipUntil(tok::r_square, false);
|
SkipUntil(tok::r_square, false, false, StopAtCodeCompletion);
|
||||||
break;
|
break;
|
||||||
case tok::l_brace:
|
case tok::l_brace:
|
||||||
// Recursively skip properly-nested braces.
|
// Recursively skip properly-nested braces.
|
||||||
ConsumeBrace();
|
ConsumeBrace();
|
||||||
SkipUntil(tok::r_brace, false);
|
SkipUntil(tok::r_brace, false, false, StopAtCodeCompletion);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Okay, we found a ']' or '}' or ')', which we think should be balanced.
|
// Okay, we found a ']' or '}' or ')', which we think should be balanced.
|
||||||
|
|
|
@ -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
|
|
|
@ -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: c-index-test -code-completion-at=%s:6:2 -remap-file="%s;%S/Inputs/remap-complete-to.c" %s | FileCheck %s
|
||||||
// RUN: FileCheck -check-prefix=CHECK-DIAGS %s < %t.err
|
|
||||||
|
|
||||||
// CHECK: FunctionDecl:{ResultType int}{TypedText f0}{LeftParen (}
|
// CHECK: FunctionDecl:{ResultType int}{TypedText f0}{LeftParen (}
|
||||||
void f() { }
|
void f() { }
|
||||||
|
|
||||||
// CHECK-DIAGS: remap-complete.c:2:19
|
|
||||||
|
|
Loading…
Reference in New Issue