From: Ilya Biryukov Date: Tue, 24 Apr 2018 13:48:53 +0000 (+0000) Subject: [CodeComplete] Fix completion at the end of keywords X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b3510c4254fb912045f1ded84df255d20ac0a1d1;p=platform%2Fupstream%2Fllvm.git [CodeComplete] Fix completion at the end of keywords Summary: Make completion behave consistently no matter if it is run at the start, in the middle or at the end of an identifier that happens to be a keyword or a macro name. Since completion is often ran on incomplete identifiers, they may turn into keywords by accident. For example, we should produce same results for all of these completion points: // ^ is completion point. ^class cla^ss class^ Previously clang produced different results for the last case (as if the completion point was after a space: `class ^`). This change also updates some offsets in tests that (unintentionally?) relied on the old behavior. Reviewers: sammccall, bkramer, arphaman, aaron.ballman Reviewed By: sammccall Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D45887 llvm-svn: 330717 --- diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp index 0d6e7b6..ecb7c87 100644 --- a/clang/lib/Lex/Lexer.cpp +++ b/clang/lib/Lex/Lexer.cpp @@ -1645,20 +1645,24 @@ FinishIdentifier: // Fill in Result.IdentifierInfo and update the token kind, // looking up the identifier in the identifier table. IdentifierInfo *II = PP->LookUpIdentifierInfo(Result); + // Note that we have to call PP->LookUpIdentifierInfo() even for code + // completion, it writes IdentifierInfo into Result, and callers rely on it. - // Finally, now that we know we have an identifier, pass this off to the - // preprocessor, which may macro expand it or something. - if (II->isHandleIdentifierCase()) - return PP->HandleIdentifier(Result); - - if (II->getTokenID() == tok::identifier && isCodeCompletionPoint(CurPtr) - && II->getPPKeywordID() == tok::pp_not_keyword - && II->getObjCKeywordID() == tok::objc_not_keyword) { + // If the completion point is at the end of an identifier, we want to treat + // the identifier as incomplete even if it resolves to a macro or a keyword. + // This allows e.g. 'class^' to complete to 'classifier'. + if (isCodeCompletionPoint(CurPtr)) { // Return the code-completion token. Result.setKind(tok::code_completion); cutOffLexing(); return true; } + + // Finally, now that we know we have an identifier, pass this off to the + // preprocessor, which may macro expand it or something. + if (II->isHandleIdentifierCase()) + return PP->HandleIdentifier(Result); + return true; } diff --git a/clang/test/CodeCompletion/end-of-ident-macro.cpp b/clang/test/CodeCompletion/end-of-ident-macro.cpp new file mode 100644 index 0000000..f288979 --- /dev/null +++ b/clang/test/CodeCompletion/end-of-ident-macro.cpp @@ -0,0 +1,16 @@ +#define FUNC(X) X +#define FUNCTOR +using FUNCTION = int(); +// We should get all three completions when the cursor is at the beginning, +// middle, or end. +FUNC(int) a = 10; +// ^FUNC(int) +// RUN: %clang_cc1 -code-completion-at=%s:6:1 -code-completion-macros %s | FileCheck %s +// FU^NC(int) +// RUN: %clang_cc1 -code-completion-at=%s:6:3 -code-completion-macros %s | FileCheck %s +// FUNC^(int) +// RUN: %clang_cc1 -code-completion-at=%s:6:5 -code-completion-macros %s | FileCheck %s + +// CHECK: COMPLETION: FUNC : FUNC(<#X#>) +// CHECK: COMPLETION: FUNCTION : FUNCTION +// CHECK: COMPLETION: FUNCTOR : FUNCTOR \ No newline at end of file diff --git a/clang/test/CodeCompletion/end-of-ident.cpp b/clang/test/CodeCompletion/end-of-ident.cpp new file mode 100644 index 0000000..f1d3700 --- /dev/null +++ b/clang/test/CodeCompletion/end-of-ident.cpp @@ -0,0 +1,20 @@ +class classifier {}; +// We should get all three completions when the cursor is at the beginning, +// middle, or end. +class cls +// ^class cls +// RUN: %clang_cc1 -code-completion-at=%s:4:1 %s | FileCheck --check-prefix=CHECK-CLS %s +// cl^ass cls +// RUN: %clang_cc1 -code-completion-at=%s:4:3 %s | FileCheck --check-prefix=CHECK-CLS %s +// class^ cls +// RUN: %clang_cc1 -code-completion-at=%s:4:6 %s | FileCheck --check-prefix=CHECK-CLS %s + +// CHECK-CLS: COMPLETION: class{{$}} +// CHECK-CLS: COMPLETION: classifier : classifier + +// class ^cls +// RUN: %clang_cc1 -code-completion-at=%s:4:7 %s | FileCheck --check-prefix=CHECK-NO-CLS %s +// class c^ls +// RUN: %clang_cc1 -code-completion-at=%s:4:8 %s | FileCheck --check-prefix=CHECK-NO-CLS %s +// CHECK-NO-CLS-NOT: COMPLETION: class{{$}} +// CHECK-NO-CLS: COMPLETION: classifier : classifier diff --git a/clang/test/CodeCompletion/macros.c b/clang/test/CodeCompletion/macros.c index 28f69b2..3cbad80 100644 --- a/clang/test/CodeCompletion/macros.c +++ b/clang/test/CodeCompletion/macros.c @@ -10,18 +10,18 @@ struct Point { void test(struct Point *p) { // RUN: %clang_cc1 -include %S/Inputs/macros.h -fsyntax-only -code-completion-macros -code-completion-at=%s:12:14 %s -o - | FileCheck -check-prefix=CC1 %s switch (p->IDENTITY(color)) { - // RUN: %clang_cc1 -include %S/Inputs/macros.h -fsyntax-only -code-completion-macros -code-completion-at=%s:14:9 %s -o - | FileCheck -check-prefix=CC2 %s + // RUN: %clang_cc1 -include %S/Inputs/macros.h -fsyntax-only -code-completion-macros -code-completion-at=%s:14:10 %s -o - | FileCheck -check-prefix=CC2 %s case } - // RUN: %clang_cc1 -include %S/Inputs/macros.h -fsyntax-only -code-completion-macros -code-completion-at=%s:17:7 %s -o - | FileCheck -check-prefix=CC3 %s + // RUN: %clang_cc1 -include %S/Inputs/macros.h -fsyntax-only -code-completion-macros -code-completion-at=%s:17:8 %s -o - | FileCheck -check-prefix=CC3 %s #ifdef Q #endif // Run the same tests, this time with macros loaded from the PCH file. // RUN: %clang_cc1 -emit-pch -o %t %S/Inputs/macros.h // RUN: %clang_cc1 -include-pch %t -fsyntax-only -code-completion-macros -code-completion-at=%s:12:14 %s -o - | FileCheck -check-prefix=CC1 %s - // RUN: %clang_cc1 -include-pch %t -fsyntax-only -code-completion-macros -code-completion-at=%s:14:9 %s -o - | FileCheck -check-prefix=CC2 %s - // RUN: %clang_cc1 -include-pch %t -fsyntax-only -code-completion-macros -code-completion-at=%s:17:7 %s -o - | FileCheck -check-prefix=CC3 %s + // RUN: %clang_cc1 -include-pch %t -fsyntax-only -code-completion-macros -code-completion-at=%s:14:10 %s -o - | FileCheck -check-prefix=CC2 %s + // RUN: %clang_cc1 -include-pch %t -fsyntax-only -code-completion-macros -code-completion-at=%s:17:8 %s -o - | FileCheck -check-prefix=CC3 %s // CC1: color // CC1: x diff --git a/clang/test/CodeCompletion/namespace.cpp b/clang/test/CodeCompletion/namespace.cpp index 8d3908a..6024a34 100644 --- a/clang/test/CodeCompletion/namespace.cpp +++ b/clang/test/CodeCompletion/namespace.cpp @@ -7,8 +7,8 @@ namespace N2 { namespace I5 { } namespace I1 { } - namespace - // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:12 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s + namespace + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:13 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s // CHECK-CC1: I1 // CHECK-CC1-NEXT: I5 diff --git a/clang/test/CodeCompletion/operator.cpp b/clang/test/CodeCompletion/operator.cpp index e0a2186..4a57f0a 100644 --- a/clang/test/CodeCompletion/operator.cpp +++ b/clang/test/CodeCompletion/operator.cpp @@ -7,8 +7,8 @@ namespace N { } void f() { typedef float Float; - operator - // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:11 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s + operator + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:12 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s // CHECK-CC1: + // CHECK-CC1: Float // CHECK-CC1: Integer diff --git a/clang/test/CodeCompletion/tag.c b/clang/test/CodeCompletion/tag.c index d49fb04..4a34c4c 100644 --- a/clang/test/CodeCompletion/tag.c +++ b/clang/test/CodeCompletion/tag.c @@ -6,7 +6,7 @@ void X(); void test() { enum X { x }; - enum - // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:9:7 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s + enum + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:9:8 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s // CHECK-CC1: X // CHECK-CC1: Y diff --git a/clang/test/CodeCompletion/tag.cpp b/clang/test/CodeCompletion/tag.cpp index c5ba6d3..d99ca05 100644 --- a/clang/test/CodeCompletion/tag.cpp +++ b/clang/test/CodeCompletion/tag.cpp @@ -14,8 +14,8 @@ namespace N { class Y; void test() { - class - // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:17:10 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s + class + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:17:11 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s // FIXME: the redundant Y is really annoying... it needs qualification to // actually be useful. Here, it just looks redundant :( // CHECK-CC1: A diff --git a/clang/test/CodeCompletion/using-namespace.cpp b/clang/test/CodeCompletion/using-namespace.cpp index 63cb589..4b93d02 100644 --- a/clang/test/CodeCompletion/using-namespace.cpp +++ b/clang/test/CodeCompletion/using-namespace.cpp @@ -11,8 +11,8 @@ namespace N2 { namespace I1 { } void foo() { - using namespace - // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:14:20 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s + using namespace + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:14:21 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s // CHECK-CC1: I1 // CHECK-CC1: I4 // CHECK-CC1: I5 diff --git a/clang/test/CodeCompletion/using.cpp b/clang/test/CodeCompletion/using.cpp index 13ebb4b..aaad8c9 100644 --- a/clang/test/CodeCompletion/using.cpp +++ b/clang/test/CodeCompletion/using.cpp @@ -13,8 +13,8 @@ namespace N2 { void foo() { int N3; - using - // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:16:10 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s + using + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:16:11 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s // CHECK-CC1: I1 // CHECK-CC1: I4 // CHECK-CC1: I5 diff --git a/clang/test/Index/complete-exprs.c b/clang/test/Index/complete-exprs.c index bace067..dbb6019 100644 --- a/clang/test/Index/complete-exprs.c +++ b/clang/test/Index/complete-exprs.c @@ -24,15 +24,15 @@ void f5(float f) { (type)f; } -// RUN: c-index-test -code-completion-at=%s:7:9 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s -// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:7:9 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s +// RUN: c-index-test -code-completion-at=%s:7:10 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s +// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:7:10 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s // CHECK-CC1: NotImplemented:{TypedText __PRETTY_FUNCTION__} (65) // CHECK-CC1: macro definition:{TypedText __VERSION__} (70) // CHECK-CC1: FunctionDecl:{ResultType int}{TypedText f}{LeftParen (}{Placeholder int}{RightParen )} (12) (unavailable) // CHECK-CC1-NOT: NotImplemented:{TypedText float} (65) // CHECK-CC1: ParmDecl:{ResultType int}{TypedText j} (8) // CHECK-CC1: NotImplemented:{ResultType size_t}{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (40) -// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:7:9 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s +// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:7:10 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC1 %s // RUN: c-index-test -code-completion-at=%s:7:14 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC3 %s // RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:7:14 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC3 %s // CHECK-CC3: macro definition:{TypedText __VERSION__} (70) diff --git a/clang/test/Index/complete-preprocessor.m b/clang/test/Index/complete-preprocessor.m index baeb4e9..d22ace6 100644 --- a/clang/test/Index/complete-preprocessor.m +++ b/clang/test/Index/complete-preprocessor.m @@ -13,7 +13,7 @@ FOO(in,t) value; -// RUN: c-index-test -code-completion-at=%s:4:2 %s | FileCheck -check-prefix=CHECK-CC1 %s +// RUN: c-index-test -code-completion-at=%s:4:3 %s | FileCheck -check-prefix=CHECK-CC1 %s // CHECK-CC1: NotImplemented:{TypedText define}{HorizontalSpace }{Placeholder macro} (40) // CHECK-CC1-NEXT: NotImplemented:{TypedText define}{HorizontalSpace }{Placeholder macro}{LeftParen (}{Placeholder args}{RightParen )} (40) // CHECK-CC1-NEXT: NotImplemented:{TypedText error}{HorizontalSpace }{Placeholder message} (40) @@ -55,8 +55,8 @@ FOO(in,t) value; // RUN: c-index-test -code-completion-at=%s:9:8 %s | FileCheck -check-prefix=CHECK-CC3 %s // CHECK-CC3: macro definition:{TypedText BAR} (40) // CHECK-CC3: macro definition:{TypedText FOO} (40) -// RUN: c-index-test -code-completion-at=%s:11:12 %s | FileCheck -check-prefix=CHECK-CC3 %s // RUN: c-index-test -code-completion-at=%s:11:13 %s | FileCheck -check-prefix=CHECK-CC3 %s +// RUN: c-index-test -code-completion-at=%s:11:14 %s | FileCheck -check-prefix=CHECK-CC3 %s // RUN: c-index-test -code-completion-at=%s:11:5 %s | FileCheck -check-prefix=CHECK-CC4 %s // CHECK-CC4: macro definition:{TypedText BAR} (70) // CHECK-CC4: macro definition:{TypedText FOO}{LeftParen (}{Placeholder a}{Comma , }{Placeholder b}{RightParen )} (70)