Index: include/clang/Lex/Preprocessor.h =================================================================== --- include/clang/Lex/Preprocessor.h +++ include/clang/Lex/Preprocessor.h @@ -265,6 +265,10 @@ /// \brief True if we hit the code-completion point. bool CodeCompletionReached; + /// \brief The code completion token containing the information + /// on the stem that is to be code completed. + IdentifierInfo *CodeCompletionII; + /// \brief The directory that the main file should be considered to occupy, /// if it does not correspond to a real file (as happens when building a /// module). @@ -984,6 +988,18 @@ /// completion point. void CodeCompleteNaturalLanguage(); + /// \brief Set the code completion token for filtering purposes. + void setCodeCompletionIdentifierInfo(IdentifierInfo *Filter) { + CodeCompletionII = Filter; + } + + /// \brief Get the code completion token for filtering purposes. + StringRef getCodeCompletionFilter() { + if (CodeCompletionII) + return CodeCompletionII->getName(); + return {}; + } + /// \brief Retrieve the preprocessing record, or NULL if there is no /// preprocessing record. PreprocessingRecord *getPreprocessingRecord() const { return Record; } Index: include/clang/Sema/CodeCompleteConsumer.h =================================================================== --- include/clang/Sema/CodeCompleteConsumer.h +++ include/clang/Sema/CodeCompleteConsumer.h @@ -913,6 +913,13 @@ /// \brief Deregisters and destroys this code-completion consumer. virtual ~CodeCompleteConsumer(); + /// \name Code-completion filtering + /// \brief Check if the result should be filtered out. + virtual bool isResultFilteredOut(StringRef Filter, + CodeCompletionResult Results) { + return false; + } + /// \name Code-completion callbacks //@{ /// \brief Process the finalized code-completion results. @@ -966,6 +973,8 @@ OverloadCandidate *Candidates, unsigned NumCandidates) override; + bool isResultFilteredOut(StringRef Filter, CodeCompletionResult Results) override; + CodeCompletionAllocator &getAllocator() override { return CCTUInfo.getAllocator(); } Index: lib/Lex/Lexer.cpp =================================================================== --- lib/Lex/Lexer.cpp +++ lib/Lex/Lexer.cpp @@ -1533,7 +1533,15 @@ // 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) { + // Return the code-completion token. + Result.setKind(tok::code_completion); + cutOffLexing(); + return true; + } return true; } Index: lib/Lex/Preprocessor.cpp =================================================================== --- lib/Lex/Preprocessor.cpp +++ lib/Lex/Preprocessor.cpp @@ -74,7 +74,7 @@ IncrementalProcessing(false), TUKind(TUKind), CodeComplete(nullptr), CodeCompletionFile(nullptr), CodeCompletionOffset(0), LastTokenWasAt(false), ModuleImportExpectsIdentifier(false), - CodeCompletionReached(0), MainFileDir(nullptr), + CodeCompletionReached(0), CodeCompletionII(0), MainFileDir(nullptr), SkipMainFilePreamble(0, true), CurPPLexer(nullptr), CurDirLookup(nullptr), CurLexerKind(CLK_Lexer), CurSubmodule(nullptr), Callbacks(nullptr), CurSubmoduleState(&NullSubmoduleState), MacroArgCache(nullptr), @@ -744,6 +744,9 @@ } } while (!ReturnedToken); + if (Result.is(tok::code_completion)) + setCodeCompletionIdentifierInfo(Result.getIdentifierInfo()); + LastTokenWasAt = Result.is(tok::at); } Index: lib/Sema/CodeCompleteConsumer.cpp =================================================================== --- lib/Sema/CodeCompleteConsumer.cpp +++ lib/Sema/CodeCompleteConsumer.cpp @@ -17,6 +17,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/Sema.h" +#include "clang/Lex/Preprocessor.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" @@ -428,6 +429,26 @@ CodeCompleteConsumer::~CodeCompleteConsumer() { } +bool PrintingCodeCompleteConsumer::isResultFilteredOut(StringRef Filter, + CodeCompletionResult Result) { + switch (Result.Kind) { + case CodeCompletionResult::RK_Declaration: { + return !(Result.Declaration->getIdentifier() && + Result.Declaration->getIdentifier()->getName().startswith(Filter)); + } + case CodeCompletionResult::RK_Keyword: { + return !StringRef(Result.Keyword).startswith(Filter); + } + case CodeCompletionResult::RK_Macro: { + return !Result.Macro->getName().startswith(Filter); + } + case CodeCompletionResult::RK_Pattern: { + return !StringRef(Result.Pattern->getAsString()).startswith(Filter); + } + default: llvm_unreachable("Unknown code completion result Kind."); + } +} + void PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, CodeCompletionContext Context, @@ -435,8 +456,12 @@ unsigned NumResults) { std::stable_sort(Results, Results + NumResults); + StringRef Filter = SemaRef.getPreprocessor().getCodeCompletionFilter(); + // Print the results. for (unsigned I = 0; I != NumResults; ++I) { + if(!Filter.empty() && isResultFilteredOut(Filter, Results[I])) + continue; OS << "COMPLETION: "; switch (Results[I].Kind) { case CodeCompletionResult::RK_Declaration: Index: test/CodeCompletion/filter-function-name.cpp =================================================================== --- /dev/null +++ test/CodeCompletion/filter-function-name.cpp @@ -0,0 +1,12 @@ +void myFunction(); + +int main() { + myFunction(); + int var = 0; + myFunction(); + // RUN: %clang_cc1 -code-completion-at=%s:4:8 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s + // CHECK-CC1: COMPLETION: myFunction : [#void#]myFunction() + // RUN: %clang_cc1 -code-completion-at=%s:6:6 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s + // CHECK-CC2: COMPLETION: myFunction : [#void#]myFunction() +} + Index: test/CodeCompletion/filter-member-access.cpp =================================================================== --- /dev/null +++ test/CodeCompletion/filter-member-access.cpp @@ -0,0 +1,28 @@ +class MyClass { +private: +int anInteger; +double aDouble; + +public: +MyClass(int i, double d) { +anInteger = i; +aDouble = d; +} +int getInt() { return anInteger; } +double getDouble() { return aDouble; } +void setInt(int value) { anInteger = value; } +void setDouble(double value) { aDouble = value; } +}; + +int main() { +MyClass* objectMyClass = new MyClass(5, 1.0); +objectMyClass->setDouble(5.0); +objectMyClass->setInt(objectMyClass->getInt()); +// RUN: %clang_cc1 -code-completion-at=%s:19:19 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s +// CHECK-CC1: COMPLETION: setDouble : [#void#]setDouble(<#double value#>) +// CHECK-CC1-NEXT: COMPLETION: setInt : [#void#]setInt(<#int value#>) +// RUN: %clang_cc1 -code-completion-at=%s:20:41 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s +// CHECK-CC2: COMPLETION: getDouble : [#double#]getDouble() +// CHECK-CC2-NEXT: COMPLETION: getInt : [#int#]getInt() +return 0; +} Index: test/CodeCompletion/filter-namespace.cpp =================================================================== --- /dev/null +++ test/CodeCompletion/filter-namespace.cpp @@ -0,0 +1,9 @@ +namespace outerspace { + namespace innerspace { } +} +using namespace outerspace; +// RUN: %clang_cc1 -code-completion-at=%s:4:23 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s +// CHECK-CC1: COMPLETION: outerspace : outerspace +using namespace outerspace::innerspace; +// RUN: %clang_cc1 -code-completion-at=%s:7:34 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s +// CHECK-CC2: COMPLETION: innerspace : innerspace Index: test/CodeCompletion/filter-ordinary-name.cpp =================================================================== --- /dev/null +++ test/CodeCompletion/filter-ordinary-name.cpp @@ -0,0 +1,8 @@ +int main() { +int myVariableOne; +int myVariableTwo; +myVariableOne; +// RUN: %clang_cc1 -code-completion-at=%s:4:5 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s +// CHECK-CC1: COMPLETION: myVariableOne : [#int#]myVariableOne +// CHECK-CC1-NEXT: COMPLETION: myVariableTwo : [#int#]myVariableTwo +} Index: test/CodeCompletion/objc-message.mm =================================================================== --- test/CodeCompletion/objc-message.mm +++ test/CodeCompletion/objc-message.mm @@ -38,9 +38,9 @@ [ptr instanceMethod1]; } -// RUN: %clang_cc1 -fsyntax-only -std=c++11 -code-completion-at=%s:33:7 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s +// RUN: %clang_cc1 -fsyntax-only -std=c++11 -code-completion-at=%s:33:8 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s // CHECK-CC1: categoryInstanceMethod : [#id#]categoryInstanceMethod // CHECK-CC1: instanceMethod1 : [#id#]instanceMethod1 // CHECK-CC1: protocolInstanceMethod : [#id#]protocolInstanceMethod -// RUN: %clang_cc1 -fsyntax-only -std=c++11 -code-completion-at=%s:38:7 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s +// RUN: %clang_cc1 -fsyntax-only -std=c++11 -code-completion-at=%s:38:8 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s // CHECK-CC2: protocolInstanceMethod : [#id#]protocolInstanceMethod Index: test/Index/complete-method-decls.m =================================================================== --- test/Index/complete-method-decls.m +++ test/Index/complete-method-decls.m @@ -195,7 +195,7 @@ // CHECK-CCG: NotImplemented:{TypedText void} (50) // CHECK-CCG: NotImplemented:{TypedText volatile} (50) // RUN: c-index-test -code-completion-at=%s:60:24 %s | FileCheck -check-prefix=CHECK-CCF %s -// RUN: c-index-test -code-completion-at=%s:60:26 %s | FileCheck -check-prefix=CHECK-CCH %s +// RUN: c-index-test -code-completion-at=%s:60:27 %s | FileCheck -check-prefix=CHECK-CCH %s // CHECK-CCH: ObjCInterfaceDecl:{TypedText A} (50) // CHECK-CCH: ObjCInterfaceDecl:{TypedText B} (50) // CHECK-CCH: NotImplemented:{TypedText bycopy} (40) Index: test/Index/complete-objc-message-id.m =================================================================== --- test/Index/complete-objc-message-id.m +++ test/Index/complete-objc-message-id.m @@ -68,7 +68,7 @@ // CHECK-SELECTOR-PREF: ObjCClassMethodDecl:{ResultType id}{TypedText new} (35) // CHECK-SELECTOR-PREF: ObjCClassMethodDecl:{ResultType Class}{TypedText superclass} (35) -// RUN: c-index-test -code-completion-at=%s:46:7 %s | FileCheck -check-prefix=CHECK-INSTANCE-QUAL-ID %s -// RUN: c-index-test -code-completion-at=%s:47:7 %s | FileCheck -check-prefix=CHECK-INSTANCE-QUAL-ID %s +// RUN: c-index-test -code-completion-at=%s:46:8 %s | FileCheck -check-prefix=CHECK-INSTANCE-QUAL-ID %s +// RUN: c-index-test -code-completion-at=%s:47:8 %s | FileCheck -check-prefix=CHECK-INSTANCE-QUAL-ID %s // CHECK-INSTANCE-QUAL-ID: ObjCInstanceMethodDecl:{ResultType int}{TypedText P1_method1} (37) // CHECK-INSTANCE-QUAL-ID: ObjCInstanceMethodDecl:{ResultType int}{TypedText P2_method1} (35) Index: test/Index/complete-objc-message.m =================================================================== --- test/Index/complete-objc-message.m +++ test/Index/complete-objc-message.m @@ -218,13 +218,13 @@ // CHECK-CC2-NEXT: Container Kind: ObjCInterfaceDecl // CHECK-CC2-NEXT: Container is complete // CHECK-CC2-NEXT: Container USR: c:objc(cs)Foo -// RUN: c-index-test -code-completion-at=%s:61:16 %s | FileCheck -check-prefix=CHECK-CC3 %s +// RUN: c-index-test -code-completion-at=%s:61:17 %s | FileCheck -check-prefix=CHECK-CC3 %s // CHECK-CC3: ObjCClassMethodDecl:{ResultType int}{TypedText MyClassMethod:}{Placeholder (id)} // CHECK-CC3: ObjCClassMethodDecl:{ResultType int}{TypedText MyPrivateMethod} -// RUN: c-index-test -code-completion-at=%s:65:16 %s | FileCheck -check-prefix=CHECK-CC4 %s +// RUN: c-index-test -code-completion-at=%s:65:17 %s | FileCheck -check-prefix=CHECK-CC4 %s // CHECK-CC4: ObjCInstanceMethodDecl:{ResultType int}{TypedText MyInstMethod:}{Placeholder (id)}{HorizontalSpace }{TypedText second:}{Placeholder (id)} // CHECK-CC4: ObjCInstanceMethodDecl:{ResultType int}{TypedText MyPrivateInstMethod} -// RUN: c-index-test -code-completion-at=%s:74:9 %s | FileCheck -check-prefix=CHECK-CC5 %s +// RUN: c-index-test -code-completion-at=%s:74:10 %s | FileCheck -check-prefix=CHECK-CC5 %s // CHECK-CC5: ObjCInstanceMethodDecl:{ResultType int}{TypedText MyInstMethod:}{Placeholder (id)}{HorizontalSpace }{TypedText second:}{Placeholder (id)} // CHECK-CC5: ObjCInstanceMethodDecl:{ResultType int}{TypedText MySubInstMethod} // RUN: c-index-test -code-completion-at=%s:82:8 %s | FileCheck -check-prefix=CHECK-CC6 %s @@ -311,7 +311,7 @@ // CHECK-CCI: ObjCInstanceMethodDecl:{ResultType void}{TypedText method1} (37) // CHECK-CCI: ObjCInstanceMethodDecl:{ResultType void}{TypedText method2} (35) -// RUN: c-index-test -code-completion-at=%s:150:5 %s | FileCheck -check-prefix=CHECK-REDUNDANT %s +// RUN: c-index-test -code-completion-at=%s:150:6 %s | FileCheck -check-prefix=CHECK-REDUNDANT %s // CHECK-REDUNDANT: ObjCInstanceMethodDecl:{ResultType void}{TypedText method2} (35) // CHECK-REDUNDANT-NOT: ObjCInstanceMethodDecl:{ResultType void}{TypedText method2} // CHECK-REDUNDANT: ObjCInstanceMethodDecl:{ResultType void}{TypedText method3} (35) Index: test/Index/complete-recovery.m =================================================================== --- test/Index/complete-recovery.m +++ test/Index/complete-recovery.m @@ -26,7 +26,7 @@ // Test case for fix committed in r145441. // RUN: env CINDEXTEST_CODE_COMPLETE_PATTERNS=1 c-index-test -code-completion-at=%s:9:20 %s -fms-compatibility | FileCheck -check-prefix=CHECK-CC1 %s -// RUN: env CINDEXTEST_CODE_COMPLETE_PATTERNS=1 c-index-test -code-completion-at=%s:10:24 %s | FileCheck -check-prefix=CHECK-CC2 %s +// RUN: env CINDEXTEST_CODE_COMPLETE_PATTERNS=1 c-index-test -code-completion-at=%s:10:25 %s | FileCheck -check-prefix=CHECK-CC2 %s // CHECK-CC2: NotImplemented:{ResultType char[]}{TypedText @encode}{LeftParen (}{Placeholder type-name}{RightParen )} // CHECK-CC2: NotImplemented:{TypedText _Bool} // CHECK-CC2: VarDecl:{ResultType A *}{TypedText a} Index: test/Index/complete-super.m =================================================================== --- test/Index/complete-super.m +++ test/Index/complete-super.m @@ -60,7 +60,7 @@ // RUN: c-index-test -code-completion-at=%s:20:16 %s | FileCheck -check-prefix=CHECK-ADD-TO %s // CHECK-ADD-TO: ObjCInstanceMethodDecl:{ResultType void}{Informative add:}{TypedText to:}{Placeholder b} (20) -// RUN: c-index-test -code-completion-at=%s:24:28 %s | FileCheck -check-prefix=CHECK-SELECTOR-FIRST %s +// RUN: c-index-test -code-completion-at=%s:24:29 %s | FileCheck -check-prefix=CHECK-SELECTOR-FIRST %s // CHECK-SELECTOR-FIRST: ObjCClassMethodDecl:{ResultType void}{Informative select:}{TypedText first:}{Placeholder a}{HorizontalSpace }{Text second:}{Placeholder b} (20) // Check "super" completion at the third identifier @@ -69,7 +69,7 @@ // Check "super" completion with missing '['. // RUN: c-index-test -code-completion-at=%s:25:10 %s | FileCheck -check-prefix=CHECK-SELECTOR-SELECTOR %s -// RUN: c-index-test -code-completion-at=%s:25:28 %s | FileCheck -check-prefix=CHECK-SELECTOR-FIRST %s +// RUN: c-index-test -code-completion-at=%s:25:29 %s | FileCheck -check-prefix=CHECK-SELECTOR-FIRST %s // RUN: c-index-test -code-completion-at=%s:25:37 %s | FileCheck -check-prefix=CHECK-SELECTOR-SECOND %s // Check "super" completion for a method declared in a category.