[PATCH] D50193: Added functionality to suggest FixIts for conversion of '->' to '.' and vice versa.
kadircet updated this revision to Diff 159510. kadircet marked 6 inline comments as done. kadircet added a comment. - Resolve discussions. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50193 Files: clangd/CodeComplete.cpp clangd/CodeComplete.h clangd/Diagnostics.cpp clangd/Protocol.h clangd/Quality.cpp clangd/Quality.h clangd/SourceCode.cpp clangd/SourceCode.h unittests/clangd/CodeCompleteTests.cpp unittests/clangd/QualityTests.cpp Index: unittests/clangd/QualityTests.cpp === --- unittests/clangd/QualityTests.cpp +++ unittests/clangd/QualityTests.cpp @@ -346,6 +346,28 @@ EXPECT_EQ(Q.Category, SymbolQualitySignals::Constructor); } +TEST(QualityTests, ItemWithFixItsRankedDown) { + CodeCompleteOptions Opts; + Opts.IncludeFixIts = true; + + auto Header = TestTU::withHeaderCode(R"cpp( +int x; + )cpp"); + auto AST = Header.build(); + + SymbolRelevanceSignals RelevanceWithFixIt; + RelevanceWithFixIt.merge( + CodeCompletionResult(&findDecl(AST, "x"), 0, nullptr, false, true, {{}})); + EXPECT_TRUE(RelevanceWithFixIt.NeedsFixIts); + + SymbolRelevanceSignals RelevanceWithoutFixIt; + RelevanceWithoutFixIt.merge( + CodeCompletionResult(&findDecl(AST, "x"), 0, nullptr, false, true, {})); + EXPECT_FALSE(RelevanceWithoutFixIt.NeedsFixIts); + + EXPECT_LT(RelevanceWithFixIt.evaluate(), RelevanceWithoutFixIt.evaluate()); +} + } // namespace } // namespace clangd } // namespace clang Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -79,6 +79,25 @@ return MemIndex::build(std::move(Slab).build()); } +CodeCompleteResult completions(ClangdServer &Server, StringRef TestCode, + Position point, + std::vector IndexSymbols = {}, + clangd::CodeCompleteOptions Opts = {}) { + std::unique_ptr OverrideIndex; + if (!IndexSymbols.empty()) { +assert(!Opts.Index && "both Index and IndexSymbols given!"); +OverrideIndex = memIndex(std::move(IndexSymbols)); +Opts.Index = OverrideIndex.get(); + } + + auto File = testPath("foo.cpp"); + runAddDocument(Server, File, TestCode); + auto CompletionList = cantFail(runCodeComplete(Server, File, point, Opts)); + return CompletionList; +} + +// Builds a server and runs code completion. +// If IndexSymbols is non-empty, an index will be built and passed to opts. CodeCompleteResult completions(ClangdServer &Server, StringRef Text, std::vector IndexSymbols = {}, clangd::CodeCompleteOptions Opts = {}) { @@ -97,8 +116,6 @@ return CompletionList; } -// Builds a server and runs code completion. -// If IndexSymbols is non-empty, an index will be built and passed to opts. CodeCompleteResult completions(StringRef Text, std::vector IndexSymbols = {}, clangd::CodeCompleteOptions Opts = {}) { @@ -1338,6 +1355,85 @@ EXPECT_THAT(Results.Context, CodeCompletionContext::CCC_DotMemberAccess); } +TEST(CompletionTest, FixItForArrowToDot) { + MockFSProvider FS; + MockCompilationDatabase CDB; + IgnoreDiagnostics DiagConsumer; + ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest()); + + CodeCompleteOptions Opts; + Opts.IncludeFixIts = true; + Annotations TestCode( + R"cpp( +class Auxilary { + public: + void AuxFunction(); +}; +class ClassWithPtr { + public: + void MemberFunction(); + Auxilary* operator->() const; + Auxilary* Aux; +}; +void f() { + ClassWithPtr x; + x[[->]]^; +} + )cpp"); + auto Results = + completions(Server, TestCode.code(), TestCode.point(), {}, Opts); + EXPECT_EQ(Results.Completions.size(), 3u); + + TextEdit ReplacementEdit; + ReplacementEdit.range = TestCode.range(); + ReplacementEdit.newText = "."; + for (const auto &C : Results.Completions) { +EXPECT_TRUE(C.FixIts.size() == 1u || C.Name == "AuxFunction"); +if (!C.FixIts.empty()) + EXPECT_THAT(C.FixIts, ElementsAre(ReplacementEdit)); + } +} + +TEST(CompletionTest, FixItForDotToArrow) { + MockFSProvider FS; + MockCompilationDatabase CDB; + IgnoreDiagnostics DiagConsumer; + ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest()); + + CodeCompleteOptions Opts; + Opts.IncludeFixIts = true; + Annotations TestCode( + R"cpp( +class Auxilary { + public: + void AuxFunction(); +}; +class ClassWithPtr { + public: + void MemberFunction(); + Auxilary* operator->() const; + Auxilary* Aux; +}; +void f() { + ClassWithPtr x;
[PATCH] D50193: Added functionality to suggest FixIts for conversion of '->' to '.' and vice versa.
kadircet updated this revision to Diff 159648. kadircet marked 3 inline comments as done. kadircet added a comment. - Resolve some more discussions. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50193 Files: clangd/CodeComplete.cpp clangd/CodeComplete.h clangd/Diagnostics.cpp clangd/Protocol.h clangd/Quality.cpp clangd/Quality.h clangd/SourceCode.cpp clangd/SourceCode.h unittests/clangd/CodeCompleteTests.cpp unittests/clangd/QualityTests.cpp Index: unittests/clangd/QualityTests.cpp === --- unittests/clangd/QualityTests.cpp +++ unittests/clangd/QualityTests.cpp @@ -346,6 +346,28 @@ EXPECT_EQ(Q.Category, SymbolQualitySignals::Constructor); } +TEST(QualityTests, ItemWithFixItsRankedDown) { + CodeCompleteOptions Opts; + Opts.IncludeFixIts = true; + + auto Header = TestTU::withHeaderCode(R"cpp( +int x; + )cpp"); + auto AST = Header.build(); + + SymbolRelevanceSignals RelevanceWithFixIt; + RelevanceWithFixIt.merge(CodeCompletionResult(&findDecl(AST, "x"), 0, nullptr, +false, true, {FixItHint{}})); + EXPECT_TRUE(RelevanceWithFixIt.NeedsFixIts); + + SymbolRelevanceSignals RelevanceWithoutFixIt; + RelevanceWithoutFixIt.merge( + CodeCompletionResult(&findDecl(AST, "x"), 0, nullptr, false, true, {})); + EXPECT_FALSE(RelevanceWithoutFixIt.NeedsFixIts); + + EXPECT_LT(RelevanceWithFixIt.evaluate(), RelevanceWithoutFixIt.evaluate()); +} + } // namespace } // namespace clangd } // namespace clang Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -79,6 +79,23 @@ return MemIndex::build(std::move(Slab).build()); } +CodeCompleteResult completions(ClangdServer &Server, StringRef TestCode, + Position point, + std::vector IndexSymbols = {}, + clangd::CodeCompleteOptions Opts = {}) { + std::unique_ptr OverrideIndex; + if (!IndexSymbols.empty()) { +assert(!Opts.Index && "both Index and IndexSymbols given!"); +OverrideIndex = memIndex(std::move(IndexSymbols)); +Opts.Index = OverrideIndex.get(); + } + + auto File = testPath("foo.cpp"); + runAddDocument(Server, File, TestCode); + auto CompletionList = cantFail(runCodeComplete(Server, File, point, Opts)); + return CompletionList; +} + CodeCompleteResult completions(ClangdServer &Server, StringRef Text, std::vector IndexSymbols = {}, clangd::CodeCompleteOptions Opts = {}) { @@ -1338,6 +1355,85 @@ EXPECT_THAT(Results.Context, CodeCompletionContext::CCC_DotMemberAccess); } +TEST(CompletionTest, FixItForArrowToDot) { + MockFSProvider FS; + MockCompilationDatabase CDB; + IgnoreDiagnostics DiagConsumer; + ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest()); + + CodeCompleteOptions Opts; + Opts.IncludeFixIts = true; + Annotations TestCode( + R"cpp( +class Auxilary { + public: + void AuxFunction(); +}; +class ClassWithPtr { + public: + void MemberFunction(); + Auxilary* operator->() const; + Auxilary* Aux; +}; +void f() { + ClassWithPtr x; + x[[->]]^; +} + )cpp"); + auto Results = + completions(Server, TestCode.code(), TestCode.point(), {}, Opts); + EXPECT_EQ(Results.Completions.size(), 3u); + + TextEdit ReplacementEdit; + ReplacementEdit.range = TestCode.range(); + ReplacementEdit.newText = "."; + for (const auto &C : Results.Completions) { +EXPECT_TRUE(C.FixIts.size() == 1u || C.Name == "AuxFunction"); +if (!C.FixIts.empty()) + EXPECT_THAT(C.FixIts, ElementsAre(ReplacementEdit)); + } +} + +TEST(CompletionTest, FixItForDotToArrow) { + MockFSProvider FS; + MockCompilationDatabase CDB; + IgnoreDiagnostics DiagConsumer; + ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest()); + + CodeCompleteOptions Opts; + Opts.IncludeFixIts = true; + Annotations TestCode( + R"cpp( +class Auxilary { + public: + void AuxFunction(); +}; +class ClassWithPtr { + public: + void MemberFunction(); + Auxilary* operator->() const; + Auxilary* Aux; +}; +void f() { + ClassWithPtr x; + x[[.]]^; +} + )cpp"); + auto Results = + completions(Server, TestCode.code(), TestCode.point(), {}, Opts); + EXPECT_EQ(Results.Completions.size(), 3u); + + TextEdit ReplacementEdit; + ReplacementEdit.range = TestCode.range(); + ReplacementEdit.newText = "->"; + for (const auto &C : Results.Completions) { +EXPECT_TRUE(C.FixIts.empty() || C.Name == "AuxFunction"); +if (!C.Fix
[PATCH] D50193: Added functionality to suggest FixIts for conversion of '->' to '.' and vice versa.
This revision was automatically updated to reflect the committed changes. Closed by commit rCTE339224: Added functionality to suggest FixIts for conversion of '->' to '.' and vice… (authored by kadircet, committed by ). Changed prior to commit: https://reviews.llvm.org/D50193?vs=159648&id=159655#toc Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50193 Files: clangd/CodeComplete.cpp clangd/CodeComplete.h clangd/Diagnostics.cpp clangd/Protocol.h clangd/Quality.cpp clangd/Quality.h clangd/SourceCode.cpp clangd/SourceCode.h unittests/clangd/CodeCompleteTests.cpp unittests/clangd/QualityTests.cpp Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -79,6 +79,23 @@ return MemIndex::build(std::move(Slab).build()); } +CodeCompleteResult completions(ClangdServer &Server, StringRef TestCode, + Position point, + std::vector IndexSymbols = {}, + clangd::CodeCompleteOptions Opts = {}) { + std::unique_ptr OverrideIndex; + if (!IndexSymbols.empty()) { +assert(!Opts.Index && "both Index and IndexSymbols given!"); +OverrideIndex = memIndex(std::move(IndexSymbols)); +Opts.Index = OverrideIndex.get(); + } + + auto File = testPath("foo.cpp"); + runAddDocument(Server, File, TestCode); + auto CompletionList = cantFail(runCodeComplete(Server, File, point, Opts)); + return CompletionList; +} + CodeCompleteResult completions(ClangdServer &Server, StringRef Text, std::vector IndexSymbols = {}, clangd::CodeCompleteOptions Opts = {}) { @@ -1342,6 +1359,85 @@ EXPECT_THAT(Results.Context, CodeCompletionContext::CCC_DotMemberAccess); } +TEST(CompletionTest, FixItForArrowToDot) { + MockFSProvider FS; + MockCompilationDatabase CDB; + IgnoreDiagnostics DiagConsumer; + ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest()); + + CodeCompleteOptions Opts; + Opts.IncludeFixIts = true; + Annotations TestCode( + R"cpp( +class Auxilary { + public: + void AuxFunction(); +}; +class ClassWithPtr { + public: + void MemberFunction(); + Auxilary* operator->() const; + Auxilary* Aux; +}; +void f() { + ClassWithPtr x; + x[[->]]^; +} + )cpp"); + auto Results = + completions(Server, TestCode.code(), TestCode.point(), {}, Opts); + EXPECT_EQ(Results.Completions.size(), 3u); + + TextEdit ReplacementEdit; + ReplacementEdit.range = TestCode.range(); + ReplacementEdit.newText = "."; + for (const auto &C : Results.Completions) { +EXPECT_TRUE(C.FixIts.size() == 1u || C.Name == "AuxFunction"); +if (!C.FixIts.empty()) + EXPECT_THAT(C.FixIts, ElementsAre(ReplacementEdit)); + } +} + +TEST(CompletionTest, FixItForDotToArrow) { + MockFSProvider FS; + MockCompilationDatabase CDB; + IgnoreDiagnostics DiagConsumer; + ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest()); + + CodeCompleteOptions Opts; + Opts.IncludeFixIts = true; + Annotations TestCode( + R"cpp( +class Auxilary { + public: + void AuxFunction(); +}; +class ClassWithPtr { + public: + void MemberFunction(); + Auxilary* operator->() const; + Auxilary* Aux; +}; +void f() { + ClassWithPtr x; + x[[.]]^; +} + )cpp"); + auto Results = + completions(Server, TestCode.code(), TestCode.point(), {}, Opts); + EXPECT_EQ(Results.Completions.size(), 3u); + + TextEdit ReplacementEdit; + ReplacementEdit.range = TestCode.range(); + ReplacementEdit.newText = "->"; + for (const auto &C : Results.Completions) { +EXPECT_TRUE(C.FixIts.empty() || C.Name == "AuxFunction"); +if (!C.FixIts.empty()) { + EXPECT_THAT(C.FixIts, ElementsAre(ReplacementEdit)); +} + } +} + } // namespace } // namespace clangd } // namespace clang Index: unittests/clangd/QualityTests.cpp === --- unittests/clangd/QualityTests.cpp +++ unittests/clangd/QualityTests.cpp @@ -346,6 +346,28 @@ EXPECT_EQ(Q.Category, SymbolQualitySignals::Constructor); } +TEST(QualityTests, ItemWithFixItsRankedDown) { + CodeCompleteOptions Opts; + Opts.IncludeFixIts = true; + + auto Header = TestTU::withHeaderCode(R"cpp( +int x; + )cpp"); + auto AST = Header.build(); + + SymbolRelevanceSignals RelevanceWithFixIt; + RelevanceWithFixIt.merge(CodeCompletionResult(&findDecl(AST, "x"), 0, nullptr, +false, true, {FixItHint{}})); + EXPECT_TRUE(RelevanceWithFixIt.NeedsFixIts); + + SymbolRelevanceSignals RelevanceWithoutFixIt; +
[PATCH] D50443: [clang] Store code completion token range in preprocessor.This change is to support a new fature in clangd, tests will be send toclang-tools-extra with that change.
kadircet created this revision. kadircet added a reviewer: ilya-biryukov. Herald added subscribers: cfe-commits, arphaman, jkorous, MaskRay, ioeric. Repository: rC Clang https://reviews.llvm.org/D50443 Files: include/clang/Lex/Preprocessor.h lib/Lex/Preprocessor.cpp Index: lib/Lex/Preprocessor.cpp === --- lib/Lex/Preprocessor.cpp +++ lib/Lex/Preprocessor.cpp @@ -868,6 +868,7 @@ if (Result.is(tok::code_completion) && Result.getIdentifierInfo()) { // Remember the identifier before code completion token. setCodeCompletionIdentifierInfo(Result.getIdentifierInfo()); +setCodeCompletionTokenRange(Result.getLocation(), Result.getEndLoc()); // Set IdenfitierInfo to null to avoid confusing code that handles both // identifiers and completion tokens. Result.setIdentifierInfo(nullptr); Index: include/clang/Lex/Preprocessor.h === --- include/clang/Lex/Preprocessor.h +++ include/clang/Lex/Preprocessor.h @@ -310,6 +310,9 @@ /// on the stem that is to be code completed. IdentifierInfo *CodeCompletionII = nullptr; + /// Range for the code completion taken. + SourceRange CodeCompletionTokenRange; + /// 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). @@ -1131,6 +1134,16 @@ CodeCompletionII = Filter; } + /// Set the code completion token range for detecting replacement range later + /// on. + void setCodeCompletionTokenRange(const SourceLocation start, + const SourceLocation end) { +CodeCompletionTokenRange = {start, end}; + } + SourceRange getCodeCompletionTokenRange() const { +return CodeCompletionTokenRange; + } + /// Get the code completion token for filtering purposes. StringRef getCodeCompletionFilter() { if (CodeCompletionII) Index: lib/Lex/Preprocessor.cpp === --- lib/Lex/Preprocessor.cpp +++ lib/Lex/Preprocessor.cpp @@ -868,6 +868,7 @@ if (Result.is(tok::code_completion) && Result.getIdentifierInfo()) { // Remember the identifier before code completion token. setCodeCompletionIdentifierInfo(Result.getIdentifierInfo()); +setCodeCompletionTokenRange(Result.getLocation(), Result.getEndLoc()); // Set IdenfitierInfo to null to avoid confusing code that handles both // identifiers and completion tokens. Result.setIdentifierInfo(nullptr); Index: include/clang/Lex/Preprocessor.h === --- include/clang/Lex/Preprocessor.h +++ include/clang/Lex/Preprocessor.h @@ -310,6 +310,9 @@ /// on the stem that is to be code completed. IdentifierInfo *CodeCompletionII = nullptr; + /// Range for the code completion taken. + SourceRange CodeCompletionTokenRange; + /// 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). @@ -1131,6 +1134,16 @@ CodeCompletionII = Filter; } + /// Set the code completion token range for detecting replacement range later + /// on. + void setCodeCompletionTokenRange(const SourceLocation start, + const SourceLocation end) { +CodeCompletionTokenRange = {start, end}; + } + SourceRange getCodeCompletionTokenRange() const { +return CodeCompletionTokenRange; + } + /// Get the code completion token for filtering purposes. StringRef getCodeCompletionFilter() { if (CodeCompletionII) ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50443: [clang] Store code completion token range in preprocessor.
kadircet updated this revision to Diff 159703. kadircet marked an inline comment as done. kadircet added a comment. - Resolve discussions. Repository: rC Clang https://reviews.llvm.org/D50443 Files: include/clang/Lex/Preprocessor.h lib/Lex/Preprocessor.cpp Index: lib/Lex/Preprocessor.cpp === --- lib/Lex/Preprocessor.cpp +++ lib/Lex/Preprocessor.cpp @@ -868,6 +868,7 @@ if (Result.is(tok::code_completion) && Result.getIdentifierInfo()) { // Remember the identifier before code completion token. setCodeCompletionIdentifierInfo(Result.getIdentifierInfo()); +setCodeCompletionTokenRange(Result.getLocation(), Result.getEndLoc()); // Set IdenfitierInfo to null to avoid confusing code that handles both // identifiers and completion tokens. Result.setIdentifierInfo(nullptr); Index: include/clang/Lex/Preprocessor.h === --- include/clang/Lex/Preprocessor.h +++ include/clang/Lex/Preprocessor.h @@ -310,6 +310,9 @@ /// on the stem that is to be code completed. IdentifierInfo *CodeCompletionII = nullptr; + /// Range for the code completion taken. + SourceRange CodeCompletionTokenRange; + /// 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). @@ -1131,6 +1134,16 @@ CodeCompletionII = Filter; } + /// Set the code completion token range for detecting replacement range later + /// on. + void setCodeCompletionTokenRange(const SourceLocation Start, + const SourceLocation End) { +CodeCompletionTokenRange = {Start, End}; + } + SourceRange getCodeCompletionTokenRange() const { +return CodeCompletionTokenRange; + } + /// Get the code completion token for filtering purposes. StringRef getCodeCompletionFilter() { if (CodeCompletionII) Index: lib/Lex/Preprocessor.cpp === --- lib/Lex/Preprocessor.cpp +++ lib/Lex/Preprocessor.cpp @@ -868,6 +868,7 @@ if (Result.is(tok::code_completion) && Result.getIdentifierInfo()) { // Remember the identifier before code completion token. setCodeCompletionIdentifierInfo(Result.getIdentifierInfo()); +setCodeCompletionTokenRange(Result.getLocation(), Result.getEndLoc()); // Set IdenfitierInfo to null to avoid confusing code that handles both // identifiers and completion tokens. Result.setIdentifierInfo(nullptr); Index: include/clang/Lex/Preprocessor.h === --- include/clang/Lex/Preprocessor.h +++ include/clang/Lex/Preprocessor.h @@ -310,6 +310,9 @@ /// on the stem that is to be code completed. IdentifierInfo *CodeCompletionII = nullptr; + /// Range for the code completion taken. + SourceRange CodeCompletionTokenRange; + /// 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). @@ -1131,6 +1134,16 @@ CodeCompletionII = Filter; } + /// Set the code completion token range for detecting replacement range later + /// on. + void setCodeCompletionTokenRange(const SourceLocation Start, + const SourceLocation End) { +CodeCompletionTokenRange = {Start, End}; + } + SourceRange getCodeCompletionTokenRange() const { +return CodeCompletionTokenRange; + } + /// Get the code completion token for filtering purposes. StringRef getCodeCompletionFilter() { if (CodeCompletionII) ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50449: [clangd] Support textEdit in addition to insertText.
kadircet created this revision. kadircet added a reviewer: ilya-biryukov. Herald added subscribers: cfe-commits, arphaman, jkorous, MaskRay, ioeric. Completion replies contains textEdits as well. Note that this change relies on https://reviews.llvm.org/D50443. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50449 Files: clangd/CodeComplete.cpp clangd/CodeComplete.h clangd/SourceCode.cpp clangd/SourceCode.h unittests/clangd/CodeCompleteTests.cpp unittests/clangd/SourceCodeTests.cpp Index: unittests/clangd/SourceCodeTests.cpp === --- unittests/clangd/SourceCodeTests.cpp +++ unittests/clangd/SourceCodeTests.cpp @@ -37,6 +37,14 @@ return Pos; } +Range range(const std::pair p1, +const std::pair p2) { + Range range; + range.start = position(p1.first, p1.second); + range.end = position(p2.first, p2.second); + return range; +} + TEST(SourceCodeTests, PositionToOffset) { // line out of bounds EXPECT_THAT_EXPECTED(positionToOffset(File, position(-1, 2)), Failed()); @@ -119,6 +127,14 @@ EXPECT_THAT(offsetToPosition(File, 30), Pos(2, 9)) << "out of bounds"; } +TEST(SourceCodeTests, IsRangeConsecutive) { + EXPECT_TRUE(IsRangeConsecutive(range({2, 2}, {2, 3}), range({2, 3}, {2, 4}))); + EXPECT_FALSE( + IsRangeConsecutive(range({0, 2}, {0, 3}), range({2, 3}, {2, 4}))); + EXPECT_FALSE( + IsRangeConsecutive(range({2, 2}, {2, 3}), range({2, 4}, {2, 5}))); +} + } // namespace } // namespace clangd } // namespace clang Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -1438,6 +1438,82 @@ } } +TEST(CompletionTest, RenderWithFixItMerged) { + TextEdit FixIt; + FixIt.range.end.character = 5; + FixIt.newText = "->"; + + CodeCompletion C; + C.Name = "x"; + C.RequiredQualifier = "Foo::"; + C.FixIts = {FixIt}; + C.textEdit.range.start.character = 5; + + CodeCompleteOptions Opts; + Opts.IncludeFixIts = true; + + auto R = C.render(Opts); + EXPECT_TRUE(R.textEdit); + EXPECT_EQ(R.textEdit->newText, "->Foo::x"); + EXPECT_TRUE(R.additionalTextEdits.empty()); +} + +TEST(CompletionTest, RenderWithFixItNonMerged) { + TextEdit FixIt; + FixIt.range.end.character = 4; + FixIt.newText = "->"; + + CodeCompletion C; + C.Name = "x"; + C.RequiredQualifier = "Foo::"; + C.FixIts = {FixIt}; + C.textEdit.range.start.character = 5; + + CodeCompleteOptions Opts; + Opts.IncludeFixIts = true; + + auto R = C.render(Opts); + EXPECT_TRUE(R.textEdit); + EXPECT_EQ(R.textEdit->newText, "Foo::x"); + EXPECT_THAT(R.additionalTextEdits, UnorderedElementsAre(FixIt)); +} + +TEST(CompletionTest, CompletionTokenRange) { + MockFSProvider FS; + MockCompilationDatabase CDB; + IgnoreDiagnostics DiagConsumer; + ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest()); + + constexpr const char *TestCodes[] = { + R"cpp( +class Auxilary { + public: + void AuxFunction(); +}; +void f() { + Auxilary x; + x.[[Aux]]^; +} + )cpp", + R"cpp( +class Auxilary { + public: + void AuxFunction(); +}; +void f() { + Auxilary x; + x.[[]]^; +} + )cpp"}; + for (const auto &Text : TestCodes) { +Annotations TestCode(Text); +auto Results = completions(Server, TestCode.code(), TestCode.point()); + +EXPECT_EQ(Results.Completions.size(), 1u); +EXPECT_THAT(Results.Completions.front().textEdit.range, TestCode.range()); + } +} + } // namespace } // namespace clangd } // namespace clang Index: clangd/SourceCode.h === --- clangd/SourceCode.h +++ clangd/SourceCode.h @@ -69,6 +69,7 @@ TextEdit toTextEdit(const FixItHint &FixIt, const SourceManager &M, const LangOptions &L); +bool IsRangeConsecutive(const Range &Left, const Range &Right); } // namespace clangd } // namespace clang #endif Index: clangd/SourceCode.cpp === --- clangd/SourceCode.cpp +++ clangd/SourceCode.cpp @@ -208,5 +208,10 @@ return Result; } +bool IsRangeConsecutive(const Range &Left, const Range &Right) { + return Left.end.line == Right.start.line && + Left.end.character == Right.start.character; +} + } // namespace clangd } // namespace clang Index: clangd/CodeComplete.h === --- clangd/CodeComplete.h +++ clangd/CodeComplete.h @@ -123,6 +123,8 @@ /// converting '->' to '.' on member access. std::vector FixIts; + TextEdit textEdit; + // Scores are used to rank completion items. struct Scores { // The score that items are ranked by. Index: clangd/CodeComplete.cpp
[PATCH] D50502: [clangd] Initial cancellation mechanism for LSP requests.
kadircet created this revision. kadircet added a reviewer: ilya-biryukov. Herald added subscribers: cfe-commits, jfb, arphaman, jkorous, MaskRay, ioeric, mgorny. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50502 Files: clangd/CMakeLists.txt clangd/Cancellation.cpp clangd/Cancellation.h clangd/ClangdLSPServer.cpp clangd/ClangdLSPServer.h clangd/ClangdServer.cpp clangd/JSONRPCDispatcher.cpp clangd/JSONRPCDispatcher.h clangd/Protocol.cpp clangd/Protocol.h clangd/ProtocolHandlers.cpp clangd/ProtocolHandlers.h unittests/clangd/CMakeLists.txt unittests/clangd/CancellationTests.cpp Index: unittests/clangd/CancellationTests.cpp === --- /dev/null +++ unittests/clangd/CancellationTests.cpp @@ -0,0 +1,34 @@ +#include "Cancellation.h" +#include "Context.h" +#include "llvm/Support/Error.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include +#include + +namespace clang { +namespace clangd { +namespace { + +TEST(CancellationTest, CancellationTest) { + { +std::shared_ptr> CancellationToken = +std::make_shared>(); +WithContext ContextWithCancellation( +CancellationHandler::SetCurrentCancellationToken(CancellationToken)); +*CancellationToken = true; +EXPECT_TRUE(CancellationHandler::HasCancelled()); + } + EXPECT_FALSE(CancellationHandler::HasCancelled()); +} + +TEST(CancellationTest, CheckForError) { + llvm::Error e = handleErrors(CancellationHandler::GetCancellationError(), + [](const TaskCancelledError &) {}); + EXPECT_TRUE(!e); +} + +} // namespace +} // namespace clangd +} // namespace clang Index: unittests/clangd/CMakeLists.txt === --- unittests/clangd/CMakeLists.txt +++ unittests/clangd/CMakeLists.txt @@ -10,6 +10,7 @@ add_extra_unittest(ClangdTests Annotations.cpp + CancellationTests.cpp ClangdTests.cpp ClangdUnitTests.cpp CodeCompleteTests.cpp Index: clangd/ProtocolHandlers.h === --- clangd/ProtocolHandlers.h +++ clangd/ProtocolHandlers.h @@ -55,6 +55,7 @@ virtual void onDocumentHighlight(TextDocumentPositionParams &Params) = 0; virtual void onHover(TextDocumentPositionParams &Params) = 0; virtual void onChangeConfiguration(DidChangeConfigurationParams &Params) = 0; + virtual void onCancelRequest(CancelParams &Params) = 0; }; void registerCallbackHandlers(JSONRPCDispatcher &Dispatcher, Index: clangd/ProtocolHandlers.cpp === --- clangd/ProtocolHandlers.cpp +++ clangd/ProtocolHandlers.cpp @@ -75,4 +75,5 @@ Register("workspace/didChangeConfiguration", &ProtocolCallbacks::onChangeConfiguration); Register("workspace/symbol", &ProtocolCallbacks::onWorkspaceSymbol); + Register("$/cancelRequest", &ProtocolCallbacks::onCancelRequest); } Index: clangd/Protocol.h === --- clangd/Protocol.h +++ clangd/Protocol.h @@ -846,6 +846,13 @@ llvm::json::Value toJSON(const DocumentHighlight &DH); llvm::raw_ostream &operator<<(llvm::raw_ostream &, const DocumentHighlight &); +struct CancelParams { + std::string ID; +}; +llvm::json::Value toJSON(const CancelParams &); +llvm::raw_ostream &operator<<(llvm::raw_ostream &, const CancelParams &); +bool fromJSON(const llvm::json::Value &, CancelParams &); + } // namespace clangd } // namespace clang Index: clangd/Protocol.cpp === --- clangd/Protocol.cpp +++ clangd/Protocol.cpp @@ -605,5 +605,31 @@ O.map("compilationDatabaseChanges", CCPC.compilationDatabaseChanges); } +json::Value toJSON(const CancelParams &CP) { + return json::Object{{"id", CP.ID}}; +} + +llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const CancelParams &CP) { + O << toJSON(CP); + return O; +} + +bool fromJSON(const json::Value &Params, CancelParams &CP) { + elog("Cancel params: {0}", Params); + json::ObjectMapper O(Params); + if (!O) +return false; + // ID is either a number or a string, check for both. + if (O.map("id", CP.ID)) +return true; + + int64_t id_number; + if (O.map("id", id_number)) { +CP.ID = utostr(id_number); +return true; + } + return false; +} + } // namespace clangd } // namespace clang Index: clangd/JSONRPCDispatcher.h === --- clangd/JSONRPCDispatcher.h +++ clangd/JSONRPCDispatcher.h @@ -111,6 +111,7 @@ JSONStreamStyle InputStyle, JSONRPCDispatcher &Dispatcher, bool &IsDone); +const llvm::json::Value *GetRequestId(); } // namespace clangd } // namespace clang Index: clangd/JSONRPCDispatcher.cpp === --- clangd
[PATCH] D50555: [clangd] Introduce scoring mechanism for SignatureInformations.
kadircet created this revision. kadircet added a reviewer: ilya-biryukov. Herald added subscribers: cfe-commits, arphaman, jkorous, MaskRay, ioeric. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50555 Files: clangd/CodeComplete.cpp clangd/Quality.cpp clangd/Quality.h unittests/clangd/CodeCompleteTests.cpp Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -1438,6 +1438,28 @@ } } +TEST(SignatureHelpTest, OverloadsOrdering) { + const auto Results = signatures(R"cpp( +void foo(int x); +void foo(int x, float y); +void foo(float x, int y); +void foo(float x, float y); +void foo(int x, int y = 0); +int main() { foo(^); } + )cpp"); + EXPECT_THAT( + Results.signatures, + ElementsAre( + Sig("foo(int x) -> void", {"int x"}), + Sig("foo(int x, int y = 0) -> void", {"int x", "int y = 0"}), + Sig("foo(float x, int y) -> void", {"float x", "int y"}), + Sig("foo(int x, float y) -> void", {"int x", "float y"}), + Sig("foo(float x, float y) -> void", {"float x", "float y"}))); + // We always prefer the first signature. + EXPECT_EQ(0, Results.activeSignature); + EXPECT_EQ(0, Results.activeParameter); +} + } // namespace } // namespace clangd } // namespace clang Index: clangd/Quality.h === --- clangd/Quality.h +++ clangd/Quality.h @@ -163,6 +163,17 @@ /// LSP. (The highest score compares smallest so it sorts at the top). std::string sortText(float Score, llvm::StringRef Tiebreak = ""); +struct SignatureQualitySignals { + uint32_t NumberOfParameters = 0; + uint32_t NumberOfOptionalParameters = 0; + bool ContainsActiveParameter = false; + CodeCompleteConsumer::OverloadCandidate::CandidateKind Kind; + + float evaluate() const; +}; +llvm::raw_ostream &operator<<(llvm::raw_ostream &, + const SignatureQualitySignals &); + } // namespace clangd } // namespace clang Index: clangd/Quality.cpp === --- clangd/Quality.cpp +++ clangd/Quality.cpp @@ -401,5 +401,36 @@ return S; } +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const SignatureQualitySignals &S) { + OS << formatv("=== Signature Quality: {0}\n", S.evaluate()); + OS << formatv("\tNumber of parameters: {0}\n", S.NumberOfParameters); + OS << formatv("\tNumber of optional parameters: {0}\n", +S.NumberOfOptionalParameters); + OS << formatv("\tContains active parameter: {0}\n", +S.ContainsActiveParameter); + OS << formatv("\tKind: {0}\n", S.Kind); + return OS; +} + +float SignatureQualitySignals::evaluate() const { + using OC = CodeCompleteConsumer::OverloadCandidate; + float score = 1; + score /= NumberOfParameters + 1; + if (ContainsActiveParameter) +score *= 10; + switch (Kind) { + case OC::CK_Function: +score *= 10; +break; + case OC::CK_FunctionType: +score *= 5; +break; + case OC::CK_FunctionTemplate: +break; + } + return score; +} + } // namespace clangd } // namespace clang Index: clangd/CodeComplete.cpp === --- clangd/CodeComplete.cpp +++ clangd/CodeComplete.cpp @@ -128,16 +128,16 @@ /// Get the optional chunk as a string. This function is possibly recursive. /// /// The parameter info for each parameter is appended to the Parameters. -std::string -getOptionalParameters(const CodeCompletionString &CCS, - std::vector &Parameters) { +std::string getOptionalParameters(const CodeCompletionString &CCS, + std::vector &Parameters, + SignatureQualitySignals &Signal) { std::string Result; for (const auto &Chunk : CCS) { switch (Chunk.Kind) { case CodeCompletionString::CK_Optional: assert(Chunk.Optional && "Expected the optional code completion string to be non-null."); - Result += getOptionalParameters(*Chunk.Optional, Parameters); + Result += getOptionalParameters(*Chunk.Optional, Parameters, Signal); break; case CodeCompletionString::CK_VerticalSpace: break; @@ -153,6 +153,8 @@ ParameterInformation Info; Info.label = Chunk.Text; Parameters.push_back(std::move(Info)); + Signal.ContainsActiveParameter = true; + Signal.NumberOfOptionalParameters++; break; } default: @@ -679,6 +681,24 @@ llvm::unique_function ResultsCallback; }; +using SignatureInformationScore = float; +using ScoredSignature = +std::pair; +struct ScoredSignatureGreater { + bool operator()(const ScoredSignature &L, const ScoredSignature &R) { +// Ordering follows: +// - High score is
[PATCH] D50449: [clangd] Support textEdit in addition to insertText.
kadircet updated this revision to Diff 160073. kadircet marked 5 inline comments as done. kadircet added a comment. Herald added a subscriber: mgrang. - Resolve discussions. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50449 Files: clangd/CodeComplete.cpp clangd/CodeComplete.h clangd/SourceCode.cpp clangd/SourceCode.h unittests/clangd/CodeCompleteTests.cpp unittests/clangd/SourceCodeTests.cpp Index: unittests/clangd/SourceCodeTests.cpp === --- unittests/clangd/SourceCodeTests.cpp +++ unittests/clangd/SourceCodeTests.cpp @@ -37,6 +37,13 @@ return Pos; } +Range range(const std::pair p1, const std::pair p2) { + Range range; + range.start = position(p1.first, p1.second); + range.end = position(p2.first, p2.second); + return range; +} + TEST(SourceCodeTests, PositionToOffset) { // line out of bounds EXPECT_THAT_EXPECTED(positionToOffset(File, position(-1, 2)), Failed()); @@ -119,6 +126,14 @@ EXPECT_THAT(offsetToPosition(File, 30), Pos(2, 9)) << "out of bounds"; } +TEST(SourceCodeTests, IsRangeConsecutive) { + EXPECT_TRUE(IsRangeConsecutive(range({2, 2}, {2, 3}), range({2, 3}, {2, 4}))); + EXPECT_FALSE( + IsRangeConsecutive(range({0, 2}, {0, 3}), range({2, 3}, {2, 4}))); + EXPECT_FALSE( + IsRangeConsecutive(range({2, 2}, {2, 3}), range({2, 4}, {2, 5}))); +} + } // namespace } // namespace clangd } // namespace clang Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -1438,6 +1438,82 @@ } } +TEST(CompletionTest, RenderWithFixItMerged) { + TextEdit FixIt; + FixIt.range.end.character = 5; + FixIt.newText = "->"; + + CodeCompletion C; + C.Name = "x"; + C.RequiredQualifier = "Foo::"; + C.FixIts = {FixIt}; + C.CompletionTokenRange.start.character = 5; + + CodeCompleteOptions Opts; + Opts.IncludeFixIts = true; + + auto R = C.render(Opts); + EXPECT_TRUE(R.textEdit); + EXPECT_EQ(R.textEdit->newText, "->Foo::x"); + EXPECT_TRUE(R.additionalTextEdits.empty()); +} + +TEST(CompletionTest, RenderWithFixItNonMerged) { + TextEdit FixIt; + FixIt.range.end.character = 4; + FixIt.newText = "->"; + + CodeCompletion C; + C.Name = "x"; + C.RequiredQualifier = "Foo::"; + C.FixIts = {FixIt}; + C.CompletionTokenRange.start.character = 5; + + CodeCompleteOptions Opts; + Opts.IncludeFixIts = true; + + auto R = C.render(Opts); + EXPECT_TRUE(R.textEdit); + EXPECT_EQ(R.textEdit->newText, "Foo::x"); + EXPECT_THAT(R.additionalTextEdits, UnorderedElementsAre(FixIt)); +} + +TEST(CompletionTest, CompletionTokenRange) { + MockFSProvider FS; + MockCompilationDatabase CDB; + IgnoreDiagnostics DiagConsumer; + ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest()); + + constexpr const char *TestCodes[] = { + R"cpp( +class Auxilary { + public: + void AuxFunction(); +}; +void f() { + Auxilary x; + x.[[Aux]]^; +} + )cpp", + R"cpp( +class Auxilary { + public: + void AuxFunction(); +}; +void f() { + Auxilary x; + x.[[]]^; +} + )cpp"}; + for (const auto &Text : TestCodes) { +Annotations TestCode(Text); +auto Results = completions(Server, TestCode.code(), TestCode.point()); + +EXPECT_EQ(Results.Completions.size(), 1u); +EXPECT_THAT(Results.Completions.front().CompletionTokenRange, TestCode.range()); + } +} + } // namespace } // namespace clangd } // namespace clang Index: clangd/SourceCode.h === --- clangd/SourceCode.h +++ clangd/SourceCode.h @@ -69,6 +69,7 @@ TextEdit toTextEdit(const FixItHint &FixIt, const SourceManager &M, const LangOptions &L); +bool IsRangeConsecutive(const Range &Left, const Range &Right); } // namespace clangd } // namespace clang #endif Index: clangd/SourceCode.cpp === --- clangd/SourceCode.cpp +++ clangd/SourceCode.cpp @@ -208,5 +208,10 @@ return Result; } +bool IsRangeConsecutive(const Range &Left, const Range &Right) { + return Left.end.line == Right.start.line && + Left.end.character == Right.start.character; +} + } // namespace clangd } // namespace clang Index: clangd/CodeComplete.h === --- clangd/CodeComplete.h +++ clangd/CodeComplete.h @@ -123,6 +123,9 @@ /// converting '->' to '.' on member access. std::vector FixIts; + /// Holds the range of the token we are going to replace with this completion. + Range CompletionTokenRange; + // Scores are used to rank completion items. struct Scores { // The score that items are ranked by. Index: clangd/CodeComplete.cpp ===
[PATCH] D50449: [clangd] Support textEdit in addition to insertText.
kadircet added inline comments. Comment at: clangd/CodeComplete.cpp:1310 + // other. + for (const auto &FixIt : FixIts) { +if (IsRangeConsecutive(FixIt.range, LSP.textEdit->range)) { ilya-biryukov wrote: > Maybe keep the `reserve` call? (we could reserve one extra element, but > that's fine) Actually we could have much more than one extra element, not for the current situation but may be in the future when we have more fixit completions. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50449 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50555: [clangd] Introduce scoring mechanism for SignatureInformations.
kadircet updated this revision to Diff 160097. kadircet marked 3 inline comments as done. kadircet added a comment. Herald added a subscriber: mgrang. - Resolve discussions. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50555 Files: clangd/CodeComplete.cpp clangd/Quality.cpp clangd/Quality.h unittests/clangd/CodeCompleteTests.cpp Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -1438,6 +1438,28 @@ } } +TEST(SignatureHelpTest, OverloadsOrdering) { + const auto Results = signatures(R"cpp( +void foo(int x); +void foo(int x, float y); +void foo(float x, int y); +void foo(float x, float y); +void foo(int x, int y = 0); +int main() { foo(^); } + )cpp"); + EXPECT_THAT( + Results.signatures, + ElementsAre( + Sig("foo(int x) -> void", {"int x"}), + Sig("foo(int x, int y = 0) -> void", {"int x", "int y = 0"}), + Sig("foo(float x, int y) -> void", {"float x", "int y"}), + Sig("foo(int x, float y) -> void", {"int x", "float y"}), + Sig("foo(float x, float y) -> void", {"float x", "float y"}))); + // We always prefer the first signature. + EXPECT_EQ(0, Results.activeSignature); + EXPECT_EQ(0, Results.activeParameter); +} + } // namespace } // namespace clangd } // namespace clang Index: clangd/Quality.h === --- clangd/Quality.h +++ clangd/Quality.h @@ -163,6 +163,16 @@ /// LSP. (The highest score compares smallest so it sorts at the top). std::string sortText(float Score, llvm::StringRef Tiebreak = ""); +struct SignatureQualitySignals { + uint32_t NumberOfParameters = 0; + uint32_t NumberOfOptionalParameters = 0; + bool ContainsActiveParameter = false; + CodeCompleteConsumer::OverloadCandidate::CandidateKind Kind = + CodeCompleteConsumer::OverloadCandidate::CandidateKind::CK_Function; +}; +llvm::raw_ostream &operator<<(llvm::raw_ostream &, + const SignatureQualitySignals &); + } // namespace clangd } // namespace clang Index: clangd/Quality.cpp === --- clangd/Quality.cpp +++ clangd/Quality.cpp @@ -401,5 +401,17 @@ return S; } +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const SignatureQualitySignals &S) { + OS << formatv("=== Signature Quality:\n"); + OS << formatv("\tNumber of parameters: {0}\n", S.NumberOfParameters); + OS << formatv("\tNumber of optional parameters: {0}\n", +S.NumberOfOptionalParameters); + OS << formatv("\tContains active parameter: {0}\n", +S.ContainsActiveParameter); + OS << formatv("\tKind: {0}\n", S.Kind); + return OS; +} + } // namespace clangd } // namespace clang Index: clangd/CodeComplete.cpp === --- clangd/CodeComplete.cpp +++ clangd/CodeComplete.cpp @@ -128,16 +128,16 @@ /// Get the optional chunk as a string. This function is possibly recursive. /// /// The parameter info for each parameter is appended to the Parameters. -std::string -getOptionalParameters(const CodeCompletionString &CCS, - std::vector &Parameters) { +std::string getOptionalParameters(const CodeCompletionString &CCS, + std::vector &Parameters, + SignatureQualitySignals &Signal) { std::string Result; for (const auto &Chunk : CCS) { switch (Chunk.Kind) { case CodeCompletionString::CK_Optional: assert(Chunk.Optional && "Expected the optional code completion string to be non-null."); - Result += getOptionalParameters(*Chunk.Optional, Parameters); + Result += getOptionalParameters(*Chunk.Optional, Parameters, Signal); break; case CodeCompletionString::CK_VerticalSpace: break; @@ -153,6 +153,8 @@ ParameterInformation Info; Info.label = Chunk.Text; Parameters.push_back(std::move(Info)); + Signal.ContainsActiveParameter = true; + Signal.NumberOfOptionalParameters++; break; } default: @@ -679,6 +681,41 @@ llvm::unique_function ResultsCallback; }; +using ScoredSignature = +std::pair; +struct ScoredSignatureGreater { + bool operator()(const ScoredSignature &L, const ScoredSignature &R) { +// Ordering follows: +// - Less number of parameters is better. +// - Function is better than FunctionType which is better than Function +// Template. +// - High score is better. +// - Shorter signature is better. +// - Alphebatically smaller is better. +if (L.first.NumberOfParameters != R.first.NumberOfParameters) + return L.first.NumberOfParameters < R.first.NumberOfParameters; +if (L.first.NumberOfOpti
[PATCH] D50443: [clang] Store code completion token range in preprocessor.
kadircet updated this revision to Diff 160299. kadircet added a comment. - Resolve discussions. - Fix typo. Repository: rC Clang https://reviews.llvm.org/D50443 Files: include/clang/Lex/Preprocessor.h lib/Lex/Preprocessor.cpp Index: lib/Lex/Preprocessor.cpp === --- lib/Lex/Preprocessor.cpp +++ lib/Lex/Preprocessor.cpp @@ -868,6 +868,7 @@ if (Result.is(tok::code_completion) && Result.getIdentifierInfo()) { // Remember the identifier before code completion token. setCodeCompletionIdentifierInfo(Result.getIdentifierInfo()); +setCodeCompletionTokenRange(Result.getLocation(), Result.getEndLoc()); // Set IdenfitierInfo to null to avoid confusing code that handles both // identifiers and completion tokens. Result.setIdentifierInfo(nullptr); Index: include/clang/Lex/Preprocessor.h === --- include/clang/Lex/Preprocessor.h +++ include/clang/Lex/Preprocessor.h @@ -310,6 +310,9 @@ /// on the stem that is to be code completed. IdentifierInfo *CodeCompletionII = nullptr; + /// Range for the code completion token. + SourceRange CodeCompletionTokenRange; + /// 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). @@ -1131,6 +1134,16 @@ CodeCompletionII = Filter; } + /// Set the code completion token range for detecting replacement range later + /// on. + void setCodeCompletionTokenRange(const SourceLocation Start, + const SourceLocation End) { +CodeCompletionTokenRange = {Start, End}; + } + SourceRange getCodeCompletionTokenRange() const { +return CodeCompletionTokenRange; + } + /// Get the code completion token for filtering purposes. StringRef getCodeCompletionFilter() { if (CodeCompletionII) Index: lib/Lex/Preprocessor.cpp === --- lib/Lex/Preprocessor.cpp +++ lib/Lex/Preprocessor.cpp @@ -868,6 +868,7 @@ if (Result.is(tok::code_completion) && Result.getIdentifierInfo()) { // Remember the identifier before code completion token. setCodeCompletionIdentifierInfo(Result.getIdentifierInfo()); +setCodeCompletionTokenRange(Result.getLocation(), Result.getEndLoc()); // Set IdenfitierInfo to null to avoid confusing code that handles both // identifiers and completion tokens. Result.setIdentifierInfo(nullptr); Index: include/clang/Lex/Preprocessor.h === --- include/clang/Lex/Preprocessor.h +++ include/clang/Lex/Preprocessor.h @@ -310,6 +310,9 @@ /// on the stem that is to be code completed. IdentifierInfo *CodeCompletionII = nullptr; + /// Range for the code completion token. + SourceRange CodeCompletionTokenRange; + /// 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). @@ -1131,6 +1134,16 @@ CodeCompletionII = Filter; } + /// Set the code completion token range for detecting replacement range later + /// on. + void setCodeCompletionTokenRange(const SourceLocation Start, + const SourceLocation End) { +CodeCompletionTokenRange = {Start, End}; + } + SourceRange getCodeCompletionTokenRange() const { +return CodeCompletionTokenRange; + } + /// Get the code completion token for filtering purposes. StringRef getCodeCompletionFilter() { if (CodeCompletionII) ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50443: [clang] Store code completion token range in preprocessor.
This revision was automatically updated to reflect the committed changes. Closed by commit rL339540: [clang] Store code completion token range in preprocessor. (authored by kadircet, committed by ). Herald added a subscriber: llvm-commits. Repository: rL LLVM https://reviews.llvm.org/D50443 Files: cfe/trunk/include/clang/Lex/Preprocessor.h cfe/trunk/lib/Lex/Preprocessor.cpp Index: cfe/trunk/lib/Lex/Preprocessor.cpp === --- cfe/trunk/lib/Lex/Preprocessor.cpp +++ cfe/trunk/lib/Lex/Preprocessor.cpp @@ -868,6 +868,7 @@ if (Result.is(tok::code_completion) && Result.getIdentifierInfo()) { // Remember the identifier before code completion token. setCodeCompletionIdentifierInfo(Result.getIdentifierInfo()); +setCodeCompletionTokenRange(Result.getLocation(), Result.getEndLoc()); // Set IdenfitierInfo to null to avoid confusing code that handles both // identifiers and completion tokens. Result.setIdentifierInfo(nullptr); Index: cfe/trunk/include/clang/Lex/Preprocessor.h === --- cfe/trunk/include/clang/Lex/Preprocessor.h +++ cfe/trunk/include/clang/Lex/Preprocessor.h @@ -310,6 +310,9 @@ /// on the stem that is to be code completed. IdentifierInfo *CodeCompletionII = nullptr; + /// Range for the code completion token. + SourceRange CodeCompletionTokenRange; + /// 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). @@ -1131,6 +1134,16 @@ CodeCompletionII = Filter; } + /// Set the code completion token range for detecting replacement range later + /// on. + void setCodeCompletionTokenRange(const SourceLocation Start, + const SourceLocation End) { +CodeCompletionTokenRange = {Start, End}; + } + SourceRange getCodeCompletionTokenRange() const { +return CodeCompletionTokenRange; + } + /// Get the code completion token for filtering purposes. StringRef getCodeCompletionFilter() { if (CodeCompletionII) Index: cfe/trunk/lib/Lex/Preprocessor.cpp === --- cfe/trunk/lib/Lex/Preprocessor.cpp +++ cfe/trunk/lib/Lex/Preprocessor.cpp @@ -868,6 +868,7 @@ if (Result.is(tok::code_completion) && Result.getIdentifierInfo()) { // Remember the identifier before code completion token. setCodeCompletionIdentifierInfo(Result.getIdentifierInfo()); +setCodeCompletionTokenRange(Result.getLocation(), Result.getEndLoc()); // Set IdenfitierInfo to null to avoid confusing code that handles both // identifiers and completion tokens. Result.setIdentifierInfo(nullptr); Index: cfe/trunk/include/clang/Lex/Preprocessor.h === --- cfe/trunk/include/clang/Lex/Preprocessor.h +++ cfe/trunk/include/clang/Lex/Preprocessor.h @@ -310,6 +310,9 @@ /// on the stem that is to be code completed. IdentifierInfo *CodeCompletionII = nullptr; + /// Range for the code completion token. + SourceRange CodeCompletionTokenRange; + /// 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). @@ -1131,6 +1134,16 @@ CodeCompletionII = Filter; } + /// Set the code completion token range for detecting replacement range later + /// on. + void setCodeCompletionTokenRange(const SourceLocation Start, + const SourceLocation End) { +CodeCompletionTokenRange = {Start, End}; + } + SourceRange getCodeCompletionTokenRange() const { +return CodeCompletionTokenRange; + } + /// Get the code completion token for filtering purposes. StringRef getCodeCompletionFilter() { if (CodeCompletionII) ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50449: [clangd] Support textEdit in addition to insertText.
kadircet updated this revision to Diff 160303. kadircet added a comment. - Rebase. - Resolve discussions. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50449 Files: clangd/CodeComplete.cpp clangd/CodeComplete.h clangd/SourceCode.cpp clangd/SourceCode.h unittests/clangd/CodeCompleteTests.cpp unittests/clangd/SourceCodeTests.cpp Index: unittests/clangd/SourceCodeTests.cpp === --- unittests/clangd/SourceCodeTests.cpp +++ unittests/clangd/SourceCodeTests.cpp @@ -37,6 +37,13 @@ return Pos; } +Range range(const std::pair p1, const std::pair p2) { + Range range; + range.start = position(p1.first, p1.second); + range.end = position(p2.first, p2.second); + return range; +} + TEST(SourceCodeTests, PositionToOffset) { // line out of bounds EXPECT_THAT_EXPECTED(positionToOffset(File, position(-1, 2)), Failed()); @@ -119,6 +126,14 @@ EXPECT_THAT(offsetToPosition(File, 30), Pos(2, 9)) << "out of bounds"; } +TEST(SourceCodeTests, IsRangeConsecutive) { + EXPECT_TRUE(IsRangeConsecutive(range({2, 2}, {2, 3}), range({2, 3}, {2, 4}))); + EXPECT_FALSE( + IsRangeConsecutive(range({0, 2}, {0, 3}), range({2, 3}, {2, 4}))); + EXPECT_FALSE( + IsRangeConsecutive(range({2, 2}, {2, 3}), range({2, 4}, {2, 5}))); +} + } // namespace } // namespace clangd } // namespace clang Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -1439,6 +1439,82 @@ } } +TEST(CompletionTest, RenderWithFixItMerged) { + TextEdit FixIt; + FixIt.range.end.character = 5; + FixIt.newText = "->"; + + CodeCompletion C; + C.Name = "x"; + C.RequiredQualifier = "Foo::"; + C.FixIts = {FixIt}; + C.CompletionTokenRange.start.character = 5; + + CodeCompleteOptions Opts; + Opts.IncludeFixIts = true; + + auto R = C.render(Opts); + EXPECT_TRUE(R.textEdit); + EXPECT_EQ(R.textEdit->newText, "->Foo::x"); + EXPECT_TRUE(R.additionalTextEdits.empty()); +} + +TEST(CompletionTest, RenderWithFixItNonMerged) { + TextEdit FixIt; + FixIt.range.end.character = 4; + FixIt.newText = "->"; + + CodeCompletion C; + C.Name = "x"; + C.RequiredQualifier = "Foo::"; + C.FixIts = {FixIt}; + C.CompletionTokenRange.start.character = 5; + + CodeCompleteOptions Opts; + Opts.IncludeFixIts = true; + + auto R = C.render(Opts); + EXPECT_TRUE(R.textEdit); + EXPECT_EQ(R.textEdit->newText, "Foo::x"); + EXPECT_THAT(R.additionalTextEdits, UnorderedElementsAre(FixIt)); +} + +TEST(CompletionTest, CompletionTokenRange) { + MockFSProvider FS; + MockCompilationDatabase CDB; + IgnoreDiagnostics DiagConsumer; + ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest()); + + constexpr const char *TestCodes[] = { + R"cpp( +class Auxilary { + public: + void AuxFunction(); +}; +void f() { + Auxilary x; + x.[[Aux]]^; +} + )cpp", + R"cpp( +class Auxilary { + public: + void AuxFunction(); +}; +void f() { + Auxilary x; + x.[[]]^; +} + )cpp"}; + for (const auto &Text : TestCodes) { +Annotations TestCode(Text); +auto Results = completions(Server, TestCode.code(), TestCode.point()); + +EXPECT_EQ(Results.Completions.size(), 1u); +EXPECT_THAT(Results.Completions.front().CompletionTokenRange, TestCode.range()); + } +} + } // namespace } // namespace clangd } // namespace clang Index: clangd/SourceCode.h === --- clangd/SourceCode.h +++ clangd/SourceCode.h @@ -76,6 +76,8 @@ /// are normalized as much as possible. llvm::Optional getRealPath(const FileEntry *F, const SourceManager &SourceMgr); + +bool IsRangeConsecutive(const Range &Left, const Range &Right); } // namespace clangd } // namespace clang #endif Index: clangd/SourceCode.cpp === --- clangd/SourceCode.cpp +++ clangd/SourceCode.cpp @@ -224,5 +224,10 @@ return Result; } +bool IsRangeConsecutive(const Range &Left, const Range &Right) { + return Left.end.line == Right.start.line && + Left.end.character == Right.start.character; +} + } // namespace clangd } // namespace clang Index: clangd/CodeComplete.h === --- clangd/CodeComplete.h +++ clangd/CodeComplete.h @@ -123,6 +123,9 @@ /// converting '->' to '.' on member access. std::vector FixIts; + /// Holds the range of the token we are going to replace with this completion. + Range CompletionTokenRange; + // Scores are used to rank completion items. struct Scores { // The score that items are ranked by. Index: clangd/CodeComplete.cpp =
[PATCH] D50449: [clangd] Support textEdit in addition to insertText.
This revision was automatically updated to reflect the committed changes. Closed by commit rL339543: [clangd] Support textEdit in addition to insertText. (authored by kadircet, committed by ). Herald added a subscriber: llvm-commits. Repository: rL LLVM https://reviews.llvm.org/D50449 Files: clang-tools-extra/trunk/clangd/CodeComplete.cpp clang-tools-extra/trunk/clangd/CodeComplete.h clang-tools-extra/trunk/clangd/SourceCode.cpp clang-tools-extra/trunk/clangd/SourceCode.h clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp clang-tools-extra/trunk/unittests/clangd/SourceCodeTests.cpp Index: clang-tools-extra/trunk/unittests/clangd/SourceCodeTests.cpp === --- clang-tools-extra/trunk/unittests/clangd/SourceCodeTests.cpp +++ clang-tools-extra/trunk/unittests/clangd/SourceCodeTests.cpp @@ -37,6 +37,13 @@ return Pos; } +Range range(const std::pair p1, const std::pair p2) { + Range range; + range.start = position(p1.first, p1.second); + range.end = position(p2.first, p2.second); + return range; +} + TEST(SourceCodeTests, PositionToOffset) { // line out of bounds EXPECT_THAT_EXPECTED(positionToOffset(File, position(-1, 2)), Failed()); @@ -119,6 +126,14 @@ EXPECT_THAT(offsetToPosition(File, 30), Pos(2, 9)) << "out of bounds"; } +TEST(SourceCodeTests, IsRangeConsecutive) { + EXPECT_TRUE(IsRangeConsecutive(range({2, 2}, {2, 3}), range({2, 3}, {2, 4}))); + EXPECT_FALSE( + IsRangeConsecutive(range({0, 2}, {0, 3}), range({2, 3}, {2, 4}))); + EXPECT_FALSE( + IsRangeConsecutive(range({2, 2}, {2, 3}), range({2, 4}, {2, 5}))); +} + } // namespace } // namespace clangd } // namespace clang Index: clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp === --- clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp +++ clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp @@ -1439,6 +1439,82 @@ } } +TEST(CompletionTest, RenderWithFixItMerged) { + TextEdit FixIt; + FixIt.range.end.character = 5; + FixIt.newText = "->"; + + CodeCompletion C; + C.Name = "x"; + C.RequiredQualifier = "Foo::"; + C.FixIts = {FixIt}; + C.CompletionTokenRange.start.character = 5; + + CodeCompleteOptions Opts; + Opts.IncludeFixIts = true; + + auto R = C.render(Opts); + EXPECT_TRUE(R.textEdit); + EXPECT_EQ(R.textEdit->newText, "->Foo::x"); + EXPECT_TRUE(R.additionalTextEdits.empty()); +} + +TEST(CompletionTest, RenderWithFixItNonMerged) { + TextEdit FixIt; + FixIt.range.end.character = 4; + FixIt.newText = "->"; + + CodeCompletion C; + C.Name = "x"; + C.RequiredQualifier = "Foo::"; + C.FixIts = {FixIt}; + C.CompletionTokenRange.start.character = 5; + + CodeCompleteOptions Opts; + Opts.IncludeFixIts = true; + + auto R = C.render(Opts); + EXPECT_TRUE(R.textEdit); + EXPECT_EQ(R.textEdit->newText, "Foo::x"); + EXPECT_THAT(R.additionalTextEdits, UnorderedElementsAre(FixIt)); +} + +TEST(CompletionTest, CompletionTokenRange) { + MockFSProvider FS; + MockCompilationDatabase CDB; + IgnoreDiagnostics DiagConsumer; + ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest()); + + constexpr const char *TestCodes[] = { + R"cpp( +class Auxilary { + public: + void AuxFunction(); +}; +void f() { + Auxilary x; + x.[[Aux]]^; +} + )cpp", + R"cpp( +class Auxilary { + public: + void AuxFunction(); +}; +void f() { + Auxilary x; + x.[[]]^; +} + )cpp"}; + for (const auto &Text : TestCodes) { +Annotations TestCode(Text); +auto Results = completions(Server, TestCode.code(), TestCode.point()); + +EXPECT_EQ(Results.Completions.size(), 1u); +EXPECT_THAT(Results.Completions.front().CompletionTokenRange, TestCode.range()); + } +} + } // namespace } // namespace clangd } // namespace clang Index: clang-tools-extra/trunk/clangd/CodeComplete.h === --- clang-tools-extra/trunk/clangd/CodeComplete.h +++ clang-tools-extra/trunk/clangd/CodeComplete.h @@ -123,6 +123,9 @@ /// converting '->' to '.' on member access. std::vector FixIts; + /// Holds the range of the token we are going to replace with this completion. + Range CompletionTokenRange; + // Scores are used to rank completion items. struct Scores { // The score that items are ranked by. Index: clang-tools-extra/trunk/clangd/SourceCode.cpp === --- clang-tools-extra/trunk/clangd/SourceCode.cpp +++ clang-tools-extra/trunk/clangd/SourceCode.cpp @@ -224,5 +224,10 @@ return Result; } +bool IsRangeConsecutive(const Range &Left, const Range &Right) { + return Left.end.line == Right.start.line && + Left.end.character == Right.start.character; +}
[PATCH] D50555: [clangd] Introduce scoring mechanism for SignatureInformations.
kadircet updated this revision to Diff 160306. kadircet marked 2 inline comments as done. kadircet added a comment. - Rebase & Resolve discussions. - Resolve discussions. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50555 Files: clangd/CodeComplete.cpp clangd/Quality.cpp clangd/Quality.h unittests/clangd/CodeCompleteTests.cpp Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -1515,6 +1515,28 @@ } } +TEST(SignatureHelpTest, OverloadsOrdering) { + const auto Results = signatures(R"cpp( +void foo(int x); +void foo(int x, float y); +void foo(float x, int y); +void foo(float x, float y); +void foo(int x, int y = 0); +int main() { foo(^); } + )cpp"); + EXPECT_THAT( + Results.signatures, + ElementsAre( + Sig("foo(int x) -> void", {"int x"}), + Sig("foo(int x, int y = 0) -> void", {"int x", "int y = 0"}), + Sig("foo(float x, int y) -> void", {"float x", "int y"}), + Sig("foo(int x, float y) -> void", {"int x", "float y"}), + Sig("foo(float x, float y) -> void", {"float x", "float y"}))); + // We always prefer the first signature. + EXPECT_EQ(0, Results.activeSignature); + EXPECT_EQ(0, Results.activeParameter); +} + } // namespace } // namespace clangd } // namespace clang Index: clangd/Quality.h === --- clangd/Quality.h +++ clangd/Quality.h @@ -163,6 +163,16 @@ /// LSP. (The highest score compares smallest so it sorts at the top). std::string sortText(float Score, llvm::StringRef Tiebreak = ""); +struct SignatureQualitySignals { + uint32_t NumberOfParameters = 0; + uint32_t NumberOfOptionalParameters = 0; + bool ContainsActiveParameter = false; + CodeCompleteConsumer::OverloadCandidate::CandidateKind Kind = + CodeCompleteConsumer::OverloadCandidate::CandidateKind::CK_Function; +}; +llvm::raw_ostream &operator<<(llvm::raw_ostream &, + const SignatureQualitySignals &); + } // namespace clangd } // namespace clang Index: clangd/Quality.cpp === --- clangd/Quality.cpp +++ clangd/Quality.cpp @@ -401,5 +401,17 @@ return S; } +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const SignatureQualitySignals &S) { + OS << formatv("=== Signature Quality:\n"); + OS << formatv("\tNumber of parameters: {0}\n", S.NumberOfParameters); + OS << formatv("\tNumber of optional parameters: {0}\n", +S.NumberOfOptionalParameters); + OS << formatv("\tContains active parameter: {0}\n", +S.ContainsActiveParameter); + OS << formatv("\tKind: {0}\n", S.Kind); + return OS; +} + } // namespace clangd } // namespace clang Index: clangd/CodeComplete.cpp === --- clangd/CodeComplete.cpp +++ clangd/CodeComplete.cpp @@ -129,16 +129,16 @@ /// Get the optional chunk as a string. This function is possibly recursive. /// /// The parameter info for each parameter is appended to the Parameters. -std::string -getOptionalParameters(const CodeCompletionString &CCS, - std::vector &Parameters) { +std::string getOptionalParameters(const CodeCompletionString &CCS, + std::vector &Parameters, + SignatureQualitySignals &Signal) { std::string Result; for (const auto &Chunk : CCS) { switch (Chunk.Kind) { case CodeCompletionString::CK_Optional: assert(Chunk.Optional && "Expected the optional code completion string to be non-null."); - Result += getOptionalParameters(*Chunk.Optional, Parameters); + Result += getOptionalParameters(*Chunk.Optional, Parameters, Signal); break; case CodeCompletionString::CK_VerticalSpace: break; @@ -154,6 +154,8 @@ ParameterInformation Info; Info.label = Chunk.Text; Parameters.push_back(std::move(Info)); + Signal.ContainsActiveParameter = true; + Signal.NumberOfOptionalParameters++; break; } default: @@ -685,6 +687,9 @@ llvm::unique_function ResultsCallback; }; +using ScoredSignature = +std::pair; + class SignatureHelpCollector final : public CodeCompleteConsumer { public: @@ -698,7 +703,9 @@ void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, OverloadCandidate *Candidates, unsigned NumCandidates) override { +std::vector ScoredSignatures; SigHelp.signatures.reserve(NumCandidates); +ScoredSignatures.reserve(NumCandidates); // FIXME(rwols): How can we determine the "active overload candidate"? // Right now the overloaded candidates seem to be p
[PATCH] D50555: [clangd] Introduce scoring mechanism for SignatureInformations.
This revision was automatically updated to reflect the committed changes. Closed by commit rCTE339547: [clangd] Introduce scoring mechanism for SignatureInformations. (authored by kadircet, committed by ). Changed prior to commit: https://reviews.llvm.org/D50555?vs=160306&id=160307#toc Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50555 Files: clangd/CodeComplete.cpp clangd/Quality.cpp clangd/Quality.h unittests/clangd/CodeCompleteTests.cpp Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -1515,6 +1515,28 @@ } } +TEST(SignatureHelpTest, OverloadsOrdering) { + const auto Results = signatures(R"cpp( +void foo(int x); +void foo(int x, float y); +void foo(float x, int y); +void foo(float x, float y); +void foo(int x, int y = 0); +int main() { foo(^); } + )cpp"); + EXPECT_THAT( + Results.signatures, + ElementsAre( + Sig("foo(int x) -> void", {"int x"}), + Sig("foo(int x, int y = 0) -> void", {"int x", "int y = 0"}), + Sig("foo(float x, int y) -> void", {"float x", "int y"}), + Sig("foo(int x, float y) -> void", {"int x", "float y"}), + Sig("foo(float x, float y) -> void", {"float x", "float y"}))); + // We always prefer the first signature. + EXPECT_EQ(0, Results.activeSignature); + EXPECT_EQ(0, Results.activeParameter); +} + } // namespace } // namespace clangd } // namespace clang Index: clangd/CodeComplete.cpp === --- clangd/CodeComplete.cpp +++ clangd/CodeComplete.cpp @@ -129,16 +129,16 @@ /// Get the optional chunk as a string. This function is possibly recursive. /// /// The parameter info for each parameter is appended to the Parameters. -std::string -getOptionalParameters(const CodeCompletionString &CCS, - std::vector &Parameters) { +std::string getOptionalParameters(const CodeCompletionString &CCS, + std::vector &Parameters, + SignatureQualitySignals &Signal) { std::string Result; for (const auto &Chunk : CCS) { switch (Chunk.Kind) { case CodeCompletionString::CK_Optional: assert(Chunk.Optional && "Expected the optional code completion string to be non-null."); - Result += getOptionalParameters(*Chunk.Optional, Parameters); + Result += getOptionalParameters(*Chunk.Optional, Parameters, Signal); break; case CodeCompletionString::CK_VerticalSpace: break; @@ -154,6 +154,8 @@ ParameterInformation Info; Info.label = Chunk.Text; Parameters.push_back(std::move(Info)); + Signal.ContainsActiveParameter = true; + Signal.NumberOfOptionalParameters++; break; } default: @@ -685,6 +687,9 @@ llvm::unique_function ResultsCallback; }; +using ScoredSignature = +std::pair; + class SignatureHelpCollector final : public CodeCompleteConsumer { public: @@ -698,7 +703,9 @@ void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, OverloadCandidate *Candidates, unsigned NumCandidates) override { +std::vector ScoredSignatures; SigHelp.signatures.reserve(NumCandidates); +ScoredSignatures.reserve(NumCandidates); // FIXME(rwols): How can we determine the "active overload candidate"? // Right now the overloaded candidates seem to be provided in a "best fit" // order, so I'm not too worried about this. @@ -712,11 +719,45 @@ CurrentArg, S, *Allocator, CCTUInfo, true); assert(CCS && "Expected the CodeCompletionString to be non-null"); // FIXME: for headers, we need to get a comment from the index. - SigHelp.signatures.push_back(processOverloadCandidate( + ScoredSignatures.push_back(processOverloadCandidate( Candidate, *CCS, getParameterDocComment(S.getASTContext(), Candidate, CurrentArg, /*CommentsFromHeaders=*/false))); } +std::sort(ScoredSignatures.begin(), ScoredSignatures.end(), + [](const ScoredSignature &L, const ScoredSignature &R) { +// Ordering follows: +// - Less number of parameters is better. +// - Function is better than FunctionType which is better than +// Function Template. +// - High score is better. +// - Shorter signature is better. +// - Alphebatically smaller is better. +if (L.first.NumberOfParameters != R.first.NumberOfParameters) + return L.first.NumberOfParameters < + R.first.NumberOfParameters; +if (L.first.NumberOfOptionalParameters != +R.first.
[PATCH] D50635: Fix lint tests for D50449
kadircet created this revision. kadircet added a reviewer: ilya-biryukov. Herald added subscribers: cfe-commits, arphaman, jkorous, ioeric. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50635 Files: test/clangd/completion-snippets.test test/clangd/completion.test Index: test/clangd/completion.test === --- test/clangd/completion.test +++ test/clangd/completion.test @@ -18,6 +18,19 @@ # CHECK-NEXT: "kind": 5, # CHECK-NEXT: "label": " a", # CHECK-NEXT: "sortText": "{{.*}}a" +# CHECK-NEXT: "textEdit": { +# CHECK-NEXT:"newText": "a", +# CHECK-NEXT:"range": { +# CHECK-NEXT: "end": { +# CHECK-NEXT:"character": 4, +# CHECK-NEXT:"line": 2 +# CHECK-NEXT: } +# CHECK-NEXT: "start": { +# CHECK-NEXT:"character": 4, +# CHECK-NEXT:"line": 2 +# CHECK-NEXT: } +# CHECK-NEXT:} +# CHECK-NEXT: } # CHECK-NEXT:} # CHECK-NEXT: ] --- @@ -38,6 +51,19 @@ # CHECK-NEXT: "kind": 5, # CHECK-NEXT: "label": " b", # CHECK-NEXT: "sortText": "{{.*}}b" +# CHECK-NEXT: "textEdit": { +# CHECK-NEXT:"newText": "b", +# CHECK-NEXT:"range": { +# CHECK-NEXT: "end": { +# CHECK-NEXT:"character": 4, +# CHECK-NEXT:"line": 2 +# CHECK-NEXT: } +# CHECK-NEXT: "start": { +# CHECK-NEXT:"character": 4, +# CHECK-NEXT:"line": 2 +# CHECK-NEXT: } +# CHECK-NEXT:} +# CHECK-NEXT: } # CHECK-NEXT:} # CHECK-NEXT: ] --- Index: test/clangd/completion-snippets.test === --- test/clangd/completion-snippets.test +++ test/clangd/completion-snippets.test @@ -34,6 +34,19 @@ # CHECK-NEXT: "kind": 3, # CHECK-NEXT: "label": " func_with_args(int a, int b)", # CHECK-NEXT: "sortText": "{{.*}}func_with_args" +# CHECK-NEXT: "textEdit": { +# CHECK-NEXT:"newText": "func_with_args(${1:int a}, ${2:int b})", +# CHECK-NEXT:"range": { +# CHECK-NEXT: "end": { +# CHECK-NEXT:"character": 7, +# CHECK-NEXT:"line": 2 +# CHECK-NEXT: } +# CHECK-NEXT: "start": { +# CHECK-NEXT:"character": 0, +# CHECK-NEXT:"line": 2 +# CHECK-NEXT: } +# CHECK-NEXT:} +# CHECK-NEXT: } # CHECK-NEXT:} # CHECK-NEXT:] # CHECK-NEXT: } Index: test/clangd/completion.test === --- test/clangd/completion.test +++ test/clangd/completion.test @@ -18,6 +18,19 @@ # CHECK-NEXT: "kind": 5, # CHECK-NEXT: "label": " a", # CHECK-NEXT: "sortText": "{{.*}}a" +# CHECK-NEXT: "textEdit": { +# CHECK-NEXT:"newText": "a", +# CHECK-NEXT:"range": { +# CHECK-NEXT: "end": { +# CHECK-NEXT:"character": 4, +# CHECK-NEXT:"line": 2 +# CHECK-NEXT: } +# CHECK-NEXT: "start": { +# CHECK-NEXT:"character": 4, +# CHECK-NEXT:"line": 2 +# CHECK-NEXT: } +# CHECK-NEXT:} +# CHECK-NEXT: } # CHECK-NEXT:} # CHECK-NEXT: ] --- @@ -38,6 +51,19 @@ # CHECK-NEXT: "kind": 5, # CHECK-NEXT: "label": " b", # CHECK-NEXT: "sortText": "{{.*}}b" +# CHECK-NEXT: "textEdit": { +# CHECK-NEXT:"newText": "b", +# CHECK-NEXT:"range": { +# CHECK-NEXT: "end": { +# CHECK-NEXT:"character": 4, +# CHECK-NEXT:"line": 2 +# CHECK-NEXT: } +# CHECK-NEXT: "start": { +# CHECK-NEXT:"character": 4, +# CHECK-NEXT:"line": 2 +# CHECK-NEXT: } +# CHECK-NEXT:} +# CHECK-NEXT: } # CHECK-NEXT:} # CHECK-NEXT: ] --- Index: test/clangd/completion-snippets.test === --- test/clangd/completion-snippets.test +++ test/clangd/completion-snippets.test @@ -34,6 +34,19 @@ # CHECK-NEXT: "kind": 3, # CHECK-NEXT: "label": " func_with_args(int a, int b)", # CHECK-NEXT: "sortText": "{{.*}}func_with_args" +# CHECK-NEXT: "textEdit": { +# CHECK-NEXT:"newText": "func_with_args(${1:int a}, ${2:int b})", +# CHECK-NEXT:"range": { +# CHECK-NEXT: "end": { +# CHECK-NEXT:"character": 7, +# CHECK-NEXT:"line": 2 +# CHECK-NEXT: } +# CHECK-NEXT: "start": { +# CHECK-NEXT:"character": 0, +# CHECK-NEXT:"line": 2 +# CHECK-NEXT: } +# CHECK-NEXT:} +# CHECK-NEXT: } # CHECK-NEXT:} # CHECK-NEXT:] # CHECK-NEXT: } ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50635: Fix lint tests for D50449
This revision was automatically updated to reflect the committed changes. Closed by commit rL339572: Fix lint tests for D50449 (authored by kadircet, committed by ). Herald added a subscriber: llvm-commits. Repository: rL LLVM https://reviews.llvm.org/D50635 Files: clang-tools-extra/trunk/test/clangd/completion-snippets.test clang-tools-extra/trunk/test/clangd/completion.test Index: clang-tools-extra/trunk/test/clangd/completion.test === --- clang-tools-extra/trunk/test/clangd/completion.test +++ clang-tools-extra/trunk/test/clangd/completion.test @@ -18,6 +18,19 @@ # CHECK-NEXT: "kind": 5, # CHECK-NEXT: "label": " a", # CHECK-NEXT: "sortText": "{{.*}}a" +# CHECK-NEXT: "textEdit": { +# CHECK-NEXT:"newText": "a", +# CHECK-NEXT:"range": { +# CHECK-NEXT: "end": { +# CHECK-NEXT:"character": 4, +# CHECK-NEXT:"line": 2 +# CHECK-NEXT: } +# CHECK-NEXT: "start": { +# CHECK-NEXT:"character": 4, +# CHECK-NEXT:"line": 2 +# CHECK-NEXT: } +# CHECK-NEXT:} +# CHECK-NEXT: } # CHECK-NEXT:} # CHECK-NEXT: ] --- @@ -38,6 +51,19 @@ # CHECK-NEXT: "kind": 5, # CHECK-NEXT: "label": " b", # CHECK-NEXT: "sortText": "{{.*}}b" +# CHECK-NEXT: "textEdit": { +# CHECK-NEXT:"newText": "b", +# CHECK-NEXT:"range": { +# CHECK-NEXT: "end": { +# CHECK-NEXT:"character": 4, +# CHECK-NEXT:"line": 2 +# CHECK-NEXT: } +# CHECK-NEXT: "start": { +# CHECK-NEXT:"character": 4, +# CHECK-NEXT:"line": 2 +# CHECK-NEXT: } +# CHECK-NEXT:} +# CHECK-NEXT: } # CHECK-NEXT:} # CHECK-NEXT: ] --- Index: clang-tools-extra/trunk/test/clangd/completion-snippets.test === --- clang-tools-extra/trunk/test/clangd/completion-snippets.test +++ clang-tools-extra/trunk/test/clangd/completion-snippets.test @@ -34,6 +34,19 @@ # CHECK-NEXT: "kind": 3, # CHECK-NEXT: "label": " func_with_args(int a, int b)", # CHECK-NEXT: "sortText": "{{.*}}func_with_args" +# CHECK-NEXT: "textEdit": { +# CHECK-NEXT:"newText": "func_with_args(${1:int a}, ${2:int b})", +# CHECK-NEXT:"range": { +# CHECK-NEXT: "end": { +# CHECK-NEXT:"character": 7, +# CHECK-NEXT:"line": 2 +# CHECK-NEXT: } +# CHECK-NEXT: "start": { +# CHECK-NEXT:"character": 0, +# CHECK-NEXT:"line": 2 +# CHECK-NEXT: } +# CHECK-NEXT:} +# CHECK-NEXT: } # CHECK-NEXT:} # CHECK-NEXT:] # CHECK-NEXT: } Index: clang-tools-extra/trunk/test/clangd/completion.test === --- clang-tools-extra/trunk/test/clangd/completion.test +++ clang-tools-extra/trunk/test/clangd/completion.test @@ -18,6 +18,19 @@ # CHECK-NEXT: "kind": 5, # CHECK-NEXT: "label": " a", # CHECK-NEXT: "sortText": "{{.*}}a" +# CHECK-NEXT: "textEdit": { +# CHECK-NEXT:"newText": "a", +# CHECK-NEXT:"range": { +# CHECK-NEXT: "end": { +# CHECK-NEXT:"character": 4, +# CHECK-NEXT:"line": 2 +# CHECK-NEXT: } +# CHECK-NEXT: "start": { +# CHECK-NEXT:"character": 4, +# CHECK-NEXT:"line": 2 +# CHECK-NEXT: } +# CHECK-NEXT:} +# CHECK-NEXT: } # CHECK-NEXT:} # CHECK-NEXT: ] --- @@ -38,6 +51,19 @@ # CHECK-NEXT: "kind": 5, # CHECK-NEXT: "label": " b", # CHECK-NEXT: "sortText": "{{.*}}b" +# CHECK-NEXT: "textEdit": { +# CHECK-NEXT:"newText": "b", +# CHECK-NEXT:"range": { +# CHECK-NEXT: "end": { +# CHECK-NEXT:"character": 4, +# CHECK-NEXT:"line": 2 +# CHECK-NEXT: } +# CHECK-NEXT: "start": { +# CHECK-NEXT:"character": 4, +# CHECK-NEXT:"line": 2 +# CHECK-NEXT: } +# CHECK-NEXT:} +# CHECK-NEXT: } # CHECK-NEXT:} # CHECK-NEXT: ] --- Index: clang-tools-extra/trunk/test/clangd/completion-snippets.test === --- clang-tools-extra/trunk/test/clangd/completion-snippets.test +++ clang-tools-extra/trunk/test/clangd/completion-snippets.test @@ -34,6 +34,19 @@ # CHECK-NEXT: "kind": 3, # CHECK-NEXT: "label": " func_with_args(int a, int b)", # CHECK-NEXT: "sortText": "{{.*}}func_with_args" +# CHECK-NEXT: "textEdit": { +# CHECK-NEXT:"newText": "func_with_args(${1:int a}, ${2:int b})", +# CHECK-NEXT:"range": { +# CHECK-NEXT: "end": { +# CHECK-NEXT:"character": 7, +# CHECK-NEXT:"line": 2 +# CHECK-NEXT: } +# CHECK-NEXT: "start": { +# CHECK-NEXT:"character":
[PATCH] D50502: [clangd] Initial cancellation mechanism for LSP requests.
kadircet updated this revision to Diff 160531. kadircet marked 7 inline comments as done. kadircet added a comment. - Polished API. - Resolved discussions. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50502 Files: clangd/CMakeLists.txt clangd/Cancellation.cpp clangd/Cancellation.h clangd/ClangdLSPServer.cpp clangd/ClangdLSPServer.h clangd/ClangdServer.cpp clangd/ClangdServer.h clangd/JSONRPCDispatcher.cpp clangd/JSONRPCDispatcher.h clangd/Protocol.cpp clangd/Protocol.h clangd/ProtocolHandlers.cpp clangd/ProtocolHandlers.h unittests/clangd/CMakeLists.txt unittests/clangd/CancellationTests.cpp Index: unittests/clangd/CancellationTests.cpp === --- /dev/null +++ unittests/clangd/CancellationTests.cpp @@ -0,0 +1,76 @@ +#include "Cancellation.h" +#include "Context.h" +#include "llvm/Support/Error.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include +#include +#include + +namespace clang { +namespace clangd { +namespace { + +TEST(CancellationTest, CancellationTest) { + { +TaskHandle TH = TaskHandle::createCancellableTaskHandle(); +WithContext ContextWithCancellation( +CancellationHandler::setCurrentCancellationToken(TH)); +EXPECT_FALSE(CancellationHandler::isCancelled()); +TH.cancel(); +EXPECT_TRUE(CancellationHandler::isCancelled()); + } + EXPECT_FALSE(CancellationHandler::isCancelled()); +} + +TEST(CancellationTest, CheckForError) { + llvm::Error e = handleErrors(CancellationHandler::getCancellationError(), + [](const TaskCancelledError &) {}); + EXPECT_FALSE(e); +} + +TEST(CancellationTest, TaskHandleTestHandleDiesContextLives) { + llvm::Optional ContextWithCancellation; + { +auto CancellableTaskHandle = TaskHandle::createCancellableTaskHandle(); +ContextWithCancellation.emplace( +CancellationHandler::setCurrentCancellationToken( +CancellableTaskHandle)); +EXPECT_FALSE(CancellationHandler::isCancelled()); +CancellableTaskHandle.cancel(); +EXPECT_TRUE(CancellationHandler::isCancelled()); + } + EXPECT_TRUE(CancellationHandler::isCancelled()); + ContextWithCancellation.reset(); + EXPECT_FALSE(CancellationHandler::isCancelled()); +} + +TEST(CancellationTest, TaskHandleContextDiesHandleLives) { + { +auto CancellableTaskHandle = TaskHandle::createCancellableTaskHandle(); +{ + WithContext ContextWithCancellation( + CancellationHandler::setCurrentCancellationToken( + CancellableTaskHandle)); + EXPECT_FALSE(CancellationHandler::isCancelled()); + CancellableTaskHandle.cancel(); + EXPECT_TRUE(CancellationHandler::isCancelled()); +} + } + EXPECT_FALSE(CancellationHandler::isCancelled()); +} + +TEST(CancellationTest, CancellationToken) { + auto CancellableTaskHandle = TaskHandle::createCancellableTaskHandle(); + WithContext ContextWithCancellation( + CancellationHandler::setCurrentCancellationToken(CancellableTaskHandle)); + auto CT = CancellationHandler::isCancelled(); + EXPECT_FALSE(CT); + CancellableTaskHandle.cancel(); + EXPECT_TRUE(CT); +} + +} // namespace +} // namespace clangd +} // namespace clang Index: unittests/clangd/CMakeLists.txt === --- unittests/clangd/CMakeLists.txt +++ unittests/clangd/CMakeLists.txt @@ -10,6 +10,7 @@ add_extra_unittest(ClangdTests Annotations.cpp + CancellationTests.cpp ClangdTests.cpp ClangdUnitTests.cpp CodeCompleteTests.cpp Index: clangd/ProtocolHandlers.h === --- clangd/ProtocolHandlers.h +++ clangd/ProtocolHandlers.h @@ -55,6 +55,7 @@ virtual void onDocumentHighlight(TextDocumentPositionParams &Params) = 0; virtual void onHover(TextDocumentPositionParams &Params) = 0; virtual void onChangeConfiguration(DidChangeConfigurationParams &Params) = 0; + virtual void onCancelRequest(CancelParams &Params) = 0; }; void registerCallbackHandlers(JSONRPCDispatcher &Dispatcher, Index: clangd/ProtocolHandlers.cpp === --- clangd/ProtocolHandlers.cpp +++ clangd/ProtocolHandlers.cpp @@ -75,4 +75,5 @@ Register("workspace/didChangeConfiguration", &ProtocolCallbacks::onChangeConfiguration); Register("workspace/symbol", &ProtocolCallbacks::onWorkspaceSymbol); + Register("$/cancelRequest", &ProtocolCallbacks::onCancelRequest); } Index: clangd/Protocol.h === --- clangd/Protocol.h +++ clangd/Protocol.h @@ -861,6 +861,13 @@ llvm::json::Value toJSON(const DocumentHighlight &DH); llvm::raw_ostream &operator<<(llvm::raw_ostream &, const DocumentHighlight &); +struct CancelParams { + std::string ID; +}; +llvm::json::Value toJSON(const CancelParams &); +llvm::raw_ostream &operator<<(llvm::raw_ostream
[PATCH] D50502: [clangd] Initial cancellation mechanism for LSP requests.
kadircet updated this revision to Diff 160636. kadircet marked 4 inline comments as done. kadircet added a comment. - Get rid of getCancellationError. - Add replyError helper. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50502 Files: clangd/CMakeLists.txt clangd/Cancellation.cpp clangd/Cancellation.h clangd/ClangdLSPServer.cpp clangd/ClangdLSPServer.h clangd/ClangdServer.cpp clangd/ClangdServer.h clangd/JSONRPCDispatcher.cpp clangd/JSONRPCDispatcher.h clangd/Protocol.cpp clangd/Protocol.h clangd/ProtocolHandlers.cpp clangd/ProtocolHandlers.h unittests/clangd/CMakeLists.txt unittests/clangd/CancellationTests.cpp Index: unittests/clangd/CancellationTests.cpp === --- /dev/null +++ unittests/clangd/CancellationTests.cpp @@ -0,0 +1,70 @@ +#include "Cancellation.h" +#include "Context.h" +#include "llvm/Support/Error.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include +#include +#include + +namespace clang { +namespace clangd { +namespace { + +TEST(CancellationTest, CancellationTest) { + { +TaskHandle TH = TaskHandle::createCancellableTaskHandle(); +WithContext ContextWithCancellation( +CancellationHandler::setCurrentCancellationToken(TH)); +EXPECT_FALSE(CancellationHandler::isCancelled()); +TH.cancel(); +EXPECT_TRUE(CancellationHandler::isCancelled()); + } + EXPECT_FALSE(CancellationHandler::isCancelled()); +} + +TEST(CancellationTest, TaskHandleTestHandleDiesContextLives) { + llvm::Optional ContextWithCancellation; + { +auto CancellableTaskHandle = TaskHandle::createCancellableTaskHandle(); +ContextWithCancellation.emplace( +CancellationHandler::setCurrentCancellationToken( +CancellableTaskHandle)); +EXPECT_FALSE(CancellationHandler::isCancelled()); +CancellableTaskHandle.cancel(); +EXPECT_TRUE(CancellationHandler::isCancelled()); + } + EXPECT_TRUE(CancellationHandler::isCancelled()); + ContextWithCancellation.reset(); + EXPECT_FALSE(CancellationHandler::isCancelled()); +} + +TEST(CancellationTest, TaskHandleContextDiesHandleLives) { + { +auto CancellableTaskHandle = TaskHandle::createCancellableTaskHandle(); +{ + WithContext ContextWithCancellation( + CancellationHandler::setCurrentCancellationToken( + CancellableTaskHandle)); + EXPECT_FALSE(CancellationHandler::isCancelled()); + CancellableTaskHandle.cancel(); + EXPECT_TRUE(CancellationHandler::isCancelled()); +} + } + EXPECT_FALSE(CancellationHandler::isCancelled()); +} + +TEST(CancellationTest, CancellationToken) { + auto CancellableTaskHandle = TaskHandle::createCancellableTaskHandle(); + WithContext ContextWithCancellation( + CancellationHandler::setCurrentCancellationToken(CancellableTaskHandle)); + auto CT = CancellationHandler::isCancelled(); + EXPECT_FALSE(CT); + CancellableTaskHandle.cancel(); + EXPECT_TRUE(CT); +} + +} // namespace +} // namespace clangd +} // namespace clang Index: unittests/clangd/CMakeLists.txt === --- unittests/clangd/CMakeLists.txt +++ unittests/clangd/CMakeLists.txt @@ -10,6 +10,7 @@ add_extra_unittest(ClangdTests Annotations.cpp + CancellationTests.cpp ClangdTests.cpp ClangdUnitTests.cpp CodeCompleteTests.cpp Index: clangd/ProtocolHandlers.h === --- clangd/ProtocolHandlers.h +++ clangd/ProtocolHandlers.h @@ -55,6 +55,7 @@ virtual void onDocumentHighlight(TextDocumentPositionParams &Params) = 0; virtual void onHover(TextDocumentPositionParams &Params) = 0; virtual void onChangeConfiguration(DidChangeConfigurationParams &Params) = 0; + virtual void onCancelRequest(CancelParams &Params) = 0; }; void registerCallbackHandlers(JSONRPCDispatcher &Dispatcher, Index: clangd/ProtocolHandlers.cpp === --- clangd/ProtocolHandlers.cpp +++ clangd/ProtocolHandlers.cpp @@ -75,4 +75,5 @@ Register("workspace/didChangeConfiguration", &ProtocolCallbacks::onChangeConfiguration); Register("workspace/symbol", &ProtocolCallbacks::onWorkspaceSymbol); + Register("$/cancelRequest", &ProtocolCallbacks::onCancelRequest); } Index: clangd/Protocol.h === --- clangd/Protocol.h +++ clangd/Protocol.h @@ -861,6 +861,13 @@ llvm::json::Value toJSON(const DocumentHighlight &DH); llvm::raw_ostream &operator<<(llvm::raw_ostream &, const DocumentHighlight &); +struct CancelParams { + std::string ID; +}; +llvm::json::Value toJSON(const CancelParams &); +llvm::raw_ostream &operator<<(llvm::raw_ostream &, const CancelParams &); +bool fromJSON(const llvm::json::Value &, CancelParams &); + } // namespace clangd } // namespace clang Index: clangd/Protocol.cpp ==
[PATCH] D50502: [clangd] Initial cancellation mechanism for LSP requests.
kadircet added inline comments. Comment at: clangd/Cancellation.cpp:17 +namespace { +static Key>> CancellationTokenKey; +} // namespace ilya-biryukov wrote: > Having a `shared_ptr` key in the Context can cause data races (e.g. if we > copy it concurrently from multiple threads). > I suggest we make `CancellationToken` move-only (i.e. disallow copies) and > return `const CancellationToken&` when getting it from the context. As talked offline, copying std::shared_ptr is thread safe. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50502 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50502: [clangd] Initial cancellation mechanism for LSP requests.
kadircet updated this revision to Diff 160652. kadircet marked 8 inline comments as done. kadircet added a comment. - Resolve discussions. - Get rid of CancellationHandler class. - Change error class name. - Improve documentation. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50502 Files: clangd/CMakeLists.txt clangd/Cancellation.cpp clangd/Cancellation.h clangd/ClangdLSPServer.cpp clangd/ClangdLSPServer.h clangd/ClangdServer.cpp clangd/ClangdServer.h clangd/JSONRPCDispatcher.cpp clangd/JSONRPCDispatcher.h clangd/Protocol.cpp clangd/Protocol.h clangd/ProtocolHandlers.cpp clangd/ProtocolHandlers.h unittests/clangd/CMakeLists.txt unittests/clangd/CancellationTests.cpp Index: unittests/clangd/CancellationTests.cpp === --- /dev/null +++ unittests/clangd/CancellationTests.cpp @@ -0,0 +1,67 @@ +#include "Cancellation.h" +#include "Context.h" +#include "llvm/Support/Error.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include +#include +#include + +namespace clang { +namespace clangd { +namespace { + +TEST(CancellationTest, CancellationTest) { + { +TaskHandle TH = TaskHandle::create(); +WithContext ContextWithCancellation(setCurrentCancellationToken(TH)); +EXPECT_FALSE(isCancelled()); +TH.cancel(); +EXPECT_TRUE(isCancelled()); + } + EXPECT_FALSE(isCancelled()); +} + +TEST(CancellationTest, TaskHandleTestHandleDiesContextLives) { + llvm::Optional ContextWithCancellation; + { +auto CancellableTaskHandle = TaskHandle::create(); +ContextWithCancellation.emplace( +setCurrentCancellationToken(CancellableTaskHandle)); +EXPECT_FALSE(isCancelled()); +CancellableTaskHandle.cancel(); +EXPECT_TRUE(isCancelled()); + } + EXPECT_TRUE(isCancelled()); + ContextWithCancellation.reset(); + EXPECT_FALSE(isCancelled()); +} + +TEST(CancellationTest, TaskHandleContextDiesHandleLives) { + { +auto CancellableTaskHandle = TaskHandle::create(); +{ + WithContext ContextWithCancellation( + setCurrentCancellationToken(CancellableTaskHandle)); + EXPECT_FALSE(isCancelled()); + CancellableTaskHandle.cancel(); + EXPECT_TRUE(isCancelled()); +} + } + EXPECT_FALSE(isCancelled()); +} + +TEST(CancellationTest, CancellationToken) { + auto CancellableTaskHandle = TaskHandle::create(); + WithContext ContextWithCancellation( + setCurrentCancellationToken(CancellableTaskHandle)); + auto CT = isCancelled(); + EXPECT_FALSE(CT); + CancellableTaskHandle.cancel(); + EXPECT_TRUE(CT); +} + +} // namespace +} // namespace clangd +} // namespace clang Index: unittests/clangd/CMakeLists.txt === --- unittests/clangd/CMakeLists.txt +++ unittests/clangd/CMakeLists.txt @@ -10,6 +10,7 @@ add_extra_unittest(ClangdTests Annotations.cpp + CancellationTests.cpp ClangdTests.cpp ClangdUnitTests.cpp CodeCompleteTests.cpp Index: clangd/ProtocolHandlers.h === --- clangd/ProtocolHandlers.h +++ clangd/ProtocolHandlers.h @@ -55,6 +55,7 @@ virtual void onDocumentHighlight(TextDocumentPositionParams &Params) = 0; virtual void onHover(TextDocumentPositionParams &Params) = 0; virtual void onChangeConfiguration(DidChangeConfigurationParams &Params) = 0; + virtual void onCancelRequest(CancelParams &Params) = 0; }; void registerCallbackHandlers(JSONRPCDispatcher &Dispatcher, Index: clangd/ProtocolHandlers.cpp === --- clangd/ProtocolHandlers.cpp +++ clangd/ProtocolHandlers.cpp @@ -75,4 +75,5 @@ Register("workspace/didChangeConfiguration", &ProtocolCallbacks::onChangeConfiguration); Register("workspace/symbol", &ProtocolCallbacks::onWorkspaceSymbol); + Register("$/cancelRequest", &ProtocolCallbacks::onCancelRequest); } Index: clangd/Protocol.h === --- clangd/Protocol.h +++ clangd/Protocol.h @@ -861,6 +861,13 @@ llvm::json::Value toJSON(const DocumentHighlight &DH); llvm::raw_ostream &operator<<(llvm::raw_ostream &, const DocumentHighlight &); +struct CancelParams { + std::string ID; +}; +llvm::json::Value toJSON(const CancelParams &); +llvm::raw_ostream &operator<<(llvm::raw_ostream &, const CancelParams &); +bool fromJSON(const llvm::json::Value &, CancelParams &); + } // namespace clangd } // namespace clang Index: clangd/Protocol.cpp === --- clangd/Protocol.cpp +++ clangd/Protocol.cpp @@ -615,5 +615,30 @@ O.map("compilationDatabaseChanges", CCPC.compilationDatabaseChanges); } +json::Value toJSON(const CancelParams &CP) { + return json::Object{{"id", CP.ID}}; +} + +llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const CancelParams &CP) { + O << toJSON(CP); +
[PATCH] D50502: [clangd] Initial cancellation mechanism for LSP requests.
kadircet added inline comments. Comment at: clangd/Cancellation.h:71 + +class TaskHandle { +public: ilya-biryukov wrote: > I wonder if we should make `TaskHandle` move-only? > > The reasoning is that is can be easily used from multiple threads (since it's > used by code dealing with async tasks anyway) and copying it concurrently is > a data race. > On the other hand, calling `cancel()` is perfectly thread-safe and shouldn't > cause any problems. As similar to above mentioned case copying doesn't introduce any data races. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50502 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50727: [clangd] Fetch documentation from the Index during signature help
kadircet accepted this revision. kadircet added a comment. This revision is now accepted and ready to land. LGTM Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50727 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50835: [clangd] Add parantheses while auto-completing functions.
kadircet created this revision. kadircet added reviewers: ioeric, ilya-biryukov, hokein. Herald added subscribers: cfe-commits, arphaman, jkorous, MaskRay. Currently we only add parantheses to the functions if snippets are enabled, which also inserts snippets for parameters into parantheses. Adding a new option to put only parantheses. Also it moves the cursor within parantheses or at the end of them by looking at whether completion item has any parameters or not. Still requires snippets support on the client side. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50835 Files: clangd/CodeComplete.cpp clangd/CodeComplete.h unittests/clangd/CodeCompleteTests.cpp Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -1590,6 +1590,44 @@ ElementsAre(Sig("foo(T, U) -> void", {"T", "U"}))); } +TEST(CompletionTest, RenderWithCursorRelocation) { + CodeCompleteOptions Opts; + Opts.EnableCursorRelocation = true; + + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = ""; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); + } + + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = "()"; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x()"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); + } + + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = "(${0:bool})"; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x(${0})"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); + } +} + } // namespace } // namespace clangd } // namespace clang Index: clangd/CodeComplete.h === --- clangd/CodeComplete.h +++ clangd/CodeComplete.h @@ -81,6 +81,12 @@ /// Include completions that require small corrections, e.g. change '.' to /// '->' on member access etc. bool IncludeFixIts = false; + + /// Enables cursor to be moved around according to completions needs even when + /// snippets are disabled. For example selecting a function with parameters as + /// completion item moves the cursor within the parameters, whereas without + /// parameters moves to after closing parantheses. + bool EnableCursorRelocation = false; }; // Semi-structured representation of a code-complete suggestion for our C++ API. Index: clangd/CodeComplete.cpp === --- clangd/CodeComplete.cpp +++ clangd/CodeComplete.cpp @@ -1373,11 +1373,21 @@ } if (Opts.EnableSnippets) LSP.textEdit->newText += SnippetSuffix; + // Check if we have cursor relocation enabled and completing a function. + else if (SnippetSuffix.size() && Opts.EnableCursorRelocation) { +// Check whether function has any parameters or not. +if (SnippetSuffix.size() > 2) + LSP.textEdit->newText += "(${0})"; +else + LSP.textEdit->newText += "()"; + } + // FIXME(kadircet): Do not even fill insertText after making sure textEdit is // compatible with most of the editors. LSP.insertText = LSP.textEdit->newText; - LSP.insertTextFormat = Opts.EnableSnippets ? InsertTextFormat::Snippet - : InsertTextFormat::PlainText; + LSP.insertTextFormat = Opts.EnableSnippets || Opts.EnableCursorRelocation + ? InsertTextFormat::Snippet + : InsertTextFormat::PlainText; if (HeaderInsertion) LSP.additionalTextEdits.push_back(*HeaderInsertion); return LSP; Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -1590,6 +1590,44 @@ ElementsAre(Sig("foo(T, U) -> void", {"T", "U"}))); } +TEST(CompletionTest, RenderWithCursorRelocation) { + CodeCompleteOptions Opts; + Opts.EnableCursorRelocation = true; + + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = ""; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); + } + + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = "()"; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x()"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); + } + + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = "(${0:bool})"; + +auto R = C.ren
[PATCH] D50502: [clangd] Initial cancellation mechanism for LSP requests.
kadircet updated this revision to Diff 160986. kadircet added a comment. - Made TaskHandle move-only. Since it is costly and most likely unnecessary to copy it other than to move it into Context. - Provided an explicit clone method for copying. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50502 Files: clangd/CMakeLists.txt clangd/Cancellation.cpp clangd/Cancellation.h clangd/ClangdLSPServer.cpp clangd/ClangdLSPServer.h clangd/ClangdServer.cpp clangd/ClangdServer.h clangd/JSONRPCDispatcher.cpp clangd/JSONRPCDispatcher.h clangd/Protocol.cpp clangd/Protocol.h clangd/ProtocolHandlers.cpp clangd/ProtocolHandlers.h unittests/clangd/CMakeLists.txt unittests/clangd/CancellationTests.cpp Index: unittests/clangd/CancellationTests.cpp === --- /dev/null +++ unittests/clangd/CancellationTests.cpp @@ -0,0 +1,68 @@ +#include "Cancellation.h" +#include "Context.h" +#include "llvm/Support/Error.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include +#include +#include + +namespace clang { +namespace clangd { +namespace { + +TEST(CancellationTest, CancellationTest) { + { +TaskHandle TH = TaskHandle::create(); +WithContext ContextWithCancellation( +setCurrentCancellationToken(TH.clone())); +EXPECT_FALSE(isCancelled()); +TH.cancel(); +EXPECT_TRUE(isCancelled()); + } + EXPECT_FALSE(isCancelled()); +} + +TEST(CancellationTest, TaskHandleTestHandleDiesContextLives) { + llvm::Optional ContextWithCancellation; + { +auto CancellableTaskHandle = TaskHandle::create(); +ContextWithCancellation.emplace( +setCurrentCancellationToken(CancellableTaskHandle.clone())); +EXPECT_FALSE(isCancelled()); +CancellableTaskHandle.cancel(); +EXPECT_TRUE(isCancelled()); + } + EXPECT_TRUE(isCancelled()); + ContextWithCancellation.reset(); + EXPECT_FALSE(isCancelled()); +} + +TEST(CancellationTest, TaskHandleContextDiesHandleLives) { + { +auto CancellableTaskHandle = TaskHandle::create(); +{ + WithContext ContextWithCancellation( + setCurrentCancellationToken(CancellableTaskHandle.clone())); + EXPECT_FALSE(isCancelled()); + CancellableTaskHandle.cancel(); + EXPECT_TRUE(isCancelled()); +} + } + EXPECT_FALSE(isCancelled()); +} + +TEST(CancellationTest, CancellationToken) { + auto CancellableTaskHandle = TaskHandle::create(); + WithContext ContextWithCancellation( + setCurrentCancellationToken(CancellableTaskHandle.clone())); + auto CT = isCancelled(); + EXPECT_FALSE(CT); + CancellableTaskHandle.cancel(); + EXPECT_TRUE(CT); +} + +} // namespace +} // namespace clangd +} // namespace clang Index: unittests/clangd/CMakeLists.txt === --- unittests/clangd/CMakeLists.txt +++ unittests/clangd/CMakeLists.txt @@ -10,6 +10,7 @@ add_extra_unittest(ClangdTests Annotations.cpp + CancellationTests.cpp ClangdTests.cpp ClangdUnitTests.cpp CodeCompleteTests.cpp Index: clangd/ProtocolHandlers.h === --- clangd/ProtocolHandlers.h +++ clangd/ProtocolHandlers.h @@ -55,6 +55,7 @@ virtual void onDocumentHighlight(TextDocumentPositionParams &Params) = 0; virtual void onHover(TextDocumentPositionParams &Params) = 0; virtual void onChangeConfiguration(DidChangeConfigurationParams &Params) = 0; + virtual void onCancelRequest(CancelParams &Params) = 0; }; void registerCallbackHandlers(JSONRPCDispatcher &Dispatcher, Index: clangd/ProtocolHandlers.cpp === --- clangd/ProtocolHandlers.cpp +++ clangd/ProtocolHandlers.cpp @@ -75,4 +75,5 @@ Register("workspace/didChangeConfiguration", &ProtocolCallbacks::onChangeConfiguration); Register("workspace/symbol", &ProtocolCallbacks::onWorkspaceSymbol); + Register("$/cancelRequest", &ProtocolCallbacks::onCancelRequest); } Index: clangd/Protocol.h === --- clangd/Protocol.h +++ clangd/Protocol.h @@ -867,6 +867,13 @@ llvm::json::Value toJSON(const DocumentHighlight &DH); llvm::raw_ostream &operator<<(llvm::raw_ostream &, const DocumentHighlight &); +struct CancelParams { + std::string ID; +}; +llvm::json::Value toJSON(const CancelParams &); +llvm::raw_ostream &operator<<(llvm::raw_ostream &, const CancelParams &); +bool fromJSON(const llvm::json::Value &, CancelParams &); + } // namespace clangd } // namespace clang Index: clangd/Protocol.cpp === --- clangd/Protocol.cpp +++ clangd/Protocol.cpp @@ -615,5 +615,30 @@ O.map("compilationDatabaseChanges", CCPC.compilationDatabaseChanges); } +json::Value toJSON(const CancelParams &CP) { + return json::Object{{"id", CP.ID}}; +} + +llvm::raw_ostream &operator<<(llvm::raw_ostr
[PATCH] D50502: [clangd] Initial cancellation mechanism for LSP requests.
kadircet updated this revision to Diff 161018. kadircet marked 21 inline comments as done. kadircet added a comment. - Resolve discussions. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50502 Files: clangd/CMakeLists.txt clangd/Cancellation.cpp clangd/Cancellation.h clangd/ClangdLSPServer.cpp clangd/ClangdLSPServer.h clangd/ClangdServer.cpp clangd/ClangdServer.h clangd/JSONRPCDispatcher.cpp clangd/JSONRPCDispatcher.h clangd/Protocol.cpp clangd/Protocol.h clangd/ProtocolHandlers.cpp clangd/ProtocolHandlers.h unittests/clangd/CMakeLists.txt unittests/clangd/CancellationTests.cpp Index: unittests/clangd/CancellationTests.cpp === --- /dev/null +++ unittests/clangd/CancellationTests.cpp @@ -0,0 +1,79 @@ +#include "Cancellation.h" +#include "Context.h" +#include "Threading.h" +#include "llvm/Support/Error.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include +#include +#include + +namespace clang { +namespace clangd { +namespace { + +TEST(CancellationTest, CancellationTest) { + TaskHandle TH = TaskHandle::create(); + WithContext ContextWithCancellation( + setCurrentCancellationToken(TH.createCancellationToken())); + EXPECT_FALSE(isCancelled()); + TH.cancel(); + EXPECT_TRUE(isCancelled()); +} + +TEST(CancellationTest, TaskHandleTestHandleDiesContextLives) { + llvm::Optional ContextWithCancellation; + { +auto CancellableTaskHandle = TaskHandle::create(); +ContextWithCancellation.emplace(setCurrentCancellationToken( +CancellableTaskHandle.createCancellationToken())); +EXPECT_FALSE(isCancelled()); +CancellableTaskHandle.cancel(); +EXPECT_TRUE(isCancelled()); + } + EXPECT_TRUE(isCancelled()); +} + +TEST(CancellationTest, TaskHandleContextDiesHandleLives) { + auto CancellableTaskHandle = TaskHandle::create(); + { +WithContext ContextWithCancellation(setCurrentCancellationToken( +CancellableTaskHandle.createCancellationToken())); +EXPECT_FALSE(isCancelled()); +CancellableTaskHandle.cancel(); +EXPECT_TRUE(isCancelled()); + } + // Still should be able to cancel without any problems. + CancellableTaskHandle.cancel(); +} + +TEST(CancellationTest, CancellationToken) { + auto CancellableTaskHandle = TaskHandle::create(); + WithContext ContextWithCancellation(setCurrentCancellationToken( + CancellableTaskHandle.createCancellationToken())); + const auto &CT = getCurrentCancellationToken(); + EXPECT_FALSE(CT); + CancellableTaskHandle.cancel(); + EXPECT_TRUE(CT); +} + +TEST(CancellationTest, AsynCancellationTest) { + std::atomic HasCancelled(false); + Notification Cancelled; + auto TaskToBeCancelled = [&](CancellationToken CT) { +WithContext ContextGuard(setCurrentCancellationToken(std::move(CT))); +Cancelled.wait(); +HasCancelled = isCancelled(); + }; + TaskHandle TH = TaskHandle::create(); + std::thread AsyncTask(TaskToBeCancelled, TH.createCancellationToken()); + TH.cancel(); + Cancelled.notify(); + AsyncTask.join(); + + EXPECT_TRUE(HasCancelled); +} + +} // namespace +} // namespace clangd +} // namespace clang Index: unittests/clangd/CMakeLists.txt === --- unittests/clangd/CMakeLists.txt +++ unittests/clangd/CMakeLists.txt @@ -10,6 +10,7 @@ add_extra_unittest(ClangdTests Annotations.cpp + CancellationTests.cpp ClangdTests.cpp ClangdUnitTests.cpp CodeCompleteTests.cpp Index: clangd/ProtocolHandlers.h === --- clangd/ProtocolHandlers.h +++ clangd/ProtocolHandlers.h @@ -55,6 +55,7 @@ virtual void onDocumentHighlight(TextDocumentPositionParams &Params) = 0; virtual void onHover(TextDocumentPositionParams &Params) = 0; virtual void onChangeConfiguration(DidChangeConfigurationParams &Params) = 0; + virtual void onCancelRequest(CancelParams &Params) = 0; }; void registerCallbackHandlers(JSONRPCDispatcher &Dispatcher, Index: clangd/ProtocolHandlers.cpp === --- clangd/ProtocolHandlers.cpp +++ clangd/ProtocolHandlers.cpp @@ -75,4 +75,5 @@ Register("workspace/didChangeConfiguration", &ProtocolCallbacks::onChangeConfiguration); Register("workspace/symbol", &ProtocolCallbacks::onWorkspaceSymbol); + Register("$/cancelRequest", &ProtocolCallbacks::onCancelRequest); } Index: clangd/Protocol.h === --- clangd/Protocol.h +++ clangd/Protocol.h @@ -867,6 +867,13 @@ llvm::json::Value toJSON(const DocumentHighlight &DH); llvm::raw_ostream &operator<<(llvm::raw_ostream &, const DocumentHighlight &); +struct CancelParams { + std::string ID; +}; +llvm::json::Value toJSON(const CancelParams &); +llvm::raw_ostream &operator<<(llvm::raw_ostream &, const CancelParams &); +bool fromJSON(const llvm::json::Value &, Cancel
[PATCH] D50502: [clangd] Initial cancellation mechanism for LSP requests.
kadircet added inline comments. Comment at: clangd/Cancellation.h:92 + operator bool() const { return isCancelled(); } + friend CancellationToken isCancelled(); + ilya-biryukov wrote: > It's a bit confusing that this name clashes with a member function. > We seem to optimize for making this work anywhere: > ``` > if (isCancelled()) // <-- get token from ctx, then use implicit conversion > to check if it was cancelled > return llvm::makeError(); > ``` > > Which is probably a nice pattern. But we could have two functions that do the > same thing with less magic (i.e. implicit conversions) involved at the call > sites: > ``` > CancellationToken getCurrentCancellation(); > void setCurrentCancellation(CancellationToken CT); > > inline bool isCancelled() { return getCurrentCancellation().isCancelled(); } > ``` > Would allow to get rid of implicit conversion and friend function with the > same signature as member. Would also make cases where we actually want to > stash the token somewhere cleaner, e.g. instead of `CancellationToken CT = > isCancelled()`, we'll have `CancellationToken CT = getCurrentCancellation()`. > WDYT? Totally agreed, actually, didn't even notice they had the same signature :D, thanks! But I still think implicit conversion of CancellationToken to bool seems like a good thing to have. Comment at: clangd/ClangdLSPServer.h:179 + // associated with only their thread. + void CleanupTaskHandle(); + void StoreTaskHandle(TaskHandle TH); ilya-biryukov wrote: > These two methods look like a nice suit for better wrapped in a RAII-object. > It would add the value to the associated map on construction and remove on > destruction. > One problem is that all operations calls would become weird, because we'll > have to move this RAII object around and moving into lambdas is not fun > without C++14 (which allows `[x=std::move(y)]() {}`.. > > Maybe add a comment that calls to this function should always be paired and a > FIXME that we should have an API that enforces this? > Yeah that would be really nice to have them in a RAII object, but the thing is cleanup can occur only after the task dies. Which we don't directly know since threads are being detached. So the only way to trigger destruction is at the callback, which is where I call cleanup currently. Maybe we can store the object within context to trigger destructor at the end of the thread, but still don't think it would look any better or ease the job of the caller. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50502 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50835: [clangd] Add parantheses while auto-completing functions.
kadircet updated this revision to Diff 161023. kadircet marked an inline comment as done. kadircet added a comment. - Change option name. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50835 Files: clangd/CodeComplete.cpp clangd/CodeComplete.h unittests/clangd/CodeCompleteTests.cpp Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -1590,6 +1590,55 @@ ElementsAre(Sig("foo(T, U) -> void", {"T", "U"}))); } +TEST(CompletionTest, RenderWithSnippetsForFunctionArgsDisabled) { + CodeCompleteOptions Opts; + Opts.DisableSnippetTemplateForFunctionArgs = true; + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = "()"; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::PlainText); + } + + Opts.EnableSnippets = true; + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = ""; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); + } + + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = "()"; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x()"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); + } + + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = "(${0:bool})"; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x(${0})"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); + } +} + } // namespace } // namespace clangd } // namespace clang Index: clangd/CodeComplete.h === --- clangd/CodeComplete.h +++ clangd/CodeComplete.h @@ -82,6 +82,10 @@ /// Include completions that require small corrections, e.g. change '.' to /// '->' on member access etc. bool IncludeFixIts = false; + + /// Disables snippet generation for function arguments. Does nothing if + /// snippets are not enabled. + bool DisableSnippetTemplateForFunctionArgs = false; }; // Semi-structured representation of a code-complete suggestion for our C++ API. Index: clangd/CodeComplete.cpp === --- clangd/CodeComplete.cpp +++ clangd/CodeComplete.cpp @@ -1371,8 +1371,14 @@ LSP.additionalTextEdits.push_back(FixIt); } } - if (Opts.EnableSnippets) -LSP.textEdit->newText += SnippetSuffix; + if (Opts.EnableSnippets && !SnippetSuffix.empty()) { +if (Opts.DisableSnippetTemplateForFunctionArgs) + // Check whether function has any parameters or not. + LSP.textEdit->newText += SnippetSuffix.size() > 2 ? "(${0})" : "()"; +else + LSP.textEdit->newText += SnippetSuffix; + } + // FIXME(kadircet): Do not even fill insertText after making sure textEdit is // compatible with most of the editors. LSP.insertText = LSP.textEdit->newText; Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -1590,6 +1590,55 @@ ElementsAre(Sig("foo(T, U) -> void", {"T", "U"}))); } +TEST(CompletionTest, RenderWithSnippetsForFunctionArgsDisabled) { + CodeCompleteOptions Opts; + Opts.DisableSnippetTemplateForFunctionArgs = true; + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = "()"; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::PlainText); + } + + Opts.EnableSnippets = true; + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = ""; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); + } + + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = "()"; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x()"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); + } + + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = "(${0:bool})"; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x(${0})"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); + } +} + } // namespace } // namespace clangd } // namespace clang Index: clangd/CodeComplete.h === --- clangd/CodeComplete.h +++ cla
[PATCH] D50835: [clangd] Add parantheses while auto-completing functions.
kadircet added inline comments. Comment at: clangd/CodeComplete.h:85 + + /// Enables cursor to be moved around according to completions needs even when + /// snippets are disabled. For example selecting a function with parameters as ioeric wrote: > IIRC, the goal of this patch is to allow disabling snippet templates for > function parameters while still allow appending `()` or `($0)` to function > candidates. If that's still the case, I think what we want is probably an > option like `DisableSnippetTemplateForFunctionArgs`? Yeah, that makes totally more sense. Thanks! Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50835 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50898: Suggest code-completions for overriding base class virtual methods.
kadircet created this revision. kadircet added reviewers: ilya-biryukov, hokein, ioeric. Herald added subscribers: cfe-commits, arphaman, jkorous. Whenever a code-completion is triggered within a class/struct/union looks at base classes and figures out non-overriden virtual functions. Than suggests completions for those. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50898 Files: clangd/CodeComplete.cpp clangd/CodeComplete.h unittests/clangd/CodeCompleteTests.cpp Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -61,6 +61,7 @@ MATCHER(InsertInclude, "") { return bool(arg.HeaderInsertion); } MATCHER_P(SnippetSuffix, Text, "") { return arg.SnippetSuffix == Text; } MATCHER_P(Origin, OriginSet, "") { return arg.Origin == OriginSet; } +MATCHER(IsOverride, "") { return bool(arg.IsOverride); } // Shorthand for Contains(Named(Name)). Matcher &> Has(std::string Name) { @@ -1648,6 +1649,58 @@ SigDoc("Doc from sema"; } +TEST(CompletionTest, SuggestOverrides) { + constexpr const char *const Text(R"cpp( + class A { + public: +virtual void vfunc(bool param); +virtual void vfunc(bool param, int p); +void func(bool param); + }; + class B : public A { + virtual void ttt(bool param); + void vfunc(bool param, int p) override; + }; + class C : public B { + public: +void vfunc(bool param) override; +^ + }; + )cpp"); + const auto Results = completions(Text); + EXPECT_THAT(Results.Completions, + AllOf(Contains(AllOf(Named("vfunc"), IsOverride(), + Labeled("vfunc(bool param, int p)"))), +Contains(AllOf(Named("ttt"), IsOverride(), + Labeled("ttt(bool param)"))), +Not(Contains(AllOf(Named("vfunc"), IsOverride(), + Labeled("vfunc(bool param)")); +} + +TEST(CompletionTest, RenderOverride) { + CodeCompletion C; + C.Name = "x"; + C.Signature = "(bool) const"; + C.SnippetSuffix = "(${0:bool})"; + C.ReturnType = "int"; + C.Documentation = "This is x()."; + C.Kind = CompletionItemKind::Method; + C.Score.Total = 1.0; + C.Origin = SymbolOrigin::AST; + C.IsOverride = true; + + CodeCompleteOptions Opts; + Opts.IncludeIndicator.NoInsert = ""; + auto R = C.render(Opts); + EXPECT_EQ(R.label, "int x(bool) const override"); + EXPECT_EQ(R.insertText, "int x(bool) const override"); + EXPECT_EQ(R.insertTextFormat, InsertTextFormat::PlainText); + EXPECT_EQ(R.filterText, "x"); + EXPECT_EQ(R.detail, "int"); + EXPECT_EQ(R.documentation, "This is x()."); + EXPECT_THAT(R.additionalTextEdits, IsEmpty()); +} + } // namespace } // namespace clangd } // namespace clang Index: clangd/CodeComplete.h === --- clangd/CodeComplete.h +++ clangd/CodeComplete.h @@ -127,6 +127,9 @@ /// Holds the range of the token we are going to replace with this completion. Range CompletionTokenRange; + /// Whether this completion is for overriding a virtual method. + bool IsOverride = false; + // Scores are used to rank completion items. struct Scores { // The score that items are ranked by. Index: clangd/CodeComplete.cpp === --- clangd/CodeComplete.cpp +++ clangd/CodeComplete.cpp @@ -188,6 +188,58 @@ return HeaderFile{std::move(*Resolved), /*Verbatim=*/false}; } +// First traverses all method definitions inside current class/struct/union +// definition. Than traverses base classes to find virtual methods that haven't +// been overriden within current context. +// FIXME(kadircet): Currently we cannot see declarations below completion point. +// It is because Sema gets run only upto completion point. Need to find a +// solution to run it for the whole class/struct/union definition. +static std::vector +getVirtualNonOverridenMethods(const DeclContext *DC, Sema *S) { + const auto *CR = llvm::dyn_cast(DC); + // If not inside a class/struct/union return empty. + if (!CR) +return {}; + // First store overrides within current class. + // These are stored by name to make querying fast in the later step. + llvm::StringMap> Overrides; + for (auto *Method : dyn_cast(DC)->methods()) { +if (!Method->isVirtual()) + continue; +const std::string Name = Method->getNameAsString(); +const auto it = Overrides.find(Name); +if (it == Overrides.end()) + Overrides.insert({Name, {Method}}); +else + it->second.push_back(Method); + } + + std::vector Results; + for (const auto &Base : CR->bases()) { +const auto *BR = Base.getType().getTypePtr()->getAsCXXRecordDecl(); +for (auto *Method : BR->methods()) { + if (!Method->isVirtual()) +continue; + const s
[PATCH] D50835: [clangd] Add parantheses while auto-completing functions.
kadircet updated this revision to Diff 161243. kadircet added a comment. - Change option name. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50835 Files: clangd/CodeComplete.cpp clangd/CodeComplete.h unittests/clangd/CodeCompleteTests.cpp Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -1590,6 +1590,56 @@ ElementsAre(Sig("foo(T, U) -> void", {"T", "U"}))); } +TEST(CompletionTest, RenderWithSnippetsForFunctionArgsDisabled) { + CodeCompleteOptions Opts; + Opts.EnableFunctionArgSnippets = true; + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = "()"; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::PlainText); + } + + Opts.EnableSnippets = true; + Opts.EnableFunctionArgSnippets = false; + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = ""; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); + } + + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = "()"; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x()"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); + } + + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = "(${0:bool})"; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x(${0})"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); + } +} + } // namespace } // namespace clangd } // namespace clang Index: clangd/CodeComplete.h === --- clangd/CodeComplete.h +++ clangd/CodeComplete.h @@ -82,6 +82,10 @@ /// Include completions that require small corrections, e.g. change '.' to /// '->' on member access etc. bool IncludeFixIts = false; + + /// Whether to generate snippets for function arguments on code-completion. + /// Needs snippets to be enabled as well. + bool EnableFunctionArgSnippets = true; }; // Semi-structured representation of a code-complete suggestion for our C++ API. Index: clangd/CodeComplete.cpp === --- clangd/CodeComplete.cpp +++ clangd/CodeComplete.cpp @@ -1371,8 +1371,14 @@ LSP.additionalTextEdits.push_back(FixIt); } } - if (Opts.EnableSnippets) -LSP.textEdit->newText += SnippetSuffix; + if (Opts.EnableSnippets && !SnippetSuffix.empty()) { +if (Opts.EnableFunctionArgSnippets) + LSP.textEdit->newText += SnippetSuffix; +else + // Check whether function has any parameters or not. + LSP.textEdit->newText += SnippetSuffix.size() > 2 ? "(${0})" : "()"; + } + // FIXME(kadircet): Do not even fill insertText after making sure textEdit is // compatible with most of the editors. LSP.insertText = LSP.textEdit->newText; Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -1590,6 +1590,56 @@ ElementsAre(Sig("foo(T, U) -> void", {"T", "U"}))); } +TEST(CompletionTest, RenderWithSnippetsForFunctionArgsDisabled) { + CodeCompleteOptions Opts; + Opts.EnableFunctionArgSnippets = true; + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = "()"; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::PlainText); + } + + Opts.EnableSnippets = true; + Opts.EnableFunctionArgSnippets = false; + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = ""; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); + } + + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = "()"; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x()"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); + } + + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = "(${0:bool})"; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x(${0})"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); + } +} + } // namespace } // namespace clangd } // namespace clang Index: clangd/CodeComplete.h === --- clangd/CodeComplete
[PATCH] D50835: [clangd] Add parantheses while auto-completing functions.
kadircet marked 3 inline comments as done. kadircet added inline comments. Comment at: clangd/CodeComplete.cpp:1377 + // Check whether function has any parameters or not. + LSP.textEdit->newText += SnippetSuffix.size() > 2 ? "(${0})" : "()"; +else ioeric wrote: > There seems to be no guarantee on whether the snippet is function arg > template when `SnippetSuffix.size() > 2`. A heuristic we could use is > probably checking that the template starts with `(` and ends with `)`? > Alternatively, we could try to avoid generating the proper snippet according > to the flag when we still have the function declaration around. Not sure if > this is feasible for index results though. Actually I was first trying to directly look at function argument count as you mentioned, but unfortunately Symbols coming from index don't have any declarations. Therefore it turns back to looking at Signature in this case, which is same with this one. Apart from that, IIUC, SnippetSuffix contains anything only when completion item is a function otherwise it is empty. So IMO this check should be OK. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50835 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50835: [clangd] Add parantheses while auto-completing functions.
kadircet updated this revision to Diff 161256. kadircet added a comment. - Only append to snippets of type function or method. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50835 Files: clangd/CodeComplete.cpp clangd/CodeComplete.h unittests/clangd/CodeCompleteTests.cpp Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -1590,6 +1590,58 @@ ElementsAre(Sig("foo(T, U) -> void", {"T", "U"}))); } +TEST(CompletionTest, RenderWithSnippetsForFunctionArgsDisabled) { + CodeCompleteOptions Opts; + Opts.EnableFunctionArgSnippets = true; + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = "()"; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::PlainText); + } + + Opts.EnableSnippets = true; + Opts.EnableFunctionArgSnippets = false; + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = ""; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); + } + + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = "()"; +C.Kind = CompletionItemKind::Method; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x()"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); + } + + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = "(${0:bool})"; +C.Kind = CompletionItemKind::Function; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x(${0})"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); + } +} + } // namespace } // namespace clangd } // namespace clang Index: clangd/CodeComplete.h === --- clangd/CodeComplete.h +++ clangd/CodeComplete.h @@ -82,6 +82,10 @@ /// Include completions that require small corrections, e.g. change '.' to /// '->' on member access etc. bool IncludeFixIts = false; + + /// Whether to generate snippets for function arguments on code-completion. + /// Needs snippets to be enabled as well. + bool EnableFunctionArgSnippets = true; }; // Semi-structured representation of a code-complete suggestion for our C++ API. Index: clangd/CodeComplete.cpp === --- clangd/CodeComplete.cpp +++ clangd/CodeComplete.cpp @@ -1371,8 +1371,17 @@ LSP.additionalTextEdits.push_back(FixIt); } } - if (Opts.EnableSnippets) -LSP.textEdit->newText += SnippetSuffix; + if (Opts.EnableSnippets && !SnippetSuffix.empty()) { +if (Opts.EnableFunctionArgSnippets) + LSP.textEdit->newText += SnippetSuffix; +else if ((Kind == CompletionItemKind::Function || + Kind == CompletionItemKind::Method) && + SnippetSuffix.front() == '(' && SnippetSuffix.back() == ')') { + // Check whether function has any parameters or not. + LSP.textEdit->newText += SnippetSuffix.size() > 2 ? "(${0})" : "()"; +} + } + // FIXME(kadircet): Do not even fill insertText after making sure textEdit is // compatible with most of the editors. LSP.insertText = LSP.textEdit->newText; ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50502: [clangd] Initial cancellation mechanism for LSP requests.
kadircet updated this revision to Diff 161261. kadircet marked 10 inline comments as done. kadircet added a comment. - Resolve discussions & Delete enclosing quotes when normalizing. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50502 Files: clangd/CMakeLists.txt clangd/Cancellation.cpp clangd/Cancellation.h clangd/ClangdLSPServer.cpp clangd/ClangdLSPServer.h clangd/ClangdServer.cpp clangd/ClangdServer.h clangd/JSONRPCDispatcher.cpp clangd/JSONRPCDispatcher.h clangd/Protocol.cpp clangd/Protocol.h clangd/ProtocolHandlers.cpp clangd/ProtocolHandlers.h unittests/clangd/CMakeLists.txt unittests/clangd/CancellationTests.cpp Index: unittests/clangd/CancellationTests.cpp === --- /dev/null +++ unittests/clangd/CancellationTests.cpp @@ -0,0 +1,79 @@ +#include "Cancellation.h" +#include "Context.h" +#include "Threading.h" +#include "llvm/Support/Error.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include +#include +#include + +namespace clang { +namespace clangd { +namespace { + +TEST(CancellationTest, CancellationTest) { + TaskHandle TH = TaskHandle::create(); + WithContext ContextWithCancellation( + setCurrentCancellationToken(TH.createCancellationToken())); + EXPECT_FALSE(isCancelled()); + TH.cancel(); + EXPECT_TRUE(isCancelled()); +} + +TEST(CancellationTest, TaskHandleTestHandleDiesContextLives) { + llvm::Optional ContextWithCancellation; + { +auto CancellableTaskHandle = TaskHandle::create(); +ContextWithCancellation.emplace(setCurrentCancellationToken( +CancellableTaskHandle.createCancellationToken())); +EXPECT_FALSE(isCancelled()); +CancellableTaskHandle.cancel(); +EXPECT_TRUE(isCancelled()); + } + EXPECT_TRUE(isCancelled()); +} + +TEST(CancellationTest, TaskHandleContextDiesHandleLives) { + auto CancellableTaskHandle = TaskHandle::create(); + { +WithContext ContextWithCancellation(setCurrentCancellationToken( +CancellableTaskHandle.createCancellationToken())); +EXPECT_FALSE(isCancelled()); +CancellableTaskHandle.cancel(); +EXPECT_TRUE(isCancelled()); + } + // Still should be able to cancel without any problems. + CancellableTaskHandle.cancel(); +} + +TEST(CancellationTest, CancellationToken) { + auto CancellableTaskHandle = TaskHandle::create(); + WithContext ContextWithCancellation(setCurrentCancellationToken( + CancellableTaskHandle.createCancellationToken())); + const auto &CT = getCurrentCancellationToken(); + EXPECT_FALSE(CT); + CancellableTaskHandle.cancel(); + EXPECT_TRUE(CT); +} + +TEST(CancellationTest, AsynCancellationTest) { + std::atomic HasCancelled(false); + Notification Cancelled; + auto TaskToBeCancelled = [&](CancellationToken CT) { +WithContext ContextGuard(setCurrentCancellationToken(std::move(CT))); +Cancelled.wait(); +HasCancelled = isCancelled(); + }; + TaskHandle TH = TaskHandle::create(); + std::thread AsyncTask(TaskToBeCancelled, TH.createCancellationToken()); + TH.cancel(); + Cancelled.notify(); + AsyncTask.join(); + + EXPECT_TRUE(HasCancelled); +} + +} // namespace +} // namespace clangd +} // namespace clang Index: unittests/clangd/CMakeLists.txt === --- unittests/clangd/CMakeLists.txt +++ unittests/clangd/CMakeLists.txt @@ -10,6 +10,7 @@ add_extra_unittest(ClangdTests Annotations.cpp + CancellationTests.cpp ClangdTests.cpp ClangdUnitTests.cpp CodeCompleteTests.cpp Index: clangd/ProtocolHandlers.h === --- clangd/ProtocolHandlers.h +++ clangd/ProtocolHandlers.h @@ -55,6 +55,7 @@ virtual void onDocumentHighlight(TextDocumentPositionParams &Params) = 0; virtual void onHover(TextDocumentPositionParams &Params) = 0; virtual void onChangeConfiguration(DidChangeConfigurationParams &Params) = 0; + virtual void onCancelRequest(CancelParams &Params) = 0; }; void registerCallbackHandlers(JSONRPCDispatcher &Dispatcher, Index: clangd/ProtocolHandlers.cpp === --- clangd/ProtocolHandlers.cpp +++ clangd/ProtocolHandlers.cpp @@ -75,4 +75,5 @@ Register("workspace/didChangeConfiguration", &ProtocolCallbacks::onChangeConfiguration); Register("workspace/symbol", &ProtocolCallbacks::onWorkspaceSymbol); + Register("$/cancelRequest", &ProtocolCallbacks::onCancelRequest); } Index: clangd/Protocol.h === --- clangd/Protocol.h +++ clangd/Protocol.h @@ -867,6 +867,16 @@ llvm::json::Value toJSON(const DocumentHighlight &DH); llvm::raw_ostream &operator<<(llvm::raw_ostream &, const DocumentHighlight &); +struct CancelParams { + /// The request id to cancel. + /// This can be either a number or string, if it is a number simply print it + /// out and always use a string. +
[PATCH] D50502: [clangd] Initial cancellation mechanism for LSP requests.
kadircet marked an inline comment as done. kadircet added inline comments. Comment at: clangd/ClangdLSPServer.cpp:621 + std::lock_guard Lock(TaskHandlesMutex); + const auto &it = TaskHandles.find(Params.ID); + if (it != TaskHandles.end()) { ilya-biryukov wrote: > Wouldn't it work incorrectly for string IDs? > When normalizing `json::Value` from `getRequestID`, we simply print out json. > For strings, this should result in quoted output, e.g. `"req"`. However, when > parsing `CancelParams`, we parse this json. So we'll end up inserting with a > key `"req"` and erasing with a key 'req' (without the quotes). You are right, that's exactly the case, thanks! Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50502 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50835: [clangd] Add parantheses while auto-completing functions.
kadircet added inline comments. Comment at: clangd/CodeComplete.cpp:1381 + // Check whether function has any parameters or not. + LSP.textEdit->newText += SnippetSuffix.size() > 2 ? "(${0})" : "()"; +} ioeric wrote: > I think we are missing one case here: `!EnableFunctionArgSnippets && ( function or method>)`? > > I think we could do something like: > ``` > if (!EnableFunctionArgSnippets && ()) > // Truncate parameter template > else > // append snippet like before > > ``` Thanks! Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50835 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50835: [clangd] Add parantheses while auto-completing functions.
kadircet updated this revision to Diff 161265. kadircet marked 3 inline comments as done. kadircet added a comment. - Resolve discussions. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50835 Files: clangd/CodeComplete.cpp clangd/CodeComplete.h unittests/clangd/CodeCompleteTests.cpp Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -1590,6 +1590,58 @@ ElementsAre(Sig("foo(T, U) -> void", {"T", "U"}))); } +TEST(CompletionTest, RenderWithSnippetsForFunctionArgsDisabled) { + CodeCompleteOptions Opts; + Opts.EnableFunctionArgSnippets = true; + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = "()"; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::PlainText); + } + + Opts.EnableSnippets = true; + Opts.EnableFunctionArgSnippets = false; + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = ""; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); + } + + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = "()"; +C.Kind = CompletionItemKind::Method; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x()"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); + } + + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = "(${0:bool})"; +C.Kind = CompletionItemKind::Function; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x(${0})"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); + } +} + } // namespace } // namespace clangd } // namespace clang Index: clangd/CodeComplete.h === --- clangd/CodeComplete.h +++ clangd/CodeComplete.h @@ -82,6 +82,10 @@ /// Include completions that require small corrections, e.g. change '.' to /// '->' on member access etc. bool IncludeFixIts = false; + + /// Whether to generate snippets for function arguments on code-completion. + /// Needs snippets to be enabled as well. + bool EnableFunctionArgSnippets = true; }; // Semi-structured representation of a code-complete suggestion for our C++ API. Index: clangd/CodeComplete.cpp === --- clangd/CodeComplete.cpp +++ clangd/CodeComplete.cpp @@ -1371,8 +1371,17 @@ LSP.additionalTextEdits.push_back(FixIt); } } - if (Opts.EnableSnippets) -LSP.textEdit->newText += SnippetSuffix; + if (Opts.EnableSnippets && !SnippetSuffix.empty()) { +if (!Opts.EnableFunctionArgSnippets && +((Kind == CompletionItemKind::Function) || + (Kind == CompletionItemKind::Method)) && +(SnippetSuffix.front() == '(') && (SnippetSuffix.back() == ')')) + // Check whether function has any parameters or not. + LSP.textEdit->newText += SnippetSuffix.size() > 2 ? "(${0})" : "()"; +else + LSP.textEdit->newText += SnippetSuffix; + } + // FIXME(kadircet): Do not even fill insertText after making sure textEdit is // compatible with most of the editors. LSP.insertText = LSP.textEdit->newText; ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50835: [clangd] Add parantheses while auto-completing functions.
This revision was automatically updated to reflect the committed changes. Closed by commit rL340040: [clangd] Add parantheses while auto-completing functions. (authored by kadircet, committed by ). Herald added a subscriber: llvm-commits. Changed prior to commit: https://reviews.llvm.org/D50835?vs=161265&id=161267#toc Repository: rL LLVM https://reviews.llvm.org/D50835 Files: clang-tools-extra/trunk/clangd/CodeComplete.cpp clang-tools-extra/trunk/clangd/CodeComplete.h clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp Index: clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp === --- clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp +++ clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp @@ -1648,6 +1648,58 @@ SigDoc("Doc from sema"; } +TEST(CompletionTest, RenderWithSnippetsForFunctionArgsDisabled) { + CodeCompleteOptions Opts; + Opts.EnableFunctionArgSnippets = true; + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = "()"; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::PlainText); + } + + Opts.EnableSnippets = true; + Opts.EnableFunctionArgSnippets = false; + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = ""; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); + } + + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = "()"; +C.Kind = CompletionItemKind::Method; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x()"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); + } + + { +CodeCompletion C; +C.RequiredQualifier = "Foo::"; +C.Name = "x"; +C.SnippetSuffix = "(${0:bool})"; +C.Kind = CompletionItemKind::Function; + +auto R = C.render(Opts); +EXPECT_EQ(R.textEdit->newText, "Foo::x(${0})"); +EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); + } +} + } // namespace } // namespace clangd } // namespace clang Index: clang-tools-extra/trunk/clangd/CodeComplete.cpp === --- clang-tools-extra/trunk/clangd/CodeComplete.cpp +++ clang-tools-extra/trunk/clangd/CodeComplete.cpp @@ -1413,8 +1413,17 @@ LSP.additionalTextEdits.push_back(FixIt); } } - if (Opts.EnableSnippets) -LSP.textEdit->newText += SnippetSuffix; + if (Opts.EnableSnippets && !SnippetSuffix.empty()) { +if (!Opts.EnableFunctionArgSnippets && +((Kind == CompletionItemKind::Function) || + (Kind == CompletionItemKind::Method)) && +(SnippetSuffix.front() == '(') && (SnippetSuffix.back() == ')')) + // Check whether function has any parameters or not. + LSP.textEdit->newText += SnippetSuffix.size() > 2 ? "(${0})" : "()"; +else + LSP.textEdit->newText += SnippetSuffix; + } + // FIXME(kadircet): Do not even fill insertText after making sure textEdit is // compatible with most of the editors. LSP.insertText = LSP.textEdit->newText; Index: clang-tools-extra/trunk/clangd/CodeComplete.h === --- clang-tools-extra/trunk/clangd/CodeComplete.h +++ clang-tools-extra/trunk/clangd/CodeComplete.h @@ -82,6 +82,10 @@ /// Include completions that require small corrections, e.g. change '.' to /// '->' on member access etc. bool IncludeFixIts = false; + + /// Whether to generate snippets for function arguments on code-completion. + /// Needs snippets to be enabled as well. + bool EnableFunctionArgSnippets = true; }; // Semi-structured representation of a code-complete suggestion for our C++ API. ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50502: [clangd] Initial cancellation mechanism for LSP requests.
kadircet updated this revision to Diff 161428. kadircet marked 2 inline comments as done. kadircet added a comment. - Check cancellation earlier && Fix normalization difference between string and integer request ids. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50502 Files: clangd/CMakeLists.txt clangd/Cancellation.cpp clangd/Cancellation.h clangd/ClangdLSPServer.cpp clangd/ClangdLSPServer.h clangd/ClangdServer.cpp clangd/ClangdServer.h clangd/JSONRPCDispatcher.cpp clangd/JSONRPCDispatcher.h clangd/Protocol.cpp clangd/Protocol.h clangd/ProtocolHandlers.cpp clangd/ProtocolHandlers.h unittests/clangd/CMakeLists.txt unittests/clangd/CancellationTests.cpp Index: unittests/clangd/CancellationTests.cpp === --- /dev/null +++ unittests/clangd/CancellationTests.cpp @@ -0,0 +1,79 @@ +#include "Cancellation.h" +#include "Context.h" +#include "Threading.h" +#include "llvm/Support/Error.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include +#include +#include + +namespace clang { +namespace clangd { +namespace { + +TEST(CancellationTest, CancellationTest) { + TaskHandle TH = TaskHandle::create(); + WithContext ContextWithCancellation( + setCurrentCancellationToken(TH.createCancellationToken())); + EXPECT_FALSE(isCancelled()); + TH.cancel(); + EXPECT_TRUE(isCancelled()); +} + +TEST(CancellationTest, TaskHandleTestHandleDiesContextLives) { + llvm::Optional ContextWithCancellation; + { +auto CancellableTaskHandle = TaskHandle::create(); +ContextWithCancellation.emplace(setCurrentCancellationToken( +CancellableTaskHandle.createCancellationToken())); +EXPECT_FALSE(isCancelled()); +CancellableTaskHandle.cancel(); +EXPECT_TRUE(isCancelled()); + } + EXPECT_TRUE(isCancelled()); +} + +TEST(CancellationTest, TaskHandleContextDiesHandleLives) { + auto CancellableTaskHandle = TaskHandle::create(); + { +WithContext ContextWithCancellation(setCurrentCancellationToken( +CancellableTaskHandle.createCancellationToken())); +EXPECT_FALSE(isCancelled()); +CancellableTaskHandle.cancel(); +EXPECT_TRUE(isCancelled()); + } + // Still should be able to cancel without any problems. + CancellableTaskHandle.cancel(); +} + +TEST(CancellationTest, CancellationToken) { + auto CancellableTaskHandle = TaskHandle::create(); + WithContext ContextWithCancellation(setCurrentCancellationToken( + CancellableTaskHandle.createCancellationToken())); + const auto &CT = getCurrentCancellationToken(); + EXPECT_FALSE(CT); + CancellableTaskHandle.cancel(); + EXPECT_TRUE(CT); +} + +TEST(CancellationTest, AsynCancellationTest) { + std::atomic HasCancelled(false); + Notification Cancelled; + auto TaskToBeCancelled = [&](CancellationToken CT) { +WithContext ContextGuard(setCurrentCancellationToken(std::move(CT))); +Cancelled.wait(); +HasCancelled = isCancelled(); + }; + TaskHandle TH = TaskHandle::create(); + std::thread AsyncTask(TaskToBeCancelled, TH.createCancellationToken()); + TH.cancel(); + Cancelled.notify(); + AsyncTask.join(); + + EXPECT_TRUE(HasCancelled); +} + +} // namespace +} // namespace clangd +} // namespace clang Index: unittests/clangd/CMakeLists.txt === --- unittests/clangd/CMakeLists.txt +++ unittests/clangd/CMakeLists.txt @@ -10,6 +10,7 @@ add_extra_unittest(ClangdTests Annotations.cpp + CancellationTests.cpp ClangdTests.cpp ClangdUnitTests.cpp CodeCompleteTests.cpp Index: clangd/ProtocolHandlers.h === --- clangd/ProtocolHandlers.h +++ clangd/ProtocolHandlers.h @@ -55,6 +55,7 @@ virtual void onDocumentHighlight(TextDocumentPositionParams &Params) = 0; virtual void onHover(TextDocumentPositionParams &Params) = 0; virtual void onChangeConfiguration(DidChangeConfigurationParams &Params) = 0; + virtual void onCancelRequest(CancelParams &Params) = 0; }; void registerCallbackHandlers(JSONRPCDispatcher &Dispatcher, Index: clangd/ProtocolHandlers.cpp === --- clangd/ProtocolHandlers.cpp +++ clangd/ProtocolHandlers.cpp @@ -75,4 +75,5 @@ Register("workspace/didChangeConfiguration", &ProtocolCallbacks::onChangeConfiguration); Register("workspace/symbol", &ProtocolCallbacks::onWorkspaceSymbol); + Register("$/cancelRequest", &ProtocolCallbacks::onCancelRequest); } Index: clangd/Protocol.h === --- clangd/Protocol.h +++ clangd/Protocol.h @@ -867,6 +867,16 @@ llvm::json::Value toJSON(const DocumentHighlight &DH); llvm::raw_ostream &operator<<(llvm::raw_ostream &, const DocumentHighlight &); +struct CancelParams { + /// The request id to cancel. + /// This can be either a number or string, if it is a number simply print it + /
[PATCH] D50502: [clangd] Initial cancellation mechanism for LSP requests.
kadircet added inline comments. Comment at: clangd/ClangdLSPServer.cpp:75 +std::string NormalizeRequestID(const json::Value &ID) { + CancelParams CP; + fromJSON(json::Object{{"id", ID}}, CP); ioeric wrote: > Use `ID.getAsString()`? Unfortunately id can be both a string or a number according to LSP specs therefore we normalize both cases into a string. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50502 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50962: [clangd] Speculative code completion index request before Sema is run.
kadircet added inline comments. Comment at: unittests/clangd/CodeCompleteTests.cpp:1710 + $bol^ + ab$ab^ + x.ab$dot^ Maybe an EXPECT for this one as well? Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50962 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50898: [clangd] Suggest code-completions for overriding base class virtual methods.
kadircet updated this revision to Diff 161683. kadircet marked 3 inline comments as done. kadircet added a comment. - Put overrides through scoring and resolve nits. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50898 Files: clangd/CodeComplete.cpp clangd/CodeComplete.h unittests/clangd/CodeCompleteTests.cpp Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -61,6 +61,7 @@ MATCHER(InsertInclude, "") { return bool(arg.HeaderInsertion); } MATCHER_P(SnippetSuffix, Text, "") { return arg.SnippetSuffix == Text; } MATCHER_P(Origin, OriginSet, "") { return arg.Origin == OriginSet; } +MATCHER(IsOverride, "") { return bool(arg.IsOverride); } // Shorthand for Contains(Named(Name)). Matcher &> Has(std::string Name) { @@ -1648,6 +1649,58 @@ SigDoc("Doc from sema"; } +TEST(CompletionTest, SuggestOverrides) { + constexpr const char *const Text(R"cpp( + class A { + public: +virtual void vfunc(bool param); +virtual void vfunc(bool param, int p); +void func(bool param); + }; + class B : public A { + virtual void ttt(bool param); + void vfunc(bool param, int p) override; + }; + class C : public B { + public: +void vfunc(bool param) override; +^ + }; + )cpp"); + const auto Results = completions(Text); + EXPECT_THAT(Results.Completions, + AllOf(Contains(AllOf(Named("vfunc"), IsOverride(), + Labeled("vfunc(bool param, int p)"))), +Contains(AllOf(Named("ttt"), IsOverride(), + Labeled("ttt(bool param)"))), +Not(Contains(AllOf(Named("vfunc"), IsOverride(), + Labeled("vfunc(bool param)")); +} + +TEST(CompletionTest, RenderOverride) { + CodeCompletion C; + C.Name = "x"; + C.Signature = "(bool) const"; + C.SnippetSuffix = "(${0:bool})"; + C.ReturnType = "int"; + C.Documentation = "This is x()."; + C.Kind = CompletionItemKind::Method; + C.Score.Total = 1.0; + C.Origin = SymbolOrigin::AST; + C.IsOverride = true; + + CodeCompleteOptions Opts; + Opts.IncludeIndicator.NoInsert = ""; + auto R = C.render(Opts); + EXPECT_EQ(R.label, "int x(bool) const override"); + EXPECT_EQ(R.insertText, "int x(bool) const override"); + EXPECT_EQ(R.insertTextFormat, InsertTextFormat::PlainText); + EXPECT_EQ(R.filterText, "x"); + EXPECT_EQ(R.detail, "int"); + EXPECT_EQ(R.documentation, "This is x()."); + EXPECT_THAT(R.additionalTextEdits, IsEmpty()); +} + } // namespace } // namespace clangd } // namespace clang Index: clangd/CodeComplete.h === --- clangd/CodeComplete.h +++ clangd/CodeComplete.h @@ -127,6 +127,9 @@ /// Holds the range of the token we are going to replace with this completion. Range CompletionTokenRange; + /// Whether this completion is for overriding a virtual method. + bool IsOverride = false; + // Scores are used to rank completion items. struct Scores { // The score that items are ranked by. Index: clangd/CodeComplete.cpp === --- clangd/CodeComplete.cpp +++ clangd/CodeComplete.cpp @@ -188,14 +188,67 @@ return HeaderFile{std::move(*Resolved), /*Verbatim=*/false}; } +// First traverses all method definitions inside current class/struct/union +// definition. Than traverses base classes to find virtual methods that haven't +// been overriden within current context. +// FIXME(kadircet): Currently we cannot see declarations below completion point. +// It is because Sema gets run only upto completion point. Need to find a +// solution to run it for the whole class/struct/union definition. +static std::vector +getVirtualNonOverridenMethods(const DeclContext *DC, Sema *S) { + const auto *CR = llvm::dyn_cast(DC); + // If not inside a class/struct/union return empty. + if (!CR) +return {}; + // First store overrides within current class. + // These are stored by name to make querying fast in the later step. + llvm::StringMap> Overrides; + for (auto *Method : CR->methods()) { +if (!Method->isVirtual()) + continue; +const std::string Name = Method->getNameAsString(); +Overrides[Name].push_back(Method); + } + + std::vector Results; + for (const auto &Base : CR->bases()) { +const auto *BR = Base.getType().getTypePtr()->getAsCXXRecordDecl(); +if (!BR) + continue; +for (auto *Method : BR->methods()) { + if (!Method->isVirtual()) +continue; + const std::string Name = Method->getNameAsString(); + const auto it = Overrides.find(Name); + bool IsOverriden = false; + if (it != Overrides.end()) +for (auto *MD : it->second) { + // If the method in current body is not an overload o
[PATCH] D50898: [clangd] Suggest code-completions for overriding base class virtual methods.
kadircet marked an inline comment as done. kadircet added inline comments. Comment at: clangd/CodeComplete.cpp:1233 +// struct/class/union definition. +const auto Overrides = getVirtualNonOverridenMethods( +Recorder->CCSema->CurContext, Recorder->CCSema); hokein wrote: > It seems that we treat it as a special case, the code path here runs out of > the `ranking` path. Put override suggestions to ranking system. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50898 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50502: [clangd] Initial cancellation mechanism for LSP requests.
kadircet updated this revision to Diff 161716. kadircet marked 4 inline comments as done. kadircet added a comment. - Get rid of CancellationToken && Resolve discussions. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50502 Files: clangd/CMakeLists.txt clangd/Cancellation.cpp clangd/Cancellation.h clangd/ClangdLSPServer.cpp clangd/ClangdLSPServer.h clangd/ClangdServer.cpp clangd/ClangdServer.h clangd/JSONRPCDispatcher.cpp clangd/JSONRPCDispatcher.h clangd/Protocol.cpp clangd/Protocol.h clangd/ProtocolHandlers.cpp clangd/ProtocolHandlers.h unittests/clangd/CMakeLists.txt unittests/clangd/CancellationTests.cpp Index: unittests/clangd/CancellationTests.cpp === --- /dev/null +++ unittests/clangd/CancellationTests.cpp @@ -0,0 +1,74 @@ +#include "Cancellation.h" +#include "Context.h" +#include "Threading.h" +#include "llvm/Support/Error.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include +#include +#include + +namespace clang { +namespace clangd { +namespace { + +TEST(CancellationTest, CancellationTest) { + TaskHandle TH = createTaskHandle(); + WithContext ContextWithCancellation(setCurrentTask(TH)); + EXPECT_FALSE(isCancelled()); + TH->cancel(); + EXPECT_TRUE(isCancelled()); +} + +TEST(CancellationTest, TaskTestHandleDiesContextLives) { + llvm::Optional ContextWithCancellation; + { +TaskHandle TH = createTaskHandle(); +ContextWithCancellation.emplace(setCurrentTask(TH)); +EXPECT_FALSE(isCancelled()); +TH->cancel(); +EXPECT_TRUE(isCancelled()); + } + EXPECT_TRUE(isCancelled()); +} + +TEST(CancellationTest, TaskContextDiesHandleLives) { + TaskHandle TH = createTaskHandle(); + { +WithContext ContextWithCancellation(setCurrentTask(TH)); +EXPECT_FALSE(isCancelled()); +TH->cancel(); +EXPECT_TRUE(isCancelled()); + } + // Still should be able to cancel without any problems. + TH->cancel(); +} + +TEST(CancellationTest, CancellationToken) { + TaskHandle TH = createTaskHandle(); + WithContext ContextWithCancellation(setCurrentTask(TH)); + const auto &CT = getCurrentTask(); + EXPECT_FALSE(CT.isCancelled()); + TH->cancel(); + EXPECT_TRUE(CT.isCancelled()); +} + +TEST(CancellationTest, AsynCancellationTest) { + std::atomic HasCancelled(false); + Notification Cancelled; + auto TaskToBeCancelled = [&](ConstTaskHandle CT) { +WithContext ContextGuard(setCurrentTask(std::move(CT))); +Cancelled.wait(); +HasCancelled = isCancelled(); + }; + TaskHandle TH = createTaskHandle(); + std::thread AsyncTask(TaskToBeCancelled, TH); + TH->cancel(); + Cancelled.notify(); + AsyncTask.join(); + + EXPECT_TRUE(HasCancelled); +} +} // namespace +} // namespace clangd +} // namespace clang Index: unittests/clangd/CMakeLists.txt === --- unittests/clangd/CMakeLists.txt +++ unittests/clangd/CMakeLists.txt @@ -10,6 +10,7 @@ add_extra_unittest(ClangdTests Annotations.cpp + CancellationTests.cpp ClangdTests.cpp ClangdUnitTests.cpp CodeCompleteTests.cpp Index: clangd/ProtocolHandlers.h === --- clangd/ProtocolHandlers.h +++ clangd/ProtocolHandlers.h @@ -55,6 +55,7 @@ virtual void onDocumentHighlight(TextDocumentPositionParams &Params) = 0; virtual void onHover(TextDocumentPositionParams &Params) = 0; virtual void onChangeConfiguration(DidChangeConfigurationParams &Params) = 0; + virtual void onCancelRequest(CancelParams &Params) = 0; }; void registerCallbackHandlers(JSONRPCDispatcher &Dispatcher, Index: clangd/ProtocolHandlers.cpp === --- clangd/ProtocolHandlers.cpp +++ clangd/ProtocolHandlers.cpp @@ -75,4 +75,5 @@ Register("workspace/didChangeConfiguration", &ProtocolCallbacks::onChangeConfiguration); Register("workspace/symbol", &ProtocolCallbacks::onWorkspaceSymbol); + Register("$/cancelRequest", &ProtocolCallbacks::onCancelRequest); } Index: clangd/Protocol.h === --- clangd/Protocol.h +++ clangd/Protocol.h @@ -867,6 +867,16 @@ llvm::json::Value toJSON(const DocumentHighlight &DH); llvm::raw_ostream &operator<<(llvm::raw_ostream &, const DocumentHighlight &); +struct CancelParams { + /// The request id to cancel. + /// This can be either a number or string, if it is a number simply print it + /// out and always use a string. + std::string ID; +}; +llvm::json::Value toJSON(const CancelParams &); +llvm::raw_ostream &operator<<(llvm::raw_ostream &, const CancelParams &); +bool fromJSON(const llvm::json::Value &, CancelParams &); + } // namespace clangd } // namespace clang Index: clangd/Protocol.cpp === --- clangd/Protocol.cpp +++ clangd/Protocol.cpp @@ -615,5 +615,30 @@
[PATCH] D51038: [clangd] Make sure codecompletion is called for calls even when inside a token.
kadircet created this revision. kadircet added reviewers: ilya-biryukov, ioeric, hokein. Herald added subscribers: cfe-commits, arphaman, jkorous, MaskRay. Currently CodeCompleteCall only gets called after a comma or parantheses. This patch makes sure it is called even at the cases like: foo(1^); Repository: rC Clang https://reviews.llvm.org/D51038 Files: include/clang/Parse/Parser.h lib/Parse/ParseExpr.cpp Index: lib/Parse/ParseExpr.cpp === --- lib/Parse/ParseExpr.cpp +++ lib/Parse/ParseExpr.cpp @@ -1648,6 +1648,10 @@ Actions.CodeCompleteCall(getCurScope(), LHS.get(), ArgExprs); })) { (void)Actions.CorrectDelayedTyposInExpr(LHS); +if (PP.isCodeCompletionReached() && !CalledOverloadCompletion) { + Actions.CodeCompleteCall(getCurScope(), LHS.get(), ArgExprs); + CalledOverloadCompletion = true; +} LHS = ExprError(); } else if (LHS.isInvalid()) { for (auto &E : ArgExprs) @@ -2813,6 +2817,7 @@ Completer(); else Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); + CalledOverloadCompletion = true; cutOffParsing(); return true; } Index: include/clang/Parse/Parser.h === --- include/clang/Parse/Parser.h +++ include/clang/Parse/Parser.h @@ -2965,6 +2965,10 @@ void CodeCompleteMacroArgument(IdentifierInfo *Macro, MacroInfo *MacroInfo, unsigned ArgumentIndex) override; void CodeCompleteNaturalLanguage() override; + + /// Gets set to true after calling CodeCompleteCall, it is for a hack to make + /// signature help working even when it is triggered inside a token. + bool CalledOverloadCompletion = false; }; } // end namespace clang Index: lib/Parse/ParseExpr.cpp === --- lib/Parse/ParseExpr.cpp +++ lib/Parse/ParseExpr.cpp @@ -1648,6 +1648,10 @@ Actions.CodeCompleteCall(getCurScope(), LHS.get(), ArgExprs); })) { (void)Actions.CorrectDelayedTyposInExpr(LHS); +if (PP.isCodeCompletionReached() && !CalledOverloadCompletion) { + Actions.CodeCompleteCall(getCurScope(), LHS.get(), ArgExprs); + CalledOverloadCompletion = true; +} LHS = ExprError(); } else if (LHS.isInvalid()) { for (auto &E : ArgExprs) @@ -2813,6 +2817,7 @@ Completer(); else Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); + CalledOverloadCompletion = true; cutOffParsing(); return true; } Index: include/clang/Parse/Parser.h === --- include/clang/Parse/Parser.h +++ include/clang/Parse/Parser.h @@ -2965,6 +2965,10 @@ void CodeCompleteMacroArgument(IdentifierInfo *Macro, MacroInfo *MacroInfo, unsigned ArgumentIndex) override; void CodeCompleteNaturalLanguage() override; + + /// Gets set to true after calling CodeCompleteCall, it is for a hack to make + /// signature help working even when it is triggered inside a token. + bool CalledOverloadCompletion = false; }; } // end namespace clang ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D51039: [clangd] Add unittests for D51038
kadircet created this revision. kadircet added reviewers: ilya-biryukov, ioeric, hokein. Herald added subscribers: cfe-commits, arphaman, jkorous, MaskRay. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D51039 Files: unittests/clangd/CodeCompleteTests.cpp Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -1590,6 +1590,56 @@ ElementsAre(Sig("foo(T, U) -> void", {"T", "U"}))); } +TEST(SignatureHelpTest, InsideArgument) { + { +const auto Results = signatures(R"cpp( + void foo(int x); + void foo(int x, int y); + int main() { foo(1+^); } +)cpp"); +EXPECT_THAT( +Results.signatures, +ElementsAre(Sig("foo(int x) -> void", {"int x"}), +Sig("foo(int x, int y) -> void", {"int x", "int y"}))); +EXPECT_EQ(0, Results.activeParameter); + } + { +const auto Results = signatures(R"cpp( + void foo(int x); + void foo(int x, int y); + int main() { foo(1^); } +)cpp"); +EXPECT_THAT( +Results.signatures, +ElementsAre(Sig("foo(int x) -> void", {"int x"}), +Sig("foo(int x, int y) -> void", {"int x", "int y"}))); +EXPECT_EQ(0, Results.activeParameter); + } + { +const auto Results = signatures(R"cpp( + void foo(int x); + void foo(int x, int y); + int main() { foo(1^0); } +)cpp"); +EXPECT_THAT( +Results.signatures, +ElementsAre(Sig("foo(int x) -> void", {"int x"}), +Sig("foo(int x, int y) -> void", {"int x", "int y"}))); +EXPECT_EQ(0, Results.activeParameter); + } + { +const auto Results = signatures(R"cpp( + void foo(int x); + void foo(int x, int y); + int bar(int x, int y); + int main() { bar(foo(2, 3^)); } +)cpp"); +EXPECT_THAT(Results.signatures, ElementsAre(Sig("foo(int x, int y) -> void", +{"int x", "int y"}))); +EXPECT_EQ(1, Results.activeParameter); + } +} + } // namespace } // namespace clangd } // namespace clang Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -1590,6 +1590,56 @@ ElementsAre(Sig("foo(T, U) -> void", {"T", "U"}))); } +TEST(SignatureHelpTest, InsideArgument) { + { +const auto Results = signatures(R"cpp( + void foo(int x); + void foo(int x, int y); + int main() { foo(1+^); } +)cpp"); +EXPECT_THAT( +Results.signatures, +ElementsAre(Sig("foo(int x) -> void", {"int x"}), +Sig("foo(int x, int y) -> void", {"int x", "int y"}))); +EXPECT_EQ(0, Results.activeParameter); + } + { +const auto Results = signatures(R"cpp( + void foo(int x); + void foo(int x, int y); + int main() { foo(1^); } +)cpp"); +EXPECT_THAT( +Results.signatures, +ElementsAre(Sig("foo(int x) -> void", {"int x"}), +Sig("foo(int x, int y) -> void", {"int x", "int y"}))); +EXPECT_EQ(0, Results.activeParameter); + } + { +const auto Results = signatures(R"cpp( + void foo(int x); + void foo(int x, int y); + int main() { foo(1^0); } +)cpp"); +EXPECT_THAT( +Results.signatures, +ElementsAre(Sig("foo(int x) -> void", {"int x"}), +Sig("foo(int x, int y) -> void", {"int x", "int y"}))); +EXPECT_EQ(0, Results.activeParameter); + } + { +const auto Results = signatures(R"cpp( + void foo(int x); + void foo(int x, int y); + int bar(int x, int y); + int main() { bar(foo(2, 3^)); } +)cpp"); +EXPECT_THAT(Results.signatures, ElementsAre(Sig("foo(int x, int y) -> void", +{"int x", "int y"}))); +EXPECT_EQ(1, Results.activeParameter); + } +} + } // namespace } // namespace clangd } // namespace clang ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50898: [clangd] Suggest code-completions for overriding base class virtual methods.
kadircet added a comment. After today's offline discussion I suppose we are not going to implement it within Sema. And also I think getVirtualNonOverridenMethods is a pretty generic function that has no ties to clangd, so it can be easily moved into Sema. Should we still move it into a separate file or leave it there? Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50898 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50502: [clangd] Initial cancellation mechanism for LSP requests.
kadircet updated this revision to Diff 161908. kadircet marked 6 inline comments as done. kadircet added a comment. - Resolve discussions. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50502 Files: clangd/CMakeLists.txt clangd/Cancellation.cpp clangd/Cancellation.h clangd/ClangdLSPServer.cpp clangd/ClangdLSPServer.h clangd/ClangdServer.cpp clangd/ClangdServer.h clangd/JSONRPCDispatcher.cpp clangd/JSONRPCDispatcher.h clangd/Protocol.cpp clangd/Protocol.h clangd/ProtocolHandlers.cpp clangd/ProtocolHandlers.h unittests/clangd/CMakeLists.txt unittests/clangd/CancellationTests.cpp Index: unittests/clangd/CancellationTests.cpp === --- /dev/null +++ unittests/clangd/CancellationTests.cpp @@ -0,0 +1,74 @@ +#include "Cancellation.h" +#include "Context.h" +#include "Threading.h" +#include "llvm/Support/Error.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include +#include +#include + +namespace clang { +namespace clangd { +namespace { + +TEST(CancellationTest, CancellationTest) { + TaskHandle TH = Task::createHandle(); + WithContext ContextWithCancellation(setCurrentTask(TH)); + EXPECT_FALSE(isCancelled()); + TH->cancel(); + EXPECT_TRUE(isCancelled()); +} + +TEST(CancellationTest, TaskTestHandleDiesContextLives) { + llvm::Optional ContextWithCancellation; + { +TaskHandle TH = Task::createHandle(); +ContextWithCancellation.emplace(setCurrentTask(TH)); +EXPECT_FALSE(isCancelled()); +TH->cancel(); +EXPECT_TRUE(isCancelled()); + } + EXPECT_TRUE(isCancelled()); +} + +TEST(CancellationTest, TaskContextDiesHandleLives) { + TaskHandle TH = Task::createHandle(); + { +WithContext ContextWithCancellation(setCurrentTask(TH)); +EXPECT_FALSE(isCancelled()); +TH->cancel(); +EXPECT_TRUE(isCancelled()); + } + // Still should be able to cancel without any problems. + TH->cancel(); +} + +TEST(CancellationTest, CancellationToken) { + TaskHandle TH = Task::createHandle(); + WithContext ContextWithCancellation(setCurrentTask(TH)); + const auto &CT = getCurrentTask(); + EXPECT_FALSE(CT.isCancelled()); + TH->cancel(); + EXPECT_TRUE(CT.isCancelled()); +} + +TEST(CancellationTest, AsynCancellationTest) { + std::atomic HasCancelled(false); + Notification Cancelled; + auto TaskToBeCancelled = [&](ConstTaskHandle CT) { +WithContext ContextGuard(setCurrentTask(std::move(CT))); +Cancelled.wait(); +HasCancelled = isCancelled(); + }; + TaskHandle TH = Task::createHandle(); + std::thread AsyncTask(TaskToBeCancelled, TH); + TH->cancel(); + Cancelled.notify(); + AsyncTask.join(); + + EXPECT_TRUE(HasCancelled); +} +} // namespace +} // namespace clangd +} // namespace clang Index: unittests/clangd/CMakeLists.txt === --- unittests/clangd/CMakeLists.txt +++ unittests/clangd/CMakeLists.txt @@ -10,6 +10,7 @@ add_extra_unittest(ClangdTests Annotations.cpp + CancellationTests.cpp ClangdTests.cpp ClangdUnitTests.cpp CodeCompleteTests.cpp Index: clangd/ProtocolHandlers.h === --- clangd/ProtocolHandlers.h +++ clangd/ProtocolHandlers.h @@ -55,6 +55,7 @@ virtual void onDocumentHighlight(TextDocumentPositionParams &Params) = 0; virtual void onHover(TextDocumentPositionParams &Params) = 0; virtual void onChangeConfiguration(DidChangeConfigurationParams &Params) = 0; + virtual void onCancelRequest(CancelParams &Params) = 0; }; void registerCallbackHandlers(JSONRPCDispatcher &Dispatcher, Index: clangd/ProtocolHandlers.cpp === --- clangd/ProtocolHandlers.cpp +++ clangd/ProtocolHandlers.cpp @@ -75,4 +75,5 @@ Register("workspace/didChangeConfiguration", &ProtocolCallbacks::onChangeConfiguration); Register("workspace/symbol", &ProtocolCallbacks::onWorkspaceSymbol); + Register("$/cancelRequest", &ProtocolCallbacks::onCancelRequest); } Index: clangd/Protocol.h === --- clangd/Protocol.h +++ clangd/Protocol.h @@ -867,6 +867,22 @@ llvm::json::Value toJSON(const DocumentHighlight &DH); llvm::raw_ostream &operator<<(llvm::raw_ostream &, const DocumentHighlight &); +struct CancelParams { + /// The request id to cancel. + /// This can be either a number or string, if it is a number simply print it + /// out and always use a string. + std::string ID; +}; +llvm::json::Value toJSON(const CancelParams &); +llvm::raw_ostream &operator<<(llvm::raw_ostream &, const CancelParams &); +bool fromJSON(const llvm::json::Value &, CancelParams &); + +/// Parses the Field in Params into Parsed. Params[Field] can be either of type +/// string or number. Returns true if parsing was succesful. In case of a number +/// converts it into a string. +bool parseNumberOrString(const llvm::json
[PATCH] D51102: [clangd] Move function argument snippet disable mechanism from LSP rendering to internal clangd reprensentation.
kadircet created this revision. kadircet added reviewers: ilya-biryukov, ioeric, hokein. Herald added subscribers: cfe-commits, arphaman, jkorous, MaskRay. We were handling the EnableFunctionArgSnippets only when we are producing LSP response. Move that code into CompletionItem generation so that internal clients can benefit from that as well. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D51102 Files: clangd/CodeComplete.cpp unittests/clangd/CodeCompleteTests.cpp Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -1140,7 +1140,7 @@ // For now we just return one of the doc strings arbitrarily. EXPECT_THAT(A.Documentation, AnyOf(HasSubstr("Overload with int"), HasSubstr("Overload with bool"))); - EXPECT_EQ(A.SnippetSuffix, "(${0})"); + EXPECT_EQ(A.SnippetSuffix, "($0)"); } TEST(CompletionTest, DocumentationFromChangedFileCrash) { @@ -1648,55 +1648,35 @@ SigDoc("Doc from sema"; } -TEST(CompletionTest, RenderWithSnippetsForFunctionArgsDisabled) { +TEST(CompletionTest, CompletionFunctionArgsDisabled) { CodeCompleteOptions Opts; - Opts.EnableFunctionArgSnippets = true; - { -CodeCompletion C; -C.RequiredQualifier = "Foo::"; -C.Name = "x"; -C.SnippetSuffix = "()"; - -auto R = C.render(Opts); -EXPECT_EQ(R.textEdit->newText, "Foo::x"); -EXPECT_EQ(R.insertTextFormat, InsertTextFormat::PlainText); - } - Opts.EnableSnippets = true; Opts.EnableFunctionArgSnippets = false; + const std::string Header = + R"cpp( + void xfoo(); + void xfoo(int x, int y); + void xbar(); + void f() { +)cpp"; { -CodeCompletion C; -C.RequiredQualifier = "Foo::"; -C.Name = "x"; -C.SnippetSuffix = ""; - -auto R = C.render(Opts); -EXPECT_EQ(R.textEdit->newText, "Foo::x"); -EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); +auto Results = completions(Header + "\nxfo^", {}, Opts); +EXPECT_THAT( +Results.Completions, +UnorderedElementsAre(AllOf(Named("xfoo"), SnippetSuffix("()")), + AllOf(Named("xfoo"), SnippetSuffix("($0)"; } - { -CodeCompletion C; -C.RequiredQualifier = "Foo::"; -C.Name = "x"; -C.SnippetSuffix = "()"; -C.Kind = CompletionItemKind::Method; - -auto R = C.render(Opts); -EXPECT_EQ(R.textEdit->newText, "Foo::x()"); -EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); +auto Results = completions(Header + "\nxba^", {}, Opts); +EXPECT_THAT(Results.Completions, UnorderedElementsAre(AllOf( + Named("xbar"), SnippetSuffix("()"; } - { -CodeCompletion C; -C.RequiredQualifier = "Foo::"; -C.Name = "x"; -C.SnippetSuffix = "(${0:bool})"; -C.Kind = CompletionItemKind::Function; - -auto R = C.render(Opts); -EXPECT_EQ(R.textEdit->newText, "Foo::x(${0})"); -EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); +Opts.BundleOverloads = true; +auto Results = completions(Header + "\nxfo^", {}, Opts); +EXPECT_THAT( +Results.Completions, +UnorderedElementsAre(AllOf(Named("xfoo"), SnippetSuffix("($0)"; } } Index: clangd/CodeComplete.cpp === --- clangd/CodeComplete.cpp +++ clangd/CodeComplete.cpp @@ -269,7 +269,8 @@ CodeCompletionString *SemaCCS, const IncludeInserter &Includes, StringRef FileName, const CodeCompleteOptions &Opts) - : ASTCtx(ASTCtx), ExtractDocumentation(Opts.IncludeComments) { + : ASTCtx(ASTCtx), ExtractDocumentation(Opts.IncludeComments), +EnableFunctionArgSnippets(Opts.EnableFunctionArgSnippets) { add(C, SemaCCS); if (C.SemaResult) { Completion.Origin |= SymbolOrigin::AST; @@ -385,10 +386,17 @@ } std::string summarizeSnippet() const { -if (auto *Snippet = onlyValue<&BundledEntry::SnippetSuffix>()) - return *Snippet; -// All bundles are function calls. -return "(${0})"; +auto *Snippet = onlyValue<&BundledEntry::SnippetSuffix>(); +if (!Snippet) + // All bundles are function calls. + return "($0)"; +if (!Snippet->empty() && !EnableFunctionArgSnippets && +((Completion.Kind == CompletionItemKind::Function) || + (Completion.Kind == CompletionItemKind::Method)) && +(Snippet->front() == '(') && (Snippet->back() == ')')) + // Check whether function has any parameters or not. + return Snippet->size() > 2 ? "($0)" : "()"; +return *Snippet; } std::string summarizeSignature() const { @@ -402,6 +410,7 @@ CodeCompletion Completion; SmallVector Bundled; bool ExtractDocumentation; + bool EnableFu
[PATCH] D50898: [clangd] Suggest code-completions for overriding base class virtual methods.
kadircet updated this revision to Diff 161963. kadircet marked 6 inline comments as done. kadircet added a comment. - Resolve discussions. - Fix a bug inside summarizeOverride. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50898 Files: clangd/CodeComplete.cpp clangd/CodeComplete.h unittests/clangd/CodeCompleteTests.cpp Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -61,6 +61,7 @@ MATCHER(InsertInclude, "") { return bool(arg.HeaderInsertion); } MATCHER_P(SnippetSuffix, Text, "") { return arg.SnippetSuffix == Text; } MATCHER_P(Origin, OriginSet, "") { return arg.Origin == OriginSet; } +MATCHER(IsOverride, "") { return bool(arg.IsOverride); } // Shorthand for Contains(Named(Name)). Matcher &> Has(std::string Name) { @@ -1700,6 +1701,58 @@ } } +TEST(CompletionTest, SuggestOverrides) { + constexpr const char *const Text(R"cpp( + class A { + public: +virtual void vfunc(bool param); +virtual void vfunc(bool param, int p); +void func(bool param); + }; + class B : public A { + virtual void ttt(bool param); + void vfunc(bool param, int p) override; + }; + class C : public B { + public: +void vfunc(bool param) override; +^ + }; + )cpp"); + const auto Results = completions(Text); + EXPECT_THAT(Results.Completions, + AllOf(Contains(AllOf(Named("vfunc"), IsOverride(), + Labeled("vfunc(bool param, int p)"))), +Contains(AllOf(Named("ttt"), IsOverride(), + Labeled("ttt(bool param)"))), +Not(Contains(AllOf(Named("vfunc"), IsOverride(), + Labeled("vfunc(bool param)")); +} + +TEST(CompletionTest, RenderOverride) { + CodeCompletion C; + C.Name = "x"; + C.Signature = "(bool) const"; + C.SnippetSuffix = "(${0:bool})"; + C.ReturnType = "int"; + C.Documentation = "This is x()."; + C.Kind = CompletionItemKind::Method; + C.Score.Total = 1.0; + C.Origin = SymbolOrigin::AST; + C.IsOverride = true; + + CodeCompleteOptions Opts; + Opts.IncludeIndicator.NoInsert = ""; + auto R = C.render(Opts); + EXPECT_EQ(R.label, "int x(bool) const override"); + EXPECT_EQ(R.insertText, "int x(bool) const override"); + EXPECT_EQ(R.insertTextFormat, InsertTextFormat::PlainText); + EXPECT_EQ(R.filterText, "x"); + EXPECT_EQ(R.detail, "int"); + EXPECT_EQ(R.documentation, "This is x()."); + EXPECT_THAT(R.additionalTextEdits, IsEmpty()); +} + } // namespace } // namespace clangd } // namespace clang Index: clangd/CodeComplete.h === --- clangd/CodeComplete.h +++ clangd/CodeComplete.h @@ -131,6 +131,9 @@ /// Holds the range of the token we are going to replace with this completion. Range CompletionTokenRange; + /// Whether this completion is for overriding a virtual method. + bool IsOverride = false; + // Scores are used to rank completion items. struct Scores { // The score that items are ranked by. Index: clangd/CodeComplete.cpp === --- clangd/CodeComplete.cpp +++ clangd/CodeComplete.cpp @@ -188,14 +188,67 @@ return HeaderFile{std::move(*Resolved), /*Verbatim=*/false}; } +// First traverses all method definitions inside current class/struct/union +// definition. Than traverses base classes to find virtual methods that haven't +// been overriden within current context. +// FIXME(kadircet): Currently we cannot see declarations below completion point. +// It is because Sema gets run only upto completion point. Need to find a +// solution to run it for the whole class/struct/union definition. +static std::vector +getNonOverridenMethodCompletionResults(const DeclContext *DC, Sema *S) { + const auto *CR = llvm::dyn_cast(DC); + // If not inside a class/struct/union return empty. + if (!CR) +return {}; + // First store overrides within current class. + // These are stored by name to make querying fast in the later step. + llvm::StringMap> Overrides; + for (auto *Method : CR->methods()) { +if (!Method->isVirtual()) + continue; +const std::string Name = Method->getNameAsString(); +Overrides[Name].push_back(Method); + } + + std::vector Results; + for (const auto &Base : CR->bases()) { +const auto *BR = Base.getType().getTypePtr()->getAsCXXRecordDecl(); +if (!BR) + continue; +for (auto *Method : BR->methods()) { + if (!Method->isVirtual()) +continue; + const auto it = Overrides.find(Method->getName()); + bool IsOverriden = false; + if (it != Overrides.end()) { +for (auto *MD : it->second) { + // If the method in current body is not an overload of this virtual + // function, that it overrides this one. +
[PATCH] D51038: [clang] Make sure codecompletion is called for calls even when inside a token.
kadircet updated this revision to Diff 161966. kadircet marked 2 inline comments as done. kadircet added a comment. - Resolve discussions. - Add tests. - Fix a bug noticed by lit tests. Repository: rC Clang https://reviews.llvm.org/D51038 Files: include/clang/Parse/Parser.h lib/Parse/ParseExpr.cpp test/CodeCompletion/function-overloads-inside-param.cpp test/CodeCompletion/function-overloads.cpp Index: test/CodeCompletion/function-overloads.cpp === --- /dev/null +++ test/CodeCompletion/function-overloads.cpp @@ -0,0 +1,8 @@ +void f(int i, int j = 2, int k = 5); +void f(float x, float y...); + +void test() { + ::f( + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:5:7 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s + // CHECK-CC1: f(<#int i#>{#, <#int j = 2#>{#, <#int k = 5#>#}#}) + // CHECK-CC1: f(<#float x#>, <#float y, ...#>) Index: test/CodeCompletion/function-overloads-inside-param.cpp === --- /dev/null +++ test/CodeCompletion/function-overloads-inside-param.cpp @@ -0,0 +1,8 @@ +void f(int i, int j = 2, int k = 5); +void f(float x, float y...); + +void test() { + ::f(1 + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:5:8 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s + // CHECK-CC1: f(<#int i#>{#, <#int j = 2#>{#, <#int k = 5#>#}#}) + // CHECK-CC1: f(<#float x#>, <#float y, ...#>) Index: lib/Parse/ParseExpr.cpp === --- lib/Parse/ParseExpr.cpp +++ lib/Parse/ParseExpr.cpp @@ -1657,10 +1657,21 @@ if (OpKind == tok::l_paren || !LHS.isInvalid()) { if (Tok.isNot(tok::r_paren)) { - if (ParseExpressionList(ArgExprs, CommaLocs, [&] { -Actions.CodeCompleteCall(getCurScope(), LHS.get(), ArgExprs); - })) { + auto Completer = [&] { +Actions.CodeCompleteCall(getCurScope(), LHS.get(), ArgExprs); +CalledOverloadCompletion = true; + }; + if (ParseExpressionList(ArgExprs, CommaLocs, Completer)) { (void)Actions.CorrectDelayedTyposInExpr(LHS); +// If we got an error when parsing expression list, we don't call +// the CodeCompleteCall handler inside the parser. So call it here +// to make sure we get overload suggestions even when we are in the +// middle of a parameter. There is a different handling mechanism in +// ObjC for that type of completion, so don't call completion and +// let the parser do it instead. +if (!getLangOpts().ObjC1 && PP.isCodeCompletionReached() && +!CalledOverloadCompletion) + Completer(); LHS = ExprError(); } else if (LHS.isInvalid()) { for (auto &E : ArgExprs) Index: include/clang/Parse/Parser.h === --- include/clang/Parse/Parser.h +++ include/clang/Parse/Parser.h @@ -214,6 +214,10 @@ /// should not be set directly. bool InMessageExpression; + /// Gets set to true after calling CodeCompleteCall, it is for a hack to make + /// signature help working even when it is triggered inside a token. + bool CalledOverloadCompletion = false; + /// The "depth" of the template parameters currently being parsed. unsigned TemplateParameterDepth; Index: test/CodeCompletion/function-overloads.cpp === --- /dev/null +++ test/CodeCompletion/function-overloads.cpp @@ -0,0 +1,8 @@ +void f(int i, int j = 2, int k = 5); +void f(float x, float y...); + +void test() { + ::f( + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:5:7 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s + // CHECK-CC1: f(<#int i#>{#, <#int j = 2#>{#, <#int k = 5#>#}#}) + // CHECK-CC1: f(<#float x#>, <#float y, ...#>) Index: test/CodeCompletion/function-overloads-inside-param.cpp === --- /dev/null +++ test/CodeCompletion/function-overloads-inside-param.cpp @@ -0,0 +1,8 @@ +void f(int i, int j = 2, int k = 5); +void f(float x, float y...); + +void test() { + ::f(1 + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:5:8 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s + // CHECK-CC1: f(<#int i#>{#, <#int j = 2#>{#, <#int k = 5#>#}#}) + // CHECK-CC1: f(<#float x#>, <#float y, ...#>) Index: lib/Parse/ParseExpr.cpp === --- lib/Parse/ParseExpr.cpp +++ lib/Parse/ParseExpr.cpp @@ -1657,10 +1657,21 @@ if (OpKind == tok::l_paren || !LHS.isInvalid()) { if (Tok.isNot(tok::r_paren)) { - if (ParseExpressionList(ArgExprs, CommaLocs, [&] { -Actions.CodeCompleteCall(getCurScope(), LHS.get(), ArgExprs); - })) { + auto Comp
[PATCH] D51102: [clangd] Move function argument snippet disable mechanism from LSP rendering to internal clangd reprensentation.
This revision was automatically updated to reflect the committed changes. Closed by commit rL340527: [clangd] Move function argument snippet disable mechanism from LSP rendering to… (authored by kadircet, committed by ). Herald added a subscriber: llvm-commits. Repository: rL LLVM https://reviews.llvm.org/D51102 Files: clang-tools-extra/trunk/clangd/CodeComplete.cpp clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp Index: clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp === --- clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp +++ clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp @@ -1140,7 +1140,7 @@ // For now we just return one of the doc strings arbitrarily. EXPECT_THAT(A.Documentation, AnyOf(HasSubstr("Overload with int"), HasSubstr("Overload with bool"))); - EXPECT_EQ(A.SnippetSuffix, "(${0})"); + EXPECT_EQ(A.SnippetSuffix, "($0)"); } TEST(CompletionTest, DocumentationFromChangedFileCrash) { @@ -1648,55 +1648,35 @@ SigDoc("Doc from sema"; } -TEST(CompletionTest, RenderWithSnippetsForFunctionArgsDisabled) { +TEST(CompletionTest, CompletionFunctionArgsDisabled) { CodeCompleteOptions Opts; - Opts.EnableFunctionArgSnippets = true; - { -CodeCompletion C; -C.RequiredQualifier = "Foo::"; -C.Name = "x"; -C.SnippetSuffix = "()"; - -auto R = C.render(Opts); -EXPECT_EQ(R.textEdit->newText, "Foo::x"); -EXPECT_EQ(R.insertTextFormat, InsertTextFormat::PlainText); - } - Opts.EnableSnippets = true; Opts.EnableFunctionArgSnippets = false; + const std::string Header = + R"cpp( + void xfoo(); + void xfoo(int x, int y); + void xbar(); + void f() { +)cpp"; { -CodeCompletion C; -C.RequiredQualifier = "Foo::"; -C.Name = "x"; -C.SnippetSuffix = ""; - -auto R = C.render(Opts); -EXPECT_EQ(R.textEdit->newText, "Foo::x"); -EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); +auto Results = completions(Header + "\nxfo^", {}, Opts); +EXPECT_THAT( +Results.Completions, +UnorderedElementsAre(AllOf(Named("xfoo"), SnippetSuffix("()")), + AllOf(Named("xfoo"), SnippetSuffix("($0)"; } - { -CodeCompletion C; -C.RequiredQualifier = "Foo::"; -C.Name = "x"; -C.SnippetSuffix = "()"; -C.Kind = CompletionItemKind::Method; - -auto R = C.render(Opts); -EXPECT_EQ(R.textEdit->newText, "Foo::x()"); -EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); +auto Results = completions(Header + "\nxba^", {}, Opts); +EXPECT_THAT(Results.Completions, UnorderedElementsAre(AllOf( + Named("xbar"), SnippetSuffix("()"; } - { -CodeCompletion C; -C.RequiredQualifier = "Foo::"; -C.Name = "x"; -C.SnippetSuffix = "(${0:bool})"; -C.Kind = CompletionItemKind::Function; - -auto R = C.render(Opts); -EXPECT_EQ(R.textEdit->newText, "Foo::x(${0})"); -EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); +Opts.BundleOverloads = true; +auto Results = completions(Header + "\nxfo^", {}, Opts); +EXPECT_THAT( +Results.Completions, +UnorderedElementsAre(AllOf(Named("xfoo"), SnippetSuffix("($0)"; } } Index: clang-tools-extra/trunk/clangd/CodeComplete.cpp === --- clang-tools-extra/trunk/clangd/CodeComplete.cpp +++ clang-tools-extra/trunk/clangd/CodeComplete.cpp @@ -269,7 +269,8 @@ CodeCompletionString *SemaCCS, const IncludeInserter &Includes, StringRef FileName, const CodeCompleteOptions &Opts) - : ASTCtx(ASTCtx), ExtractDocumentation(Opts.IncludeComments) { + : ASTCtx(ASTCtx), ExtractDocumentation(Opts.IncludeComments), +EnableFunctionArgSnippets(Opts.EnableFunctionArgSnippets) { add(C, SemaCCS); if (C.SemaResult) { Completion.Origin |= SymbolOrigin::AST; @@ -385,10 +386,17 @@ } std::string summarizeSnippet() const { -if (auto *Snippet = onlyValue<&BundledEntry::SnippetSuffix>()) - return *Snippet; -// All bundles are function calls. -return "(${0})"; +auto *Snippet = onlyValue<&BundledEntry::SnippetSuffix>(); +if (!Snippet) + // All bundles are function calls. + return "($0)"; +if (!Snippet->empty() && !EnableFunctionArgSnippets && +((Completion.Kind == CompletionItemKind::Function) || + (Completion.Kind == CompletionItemKind::Method)) && +(Snippet->front() == '(') && (Snippet->back() == ')')) + // Check whether function has any parameters or not. + return Snippet->size() > 2 ? "($0)" : "()"; +return *Snippet; } std::string summarizeSignature() const { @@ -402,6 +410,7 @@ CodeC
[PATCH] D50898: [clangd] Suggest code-completions for overriding base class virtual methods.
kadircet updated this revision to Diff 162151. kadircet added a comment. - Resolve discussions. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50898 Files: clangd/CodeComplete.cpp clangd/CodeComplete.h unittests/clangd/CodeCompleteTests.cpp Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -61,6 +61,7 @@ MATCHER(InsertInclude, "") { return bool(arg.HeaderInsertion); } MATCHER_P(SnippetSuffix, Text, "") { return arg.SnippetSuffix == Text; } MATCHER_P(Origin, OriginSet, "") { return arg.Origin == OriginSet; } +MATCHER(IsOverride, "") { return bool(arg.IsOverride); } // Shorthand for Contains(Named(Name)). Matcher &> Has(std::string Name) { @@ -1700,6 +1701,58 @@ } } +TEST(CompletionTest, SuggestOverrides) { + constexpr const char *const Text(R"cpp( + class A { + public: +virtual void vfunc(bool param); +virtual void vfunc(bool param, int p); +void func(bool param); + }; + class B : public A { + virtual void ttt(bool param); + void vfunc(bool param, int p) override; + }; + class C : public B { + public: +void vfunc(bool param) override; +^ + }; + )cpp"); + const auto Results = completions(Text); + EXPECT_THAT(Results.Completions, + AllOf(Contains(AllOf(Named("vfunc"), IsOverride(), + Labeled("vfunc(bool param, int p)"))), +Contains(AllOf(Named("ttt"), IsOverride(), + Labeled("ttt(bool param)"))), +Not(Contains(AllOf(Named("vfunc"), IsOverride(), + Labeled("vfunc(bool param)")); +} + +TEST(CompletionTest, RenderOverride) { + CodeCompletion C; + C.Name = "x"; + C.Signature = "(bool) const"; + C.SnippetSuffix = "(${0:bool})"; + C.ReturnType = "int"; + C.Documentation = "This is x()."; + C.Kind = CompletionItemKind::Method; + C.Score.Total = 1.0; + C.Origin = SymbolOrigin::AST; + C.IsOverride = true; + + CodeCompleteOptions Opts; + Opts.IncludeIndicator.NoInsert = ""; + auto R = C.render(Opts); + EXPECT_EQ(R.label, "int x(bool) const override"); + EXPECT_EQ(R.insertText, "int x(bool) const override"); + EXPECT_EQ(R.insertTextFormat, InsertTextFormat::PlainText); + EXPECT_EQ(R.filterText, "x"); + EXPECT_EQ(R.detail, "int"); + EXPECT_EQ(R.documentation, "This is x()."); + EXPECT_THAT(R.additionalTextEdits, IsEmpty()); +} + } // namespace } // namespace clangd } // namespace clang Index: clangd/CodeComplete.h === --- clangd/CodeComplete.h +++ clangd/CodeComplete.h @@ -131,6 +131,9 @@ /// Holds the range of the token we are going to replace with this completion. Range CompletionTokenRange; + /// Whether this completion is for overriding a virtual method. + bool IsOverride = false; + // Scores are used to rank completion items. struct Scores { // The score that items are ranked by. Index: clangd/CodeComplete.cpp === --- clangd/CodeComplete.cpp +++ clangd/CodeComplete.cpp @@ -188,14 +188,66 @@ return HeaderFile{std::move(*Resolved), /*Verbatim=*/false}; } +// First traverses all method definitions inside current class/struct/union +// definition. Than traverses base classes to find virtual methods that haven't +// been overriden within current context. +// FIXME(kadircet): Currently we cannot see declarations below completion point. +// It is because Sema gets run only upto completion point. Need to find a +// solution to run it for the whole class/struct/union definition. +static std::vector +getNonOverridenMethodCompletionResults(const DeclContext *DC, Sema *S) { + const auto *CR = llvm::dyn_cast(DC); + // If not inside a class/struct/union return empty. + if (!CR) +return {}; + // First store overrides within current class. + // These are stored by name to make querying fast in the later step. + llvm::StringMap> Overrides; + for (auto *Method : CR->methods()) { +if (!Method->isVirtual()) + continue; +Overrides[Method->getName()].push_back(Method); + } + + std::vector Results; + for (const auto &Base : CR->bases()) { +const auto *BR = Base.getType().getTypePtr()->getAsCXXRecordDecl(); +if (!BR) + continue; +for (auto *Method : BR->methods()) { + if (!Method->isVirtual()) +continue; + const auto it = Overrides.find(Method->getName()); + bool IsOverriden = false; + if (it != Overrides.end()) { +for (auto *MD : it->second) { + // If the method in current body is not an overload of this virtual + // function, that it overrides this one. + if (!S->IsOverload(MD, Method, false)) { +IsOverriden = true; +break; + } +} +
[PATCH] D50898: [clangd] Suggest code-completions for overriding base class virtual methods.
kadircet updated this revision to Diff 162157. kadircet added a comment. - Resolve discussions. - Move override generation logic from render to item generation so that internal clients can use it as well, also use a boolean for checking override status of a bundle to be more efficient. - Change unittests accordingly, get rid of unused IsOverride field. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50898 Files: clangd/CodeComplete.cpp unittests/clangd/CodeCompleteTests.cpp Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -1680,6 +1680,31 @@ } } +TEST(CompletionTest, SuggestOverrides) { + constexpr const char *const Text(R"cpp( + class A { + public: +virtual void vfunc(bool param); +virtual void vfunc(bool param, int p); +void func(bool param); + }; + class B : public A { + virtual void ttt(bool param) const; + void vfunc(bool param, int p) override; + }; + class C : public B { + public: +void vfunc(bool param) override; +^ + }; + )cpp"); + const auto Results = completions(Text); + EXPECT_THAT(Results.Completions, + AllOf(Contains(Labeled("void vfunc(bool param, int p) override")), +Contains(Labeled("void ttt(bool param) const override")), +Not(Contains(Labeled("void vfunc(bool param) override"); +} + } // namespace } // namespace clangd } // namespace clang Index: clangd/CodeComplete.cpp === --- clangd/CodeComplete.cpp +++ clangd/CodeComplete.cpp @@ -188,14 +188,66 @@ return HeaderFile{std::move(*Resolved), /*Verbatim=*/false}; } +// First traverses all method definitions inside current class/struct/union +// definition. Than traverses base classes to find virtual methods that haven't +// been overriden within current context. +// FIXME(kadircet): Currently we cannot see declarations below completion point. +// It is because Sema gets run only upto completion point. Need to find a +// solution to run it for the whole class/struct/union definition. +static std::vector +getNonOverridenMethodCompletionResults(const DeclContext *DC, Sema *S) { + const auto *CR = llvm::dyn_cast(DC); + // If not inside a class/struct/union return empty. + if (!CR) +return {}; + // First store overrides within current class. + // These are stored by name to make querying fast in the later step. + llvm::StringMap> Overrides; + for (auto *Method : CR->methods()) { +if (!Method->isVirtual()) + continue; +Overrides[Method->getName()].push_back(Method); + } + + std::vector Results; + for (const auto &Base : CR->bases()) { +const auto *BR = Base.getType().getTypePtr()->getAsCXXRecordDecl(); +if (!BR) + continue; +for (auto *Method : BR->methods()) { + if (!Method->isVirtual()) +continue; + const auto it = Overrides.find(Method->getName()); + bool IsOverriden = false; + if (it != Overrides.end()) { +for (auto *MD : it->second) { + // If the method in current body is not an overload of this virtual + // function, that it overrides this one. + if (!S->IsOverload(MD, Method, false)) { +IsOverriden = true; +break; + } +} + } + if (!IsOverriden) +Results.emplace_back(Method, 0); +} + } + + return Results; +} + /// A code completion result, in clang-native form. /// It may be promoted to a CompletionItem if it's among the top-ranked results. struct CompletionCandidate { llvm::StringRef Name; // Used for filtering and sorting. // We may have a result from Sema, from the index, or both. const CodeCompletionResult *SemaResult = nullptr; const Symbol *IndexResult = nullptr; + // States whether this item is an override suggestion. + bool IsOverride = false; + // Returns a token identifying the overload set this is part of. // 0 indicates it's not part of any overload set. size_t overloadSet() const { @@ -352,21 +404,30 @@ Completion.Documentation = getDocComment(ASTCtx, *C.SemaResult, /*CommentsFromHeader=*/false); } +if (C.IsOverride) + S.OverrideSuffix = true; } CodeCompletion build() { Completion.ReturnType = summarizeReturnType(); Completion.Signature = summarizeSignature(); Completion.SnippetSuffix = summarizeSnippet(); Completion.BundleSize = Bundled.size(); +if (summarizeOverride()) { + Completion.Name = Completion.ReturnType + ' ' + +std::move(Completion.Name) + +std::move(Completion.Signature) + " override"; + Completion.Signature.clear(); +} return std::move(Completion); } private: struct BundledEntry { std::str
[PATCH] D50898: [clangd] Suggest code-completions for overriding base class virtual methods.
This revision was automatically updated to reflect the committed changes. Closed by commit rCTE340530: [clangd] Suggest code-completions for overriding base class virtual methods. (authored by kadircet, committed by ). Changed prior to commit: https://reviews.llvm.org/D50898?vs=162157&id=162158#toc Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50898 Files: clangd/CodeComplete.cpp unittests/clangd/CodeCompleteTests.cpp Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -1680,6 +1680,31 @@ } } +TEST(CompletionTest, SuggestOverrides) { + constexpr const char *const Text(R"cpp( + class A { + public: +virtual void vfunc(bool param); +virtual void vfunc(bool param, int p); +void func(bool param); + }; + class B : public A { + virtual void ttt(bool param) const; + void vfunc(bool param, int p) override; + }; + class C : public B { + public: +void vfunc(bool param) override; +^ + }; + )cpp"); + const auto Results = completions(Text); + EXPECT_THAT(Results.Completions, + AllOf(Contains(Labeled("void vfunc(bool param, int p) override")), +Contains(Labeled("void ttt(bool param) const override")), +Not(Contains(Labeled("void vfunc(bool param) override"); +} + } // namespace } // namespace clangd } // namespace clang Index: clangd/CodeComplete.cpp === --- clangd/CodeComplete.cpp +++ clangd/CodeComplete.cpp @@ -188,14 +188,66 @@ return HeaderFile{std::move(*Resolved), /*Verbatim=*/false}; } +// First traverses all method definitions inside current class/struct/union +// definition. Than traverses base classes to find virtual methods that haven't +// been overriden within current context. +// FIXME(kadircet): Currently we cannot see declarations below completion point. +// It is because Sema gets run only upto completion point. Need to find a +// solution to run it for the whole class/struct/union definition. +static std::vector +getNonOverridenMethodCompletionResults(const DeclContext *DC, Sema *S) { + const auto *CR = llvm::dyn_cast(DC); + // If not inside a class/struct/union return empty. + if (!CR) +return {}; + // First store overrides within current class. + // These are stored by name to make querying fast in the later step. + llvm::StringMap> Overrides; + for (auto *Method : CR->methods()) { +if (!Method->isVirtual()) + continue; +Overrides[Method->getName()].push_back(Method); + } + + std::vector Results; + for (const auto &Base : CR->bases()) { +const auto *BR = Base.getType().getTypePtr()->getAsCXXRecordDecl(); +if (!BR) + continue; +for (auto *Method : BR->methods()) { + if (!Method->isVirtual()) +continue; + const auto it = Overrides.find(Method->getName()); + bool IsOverriden = false; + if (it != Overrides.end()) { +for (auto *MD : it->second) { + // If the method in current body is not an overload of this virtual + // function, that it overrides this one. + if (!S->IsOverload(MD, Method, false)) { +IsOverriden = true; +break; + } +} + } + if (!IsOverriden) +Results.emplace_back(Method, 0); +} + } + + return Results; +} + /// A code completion result, in clang-native form. /// It may be promoted to a CompletionItem if it's among the top-ranked results. struct CompletionCandidate { llvm::StringRef Name; // Used for filtering and sorting. // We may have a result from Sema, from the index, or both. const CodeCompletionResult *SemaResult = nullptr; const Symbol *IndexResult = nullptr; + // States whether this item is an override suggestion. + bool IsOverride = false; + // Returns a token identifying the overload set this is part of. // 0 indicates it's not part of any overload set. size_t overloadSet() const { @@ -352,21 +404,30 @@ Completion.Documentation = getDocComment(ASTCtx, *C.SemaResult, /*CommentsFromHeader=*/false); } +if (C.IsOverride) + S.OverrideSuffix = true; } CodeCompletion build() { Completion.ReturnType = summarizeReturnType(); Completion.Signature = summarizeSignature(); Completion.SnippetSuffix = summarizeSnippet(); Completion.BundleSize = Bundled.size(); +if (summarizeOverride()) { + Completion.Name = Completion.ReturnType + ' ' + +std::move(Completion.Name) + +std::move(Completion.Signature) + " override"; + Completion.Signature.clear(); +} return std::move(Completion); } private: struct BundledEntry { std::string SnippetSuffix; std::string Signature; std
[PATCH] D51163: [clangd] Check for include overlapping looks for only the line now.
kadircet created this revision. kadircet added reviewers: ilya-biryukov, hokein, ioeric. Herald added subscribers: cfe-commits, arphaman, jkorous, MaskRay. Currently we match an include only if we are inside filename, with this patch we will match whenever we are on the starting line of the include. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D51163 Files: clangd/XRefs.cpp unittests/clangd/XRefsTests.cpp Index: unittests/clangd/XRefsTests.cpp === --- unittests/clangd/XRefsTests.cpp +++ unittests/clangd/XRefsTests.cpp @@ -1014,11 +1014,13 @@ Locations = runFindDefinitions(Server, FooCpp, SourceAnnotations.point("5")); ASSERT_TRUE(bool(Locations)) << "findDefinitions returned an error"; - EXPECT_THAT(*Locations, IsEmpty()); + EXPECT_THAT(*Locations, + ElementsAre(Location{FooHUri, HeaderAnnotations.range()})); Locations = runFindDefinitions(Server, FooCpp, SourceAnnotations.point("7")); ASSERT_TRUE(bool(Locations)) << "findDefinitions returned an error"; - EXPECT_THAT(*Locations, IsEmpty()); + EXPECT_THAT(*Locations, + ElementsAre(Location{FooHUri, HeaderAnnotations.range()})); } TEST(GoToDefinition, WithPreamble) { Index: clangd/XRefs.cpp === --- clangd/XRefs.cpp +++ clangd/XRefs.cpp @@ -211,7 +211,7 @@ std::vector Result; // Handle goto definition for #include. for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) { -if (!Inc.Resolved.empty() && Inc.R.contains(Pos)) +if (!Inc.Resolved.empty() && Inc.R.start.line == Pos.line) Result.push_back(Location{URIForFile{Inc.Resolved}, {}}); } if (!Result.empty()) Index: unittests/clangd/XRefsTests.cpp === --- unittests/clangd/XRefsTests.cpp +++ unittests/clangd/XRefsTests.cpp @@ -1014,11 +1014,13 @@ Locations = runFindDefinitions(Server, FooCpp, SourceAnnotations.point("5")); ASSERT_TRUE(bool(Locations)) << "findDefinitions returned an error"; - EXPECT_THAT(*Locations, IsEmpty()); + EXPECT_THAT(*Locations, + ElementsAre(Location{FooHUri, HeaderAnnotations.range()})); Locations = runFindDefinitions(Server, FooCpp, SourceAnnotations.point("7")); ASSERT_TRUE(bool(Locations)) << "findDefinitions returned an error"; - EXPECT_THAT(*Locations, IsEmpty()); + EXPECT_THAT(*Locations, + ElementsAre(Location{FooHUri, HeaderAnnotations.range()})); } TEST(GoToDefinition, WithPreamble) { Index: clangd/XRefs.cpp === --- clangd/XRefs.cpp +++ clangd/XRefs.cpp @@ -211,7 +211,7 @@ std::vector Result; // Handle goto definition for #include. for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) { -if (!Inc.Resolved.empty() && Inc.R.contains(Pos)) +if (!Inc.Resolved.empty() && Inc.R.start.line == Pos.line) Result.push_back(Location{URIForFile{Inc.Resolved}, {}}); } if (!Result.empty()) ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D51163: [clangd] Check for include overlapping looks for only the line now.
This revision was automatically updated to reflect the committed changes. Closed by commit rL340539: [clangd] Check for include overlapping looks for only the line now. (authored by kadircet, committed by ). Herald added a subscriber: llvm-commits. Repository: rL LLVM https://reviews.llvm.org/D51163 Files: clang-tools-extra/trunk/clangd/XRefs.cpp clang-tools-extra/trunk/unittests/clangd/XRefsTests.cpp Index: clang-tools-extra/trunk/unittests/clangd/XRefsTests.cpp === --- clang-tools-extra/trunk/unittests/clangd/XRefsTests.cpp +++ clang-tools-extra/trunk/unittests/clangd/XRefsTests.cpp @@ -1014,11 +1014,13 @@ Locations = runFindDefinitions(Server, FooCpp, SourceAnnotations.point("5")); ASSERT_TRUE(bool(Locations)) << "findDefinitions returned an error"; - EXPECT_THAT(*Locations, IsEmpty()); + EXPECT_THAT(*Locations, + ElementsAre(Location{FooHUri, HeaderAnnotations.range()})); Locations = runFindDefinitions(Server, FooCpp, SourceAnnotations.point("7")); ASSERT_TRUE(bool(Locations)) << "findDefinitions returned an error"; - EXPECT_THAT(*Locations, IsEmpty()); + EXPECT_THAT(*Locations, + ElementsAre(Location{FooHUri, HeaderAnnotations.range()})); } TEST(GoToDefinition, WithPreamble) { Index: clang-tools-extra/trunk/clangd/XRefs.cpp === --- clang-tools-extra/trunk/clangd/XRefs.cpp +++ clang-tools-extra/trunk/clangd/XRefs.cpp @@ -211,7 +211,7 @@ std::vector Result; // Handle goto definition for #include. for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) { -if (!Inc.Resolved.empty() && Inc.R.contains(Pos)) +if (!Inc.Resolved.empty() && Inc.R.start.line == Pos.line) Result.push_back(Location{URIForFile{Inc.Resolved}, {}}); } if (!Result.empty()) Index: clang-tools-extra/trunk/unittests/clangd/XRefsTests.cpp === --- clang-tools-extra/trunk/unittests/clangd/XRefsTests.cpp +++ clang-tools-extra/trunk/unittests/clangd/XRefsTests.cpp @@ -1014,11 +1014,13 @@ Locations = runFindDefinitions(Server, FooCpp, SourceAnnotations.point("5")); ASSERT_TRUE(bool(Locations)) << "findDefinitions returned an error"; - EXPECT_THAT(*Locations, IsEmpty()); + EXPECT_THAT(*Locations, + ElementsAre(Location{FooHUri, HeaderAnnotations.range()})); Locations = runFindDefinitions(Server, FooCpp, SourceAnnotations.point("7")); ASSERT_TRUE(bool(Locations)) << "findDefinitions returned an error"; - EXPECT_THAT(*Locations, IsEmpty()); + EXPECT_THAT(*Locations, + ElementsAre(Location{FooHUri, HeaderAnnotations.range()})); } TEST(GoToDefinition, WithPreamble) { Index: clang-tools-extra/trunk/clangd/XRefs.cpp === --- clang-tools-extra/trunk/clangd/XRefs.cpp +++ clang-tools-extra/trunk/clangd/XRefs.cpp @@ -211,7 +211,7 @@ std::vector Result; // Handle goto definition for #include. for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) { -if (!Inc.Resolved.empty() && Inc.R.contains(Pos)) +if (!Inc.Resolved.empty() && Inc.R.start.line == Pos.line) Result.push_back(Location{URIForFile{Inc.Resolved}, {}}); } if (!Result.empty()) ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50502: [clangd] Initial cancellation mechanism for LSP requests.
kadircet updated this revision to Diff 162342. kadircet marked 3 inline comments as done. kadircet added a comment. - Change a few comments. - Add some assertions. - Fix a data race. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50502 Files: clangd/CMakeLists.txt clangd/Cancellation.cpp clangd/Cancellation.h clangd/ClangdLSPServer.cpp clangd/ClangdLSPServer.h clangd/ClangdServer.cpp clangd/ClangdServer.h clangd/JSONRPCDispatcher.cpp clangd/JSONRPCDispatcher.h clangd/Protocol.cpp clangd/Protocol.h clangd/ProtocolHandlers.cpp clangd/ProtocolHandlers.h unittests/clangd/CMakeLists.txt unittests/clangd/CancellationTests.cpp Index: unittests/clangd/CancellationTests.cpp === --- /dev/null +++ unittests/clangd/CancellationTests.cpp @@ -0,0 +1,74 @@ +#include "Cancellation.h" +#include "Context.h" +#include "Threading.h" +#include "llvm/Support/Error.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include +#include +#include + +namespace clang { +namespace clangd { +namespace { + +TEST(CancellationTest, CancellationTest) { + TaskHandle TH = Task::createHandle(); + WithContext ContextWithCancellation(setCurrentTask(TH)); + EXPECT_FALSE(isCancelled()); + TH->cancel(); + EXPECT_TRUE(isCancelled()); +} + +TEST(CancellationTest, TaskTestHandleDiesContextLives) { + llvm::Optional ContextWithCancellation; + { +TaskHandle TH = Task::createHandle(); +ContextWithCancellation.emplace(setCurrentTask(TH)); +EXPECT_FALSE(isCancelled()); +TH->cancel(); +EXPECT_TRUE(isCancelled()); + } + EXPECT_TRUE(isCancelled()); +} + +TEST(CancellationTest, TaskContextDiesHandleLives) { + TaskHandle TH = Task::createHandle(); + { +WithContext ContextWithCancellation(setCurrentTask(TH)); +EXPECT_FALSE(isCancelled()); +TH->cancel(); +EXPECT_TRUE(isCancelled()); + } + // Still should be able to cancel without any problems. + TH->cancel(); +} + +TEST(CancellationTest, CancellationToken) { + TaskHandle TH = Task::createHandle(); + WithContext ContextWithCancellation(setCurrentTask(TH)); + const auto &CT = getCurrentTask(); + EXPECT_FALSE(CT.isCancelled()); + TH->cancel(); + EXPECT_TRUE(CT.isCancelled()); +} + +TEST(CancellationTest, AsynCancellationTest) { + std::atomic HasCancelled(false); + Notification Cancelled; + auto TaskToBeCancelled = [&](ConstTaskHandle CT) { +WithContext ContextGuard(setCurrentTask(std::move(CT))); +Cancelled.wait(); +HasCancelled = isCancelled(); + }; + TaskHandle TH = Task::createHandle(); + std::thread AsyncTask(TaskToBeCancelled, TH); + TH->cancel(); + Cancelled.notify(); + AsyncTask.join(); + + EXPECT_TRUE(HasCancelled); +} +} // namespace +} // namespace clangd +} // namespace clang Index: unittests/clangd/CMakeLists.txt === --- unittests/clangd/CMakeLists.txt +++ unittests/clangd/CMakeLists.txt @@ -10,6 +10,7 @@ add_extra_unittest(ClangdTests Annotations.cpp + CancellationTests.cpp ClangdTests.cpp ClangdUnitTests.cpp CodeCompleteTests.cpp Index: clangd/ProtocolHandlers.h === --- clangd/ProtocolHandlers.h +++ clangd/ProtocolHandlers.h @@ -55,6 +55,7 @@ virtual void onDocumentHighlight(TextDocumentPositionParams &Params) = 0; virtual void onHover(TextDocumentPositionParams &Params) = 0; virtual void onChangeConfiguration(DidChangeConfigurationParams &Params) = 0; + virtual void onCancelRequest(CancelParams &Params) = 0; }; void registerCallbackHandlers(JSONRPCDispatcher &Dispatcher, Index: clangd/ProtocolHandlers.cpp === --- clangd/ProtocolHandlers.cpp +++ clangd/ProtocolHandlers.cpp @@ -75,4 +75,5 @@ Register("workspace/didChangeConfiguration", &ProtocolCallbacks::onChangeConfiguration); Register("workspace/symbol", &ProtocolCallbacks::onWorkspaceSymbol); + Register("$/cancelRequest", &ProtocolCallbacks::onCancelRequest); } Index: clangd/Protocol.h === --- clangd/Protocol.h +++ clangd/Protocol.h @@ -867,6 +867,22 @@ llvm::json::Value toJSON(const DocumentHighlight &DH); llvm::raw_ostream &operator<<(llvm::raw_ostream &, const DocumentHighlight &); +struct CancelParams { + /// The request id to cancel. + /// This can be either a number or string, if it is a number simply print it + /// out and always use a string. + std::string ID; +}; +llvm::json::Value toJSON(const CancelParams &); +llvm::raw_ostream &operator<<(llvm::raw_ostream &, const CancelParams &); +bool fromJSON(const llvm::json::Value &, CancelParams &); + +/// Parses the Field in Params into Parsed. Params[Field] can be either of type +/// string or number. Returns true if parsing was succesful. In case of a number +/// converts it into a string
[PATCH] D50502: [clangd] Initial cancellation mechanism for LSP requests.
kadircet marked 2 inline comments as done. kadircet added inline comments. Comment at: clangd/ClangdLSPServer.cpp:351 + [this](llvm::Expected List) { +auto _ = llvm::make_scope_exit([this]() { CleanupTaskHandle(); }); + ilya-biryukov wrote: > CleanupTaskHandle() can run in a separate thread, so can potentially run > before the `StoreTaskHandle` call. > To avoid memory leaks in that case, let's preallocate the entry **before** > calling `codeComplete` Thanks! Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50502 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50502: [clangd] Initial cancellation mechanism for LSP requests.
kadircet added inline comments. Comment at: clangd/Protocol.h:883 +/// converts it into a string. +bool parseNumberOrString(const llvm::json::Value &Params, std::string &Parsed, + const std::string &Field); ilya-biryukov wrote: > Maybe simplify the signature to: `Optional parseNumberOrString(const > llvm::json::Value&);` > And call as `parseNumberOrString(obj["id"])` instead of > `parseNumberOrString(obj, "id")`? > > Also, maybe call it `normalizeRequestId`? LSP has a few more places that can have paremeters of type number | string so I believe this one could be used with them as well. Therefore I think it is better to keep the name that way. The normalizeRequestID is a sepcial case and handled within ClangdLSPServer. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50502 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D50502: [clangd] Initial cancellation mechanism for LSP requests.
kadircet updated this revision to Diff 162354. kadircet marked 2 inline comments as done. kadircet added a comment. - Change helper for normalizing Number | String. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50502 Files: clangd/CMakeLists.txt clangd/Cancellation.cpp clangd/Cancellation.h clangd/ClangdLSPServer.cpp clangd/ClangdLSPServer.h clangd/ClangdServer.cpp clangd/ClangdServer.h clangd/JSONRPCDispatcher.cpp clangd/JSONRPCDispatcher.h clangd/Protocol.cpp clangd/Protocol.h clangd/ProtocolHandlers.cpp clangd/ProtocolHandlers.h unittests/clangd/CMakeLists.txt unittests/clangd/CancellationTests.cpp Index: unittests/clangd/CancellationTests.cpp === --- /dev/null +++ unittests/clangd/CancellationTests.cpp @@ -0,0 +1,74 @@ +#include "Cancellation.h" +#include "Context.h" +#include "Threading.h" +#include "llvm/Support/Error.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include +#include +#include + +namespace clang { +namespace clangd { +namespace { + +TEST(CancellationTest, CancellationTest) { + TaskHandle TH = Task::createHandle(); + WithContext ContextWithCancellation(setCurrentTask(TH)); + EXPECT_FALSE(isCancelled()); + TH->cancel(); + EXPECT_TRUE(isCancelled()); +} + +TEST(CancellationTest, TaskTestHandleDiesContextLives) { + llvm::Optional ContextWithCancellation; + { +TaskHandle TH = Task::createHandle(); +ContextWithCancellation.emplace(setCurrentTask(TH)); +EXPECT_FALSE(isCancelled()); +TH->cancel(); +EXPECT_TRUE(isCancelled()); + } + EXPECT_TRUE(isCancelled()); +} + +TEST(CancellationTest, TaskContextDiesHandleLives) { + TaskHandle TH = Task::createHandle(); + { +WithContext ContextWithCancellation(setCurrentTask(TH)); +EXPECT_FALSE(isCancelled()); +TH->cancel(); +EXPECT_TRUE(isCancelled()); + } + // Still should be able to cancel without any problems. + TH->cancel(); +} + +TEST(CancellationTest, CancellationToken) { + TaskHandle TH = Task::createHandle(); + WithContext ContextWithCancellation(setCurrentTask(TH)); + const auto &CT = getCurrentTask(); + EXPECT_FALSE(CT.isCancelled()); + TH->cancel(); + EXPECT_TRUE(CT.isCancelled()); +} + +TEST(CancellationTest, AsynCancellationTest) { + std::atomic HasCancelled(false); + Notification Cancelled; + auto TaskToBeCancelled = [&](ConstTaskHandle CT) { +WithContext ContextGuard(setCurrentTask(std::move(CT))); +Cancelled.wait(); +HasCancelled = isCancelled(); + }; + TaskHandle TH = Task::createHandle(); + std::thread AsyncTask(TaskToBeCancelled, TH); + TH->cancel(); + Cancelled.notify(); + AsyncTask.join(); + + EXPECT_TRUE(HasCancelled); +} +} // namespace +} // namespace clangd +} // namespace clang Index: unittests/clangd/CMakeLists.txt === --- unittests/clangd/CMakeLists.txt +++ unittests/clangd/CMakeLists.txt @@ -10,6 +10,7 @@ add_extra_unittest(ClangdTests Annotations.cpp + CancellationTests.cpp ClangdTests.cpp ClangdUnitTests.cpp CodeCompleteTests.cpp Index: clangd/ProtocolHandlers.h === --- clangd/ProtocolHandlers.h +++ clangd/ProtocolHandlers.h @@ -55,6 +55,7 @@ virtual void onDocumentHighlight(TextDocumentPositionParams &Params) = 0; virtual void onHover(TextDocumentPositionParams &Params) = 0; virtual void onChangeConfiguration(DidChangeConfigurationParams &Params) = 0; + virtual void onCancelRequest(CancelParams &Params) = 0; }; void registerCallbackHandlers(JSONRPCDispatcher &Dispatcher, Index: clangd/ProtocolHandlers.cpp === --- clangd/ProtocolHandlers.cpp +++ clangd/ProtocolHandlers.cpp @@ -75,4 +75,5 @@ Register("workspace/didChangeConfiguration", &ProtocolCallbacks::onChangeConfiguration); Register("workspace/symbol", &ProtocolCallbacks::onWorkspaceSymbol); + Register("$/cancelRequest", &ProtocolCallbacks::onCancelRequest); } Index: clangd/Protocol.h === --- clangd/Protocol.h +++ clangd/Protocol.h @@ -867,6 +867,20 @@ llvm::json::Value toJSON(const DocumentHighlight &DH); llvm::raw_ostream &operator<<(llvm::raw_ostream &, const DocumentHighlight &); +struct CancelParams { + /// The request id to cancel. + /// This can be either a number or string, if it is a number simply print it + /// out and always use a string. + std::string ID; +}; +llvm::json::Value toJSON(const CancelParams &); +llvm::raw_ostream &operator<<(llvm::raw_ostream &, const CancelParams &); +bool fromJSON(const llvm::json::Value &, CancelParams &); + +/// Param can be either of type string or number. Returns the result as a +/// string. +llvm::Optional parseNumberOrString(const llvm::json::Value *Param); + } // namespace clangd } // namespace clang Index
[PATCH] D50502: [clangd] Initial cancellation mechanism for LSP requests.
kadircet updated this revision to Diff 162365. kadircet marked 2 inline comments as done. kadircet added a comment. - Resolve comments. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D50502 Files: clangd/CMakeLists.txt clangd/Cancellation.cpp clangd/Cancellation.h clangd/ClangdLSPServer.cpp clangd/ClangdLSPServer.h clangd/ClangdServer.cpp clangd/ClangdServer.h clangd/JSONRPCDispatcher.cpp clangd/JSONRPCDispatcher.h clangd/Protocol.cpp clangd/Protocol.h clangd/ProtocolHandlers.cpp clangd/ProtocolHandlers.h unittests/clangd/CMakeLists.txt unittests/clangd/CancellationTests.cpp Index: unittests/clangd/CancellationTests.cpp === --- /dev/null +++ unittests/clangd/CancellationTests.cpp @@ -0,0 +1,74 @@ +#include "Cancellation.h" +#include "Context.h" +#include "Threading.h" +#include "llvm/Support/Error.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include +#include +#include + +namespace clang { +namespace clangd { +namespace { + +TEST(CancellationTest, CancellationTest) { + TaskHandle TH = Task::createHandle(); + WithContext ContextWithCancellation(setCurrentTask(TH)); + EXPECT_FALSE(isCancelled()); + TH->cancel(); + EXPECT_TRUE(isCancelled()); +} + +TEST(CancellationTest, TaskTestHandleDiesContextLives) { + llvm::Optional ContextWithCancellation; + { +TaskHandle TH = Task::createHandle(); +ContextWithCancellation.emplace(setCurrentTask(TH)); +EXPECT_FALSE(isCancelled()); +TH->cancel(); +EXPECT_TRUE(isCancelled()); + } + EXPECT_TRUE(isCancelled()); +} + +TEST(CancellationTest, TaskContextDiesHandleLives) { + TaskHandle TH = Task::createHandle(); + { +WithContext ContextWithCancellation(setCurrentTask(TH)); +EXPECT_FALSE(isCancelled()); +TH->cancel(); +EXPECT_TRUE(isCancelled()); + } + // Still should be able to cancel without any problems. + TH->cancel(); +} + +TEST(CancellationTest, CancellationToken) { + TaskHandle TH = Task::createHandle(); + WithContext ContextWithCancellation(setCurrentTask(TH)); + const auto &CT = getCurrentTask(); + EXPECT_FALSE(CT.isCancelled()); + TH->cancel(); + EXPECT_TRUE(CT.isCancelled()); +} + +TEST(CancellationTest, AsynCancellationTest) { + std::atomic HasCancelled(false); + Notification Cancelled; + auto TaskToBeCancelled = [&](ConstTaskHandle CT) { +WithContext ContextGuard(setCurrentTask(std::move(CT))); +Cancelled.wait(); +HasCancelled = isCancelled(); + }; + TaskHandle TH = Task::createHandle(); + std::thread AsyncTask(TaskToBeCancelled, TH); + TH->cancel(); + Cancelled.notify(); + AsyncTask.join(); + + EXPECT_TRUE(HasCancelled); +} +} // namespace +} // namespace clangd +} // namespace clang Index: unittests/clangd/CMakeLists.txt === --- unittests/clangd/CMakeLists.txt +++ unittests/clangd/CMakeLists.txt @@ -10,6 +10,7 @@ add_extra_unittest(ClangdTests Annotations.cpp + CancellationTests.cpp ClangdTests.cpp ClangdUnitTests.cpp CodeCompleteTests.cpp Index: clangd/ProtocolHandlers.h === --- clangd/ProtocolHandlers.h +++ clangd/ProtocolHandlers.h @@ -55,6 +55,7 @@ virtual void onDocumentHighlight(TextDocumentPositionParams &Params) = 0; virtual void onHover(TextDocumentPositionParams &Params) = 0; virtual void onChangeConfiguration(DidChangeConfigurationParams &Params) = 0; + virtual void onCancelRequest(CancelParams &Params) = 0; }; void registerCallbackHandlers(JSONRPCDispatcher &Dispatcher, Index: clangd/ProtocolHandlers.cpp === --- clangd/ProtocolHandlers.cpp +++ clangd/ProtocolHandlers.cpp @@ -75,4 +75,5 @@ Register("workspace/didChangeConfiguration", &ProtocolCallbacks::onChangeConfiguration); Register("workspace/symbol", &ProtocolCallbacks::onWorkspaceSymbol); + Register("$/cancelRequest", &ProtocolCallbacks::onCancelRequest); } Index: clangd/Protocol.h === --- clangd/Protocol.h +++ clangd/Protocol.h @@ -867,6 +867,20 @@ llvm::json::Value toJSON(const DocumentHighlight &DH); llvm::raw_ostream &operator<<(llvm::raw_ostream &, const DocumentHighlight &); +struct CancelParams { + /// The request id to cancel. + /// This can be either a number or string, if it is a number simply print it + /// out and always use a string. + std::string ID; +}; +llvm::json::Value toJSON(const CancelParams &); +llvm::raw_ostream &operator<<(llvm::raw_ostream &, const CancelParams &); +bool fromJSON(const llvm::json::Value &, CancelParams &); + +/// Param can be either of type string or number. Returns the result as a +/// string. +llvm::Optional parseNumberOrString(const llvm::json::Value *Param); + } // namespace clangd } // namespace clang Index: clangd/Protocol.cpp ===
[PATCH] D50502: [clangd] Initial cancellation mechanism for LSP requests.
This revision was automatically updated to reflect the committed changes. Closed by commit rL340607: [clangd] Initial cancellation mechanism for LSP requests. (authored by kadircet, committed by ). Herald added a subscriber: llvm-commits. Changed prior to commit: https://reviews.llvm.org/D50502?vs=162365&id=162366#toc Repository: rL LLVM https://reviews.llvm.org/D50502 Files: clang-tools-extra/trunk/clangd/CMakeLists.txt clang-tools-extra/trunk/clangd/Cancellation.cpp clang-tools-extra/trunk/clangd/Cancellation.h clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp clang-tools-extra/trunk/clangd/ClangdLSPServer.h clang-tools-extra/trunk/clangd/ClangdServer.cpp clang-tools-extra/trunk/clangd/ClangdServer.h clang-tools-extra/trunk/clangd/JSONRPCDispatcher.cpp clang-tools-extra/trunk/clangd/JSONRPCDispatcher.h clang-tools-extra/trunk/clangd/Protocol.cpp clang-tools-extra/trunk/clangd/Protocol.h clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp clang-tools-extra/trunk/clangd/ProtocolHandlers.h clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt clang-tools-extra/trunk/unittests/clangd/CancellationTests.cpp Index: clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt === --- clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt +++ clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt @@ -10,6 +10,7 @@ add_extra_unittest(ClangdTests Annotations.cpp + CancellationTests.cpp ClangdTests.cpp ClangdUnitTests.cpp CodeCompleteTests.cpp Index: clang-tools-extra/trunk/unittests/clangd/CancellationTests.cpp === --- clang-tools-extra/trunk/unittests/clangd/CancellationTests.cpp +++ clang-tools-extra/trunk/unittests/clangd/CancellationTests.cpp @@ -0,0 +1,74 @@ +#include "Cancellation.h" +#include "Context.h" +#include "Threading.h" +#include "llvm/Support/Error.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include +#include +#include + +namespace clang { +namespace clangd { +namespace { + +TEST(CancellationTest, CancellationTest) { + TaskHandle TH = Task::createHandle(); + WithContext ContextWithCancellation(setCurrentTask(TH)); + EXPECT_FALSE(isCancelled()); + TH->cancel(); + EXPECT_TRUE(isCancelled()); +} + +TEST(CancellationTest, TaskTestHandleDiesContextLives) { + llvm::Optional ContextWithCancellation; + { +TaskHandle TH = Task::createHandle(); +ContextWithCancellation.emplace(setCurrentTask(TH)); +EXPECT_FALSE(isCancelled()); +TH->cancel(); +EXPECT_TRUE(isCancelled()); + } + EXPECT_TRUE(isCancelled()); +} + +TEST(CancellationTest, TaskContextDiesHandleLives) { + TaskHandle TH = Task::createHandle(); + { +WithContext ContextWithCancellation(setCurrentTask(TH)); +EXPECT_FALSE(isCancelled()); +TH->cancel(); +EXPECT_TRUE(isCancelled()); + } + // Still should be able to cancel without any problems. + TH->cancel(); +} + +TEST(CancellationTest, CancellationToken) { + TaskHandle TH = Task::createHandle(); + WithContext ContextWithCancellation(setCurrentTask(TH)); + const auto &CT = getCurrentTask(); + EXPECT_FALSE(CT.isCancelled()); + TH->cancel(); + EXPECT_TRUE(CT.isCancelled()); +} + +TEST(CancellationTest, AsynCancellationTest) { + std::atomic HasCancelled(false); + Notification Cancelled; + auto TaskToBeCancelled = [&](ConstTaskHandle CT) { +WithContext ContextGuard(setCurrentTask(std::move(CT))); +Cancelled.wait(); +HasCancelled = isCancelled(); + }; + TaskHandle TH = Task::createHandle(); + std::thread AsyncTask(TaskToBeCancelled, TH); + TH->cancel(); + Cancelled.notify(); + AsyncTask.join(); + + EXPECT_TRUE(HasCancelled); +} +} // namespace +} // namespace clangd +} // namespace clang Index: clang-tools-extra/trunk/clangd/Protocol.cpp === --- clang-tools-extra/trunk/clangd/Protocol.cpp +++ clang-tools-extra/trunk/clangd/Protocol.cpp @@ -616,5 +616,38 @@ O.map("compilationDatabaseChanges", CCPC.compilationDatabaseChanges); } +json::Value toJSON(const CancelParams &CP) { + return json::Object{{"id", CP.ID}}; +} + +llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const CancelParams &CP) { + O << toJSON(CP); + return O; +} + +llvm::Optional parseNumberOrString(const json::Value *Params) { + if (!Params) +return llvm::None; + // ID is either a number or a string, check for both. + if(const auto AsString = Params->getAsString()) +return AsString->str(); + + if(const auto AsNumber = Params->getAsInteger()) +return itostr(AsNumber.getValue()); + + return llvm::None; +} + +bool fromJSON(const json::Value &Params, CancelParams &CP) { + const auto ParamsAsObject = Params.getAsObject(); + if (!ParamsAsObject) +return false; + if (auto Parsed = parseNumberOrString(ParamsAsObject->get("id"))) { +CP.ID = std::move(*Parsed); +return true;
[PATCH] D51214: [clangd] Add options to enable/disable fixits and function argument snippets.
kadircet created this revision. kadircet added reviewers: hokein, ioeric, ilya-biryukov. Herald added subscribers: cfe-commits, arphaman, jkorous, MaskRay. Currently LSP clients cannot directly change IncludeFixIts or EnableFunctionArgSnippets parameters. This patch is to provide them with a way to enable/disable that functionality. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D51214 Files: clangd/tool/ClangdMain.cpp Index: clangd/tool/ClangdMain.cpp === --- clangd/tool/ClangdMain.cpp +++ clangd/tool/ClangdMain.cpp @@ -194,6 +194,19 @@ "'compile_commands.json' files")), llvm::cl::init(FilesystemCompileArgs), llvm::cl::Hidden); +static llvm::cl::opt IncludeFixIts( +"include-fixits", +llvm::cl::desc( +"Enables suggestion of completion items that needs additional changes. " +"Like changing an arrow(->) member access to dot(.) member access."), +llvm::cl::init(clangd::CodeCompleteOptions().IncludeFixIts)); + +static llvm::cl::opt EnableFunctionArgSnippets( +"enable-function-arg-snippets", +llvm::cl::desc("Gives snippets for function arguments, when disabled only " + "gives parantheses for the call."), +llvm::cl::init(clangd::CodeCompleteOptions().EnableFunctionArgSnippets)); + int main(int argc, char *argv[]) { llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); llvm::cl::SetVersionPrinter([](llvm::raw_ostream &OS) { @@ -309,6 +322,8 @@ CCOpts.IncludeIndicator.NoInsert.clear(); } CCOpts.SpeculativeIndexRequest = Opts.StaticIndex; + CCOpts.IncludeFixIts = IncludeFixIts; + CCOpts.EnableFunctionArgSnippets = EnableFunctionArgSnippets; // Initialize and run ClangdLSPServer. ClangdLSPServer LSPServer( Index: clangd/tool/ClangdMain.cpp === --- clangd/tool/ClangdMain.cpp +++ clangd/tool/ClangdMain.cpp @@ -194,6 +194,19 @@ "'compile_commands.json' files")), llvm::cl::init(FilesystemCompileArgs), llvm::cl::Hidden); +static llvm::cl::opt IncludeFixIts( +"include-fixits", +llvm::cl::desc( +"Enables suggestion of completion items that needs additional changes. " +"Like changing an arrow(->) member access to dot(.) member access."), +llvm::cl::init(clangd::CodeCompleteOptions().IncludeFixIts)); + +static llvm::cl::opt EnableFunctionArgSnippets( +"enable-function-arg-snippets", +llvm::cl::desc("Gives snippets for function arguments, when disabled only " + "gives parantheses for the call."), +llvm::cl::init(clangd::CodeCompleteOptions().EnableFunctionArgSnippets)); + int main(int argc, char *argv[]) { llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); llvm::cl::SetVersionPrinter([](llvm::raw_ostream &OS) { @@ -309,6 +322,8 @@ CCOpts.IncludeIndicator.NoInsert.clear(); } CCOpts.SpeculativeIndexRequest = Opts.StaticIndex; + CCOpts.IncludeFixIts = IncludeFixIts; + CCOpts.EnableFunctionArgSnippets = EnableFunctionArgSnippets; // Initialize and run ClangdLSPServer. ClangdLSPServer LSPServer( ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D51311: (WIP) Type hierarchy
kadircet added inline comments. Comment at: clangd/Protocol.h:889 + // Does this node implement the method targeted by the request? + bool DeclaresMethod; + I think comment and the name is in contradiction here, do you mean DefinesMethod? Comment at: clangd/XRefs.cpp:669 + const CXXMethodDecl *Candidate) { + // FIXME: How do I determine if Method overrides Candidate? + https://github.com/llvm-mirror/clang/blob/master/lib/Sema/SemaDecl.cpp you can check this sample, which simply traverses all base classes and gets methods with the same name, then checks whether one is overload of the other. If it they are not overloads then one in the base classes gets overriden by the other. Another approach could be to search for one method in others overriden_methods. But they are both inefficient, I would suggest calling these functions only when one of them is defined in the base class of other then you can just check for name equality and not being an overload. Comment at: clangd/XRefs.cpp:693 + +std::cerr << " >>> A parent is " << ParentDecl->getName().str() + << std::endl; If you plan to keep it for later debugging info, consider using {d,v}log Comment at: unittests/clangd/XRefsTests.cpp:1075 +$ParentDef^struct Parent +{ + int a; NIT: Maybe format test code as well. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D51311 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D51311: (WIP) Type hierarchy
kadircet added inline comments. Comment at: clangd/ProtocolHandlers.cpp:70 Register("textDocument/hover", &ProtocolCallbacks::onHover); + Register("textDocument/typeHierarchy", &ProtocolCallbacks::onTypeHierarchy); Register("textDocument/documentSymbol", &ProtocolCallbacks::onDocumentSymbol); LSP doesn't have such an entry, maybe we should use [[ https://microsoft.github.io/language-server-protocol/specification#workspace_executeCommand | workspace/executeCommand ]]. WDYT @ilya-biryukov Comment at: clangd/XRefs.cpp:669 + const CXXMethodDecl *Candidate) { + // FIXME: How do I determine if Method overrides Candidate? + ilya-biryukov wrote: > simark wrote: > > kadircet wrote: > > > https://github.com/llvm-mirror/clang/blob/master/lib/Sema/SemaDecl.cpp > > > > > > you can check this sample, which simply traverses all base classes and > > > gets methods with the same name, then checks whether one is overload of > > > the other. If it they are not overloads then one in the base classes gets > > > overriden by the other. > > > > > > > > > Another approach could be to search for one method in others > > > overriden_methods. > > > > > > But they are both inefficient, I would suggest calling these functions > > > only when one of them is defined in the base class of other then you can > > > just check for name equality and not being an overload. > > > https://github.com/llvm-mirror/clang/blob/master/lib/Sema/SemaDecl.cpp > > > > Did you mean to link to a particular line? > > > > > you can check this sample, which simply traverses all base classes and > > > gets methods with the same name, then checks whether one is overload of > > > the other. If it they are not overloads then one in the base classes gets > > > overriden by the other. > > > > > Another approach could be to search for one method in others > > > overriden_methods. > > > > I have tried using `overriden_methods`, but it only contains methods marked > > virtual. For this feature, I would like to consider non-virtual methods > > too. > > > > > But they are both inefficient, I would suggest calling these functions > > > only when one of them is defined in the base class of other then you can > > > just check for name equality and not being an overload. > > > > I am not sure I understand, but maybe it will be clearer when I will see > > the sample. > See the code that actually computes a list for `override_methods()`: > Sema::AddOverriddenMethods. > Did you mean to link to a particular line? Yeah sorry, I was trying to link the function ilya mentioned. https://github.com/llvm-mirror/clang/blob/master/lib/Sema/SemaDecl.cpp#L7615 Since you also mentioned checking non-virtual method as well you might wanna look at https://github.com/llvm-mirror/clang/blob/master/lib/Sema/SemaDecl.cpp#L7555 as well. Also I got the chance to look the rest of the patch, as I mentioned above you are already checking two methods iff one lies in the others base classes. So you can simply check for name equality and not being an overload case. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D51311 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D51539: [clangd] Add symbol slab size to index memory consumption estimates
kadircet added inline comments. Comment at: clang-tools-extra/clangd/index/dex/DexIndex.cpp:184 + size_t Bytes = PairedSlabSize; + Bytes += LookupTable.size() * sizeof(std::pair); Bytes += SymbolQuality.size() * sizeof(std::pair); Why not use `LookupTable.getMemorySize()` directly? Is it intentionally for not counting non-used but allocated buckets? Same for the below two as well. https://reviews.llvm.org/D51539 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D51539: [clangd] Add symbol slab size to index memory consumption estimates
kadircet added inline comments. Comment at: clang-tools-extra/clangd/index/FileIndex.cpp:91 + for (const auto &P : FileToSlabs) +Result += P.second->size(); + return Result; Why not `bytes` here as well? https://reviews.llvm.org/D51539 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D51039: [clangd] Add unittests for D51038
kadircet updated this revision to Diff 163968. kadircet added a comment. Rebase Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D51039 Files: unittests/clangd/CodeCompleteTests.cpp Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -1882,6 +1882,56 @@ AllOf(Named("Func"), HasInclude("\"foo.h\""), Not(InsertInclude(); } +TEST(SignatureHelpTest, InsideArgument) { + { +const auto Results = signatures(R"cpp( + void foo(int x); + void foo(int x, int y); + int main() { foo(1+^); } +)cpp"); +EXPECT_THAT( +Results.signatures, +ElementsAre(Sig("foo(int x) -> void", {"int x"}), +Sig("foo(int x, int y) -> void", {"int x", "int y"}))); +EXPECT_EQ(0, Results.activeParameter); + } + { +const auto Results = signatures(R"cpp( + void foo(int x); + void foo(int x, int y); + int main() { foo(1^); } +)cpp"); +EXPECT_THAT( +Results.signatures, +ElementsAre(Sig("foo(int x) -> void", {"int x"}), +Sig("foo(int x, int y) -> void", {"int x", "int y"}))); +EXPECT_EQ(0, Results.activeParameter); + } + { +const auto Results = signatures(R"cpp( + void foo(int x); + void foo(int x, int y); + int main() { foo(1^0); } +)cpp"); +EXPECT_THAT( +Results.signatures, +ElementsAre(Sig("foo(int x) -> void", {"int x"}), +Sig("foo(int x, int y) -> void", {"int x", "int y"}))); +EXPECT_EQ(0, Results.activeParameter); + } + { +const auto Results = signatures(R"cpp( + void foo(int x); + void foo(int x, int y); + int bar(int x, int y); + int main() { bar(foo(2, 3^)); } +)cpp"); +EXPECT_THAT(Results.signatures, ElementsAre(Sig("foo(int x, int y) -> void", +{"int x", "int y"}))); +EXPECT_EQ(1, Results.activeParameter); + } +} + } // namespace } // namespace clangd } // namespace clang Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -1882,6 +1882,56 @@ AllOf(Named("Func"), HasInclude("\"foo.h\""), Not(InsertInclude(); } +TEST(SignatureHelpTest, InsideArgument) { + { +const auto Results = signatures(R"cpp( + void foo(int x); + void foo(int x, int y); + int main() { foo(1+^); } +)cpp"); +EXPECT_THAT( +Results.signatures, +ElementsAre(Sig("foo(int x) -> void", {"int x"}), +Sig("foo(int x, int y) -> void", {"int x", "int y"}))); +EXPECT_EQ(0, Results.activeParameter); + } + { +const auto Results = signatures(R"cpp( + void foo(int x); + void foo(int x, int y); + int main() { foo(1^); } +)cpp"); +EXPECT_THAT( +Results.signatures, +ElementsAre(Sig("foo(int x) -> void", {"int x"}), +Sig("foo(int x, int y) -> void", {"int x", "int y"}))); +EXPECT_EQ(0, Results.activeParameter); + } + { +const auto Results = signatures(R"cpp( + void foo(int x); + void foo(int x, int y); + int main() { foo(1^0); } +)cpp"); +EXPECT_THAT( +Results.signatures, +ElementsAre(Sig("foo(int x) -> void", {"int x"}), +Sig("foo(int x, int y) -> void", {"int x", "int y"}))); +EXPECT_EQ(0, Results.activeParameter); + } + { +const auto Results = signatures(R"cpp( + void foo(int x); + void foo(int x, int y); + int bar(int x, int y); + int main() { bar(foo(2, 3^)); } +)cpp"); +EXPECT_THAT(Results.signatures, ElementsAre(Sig("foo(int x, int y) -> void", +{"int x", "int y"}))); +EXPECT_EQ(1, Results.activeParameter); + } +} + } // namespace } // namespace clangd } // namespace clang ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D51038: [clang] Make sure codecompletion is called for calls even when inside a token.
kadircet updated this revision to Diff 163970. kadircet added a comment. - Update tests. - Update comment. - Rebase. Repository: rC Clang https://reviews.llvm.org/D51038 Files: include/clang/Parse/Parser.h lib/Parse/ParseExpr.cpp test/CodeCompletion/function-overloads-inside-param.cpp test/CodeCompletion/function-overloads.cpp test/Index/complete-block-property-assignment.m Index: test/Index/complete-block-property-assignment.m === --- test/Index/complete-block-property-assignment.m +++ test/Index/complete-block-property-assignment.m @@ -60,13 +60,15 @@ // RUN: c-index-test -code-completion-at=%s:51:16 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:52:23 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:53:12 %s | FileCheck -check-prefix=CHECK-NO %s -// RUN: c-index-test -code-completion-at=%s:54:15 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:56:15 %s | FileCheck -check-prefix=CHECK-NO %s // CHECK-NO: ObjCPropertyDecl:{ResultType int}{TypedText foo} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType Obj *}{TypedText obj} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType void (^)(Obj *)}{TypedText onAction} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType FooBlock}{TypedText onEventHandler} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType void (^)(int *)}{TypedText onReadonly} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType int (^)(int)}{TypedText processEvent} (35) +// RUN: c-index-test -code-completion-at=%s:54:15 %s | FileCheck -check-prefix=CHECK-NO1 %s +// CHECK-NO1: ObjCPropertyDecl:{ResultType int}{TypedText foo} (35) +// CHECK-NO1-NEXT: FunctionDecl:{ResultType void}{TypedText func}{LeftParen (}{Placeholder int x}{RightParen )} (50) @end Index: test/CodeCompletion/function-overloads.cpp === --- /dev/null +++ test/CodeCompletion/function-overloads.cpp @@ -0,0 +1,8 @@ +void f(int i, int j = 2, int k = 5); +void f(float x, float y...); + +void test() { + ::f( + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:5:7 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s + // CHECK-CC1: f(<#int i#>{#, <#int j = 2#>{#, <#int k = 5#>#}#}) + // CHECK-CC1: f(<#float x#>, <#float y, ...#>) Index: test/CodeCompletion/function-overloads-inside-param.cpp === --- /dev/null +++ test/CodeCompletion/function-overloads-inside-param.cpp @@ -0,0 +1,8 @@ +void f(int i, int j = 2, int k = 5); +void f(float x, float y...); + +void test() { + ::f(1 + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:5:8 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s + // CHECK-CC1: f(<#int i#>{#, <#int j = 2#>{#, <#int k = 5#>#}#}) + // CHECK-CC1: f(<#float x#>, <#float y, ...#>) Index: lib/Parse/ParseExpr.cpp === --- lib/Parse/ParseExpr.cpp +++ lib/Parse/ParseExpr.cpp @@ -1658,11 +1658,21 @@ if (OpKind == tok::l_paren || !LHS.isInvalid()) { if (Tok.isNot(tok::r_paren)) { - if (ParseExpressionList(ArgExprs, CommaLocs, [&] { -Actions.CodeCompleteCall(getCurScope(), LHS.get(), ArgExprs, - PT.getOpenLocation()); - })) { + auto Completer = [&] { +if (CalledOverloadCompletion) + return; +Actions.CodeCompleteCall(getCurScope(), LHS.get(), ArgExprs, + PT.getOpenLocation()); +CalledOverloadCompletion = true; + }; + if (ParseExpressionList(ArgExprs, CommaLocs, Completer)) { (void)Actions.CorrectDelayedTyposInExpr(LHS); +// If we got an error when parsing expression list, we don't call +// the CodeCompleteCall handler inside the parser. So call it here +// to make sure we get overload suggestions even when we are in the +// middle of a parameter. +if (PP.isCodeCompletionReached()) + Completer(); LHS = ExprError(); } else if (LHS.isInvalid()) { for (auto &E : ArgExprs) Index: include/clang/Parse/Parser.h === --- include/clang/Parse/Parser.h +++ include/clang/Parse/Parser.h @@ -214,6 +214,10 @@ /// should not be set directly. bool InMessageExpression; + /// Gets set to true after calling CodeCompleteCall, it is for a hack to make + /// signature help working even when it is triggered inside a token. + bool CalledOverloadCompletion = false; + /// The "depth" of the template parameters currently being parsed. unsigned TemplateParameterDepth; Index: test/Index/complete-block-property-assignment.m ===
[PATCH] D51038: [clang] Make sure codecompletion is called for calls even when inside a token.
kadircet updated this revision to Diff 163971. kadircet added a comment. - Update comments. Repository: rC Clang https://reviews.llvm.org/D51038 Files: include/clang/Parse/Parser.h lib/Parse/ParseExpr.cpp test/CodeCompletion/function-overloads-inside-param.cpp test/CodeCompletion/function-overloads.cpp test/Index/complete-block-property-assignment.m Index: test/Index/complete-block-property-assignment.m === --- test/Index/complete-block-property-assignment.m +++ test/Index/complete-block-property-assignment.m @@ -60,13 +60,15 @@ // RUN: c-index-test -code-completion-at=%s:51:16 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:52:23 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:53:12 %s | FileCheck -check-prefix=CHECK-NO %s -// RUN: c-index-test -code-completion-at=%s:54:15 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:56:15 %s | FileCheck -check-prefix=CHECK-NO %s // CHECK-NO: ObjCPropertyDecl:{ResultType int}{TypedText foo} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType Obj *}{TypedText obj} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType void (^)(Obj *)}{TypedText onAction} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType FooBlock}{TypedText onEventHandler} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType void (^)(int *)}{TypedText onReadonly} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType int (^)(int)}{TypedText processEvent} (35) +// RUN: c-index-test -code-completion-at=%s:54:15 %s | FileCheck -check-prefix=CHECK-NO1 %s +// CHECK-NO1: ObjCPropertyDecl:{ResultType int}{TypedText foo} (35) +// CHECK-NO1-NEXT: FunctionDecl:{ResultType void}{TypedText func}{LeftParen (}{Placeholder int x}{RightParen )} (50) @end Index: test/CodeCompletion/function-overloads.cpp === --- /dev/null +++ test/CodeCompletion/function-overloads.cpp @@ -0,0 +1,8 @@ +void f(int i, int j = 2, int k = 5); +void f(float x, float y...); + +void test() { + ::f( + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:5:7 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s + // CHECK-CC1: f(<#int i#>{#, <#int j = 2#>{#, <#int k = 5#>#}#}) + // CHECK-CC1: f(<#float x#>, <#float y, ...#>) Index: test/CodeCompletion/function-overloads-inside-param.cpp === --- /dev/null +++ test/CodeCompletion/function-overloads-inside-param.cpp @@ -0,0 +1,8 @@ +void f(int i, int j = 2, int k = 5); +void f(float x, float y...); + +void test() { + ::f(1 + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:5:8 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s + // CHECK-CC1: f(<#int i#>{#, <#int j = 2#>{#, <#int k = 5#>#}#}) + // CHECK-CC1: f(<#float x#>, <#float y, ...#>) Index: lib/Parse/ParseExpr.cpp === --- lib/Parse/ParseExpr.cpp +++ lib/Parse/ParseExpr.cpp @@ -1658,11 +1658,21 @@ if (OpKind == tok::l_paren || !LHS.isInvalid()) { if (Tok.isNot(tok::r_paren)) { - if (ParseExpressionList(ArgExprs, CommaLocs, [&] { -Actions.CodeCompleteCall(getCurScope(), LHS.get(), ArgExprs, - PT.getOpenLocation()); - })) { + auto Completer = [&] { +if (CalledOverloadCompletion) + return; +Actions.CodeCompleteCall(getCurScope(), LHS.get(), ArgExprs, + PT.getOpenLocation()); +CalledOverloadCompletion = true; + }; + if (ParseExpressionList(ArgExprs, CommaLocs, Completer)) { (void)Actions.CorrectDelayedTyposInExpr(LHS); +// If we got an error when parsing expression list, we don't call +// the CodeCompleteCall handler inside the parser. So call it here +// to make sure we get overload suggestions even when we are in the +// middle of a parameter. +if (PP.isCodeCompletionReached()) + Completer(); LHS = ExprError(); } else if (LHS.isInvalid()) { for (auto &E : ArgExprs) Index: include/clang/Parse/Parser.h === --- include/clang/Parse/Parser.h +++ include/clang/Parse/Parser.h @@ -214,6 +214,10 @@ /// should not be set directly. bool InMessageExpression; + /// Gets set to true after calling CodeCompleteCall, it is for a workaround to + /// make sure CodeComleteCall is only called at the deepest level. + bool CalledOverloadCompletion = false; + /// The "depth" of the template parameters currently being parsed. unsigned TemplateParameterDepth; Index: test/Index/complete-block-property-assignment.m
[PATCH] D51724: [clangd] Add "Deprecated" field to Symbol and CodeCompletion.
kadircet added inline comments. Comment at: clangd/index/Index.h:171 + /// See also isIndexedForCodeCompletion(). + IsIndexedForCodeCompletion = 1 << 0, + /// Indicates if the symbol is deprecated. nit: rename to IndexedForCodeCompletion, since it is more of an attribute having is in the name doesn't seem so cool. Instead of the attributes themselves maybe the checkers below should have "is" prefix. Comment at: clangd/index/Index.h:172 + IsIndexedForCodeCompletion = 1 << 0, + /// Indicates if the symbol is deprecated. + Deprecated = 1 << 1, nit: Add a comment similar to above one leading to Deprecated()? Comment at: clangd/index/Index.h:268 + /// FIXME: also add deprecation message and fixit? + bool Deprecated() const { +return static_cast(Flags & SymbolFlag::Deprecated); nit: rename to isDeprecated ? Comment at: unittests/clangd/CodeCompleteTests.cpp:1359 C.Origin = SymbolOrigin::AST | SymbolOrigin::Static; + C.Deprecated = true; Maybe do this on its own render so that we can have both code paths covered. Just before rendering with `Opts.EnableSnippets = true` below. We can simply set this one render again and check deprecated is set to true. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D51724 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D51724: [clangd] Add "Deprecated" field to Symbol and CodeCompletion.
kadircet added inline comments. Comment at: unittests/clangd/SymbolCollectorTests.cpp:1020 + const std::string Header = R"( +void TestClangc() __attribute__((deprecated("", ""))); +void TestClangd(); No need for the optional parameters, ``` void TestClangc() __attribute__((deprecated)); ``` should work as well Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D51724 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D51747: [clangd] Implement deprecation diagnostics with lower severity.
kadircet created this revision. kadircet added reviewers: ioeric, sammccall, ilya-biryukov, hokein. Herald added subscribers: cfe-commits, arphaman, jkorous, MaskRay. Adds deprecation warnings to diagnostics. Also lowers the severity from warning to notes to not to annoy people that work on big codebases. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D51747 Files: clangd/ClangdServer.cpp clangd/Diagnostics.cpp unittests/clangd/ClangdUnitTests.cpp Index: unittests/clangd/ClangdUnitTests.cpp === --- unittests/clangd/ClangdUnitTests.cpp +++ unittests/clangd/ClangdUnitTests.cpp @@ -38,6 +38,13 @@ return arg.Range == Range && arg.Message == Message; } +MATCHER_P3(Diag, Range, Message, Severity, + "Diag at " + llvm::to_string(Range) + " = [" + Message + + "] with Severity:" + llvm::to_string(Severity)) { + return arg.Range == Range && arg.Message == Message && + arg.Severity == Severity; +} + MATCHER_P3(Fix, Range, Replacement, Message, "Fix " + llvm::to_string(Range) + " => " + testing::PrintToString(Replacement) + " = [" + Message + "]") { @@ -220,6 +227,48 @@ } } +TEST(DiagnosticsTest, DiagnosticDeprecated) { + Annotations Test(R"cpp( +void foo() __attribute__(($foodeprecation[[deprecated]])); +class A { +public: + int x __attribute__(($xdeprecation[[deprecated]])); +}; +int main() { + $foo[[foo]](); + return A().$x[[x]]; +} + )cpp"); + EXPECT_THAT( + TestTU::withCode(Test.code()).build().getDiagnostics(), + ElementsAre( + AllOf(Diag(Test.range("foo"), "'foo' is deprecated", + DiagnosticsEngine::Note), +WithNote( +Diag(Test.range("foodeprecation"), + "'foo' has been explicitly marked deprecated here"))), + AllOf(Diag(Test.range("x"), "'x' is deprecated", + DiagnosticsEngine::Note), +WithNote( +Diag(Test.range("xdeprecation"), + "'x' has been explicitly marked deprecated here"); +} + +TEST(DiagnosticsTest, DiagnosticDeprecatedWithFix) { + Annotations Test(R"cpp( +void bar(); +void foo() __attribute__((deprecated("", "bar"))); +int main() { + $deprecated[[foo]](); +} + )cpp"); + EXPECT_THAT( + TestTU::withCode(Test.code()).build().getDiagnostics(), + ElementsAre( + WithFix(Fix(Test.range("deprecated"), "bar", "change 'foo' to 'bar'")) + )); +} + } // namespace } // namespace clangd } // namespace clang Index: clangd/Diagnostics.cpp === --- clangd/Diagnostics.cpp +++ clangd/Diagnostics.cpp @@ -292,10 +292,11 @@ D.Message = Message.str(); D.InsideMainFile = InsideMainFile; D.File = Info.getSourceManager().getFilename(Info.getLocation()); -D.Severity = DiagLevel; D.Category = DiagnosticIDs::getCategoryNameFromID( DiagnosticIDs::getCategoryNumberForDiag(Info.getID())) .str(); +D.Severity = +D.Category == "Deprecations" ? DiagnosticsEngine::Note : DiagLevel; return D; }; Index: clangd/ClangdServer.cpp === --- clangd/ClangdServer.cpp +++ clangd/ClangdServer.cpp @@ -534,6 +534,7 @@ // Inject the resource dir. // FIXME: Don't overwrite it if it's already there. C->CommandLine.push_back("-resource-dir=" + ResourceDir); + C->CommandLine.push_back("-Wdeprecated-declarations"); return std::move(*C); } Index: unittests/clangd/ClangdUnitTests.cpp === --- unittests/clangd/ClangdUnitTests.cpp +++ unittests/clangd/ClangdUnitTests.cpp @@ -38,6 +38,13 @@ return arg.Range == Range && arg.Message == Message; } +MATCHER_P3(Diag, Range, Message, Severity, + "Diag at " + llvm::to_string(Range) + " = [" + Message + + "] with Severity:" + llvm::to_string(Severity)) { + return arg.Range == Range && arg.Message == Message && + arg.Severity == Severity; +} + MATCHER_P3(Fix, Range, Replacement, Message, "Fix " + llvm::to_string(Range) + " => " + testing::PrintToString(Replacement) + " = [" + Message + "]") { @@ -220,6 +227,48 @@ } } +TEST(DiagnosticsTest, DiagnosticDeprecated) { + Annotations Test(R"cpp( +void foo() __attribute__(($foodeprecation[[deprecated]])); +class A { +public: + int x __attribute__(($xdeprecation[[deprecated]])); +}; +int main() { + $foo[[foo]](); + return A().$x[[x]]; +} + )cpp"); + EXPECT_THAT( + TestTU::withCode(Test.code()).build().getDiagnostics(), + ElementsAre( + AllOf(Diag(Test.range("foo"), "'foo' is deprecated", +
[PATCH] D51747: [clangd] Implement deprecation diagnostics with lower severity.
kadircet added inline comments. Comment at: clangd/Diagnostics.cpp:299 +D.Severity = +D.Category == "Deprecations" ? DiagnosticsEngine::Note : DiagLevel; return D; Couldn't find a better way to check for this one. Category types are coming from tablegen file https://github.com/llvm-mirror/clang/blob/master/include/clang/Basic/DiagnosticGroups.td#L128 which does not expose category id, at least I couldn't find even if it does. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D51747 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D51747: [clangd] Implement deprecation diagnostics with lower severity.
kadircet updated this revision to Diff 164268. kadircet added a comment. - Formatting. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D51747 Files: clangd/ClangdServer.cpp clangd/Diagnostics.cpp unittests/clangd/ClangdUnitTests.cpp Index: unittests/clangd/ClangdUnitTests.cpp === --- unittests/clangd/ClangdUnitTests.cpp +++ unittests/clangd/ClangdUnitTests.cpp @@ -38,6 +38,13 @@ return arg.Range == Range && arg.Message == Message; } +MATCHER_P3(Diag, Range, Message, Severity, + "Diag at " + llvm::to_string(Range) + " = [" + Message + + "] with Severity:" + llvm::to_string(Severity)) { + return arg.Range == Range && arg.Message == Message && + arg.Severity == Severity; +} + MATCHER_P3(Fix, Range, Replacement, Message, "Fix " + llvm::to_string(Range) + " => " + testing::PrintToString(Replacement) + " = [" + Message + "]") { @@ -220,6 +227,46 @@ } } +TEST(DiagnosticsTest, DiagnosticDeprecated) { + Annotations Test(R"cpp( +void foo() __attribute__(($foodeprecation[[deprecated]])); +class A { +public: + int x __attribute__(($xdeprecation[[deprecated]])); +}; +int main() { + $foo[[foo]](); + return A().$x[[x]]; +} + )cpp"); + EXPECT_THAT( + TestTU::withCode(Test.code()).build().getDiagnostics(), + ElementsAre( + AllOf(Diag(Test.range("foo"), "'foo' is deprecated", + DiagnosticsEngine::Note), +WithNote( +Diag(Test.range("foodeprecation"), + "'foo' has been explicitly marked deprecated here"))), + AllOf(Diag(Test.range("x"), "'x' is deprecated", + DiagnosticsEngine::Note), +WithNote( +Diag(Test.range("xdeprecation"), + "'x' has been explicitly marked deprecated here"); +} + +TEST(DiagnosticsTest, DiagnosticDeprecatedWithFix) { + Annotations Test(R"cpp( +void bar(); +void foo() __attribute__((deprecated("", "bar"))); +int main() { + $deprecated[[foo]](); +} + )cpp"); + EXPECT_THAT(TestTU::withCode(Test.code()).build().getDiagnostics(), + ElementsAre(WithFix(Fix(Test.range("deprecated"), "bar", + "change 'foo' to 'bar'"; +} + } // namespace } // namespace clangd } // namespace clang Index: clangd/Diagnostics.cpp === --- clangd/Diagnostics.cpp +++ clangd/Diagnostics.cpp @@ -292,10 +292,11 @@ D.Message = Message.str(); D.InsideMainFile = InsideMainFile; D.File = Info.getSourceManager().getFilename(Info.getLocation()); -D.Severity = DiagLevel; D.Category = DiagnosticIDs::getCategoryNameFromID( DiagnosticIDs::getCategoryNumberForDiag(Info.getID())) .str(); +D.Severity = +D.Category == "Deprecations" ? DiagnosticsEngine::Note : DiagLevel; return D; }; Index: clangd/ClangdServer.cpp === --- clangd/ClangdServer.cpp +++ clangd/ClangdServer.cpp @@ -534,6 +534,7 @@ // Inject the resource dir. // FIXME: Don't overwrite it if it's already there. C->CommandLine.push_back("-resource-dir=" + ResourceDir); + C->CommandLine.push_back("-Wdeprecated-declarations"); return std::move(*C); } Index: unittests/clangd/ClangdUnitTests.cpp === --- unittests/clangd/ClangdUnitTests.cpp +++ unittests/clangd/ClangdUnitTests.cpp @@ -38,6 +38,13 @@ return arg.Range == Range && arg.Message == Message; } +MATCHER_P3(Diag, Range, Message, Severity, + "Diag at " + llvm::to_string(Range) + " = [" + Message + + "] with Severity:" + llvm::to_string(Severity)) { + return arg.Range == Range && arg.Message == Message && + arg.Severity == Severity; +} + MATCHER_P3(Fix, Range, Replacement, Message, "Fix " + llvm::to_string(Range) + " => " + testing::PrintToString(Replacement) + " = [" + Message + "]") { @@ -220,6 +227,46 @@ } } +TEST(DiagnosticsTest, DiagnosticDeprecated) { + Annotations Test(R"cpp( +void foo() __attribute__(($foodeprecation[[deprecated]])); +class A { +public: + int x __attribute__(($xdeprecation[[deprecated]])); +}; +int main() { + $foo[[foo]](); + return A().$x[[x]]; +} + )cpp"); + EXPECT_THAT( + TestTU::withCode(Test.code()).build().getDiagnostics(), + ElementsAre( + AllOf(Diag(Test.range("foo"), "'foo' is deprecated", + DiagnosticsEngine::Note), +WithNote( +Diag(Test.range("foodeprecation"), + "'foo' has been explicitly marked deprecated here"))), + AllO
[PATCH] D51038: [clang] Make sure codecompletion is called for calls even when inside a token.
kadircet added inline comments. Comment at: test/Index/complete-block-property-assignment.m:71 +// RUN: c-index-test -code-completion-at=%s:54:15 %s | FileCheck -check-prefix=CHECK-NO1 %s +// CHECK-NO1: ObjCPropertyDecl:{ResultType int}{TypedText foo} (35) ilya-biryukov wrote: > ilya-biryukov wrote: > > Any idea why behavior changed in that case? > Looked at it more thoroughly now... > So we're now showing both the signature help and the completion, right? > If that the case, LG, but can we include the rest of completion items from > CHECK-N0? > > Maybe also add a comment that the last item is from overload set completion, > rather than the ordinary code completion? (To avoid confusion and make it > clear why we need an extra check there) Yes, c-index-test binary collects results from both ProcessOverloadCandidate and ProcessCodeCompleteResults. Therefore they are merged. Adding the same set of results on the above is not enough for that particular case, due to the clever nature of CodeCompleteOverloadResult at https://github.com/llvm-mirror/clang/blob/master/lib/Sema/SemaCodeComplete.cpp#L4439. It doesn't just try to tell you the overloads of that particular function but also tries to complete the current argument. Therefore the list simply gets huge by expansion of all the macros and other stuff. But when looking into it I found out I was checking for wrong return values fixing that with the new diff. Repository: rC Clang https://reviews.llvm.org/D51038 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D51038: [clang] Make sure codecompletion is called for calls even when inside a token.
kadircet updated this revision to Diff 164307. kadircet added a comment. - Fix tests. Repository: rC Clang https://reviews.llvm.org/D51038 Files: include/clang/Parse/Parser.h lib/Parse/ParseExpr.cpp test/CodeCompletion/function-overloads-inside-param.cpp test/CodeCompletion/function-overloads.cpp test/Index/complete-block-property-assignment.m Index: test/Index/complete-block-property-assignment.m === --- test/Index/complete-block-property-assignment.m +++ test/Index/complete-block-property-assignment.m @@ -60,13 +60,14 @@ // RUN: c-index-test -code-completion-at=%s:51:16 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:52:23 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:53:12 %s | FileCheck -check-prefix=CHECK-NO %s -// RUN: c-index-test -code-completion-at=%s:54:15 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:56:15 %s | FileCheck -check-prefix=CHECK-NO %s // CHECK-NO: ObjCPropertyDecl:{ResultType int}{TypedText foo} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType Obj *}{TypedText obj} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType void (^)(Obj *)}{TypedText onAction} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType FooBlock}{TypedText onEventHandler} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType void (^)(int *)}{TypedText onReadonly} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType int (^)(int)}{TypedText processEvent} (35) +// RUN: c-index-test -code-completion-at=%s:54:15 %s | FileCheck -check-prefix=CHECK-NO1 %s +// CHECK-NO1: OverloadCandidate:{ResultType void}{Text func}{LeftParen (}{CurrentParameter int x}{RightParen )} (1) @end Index: test/CodeCompletion/function-overloads.cpp === --- /dev/null +++ test/CodeCompletion/function-overloads.cpp @@ -0,0 +1,8 @@ +void f(int i, int j = 2, int k = 5); +void f(float x, float y...); + +void test() { + ::f( + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:5:7 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s + // CHECK-CC1: f(<#int i#>{#, <#int j = 2#>{#, <#int k = 5#>#}#}) + // CHECK-CC1: f(<#float x#>, <#float y, ...#>) Index: test/CodeCompletion/function-overloads-inside-param.cpp === --- /dev/null +++ test/CodeCompletion/function-overloads-inside-param.cpp @@ -0,0 +1,8 @@ +void f(int i, int j = 2, int k = 5); +void f(float x, float y...); + +void test() { + ::f(1 + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:5:8 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s + // CHECK-CC1: f(<#int i#>{#, <#int j = 2#>{#, <#int k = 5#>#}#}) + // CHECK-CC1: f(<#float x#>, <#float y, ...#>) Index: lib/Parse/ParseExpr.cpp === --- lib/Parse/ParseExpr.cpp +++ lib/Parse/ParseExpr.cpp @@ -1658,11 +1658,21 @@ if (OpKind == tok::l_paren || !LHS.isInvalid()) { if (Tok.isNot(tok::r_paren)) { - if (ParseExpressionList(ArgExprs, CommaLocs, [&] { -Actions.CodeCompleteCall(getCurScope(), LHS.get(), ArgExprs, - PT.getOpenLocation()); - })) { + auto Completer = [&] { +if (CalledOverloadCompletion) + return; +Actions.CodeCompleteCall(getCurScope(), LHS.get(), ArgExprs, + PT.getOpenLocation()); +CalledOverloadCompletion = true; + }; + if (ParseExpressionList(ArgExprs, CommaLocs, Completer)) { (void)Actions.CorrectDelayedTyposInExpr(LHS); +// If we got an error when parsing expression list, we don't call +// the CodeCompleteCall handler inside the parser. So call it here +// to make sure we get overload suggestions even when we are in the +// middle of a parameter. +if (PP.isCodeCompletionReached()) + Completer(); LHS = ExprError(); } else if (LHS.isInvalid()) { for (auto &E : ArgExprs) Index: include/clang/Parse/Parser.h === --- include/clang/Parse/Parser.h +++ include/clang/Parse/Parser.h @@ -214,6 +214,10 @@ /// should not be set directly. bool InMessageExpression; + /// Gets set to true after calling CodeCompleteCall, it is for a workaround to + /// make sure CodeComleteCall is only called at the deepest level. + bool CalledOverloadCompletion = false; + /// The "depth" of the template parameters currently being parsed. unsigned TemplateParameterDepth; Index: test/Index/complete-block-property-assignment.m === --- test/Index/complete-block-property-assignment.m
[PATCH] D51038: [clang] Make sure codecompletion is called for calls even when inside a token.
kadircet updated this revision to Diff 164477. kadircet added a comment. - Rebase and use new signature help. Currently the problem is, there are again some tests out there that rely on CodeCompeleteOrdinaryName to be called even when getting overloads at an unknown parameter type. These tests are: Clang :: CodeCompletion/call.cpp Clang :: Index/code-completion.cpp Clang :: Index/complete-call.cpp Clang :: Index/complete-functor-call.cpp Clang :: Index/complete-optional-params.cpp Clang :: Index/complete-pointer-and-reference-to-functions.cpp You can run something like this to check for the output(change ../clangd_bugs): ninja c-index-test && ./bin/c-index-test -code-completion-at=../clangd_bugs/tools/clang/test/Index/complete-call.cpp:53:12 ../clan gd_bugs/tools/clang/test/Index/complete-call.cpp As you can see current version generates only overloadcandidates, but tests don't check them with a next loop, because they expect other completions, which is not problematic but after checks for the items they also look for completion context, which is not set as desired if CodeCompleteOrdinaryName or CodeCompleteExpression is not called. But for the first test case it is more complicated, it checks for code patterns like dynamic_cast(EXPR); which is not generated if we don't call CodeCompletionOrdinaryName or Expressions. Repository: rC Clang https://reviews.llvm.org/D51038 Files: include/clang/Parse/Parser.h lib/Parse/ParseExpr.cpp test/CodeCompletion/function-overloads-inside-param.cpp test/CodeCompletion/function-overloads.cpp test/Index/complete-block-property-assignment.m Index: test/Index/complete-block-property-assignment.m === --- test/Index/complete-block-property-assignment.m +++ test/Index/complete-block-property-assignment.m @@ -60,13 +60,20 @@ // RUN: c-index-test -code-completion-at=%s:51:16 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:52:23 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:53:12 %s | FileCheck -check-prefix=CHECK-NO %s -// RUN: c-index-test -code-completion-at=%s:54:15 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:56:15 %s | FileCheck -check-prefix=CHECK-NO %s // CHECK-NO: ObjCPropertyDecl:{ResultType int}{TypedText foo} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType Obj *}{TypedText obj} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType void (^)(Obj *)}{TypedText onAction} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType FooBlock}{TypedText onEventHandler} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType void (^)(int *)}{TypedText onReadonly} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType int (^)(int)}{TypedText processEvent} (35) +// RUN: c-index-test -code-completion-at=%s:54:15 %s | FileCheck -check-prefix=CHECK-NO1 %s +// CHECK-NO1: ObjCPropertyDecl:{ResultType int}{TypedText foo} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType Obj *}{TypedText obj} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType void (^)(Obj *)}{TypedText onAction} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType FooBlock}{TypedText onEventHandler} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType void (^)(int *)}{TypedText onReadonly} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType int (^)(int)}{TypedText processEvent} (35) +// CHECK-NO1-NEXT: OverloadCandidate:{ResultType void}{Text func}{LeftParen (}{CurrentParameter int x}{RightParen )} (1) @end Index: test/CodeCompletion/function-overloads.cpp === --- /dev/null +++ test/CodeCompletion/function-overloads.cpp @@ -0,0 +1,8 @@ +void f(int i, int j = 2, int k = 5); +void f(float x, float y...); + +void test() { + ::f( + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:5:7 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s + // CHECK-CC1: f(<#int i#>{#, <#int j = 2#>{#, <#int k = 5#>#}#}) + // CHECK-CC1: f(<#float x#>, <#float y, ...#>) Index: test/CodeCompletion/function-overloads-inside-param.cpp === --- /dev/null +++ test/CodeCompletion/function-overloads-inside-param.cpp @@ -0,0 +1,8 @@ +void f(int i, int j = 2, int k = 5); +void f(float x, float y...); + +void test() { + ::f(1 + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:5:8 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s + // CHECK-CC1: f(<#int i#>{#, <#int j = 2#>{#, <#int k = 5#>#}#}) + // CHECK-CC1: f(<#float x#>, <#float y, ...#>) Index: lib/Parse/ParseExpr.cpp === --- lib/Parse/ParseExpr.cpp +++ lib/Parse/ParseExpr.cpp @@ -1659,12 +1659,27 @@ if (OpKind == tok::l_paren || !LHS.isInvalid()) { if (Tok.isNot(tok::r_paren)) { - if (ParseExpressionList(ArgExprs, CommaLocs, [&] { -
[PATCH] D51747: [clangd] Implement deprecation diagnostics with lower severity.
kadircet added a comment. In https://reviews.llvm.org/D51747#1227089, @ilya-biryukov wrote: > Not sure if it's fine to hijack our own diagnostic-specific flags in to clang > command args. > > Cons that I see: > > 1. There is no way for the users to turn them off if they find them > non-useful. If we add a way, it would be more config parameters which overlap > with other mechanism that we have - compiler flags. > 2. Users who are used to having them as warnings will now see them as notes. > Again, no way to tweak this behavior. > > What's our use-case? Maybe we should ask the clients to add -Wdeprecated if > they care about those? > > PS In case I'm missing the context here, please let me know. Agree with you, I think it would be better to provide it as an option. https://reviews.llvm.org/D51724 with this one we added a way to show deprecated symbols on code completion responses and wanted to move forward with showing the ones that are already in existing code. Comment at: clangd/Diagnostics.cpp:299 +D.Severity = +D.Category == "Deprecations" ? DiagnosticsEngine::Note : DiagLevel; return D; ioeric wrote: > kadircet wrote: > > Couldn't find a better way to check for this one. Category types are coming > > from tablegen file > > https://github.com/llvm-mirror/clang/blob/master/include/clang/Basic/DiagnosticGroups.td#L128 > > which does not expose category id, at least I couldn't find even if it > > does. > Have you tried the Diagnostic ID (i.e. `Info.getID()`)? It matches the diag > kinds defined in `DiagnosticSemaKinds.inc` (e.g. `warn_deprecated`). Unfortunately these are also internal, https://github.com/llvm-mirror/clang/blob/master/lib/Basic/DiagnosticIDs.cpp#L97 Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D51747 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D51038: [clang] Make sure codecompletion is called for calls even when inside a token.
kadircet added a comment. In https://reviews.llvm.org/D51038#1228618, @ilya-biryukov wrote: > > Currently the problem is, there are again some tests out there that rely on > > CodeCompeleteOrdinaryName to be called even when getting overloads at an > > unknown > > parameter type > > CodeCompleteExpression works just fine there. Unknown parameter type should > not block code completion. > The idea is that anywhere except the start of the argument expression, we > need to call **only** signature help. At the start of the argument, we have > to call both signature help and code completion. Yeah you are right, I thought I could check whether I am inside a parameter or not by looking at qual type, which was apparently wrong :D But, unfortunately, there were still tests failing which was caused by printing of completion strings for overloaded methods with optional parameters. It was trying to access Text field, which is not defined for Optional parameters. Since it didn't print optional parameters in the original behavior I kept it that way. Can send it as a different patch if need be. Repository: rC Clang https://reviews.llvm.org/D51038 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D51038: [clang] Make sure codecompletion is called for calls even when inside a token.
kadircet updated this revision to Diff 164639. kadircet marked an inline comment as done. kadircet added a comment. - Change "inside parameter" checking and fix completion string printing for optional parameters. - Update tests. Repository: rC Clang https://reviews.llvm.org/D51038 Files: include/clang/Parse/Parser.h lib/Parse/ParseDecl.cpp lib/Parse/ParseExpr.cpp lib/Parse/ParseExprCXX.cpp lib/Parse/ParseOpenMP.cpp lib/Sema/CodeCompleteConsumer.cpp test/CodeCompletion/function-overloads.cpp test/Index/complete-block-property-assignment.m Index: test/Index/complete-block-property-assignment.m === --- test/Index/complete-block-property-assignment.m +++ test/Index/complete-block-property-assignment.m @@ -60,13 +60,20 @@ // RUN: c-index-test -code-completion-at=%s:51:16 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:52:23 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:53:12 %s | FileCheck -check-prefix=CHECK-NO %s -// RUN: c-index-test -code-completion-at=%s:54:15 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:56:15 %s | FileCheck -check-prefix=CHECK-NO %s // CHECK-NO: ObjCPropertyDecl:{ResultType int}{TypedText foo} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType Obj *}{TypedText obj} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType void (^)(Obj *)}{TypedText onAction} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType FooBlock}{TypedText onEventHandler} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType void (^)(int *)}{TypedText onReadonly} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType int (^)(int)}{TypedText processEvent} (35) +// RUN: c-index-test -code-completion-at=%s:54:15 %s | FileCheck -check-prefix=CHECK-NO1 %s +// CHECK-NO1: ObjCPropertyDecl:{ResultType int}{TypedText foo} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType Obj *}{TypedText obj} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType void (^)(Obj *)}{TypedText onAction} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType FooBlock}{TypedText onEventHandler} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType void (^)(int *)}{TypedText onReadonly} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType int (^)(int)}{TypedText processEvent} (35) +// CHECK-NO1-NEXT: OverloadCandidate:{ResultType void}{Text func}{LeftParen (}{CurrentParameter int x}{RightParen )} (1) @end Index: test/CodeCompletion/function-overloads.cpp === --- /dev/null +++ test/CodeCompletion/function-overloads.cpp @@ -0,0 +1,27 @@ +int f(int i, int j = 2, int k = 5); +int f(float x, float y...); + +class A { + public: + A(int, int, int); +}; + +void test() { + A a(f(1, 2, 3, 4), 2, 3); +} + +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:9 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:10 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:17 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:19 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:20 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:21 %s -o - | FileCheck -check-prefix=CHECK-CC4 %s +// CHECK-CC1: OVERLOAD: [#int#]f(<#float x#>, float y) +// CHECK-CC1: OVERLOAD: [#int#]f(<#int i#>) +// CHECK-CC1-NOT, CHECK-CC2-NOT: OVERLOAD: A( +// CHECK-CC2: OVERLOAD: [#int#]f(float x, float y) +// CHECK-CC2-NOT: OVERLOAD: [#int#]f(int i) +// CHECK-CC3: OVERLOAD: A(<#int#>, int, int) +// CHECK-CC3: OVERLOAD: A(<#const A >) +// CHECK-CC3: OVERLOAD: A(<#A &>) +// CHECK-CC4: OVERLOAD: A(int, <#int#>, int) Index: lib/Sema/CodeCompleteConsumer.cpp === --- lib/Sema/CodeCompleteConsumer.cpp +++ lib/Sema/CodeCompleteConsumer.cpp @@ -619,6 +619,9 @@ OS << "<#" << C.Text << "#>"; break; +case CodeCompletionString::CK_Optional: + break; + default: OS << C.Text; break; } } Index: lib/Parse/ParseOpenMP.cpp === --- lib/Parse/ParseOpenMP.cpp +++ lib/Parse/ParseOpenMP.cpp @@ -416,14 +416,20 @@ CommaLocsTy CommaLocs; SourceLocation LParLoc = T.getOpenLocation(); -if (ParseExpressionList( -Exprs, CommaLocs, [this, OmpPrivParm, LParLoc, &Exprs] { - QualType PreferredType = Actions.ProduceConstructorSignatureHelp( - getCurScope(), - OmpPrivParm->getType()->getCanonicalTypeInternal(), - OmpPrivParm->getLocation(), Exprs, LParLoc); - Actions.CodeCompleteExpression(getCurScope(), Preferr
[PATCH] D51038: [clang] Make sure codecompletion is called for calls even when inside a token.
kadircet updated this revision to Diff 164649. kadircet marked 2 inline comments as done. kadircet added a comment. - Resolve discussions. Repository: rC Clang https://reviews.llvm.org/D51038 Files: include/clang/Parse/Parser.h lib/Parse/ParseDecl.cpp lib/Parse/ParseExpr.cpp lib/Parse/ParseExprCXX.cpp lib/Parse/ParseOpenMP.cpp lib/Sema/CodeCompleteConsumer.cpp test/CodeCompletion/function-overloads.cpp test/Index/complete-block-property-assignment.m Index: test/Index/complete-block-property-assignment.m === --- test/Index/complete-block-property-assignment.m +++ test/Index/complete-block-property-assignment.m @@ -60,13 +60,20 @@ // RUN: c-index-test -code-completion-at=%s:51:16 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:52:23 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:53:12 %s | FileCheck -check-prefix=CHECK-NO %s -// RUN: c-index-test -code-completion-at=%s:54:15 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:56:15 %s | FileCheck -check-prefix=CHECK-NO %s // CHECK-NO: ObjCPropertyDecl:{ResultType int}{TypedText foo} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType Obj *}{TypedText obj} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType void (^)(Obj *)}{TypedText onAction} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType FooBlock}{TypedText onEventHandler} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType void (^)(int *)}{TypedText onReadonly} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType int (^)(int)}{TypedText processEvent} (35) +// RUN: c-index-test -code-completion-at=%s:54:15 %s | FileCheck -check-prefix=CHECK-NO1 %s +// CHECK-NO1: ObjCPropertyDecl:{ResultType int}{TypedText foo} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType Obj *}{TypedText obj} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType void (^)(Obj *)}{TypedText onAction} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType FooBlock}{TypedText onEventHandler} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType void (^)(int *)}{TypedText onReadonly} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType int (^)(int)}{TypedText processEvent} (35) +// CHECK-NO1-NEXT: OverloadCandidate:{ResultType void}{Text func}{LeftParen (}{CurrentParameter int x}{RightParen )} (1) @end Index: test/CodeCompletion/function-overloads.cpp === --- /dev/null +++ test/CodeCompletion/function-overloads.cpp @@ -0,0 +1,27 @@ +int f(int i, int j = 2, int k = 5); +int f(float x, float y...); + +class A { + public: + A(int, int, int); +}; + +void test() { + A a(f(1, 2, 3, 4), 2, 3); +} + +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:9 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:10 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:17 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:19 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:20 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:21 %s -o - | FileCheck -check-prefix=CHECK-CC4 %s +// CHECK-CC1: OVERLOAD: [#int#]f(<#float x#>, float y) +// CHECK-CC1: OVERLOAD: [#int#]f(<#int i#>) +// CHECK-CC1-NOT, CHECK-CC2-NOT: OVERLOAD: A( +// CHECK-CC2: OVERLOAD: [#int#]f(float x, float y) +// CHECK-CC2-NOT: OVERLOAD: [#int#]f(int i) +// CHECK-CC3: OVERLOAD: A(<#int#>, int, int) +// CHECK-CC3: OVERLOAD: A(<#const A >) +// CHECK-CC3: OVERLOAD: A(<#A &>) +// CHECK-CC4: OVERLOAD: A(int, <#int#>, int) Index: lib/Sema/CodeCompleteConsumer.cpp === --- lib/Sema/CodeCompleteConsumer.cpp +++ lib/Sema/CodeCompleteConsumer.cpp @@ -619,6 +619,9 @@ OS << "<#" << C.Text << "#>"; break; +case CodeCompletionString::CK_Optional: + break; + default: OS << C.Text; break; } } Index: lib/Parse/ParseOpenMP.cpp === --- lib/Parse/ParseOpenMP.cpp +++ lib/Parse/ParseOpenMP.cpp @@ -416,14 +416,20 @@ CommaLocsTy CommaLocs; SourceLocation LParLoc = T.getOpenLocation(); -if (ParseExpressionList( -Exprs, CommaLocs, [this, OmpPrivParm, LParLoc, &Exprs] { - QualType PreferredType = Actions.ProduceConstructorSignatureHelp( - getCurScope(), - OmpPrivParm->getType()->getCanonicalTypeInternal(), - OmpPrivParm->getLocation(), Exprs, LParLoc); - Actions.CodeCompleteExpression(getCurScope(), PreferredType); -})) { +auto Completer = [this, OmpPrivParm, LParLoc, &Exprs]() {
[PATCH] D51038: [clang] Make sure codecompletion is called for calls even when inside a token.
kadircet updated this revision to Diff 164659. kadircet added a comment. - Inline completers. Repository: rC Clang https://reviews.llvm.org/D51038 Files: include/clang/Parse/Parser.h lib/Parse/ParseDecl.cpp lib/Parse/ParseExpr.cpp lib/Parse/ParseExprCXX.cpp lib/Parse/ParseOpenMP.cpp lib/Sema/CodeCompleteConsumer.cpp test/CodeCompletion/function-overloads.cpp test/Index/complete-block-property-assignment.m Index: test/Index/complete-block-property-assignment.m === --- test/Index/complete-block-property-assignment.m +++ test/Index/complete-block-property-assignment.m @@ -60,13 +60,20 @@ // RUN: c-index-test -code-completion-at=%s:51:16 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:52:23 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:53:12 %s | FileCheck -check-prefix=CHECK-NO %s -// RUN: c-index-test -code-completion-at=%s:54:15 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:56:15 %s | FileCheck -check-prefix=CHECK-NO %s // CHECK-NO: ObjCPropertyDecl:{ResultType int}{TypedText foo} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType Obj *}{TypedText obj} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType void (^)(Obj *)}{TypedText onAction} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType FooBlock}{TypedText onEventHandler} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType void (^)(int *)}{TypedText onReadonly} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType int (^)(int)}{TypedText processEvent} (35) +// RUN: c-index-test -code-completion-at=%s:54:15 %s | FileCheck -check-prefix=CHECK-NO1 %s +// CHECK-NO1: ObjCPropertyDecl:{ResultType int}{TypedText foo} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType Obj *}{TypedText obj} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType void (^)(Obj *)}{TypedText onAction} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType FooBlock}{TypedText onEventHandler} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType void (^)(int *)}{TypedText onReadonly} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType int (^)(int)}{TypedText processEvent} (35) +// CHECK-NO1-NEXT: OverloadCandidate:{ResultType void}{Text func}{LeftParen (}{CurrentParameter int x}{RightParen )} (1) @end Index: test/CodeCompletion/function-overloads.cpp === --- /dev/null +++ test/CodeCompletion/function-overloads.cpp @@ -0,0 +1,27 @@ +int f(int i, int j = 2, int k = 5); +int f(float x, float y...); + +class A { + public: + A(int, int, int); +}; + +void test() { + A a(f(1, 2, 3, 4), 2, 3); +} + +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:9 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:10 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:17 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:19 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:20 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:21 %s -o - | FileCheck -check-prefix=CHECK-CC4 %s +// CHECK-CC1: OVERLOAD: [#int#]f(<#float x#>, float y) +// CHECK-CC1: OVERLOAD: [#int#]f(<#int i#>) +// CHECK-CC1-NOT, CHECK-CC2-NOT: OVERLOAD: A( +// CHECK-CC2: OVERLOAD: [#int#]f(float x, float y) +// CHECK-CC2-NOT: OVERLOAD: [#int#]f(int i) +// CHECK-CC3: OVERLOAD: A(<#int#>, int, int) +// CHECK-CC3: OVERLOAD: A(<#const A >) +// CHECK-CC3: OVERLOAD: A(<#A &>) +// CHECK-CC4: OVERLOAD: A(int, <#int#>, int) Index: lib/Sema/CodeCompleteConsumer.cpp === --- lib/Sema/CodeCompleteConsumer.cpp +++ lib/Sema/CodeCompleteConsumer.cpp @@ -619,6 +619,10 @@ OS << "<#" << C.Text << "#>"; break; +// FIXME: We can also print optional parameters of an overload. +case CodeCompletionString::CK_Optional: + break; + default: OS << C.Text; break; } } Index: lib/Parse/ParseOpenMP.cpp === --- lib/Parse/ParseOpenMP.cpp +++ lib/Parse/ParseOpenMP.cpp @@ -417,13 +417,20 @@ SourceLocation LParLoc = T.getOpenLocation(); if (ParseExpressionList( -Exprs, CommaLocs, [this, OmpPrivParm, LParLoc, &Exprs] { +Exprs, CommaLocs, [this, OmpPrivParm, LParLoc, &Exprs]() { QualType PreferredType = Actions.ProduceConstructorSignatureHelp( getCurScope(), OmpPrivParm->getType()->getCanonicalTypeInternal(), OmpPrivParm->getLocation(), Exprs, LParLoc); + CalledSignatureHelp = true; Actions.CodeCompleteExpression(g
[PATCH] D51038: [clang] Make sure codecompletion is called for calls even when inside a token.
kadircet updated this revision to Diff 164661. kadircet marked an inline comment as done. kadircet added a comment. - One last completer Repository: rC Clang https://reviews.llvm.org/D51038 Files: include/clang/Parse/Parser.h lib/Parse/ParseDecl.cpp lib/Parse/ParseExpr.cpp lib/Parse/ParseExprCXX.cpp lib/Parse/ParseOpenMP.cpp lib/Sema/CodeCompleteConsumer.cpp test/CodeCompletion/function-overloads.cpp test/Index/complete-block-property-assignment.m Index: test/Index/complete-block-property-assignment.m === --- test/Index/complete-block-property-assignment.m +++ test/Index/complete-block-property-assignment.m @@ -60,13 +60,20 @@ // RUN: c-index-test -code-completion-at=%s:51:16 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:52:23 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:53:12 %s | FileCheck -check-prefix=CHECK-NO %s -// RUN: c-index-test -code-completion-at=%s:54:15 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:56:15 %s | FileCheck -check-prefix=CHECK-NO %s // CHECK-NO: ObjCPropertyDecl:{ResultType int}{TypedText foo} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType Obj *}{TypedText obj} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType void (^)(Obj *)}{TypedText onAction} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType FooBlock}{TypedText onEventHandler} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType void (^)(int *)}{TypedText onReadonly} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType int (^)(int)}{TypedText processEvent} (35) +// RUN: c-index-test -code-completion-at=%s:54:15 %s | FileCheck -check-prefix=CHECK-NO1 %s +// CHECK-NO1: ObjCPropertyDecl:{ResultType int}{TypedText foo} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType Obj *}{TypedText obj} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType void (^)(Obj *)}{TypedText onAction} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType FooBlock}{TypedText onEventHandler} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType void (^)(int *)}{TypedText onReadonly} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType int (^)(int)}{TypedText processEvent} (35) +// CHECK-NO1-NEXT: OverloadCandidate:{ResultType void}{Text func}{LeftParen (}{CurrentParameter int x}{RightParen )} (1) @end Index: test/CodeCompletion/function-overloads.cpp === --- /dev/null +++ test/CodeCompletion/function-overloads.cpp @@ -0,0 +1,27 @@ +int f(int i, int j = 2, int k = 5); +int f(float x, float y...); + +class A { + public: + A(int, int, int); +}; + +void test() { + A a(f(1, 2, 3, 4), 2, 3); +} + +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:9 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:10 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:17 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:19 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:20 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:21 %s -o - | FileCheck -check-prefix=CHECK-CC4 %s +// CHECK-CC1: OVERLOAD: [#int#]f(<#float x#>, float y) +// CHECK-CC1: OVERLOAD: [#int#]f(<#int i#>) +// CHECK-CC1-NOT, CHECK-CC2-NOT: OVERLOAD: A( +// CHECK-CC2: OVERLOAD: [#int#]f(float x, float y) +// CHECK-CC2-NOT: OVERLOAD: [#int#]f(int i) +// CHECK-CC3: OVERLOAD: A(<#int#>, int, int) +// CHECK-CC3: OVERLOAD: A(<#const A >) +// CHECK-CC3: OVERLOAD: A(<#A &>) +// CHECK-CC4: OVERLOAD: A(int, <#int#>, int) Index: lib/Sema/CodeCompleteConsumer.cpp === --- lib/Sema/CodeCompleteConsumer.cpp +++ lib/Sema/CodeCompleteConsumer.cpp @@ -619,6 +619,10 @@ OS << "<#" << C.Text << "#>"; break; +// FIXME: We can also print optional parameters of an overload. +case CodeCompletionString::CK_Optional: + break; + default: OS << C.Text; break; } } Index: lib/Parse/ParseOpenMP.cpp === --- lib/Parse/ParseOpenMP.cpp +++ lib/Parse/ParseOpenMP.cpp @@ -422,8 +422,15 @@ getCurScope(), OmpPrivParm->getType()->getCanonicalTypeInternal(), OmpPrivParm->getLocation(), Exprs, LParLoc); + CalledSignatureHelp = true; Actions.CodeCompleteExpression(getCurScope(), PreferredType); })) { + if (PP.isCodeCompletionReached() && !CalledSignatureHelp) { +Actions.ProduceConstructorSignatureHelp( +getCurScope(), OmpPrivParm->getType()->getCanonicalTypeInternal(), +OmpPr
[PATCH] D51038: [clang] Make sure codecompletion is called for calls even when inside a token.
This revision was automatically updated to reflect the committed changes. Closed by commit rL341824: [clang] Make sure codecompletion is called for calls even when inside a token. (authored by kadircet, committed by ). Herald added a subscriber: llvm-commits. Repository: rL LLVM https://reviews.llvm.org/D51038 Files: cfe/trunk/include/clang/Parse/Parser.h cfe/trunk/lib/Parse/ParseDecl.cpp cfe/trunk/lib/Parse/ParseExpr.cpp cfe/trunk/lib/Parse/ParseExprCXX.cpp cfe/trunk/lib/Parse/ParseOpenMP.cpp cfe/trunk/lib/Sema/CodeCompleteConsumer.cpp cfe/trunk/test/CodeCompletion/function-overloads.cpp cfe/trunk/test/Index/complete-block-property-assignment.m Index: cfe/trunk/include/clang/Parse/Parser.h === --- cfe/trunk/include/clang/Parse/Parser.h +++ cfe/trunk/include/clang/Parse/Parser.h @@ -214,6 +214,11 @@ /// should not be set directly. bool InMessageExpression; + /// Gets set to true after calling ProduceSignatureHelp, it is for a + /// workaround to make sure ProduceSignatureHelp is only called at the deepest + /// function call. + bool CalledSignatureHelp = false; + /// The "depth" of the template parameters currently being parsed. unsigned TemplateParameterDepth; Index: cfe/trunk/test/Index/complete-block-property-assignment.m === --- cfe/trunk/test/Index/complete-block-property-assignment.m +++ cfe/trunk/test/Index/complete-block-property-assignment.m @@ -60,13 +60,20 @@ // RUN: c-index-test -code-completion-at=%s:51:16 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:52:23 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:53:12 %s | FileCheck -check-prefix=CHECK-NO %s -// RUN: c-index-test -code-completion-at=%s:54:15 %s | FileCheck -check-prefix=CHECK-NO %s // RUN: c-index-test -code-completion-at=%s:56:15 %s | FileCheck -check-prefix=CHECK-NO %s // CHECK-NO: ObjCPropertyDecl:{ResultType int}{TypedText foo} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType Obj *}{TypedText obj} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType void (^)(Obj *)}{TypedText onAction} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType FooBlock}{TypedText onEventHandler} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType void (^)(int *)}{TypedText onReadonly} (35) // CHECK-NO-NEXT: ObjCPropertyDecl:{ResultType int (^)(int)}{TypedText processEvent} (35) +// RUN: c-index-test -code-completion-at=%s:54:15 %s | FileCheck -check-prefix=CHECK-NO1 %s +// CHECK-NO1: ObjCPropertyDecl:{ResultType int}{TypedText foo} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType Obj *}{TypedText obj} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType void (^)(Obj *)}{TypedText onAction} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType FooBlock}{TypedText onEventHandler} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType void (^)(int *)}{TypedText onReadonly} (35) +// CHECK-NO1-NEXT: ObjCPropertyDecl:{ResultType int (^)(int)}{TypedText processEvent} (35) +// CHECK-NO1-NEXT: OverloadCandidate:{ResultType void}{Text func}{LeftParen (}{CurrentParameter int x}{RightParen )} (1) @end Index: cfe/trunk/test/CodeCompletion/function-overloads.cpp === --- cfe/trunk/test/CodeCompletion/function-overloads.cpp +++ cfe/trunk/test/CodeCompletion/function-overloads.cpp @@ -0,0 +1,27 @@ +int f(int i, int j = 2, int k = 5); +int f(float x, float y...); + +class A { + public: + A(int, int, int); +}; + +void test() { + A a(f(1, 2, 3, 4), 2, 3); +} + +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:9 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:10 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:17 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:19 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:20 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:21 %s -o - | FileCheck -check-prefix=CHECK-CC4 %s +// CHECK-CC1: OVERLOAD: [#int#]f(<#float x#>, float y) +// CHECK-CC1: OVERLOAD: [#int#]f(<#int i#>) +// CHECK-CC1-NOT, CHECK-CC2-NOT: OVERLOAD: A( +// CHECK-CC2: OVERLOAD: [#int#]f(float x, float y) +// CHECK-CC2-NOT: OVERLOAD: [#int#]f(int i) +// CHECK-CC3: OVERLOAD: A(<#int#>, int, int) +// CHECK-CC3: OVERLOAD: A(<#const A >) +// CHECK-CC3: OVERLOAD: A(<#A &>) +// CHECK-CC4: OVERLOAD: A(int, <#int#>, int) Index: cfe/trunk/lib/Sema/CodeCompleteConsumer.cpp === --- cfe/trunk/lib/Sema/CodeCompleteConsumer.cpp +++ cfe/trunk/lib/Sema/CodeCompleteConsumer.cpp @@ -619,6 +619,10 @@
[PATCH] D51039: [clangd] Add unittests for D51038
This revision was automatically updated to reflect the committed changes. Closed by commit rL341830: [clangd] Add unittests for D51038 (authored by kadircet, committed by ). Herald added a subscriber: llvm-commits. Changed prior to commit: https://reviews.llvm.org/D51039?vs=163968&id=164668#toc Repository: rL LLVM https://reviews.llvm.org/D51039 Files: clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp Index: clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp === --- clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp +++ clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp @@ -1917,6 +1917,56 @@ AllOf(Named("TestClangc"), Deprecated(; } +TEST(SignatureHelpTest, InsideArgument) { + { +const auto Results = signatures(R"cpp( + void foo(int x); + void foo(int x, int y); + int main() { foo(1+^); } +)cpp"); +EXPECT_THAT( +Results.signatures, +ElementsAre(Sig("foo(int x) -> void", {"int x"}), +Sig("foo(int x, int y) -> void", {"int x", "int y"}))); +EXPECT_EQ(0, Results.activeParameter); + } + { +const auto Results = signatures(R"cpp( + void foo(int x); + void foo(int x, int y); + int main() { foo(1^); } +)cpp"); +EXPECT_THAT( +Results.signatures, +ElementsAre(Sig("foo(int x) -> void", {"int x"}), +Sig("foo(int x, int y) -> void", {"int x", "int y"}))); +EXPECT_EQ(0, Results.activeParameter); + } + { +const auto Results = signatures(R"cpp( + void foo(int x); + void foo(int x, int y); + int main() { foo(1^0); } +)cpp"); +EXPECT_THAT( +Results.signatures, +ElementsAre(Sig("foo(int x) -> void", {"int x"}), +Sig("foo(int x, int y) -> void", {"int x", "int y"}))); +EXPECT_EQ(0, Results.activeParameter); + } + { +const auto Results = signatures(R"cpp( + void foo(int x); + void foo(int x, int y); + int bar(int x, int y); + int main() { bar(foo(2, 3^)); } +)cpp"); +EXPECT_THAT(Results.signatures, ElementsAre(Sig("foo(int x, int y) -> void", +{"int x", "int y"}))); +EXPECT_EQ(1, Results.activeParameter); + } +} + } // namespace } // namespace clangd } // namespace clang Index: clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp === --- clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp +++ clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp @@ -1917,6 +1917,56 @@ AllOf(Named("TestClangc"), Deprecated(; } +TEST(SignatureHelpTest, InsideArgument) { + { +const auto Results = signatures(R"cpp( + void foo(int x); + void foo(int x, int y); + int main() { foo(1+^); } +)cpp"); +EXPECT_THAT( +Results.signatures, +ElementsAre(Sig("foo(int x) -> void", {"int x"}), +Sig("foo(int x, int y) -> void", {"int x", "int y"}))); +EXPECT_EQ(0, Results.activeParameter); + } + { +const auto Results = signatures(R"cpp( + void foo(int x); + void foo(int x, int y); + int main() { foo(1^); } +)cpp"); +EXPECT_THAT( +Results.signatures, +ElementsAre(Sig("foo(int x) -> void", {"int x"}), +Sig("foo(int x, int y) -> void", {"int x", "int y"}))); +EXPECT_EQ(0, Results.activeParameter); + } + { +const auto Results = signatures(R"cpp( + void foo(int x); + void foo(int x, int y); + int main() { foo(1^0); } +)cpp"); +EXPECT_THAT( +Results.signatures, +ElementsAre(Sig("foo(int x) -> void", {"int x"}), +Sig("foo(int x, int y) -> void", {"int x", "int y"}))); +EXPECT_EQ(0, Results.activeParameter); + } + { +const auto Results = signatures(R"cpp( + void foo(int x); + void foo(int x, int y); + int bar(int x, int y); + int main() { bar(foo(2, 3^)); } +)cpp"); +EXPECT_THAT(Results.signatures, ElementsAre(Sig("foo(int x, int y) -> void", +{"int x", "int y"}))); +EXPECT_EQ(1, Results.activeParameter); + } +} + } // namespace } // namespace clangd } // namespace clang ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D51917: [CodeCompletion] Enable signature help when initializing class/struct/union members.
kadircet created this revision. kadircet added reviewers: sammccall, ilya-biryukov, ioeric. Herald added a subscriber: cfe-commits. Factors out member decleration gathering and uses it in parsing to call signature help. Doesn't support signature help for base class constructors, the code was too coupled with diagnostic handling, but still can be factored out but just needs more afford. Repository: rC Clang https://reviews.llvm.org/D51917 Files: include/clang/Sema/Sema.h lib/Parse/ParseDeclCXX.cpp lib/Sema/SemaDeclCXX.cpp test/CodeCompletion/ctor-initializer.cpp Index: test/CodeCompletion/ctor-initializer.cpp === --- test/CodeCompletion/ctor-initializer.cpp +++ test/CodeCompletion/ctor-initializer.cpp @@ -64,3 +64,26 @@ // CHECK-CC8: COMPLETION: Pattern : member2(<#args#> int member1, member2; }; + +struct Base2 { + Base2(int); +}; + +struct Composition1 { + Composition1() : b2_elem() {} + // RUN: %clang_cc1 -fsyntax-only -std=c++98 -code-completion-at=%s:73:28 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // RUN: %clang_cc1 -fsyntax-only -std=c++14 -code-completion-at=%s:73:28 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // CHECK-CC9: OVERLOAD: Base2(<#int#>) + // CHECK-CC9: OVERLOAD: Base2(<#const Base2 >) + Composition1(Base2); + Base2 b2_elem; +}; + +struct Composition2 { + Composition2() : c1_elem(Base2(1)) {} + // RUN: %clang_cc1 -fsyntax-only -std=c++98 -code-completion-at=%s:83:34 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // RUN: %clang_cc1 -fsyntax-only -std=c++14 -code-completion-at=%s:83:34 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // RUN: %clang_cc1 -fsyntax-only -std=c++98 -code-completion-at=%s:83:35 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // RUN: %clang_cc1 -fsyntax-only -std=c++14 -code-completion-at=%s:83:35 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + Composition1 c1_elem; +}; Index: lib/Sema/SemaDeclCXX.cpp === --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -3777,6 +3777,23 @@ } +ValueDecl *clang::tryGetMember(CXXRecordDecl *ClassDecl, CXXScopeSpec &SS, +ParsedType TemplateTypeTy, +IdentifierInfo *MemberOrBase) { + if (!SS.getScopeRep() && !TemplateTypeTy) { +// Look for a member, first. +DeclContext::lookup_result Result = ClassDecl->lookup(MemberOrBase); +if (!Result.empty()) { + ValueDecl *Member; + if ((Member = dyn_cast(Result.front())) || + (Member = dyn_cast(Result.front( { +return Member; + } +} + } + return nullptr; +} + /// Handle a C++ member initializer. MemInitResult Sema::BuildMemInitializer(Decl *ConstructorD, @@ -3820,21 +3837,14 @@ // of a single identifier refers to the class member. A // mem-initializer-id for the hidden base class may be specified // using a qualified name. ] - if (!SS.getScopeRep() && !TemplateTypeTy) { -// Look for a member, first. -DeclContext::lookup_result Result = ClassDecl->lookup(MemberOrBase); -if (!Result.empty()) { - ValueDecl *Member; - if ((Member = dyn_cast(Result.front())) || - (Member = dyn_cast(Result.front( { -if (EllipsisLoc.isValid()) - Diag(EllipsisLoc, diag::err_pack_expansion_member_init) -<< MemberOrBase -<< SourceRange(IdLoc, Init->getSourceRange().getEnd()); - -return BuildMemberInitializer(Member, Init, IdLoc); - } -} + if (ValueDecl *Member = + tryGetMember(ClassDecl, SS, TemplateTypeTy, MemberOrBase)) { +if (EllipsisLoc.isValid()) + Diag(EllipsisLoc, diag::err_pack_expansion_member_init) + << MemberOrBase + << SourceRange(IdLoc, Init->getSourceRange().getEnd()); + +return BuildMemberInitializer(Member, Init, IdLoc); } // It didn't name a member, so see if it names a class. QualType BaseType; Index: lib/Parse/ParseDeclCXX.cpp === --- lib/Parse/ParseDeclCXX.cpp +++ lib/Parse/ParseDeclCXX.cpp @@ -3449,6 +3449,7 @@ if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); +// FIXME: Add support for signature help inside initializer lists. ExprResult InitList = ParseBraceInitializer(); if (InitList.isInvalid()) return true; @@ -3466,7 +3467,26 @@ // Parse the optional expression-list. ExprVector ArgExprs; CommaLocsTy CommaLocs; -if (Tok.isNot(tok::r_paren) && ParseExpressionList(ArgExprs, CommaLocs)) { +auto SignatureHelpCaller = [&] { + if (CalledSignatureHelp) +return; + CXXConstructorDecl *Constructor = + dyn_cast(ConstructorDecl); + if (!Constructor) +return; + // FIXME: Add support for Base class constructors as well. +
[PATCH] D51297: [docs] Create a guide for Vim users on how to set up Clangd
kadircet added a comment. In https://reviews.llvm.org/D51297#1228725, @ioeric wrote: > I also support having some instructions/pointers on editor integration. That > said, I think we should have a section "Editor integration" with a list of > editor clients that are known to work with clangd, instead of having a > section just for vim. Something like: > > #Editor (or client?) integration > > ##Vim > Some LSP clients that are known to work with clangd: >- nvim, LanguageClient-neovim .. >- ... > > ## vscode > > ## emacs? > > > > What do you think? Sorry I am trespassing, just wanted to say +1 to this. https://reviews.llvm.org/D51297 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D51214: [clangd] Add options to enable/disable fixits and function argument snippets.
kadircet updated this revision to Diff 164830. kadircet marked 5 inline comments as done. kadircet added a comment. - Change flag's name and rebase. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D51214 Files: clangd/tool/ClangdMain.cpp Index: clangd/tool/ClangdMain.cpp === --- clangd/tool/ClangdMain.cpp +++ clangd/tool/ClangdMain.cpp @@ -168,6 +168,19 @@ "'compile_commands.json' files")), llvm::cl::init(FilesystemCompileArgs), llvm::cl::Hidden); +static llvm::cl::opt IncludeFixIts( +"completions-with-fixes", +llvm::cl::desc( +"Enables suggestion of completion items that needs additional changes. " +"Like changing an arrow(->) member access to dot(.) member access."), +llvm::cl::init(clangd::CodeCompleteOptions().IncludeFixIts)); + +static llvm::cl::opt EnableFunctionArgSnippets( +"enable-function-arg-snippets", +llvm::cl::desc("Gives snippets for function arguments, when disabled only " + "gives parantheses for the call."), +llvm::cl::init(clangd::CodeCompleteOptions().EnableFunctionArgSnippets)); + int main(int argc, char *argv[]) { llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); llvm::cl::SetVersionPrinter([](llvm::raw_ostream &OS) { @@ -295,6 +308,8 @@ CCOpts.IncludeIndicator.NoInsert.clear(); } CCOpts.SpeculativeIndexRequest = Opts.StaticIndex; + CCOpts.IncludeFixIts = IncludeFixIts; + CCOpts.EnableFunctionArgSnippets = EnableFunctionArgSnippets; // Initialize and run ClangdLSPServer. ClangdLSPServer LSPServer( Index: clangd/tool/ClangdMain.cpp === --- clangd/tool/ClangdMain.cpp +++ clangd/tool/ClangdMain.cpp @@ -168,6 +168,19 @@ "'compile_commands.json' files")), llvm::cl::init(FilesystemCompileArgs), llvm::cl::Hidden); +static llvm::cl::opt IncludeFixIts( +"completions-with-fixes", +llvm::cl::desc( +"Enables suggestion of completion items that needs additional changes. " +"Like changing an arrow(->) member access to dot(.) member access."), +llvm::cl::init(clangd::CodeCompleteOptions().IncludeFixIts)); + +static llvm::cl::opt EnableFunctionArgSnippets( +"enable-function-arg-snippets", +llvm::cl::desc("Gives snippets for function arguments, when disabled only " + "gives parantheses for the call."), +llvm::cl::init(clangd::CodeCompleteOptions().EnableFunctionArgSnippets)); + int main(int argc, char *argv[]) { llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); llvm::cl::SetVersionPrinter([](llvm::raw_ostream &OS) { @@ -295,6 +308,8 @@ CCOpts.IncludeIndicator.NoInsert.clear(); } CCOpts.SpeculativeIndexRequest = Opts.StaticIndex; + CCOpts.IncludeFixIts = IncludeFixIts; + CCOpts.EnableFunctionArgSnippets = EnableFunctionArgSnippets; // Initialize and run ClangdLSPServer. ClangdLSPServer LSPServer( ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D51917: [CodeCompletion] Enable signature help when initializing class/struct/union members.
kadircet updated this revision to Diff 164844. kadircet marked 3 inline comments as done. kadircet added a comment. - Move ValueDecl extraction to a helper. - Call completion handlers as well. Repository: rC Clang https://reviews.llvm.org/D51917 Files: include/clang/Sema/Sema.h lib/Parse/ParseDeclCXX.cpp lib/Sema/SemaCodeComplete.cpp lib/Sema/SemaDeclCXX.cpp test/CodeCompletion/ctor-initializer.cpp Index: test/CodeCompletion/ctor-initializer.cpp === --- test/CodeCompletion/ctor-initializer.cpp +++ test/CodeCompletion/ctor-initializer.cpp @@ -64,3 +64,26 @@ // CHECK-CC8: COMPLETION: Pattern : member2(<#args#> int member1, member2; }; + +struct Base2 { + Base2(int); +}; + +struct Composition1 { + Composition1() : b2_elem() {} + // RUN: %clang_cc1 -fsyntax-only -std=c++98 -code-completion-at=%s:73:28 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // RUN: %clang_cc1 -fsyntax-only -std=c++14 -code-completion-at=%s:73:28 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // CHECK-CC9: OVERLOAD: Base2(<#int#>) + // CHECK-CC9: OVERLOAD: Base2(<#const Base2 >) + Composition1(Base2); + Base2 b2_elem; +}; + +struct Composition2 { + Composition2() : c1_elem(Base2(1)) {} + // RUN: %clang_cc1 -fsyntax-only -std=c++98 -code-completion-at=%s:83:34 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // RUN: %clang_cc1 -fsyntax-only -std=c++14 -code-completion-at=%s:83:34 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // RUN: %clang_cc1 -fsyntax-only -std=c++98 -code-completion-at=%s:83:35 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // RUN: %clang_cc1 -fsyntax-only -std=c++14 -code-completion-at=%s:83:35 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + Composition1 c1_elem; +}; Index: lib/Sema/SemaDeclCXX.cpp === --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -3777,6 +3777,24 @@ } +ValueDecl *Sema::tryLookupCtorInitMemberDecl(CXXRecordDecl *ClassDecl, + CXXScopeSpec &SS, + ParsedType TemplateTypeTy, + IdentifierInfo *MemberOrBase) { + if (!SS.getScopeRep() && !TemplateTypeTy) { +// Look for a member, first. +DeclContext::lookup_result Result = ClassDecl->lookup(MemberOrBase); +if (!Result.empty()) { + ValueDecl *Member; + if ((Member = dyn_cast(Result.front())) || + (Member = dyn_cast(Result.front( { +return Member; + } +} + } + return nullptr; +} + /// Handle a C++ member initializer. MemInitResult Sema::BuildMemInitializer(Decl *ConstructorD, @@ -3820,21 +3838,14 @@ // of a single identifier refers to the class member. A // mem-initializer-id for the hidden base class may be specified // using a qualified name. ] - if (!SS.getScopeRep() && !TemplateTypeTy) { -// Look for a member, first. -DeclContext::lookup_result Result = ClassDecl->lookup(MemberOrBase); -if (!Result.empty()) { - ValueDecl *Member; - if ((Member = dyn_cast(Result.front())) || - (Member = dyn_cast(Result.front( { -if (EllipsisLoc.isValid()) - Diag(EllipsisLoc, diag::err_pack_expansion_member_init) -<< MemberOrBase -<< SourceRange(IdLoc, Init->getSourceRange().getEnd()); - -return BuildMemberInitializer(Member, Init, IdLoc); - } -} + if (ValueDecl *Member = tryLookupCtorInitMemberDecl( + ClassDecl, SS, TemplateTypeTy, MemberOrBase)) { +if (EllipsisLoc.isValid()) + Diag(EllipsisLoc, diag::err_pack_expansion_member_init) + << MemberOrBase + << SourceRange(IdLoc, Init->getSourceRange().getEnd()); + +return BuildMemberInitializer(Member, Init, IdLoc); } // It didn't name a member, so see if it names a class. QualType BaseType; Index: lib/Sema/SemaCodeComplete.cpp === --- lib/Sema/SemaCodeComplete.cpp +++ lib/Sema/SemaCodeComplete.cpp @@ -4586,6 +4586,25 @@ return ProduceSignatureHelp(*this, S, Results, Args.size(), OpenParLoc); } +QualType Sema::ProduceCtorInitMemberSignatureHelp( +Scope *S, Decl *ConstructorDecl, CXXScopeSpec SS, ParsedType TemplateTypeTy, +ArrayRef ArgExprs, IdentifierInfo *II, SourceLocation OpenParLoc) { + if (!CodeCompleter) +return QualType(); + + CXXConstructorDecl *Constructor = + dyn_cast(ConstructorDecl); + if (!Constructor) +return QualType(); + // FIXME: Add support for Base class constructors as well. + if (ValueDecl *MemberDecl = tryLookupCtorInitMemberDecl( + Constructor->getParent(), SS, TemplateTypeTy, II)) +return ProduceConstructorSignatureHelp(getCurScope(), MemberDecl->getType(), + MemberDecl->getLocation(), ArgExprs, +
[PATCH] D51924: [clangd] Add unittests for D51917
kadircet created this revision. kadircet added a reviewer: ilya-biryukov. Herald added subscribers: cfe-commits, arphaman, jkorous, MaskRay, ioeric. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D51924 Files: unittests/clangd/CodeCompleteTests.cpp Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -1917,6 +1917,45 @@ AllOf(Named("TestClangc"), Deprecated(; } +TEST(SignatureHelpTest, ConstructorInitializeFields) { + { +const auto Results = signatures(R"cpp( + struct A { +A(int); + }; + struct B { +B() : a_elem(^) {} +A a_elem; + }; +)cpp"); +EXPECT_THAT(Results.signatures, UnorderedElementsAre( +Sig("A(int)", {"int"}), +Sig("A(A &&)", {"A &&"}), +Sig("A(const A &)", {"const A &"}) +)); + } + { +const auto Results = signatures(R"cpp( + struct A { +A(int); + }; + struct C { +C(int); +C(A); + }; + struct B { +B() : c_elem(A(1^)) {} +C c_elem; + }; +)cpp"); +EXPECT_THAT(Results.signatures, UnorderedElementsAre( +Sig("A(int)", {"int"}), +Sig("A(A &&)", {"A &&"}), +Sig("A(const A &)", {"const A &"}) +)); + } +} + } // namespace } // namespace clangd } // namespace clang Index: unittests/clangd/CodeCompleteTests.cpp === --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -1917,6 +1917,45 @@ AllOf(Named("TestClangc"), Deprecated(; } +TEST(SignatureHelpTest, ConstructorInitializeFields) { + { +const auto Results = signatures(R"cpp( + struct A { +A(int); + }; + struct B { +B() : a_elem(^) {} +A a_elem; + }; +)cpp"); +EXPECT_THAT(Results.signatures, UnorderedElementsAre( +Sig("A(int)", {"int"}), +Sig("A(A &&)", {"A &&"}), +Sig("A(const A &)", {"const A &"}) +)); + } + { +const auto Results = signatures(R"cpp( + struct A { +A(int); + }; + struct C { +C(int); +C(A); + }; + struct B { +B() : c_elem(A(1^)) {} +C c_elem; + }; +)cpp"); +EXPECT_THAT(Results.signatures, UnorderedElementsAre( +Sig("A(int)", {"int"}), +Sig("A(A &&)", {"A &&"}), +Sig("A(const A &)", {"const A &"}) +)); + } +} + } // namespace } // namespace clangd } // namespace clang ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D51214: [clangd] Add options to enable/disable fixits and function argument snippets.
kadircet updated this revision to Diff 164847. kadircet marked 4 inline comments as done. kadircet added a comment. - Update descriptions and change parameter name. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D51214 Files: clangd/tool/ClangdMain.cpp Index: clangd/tool/ClangdMain.cpp === --- clangd/tool/ClangdMain.cpp +++ clangd/tool/ClangdMain.cpp @@ -168,6 +168,20 @@ "'compile_commands.json' files")), llvm::cl::init(FilesystemCompileArgs), llvm::cl::Hidden); +static llvm::cl::opt IncludeFixIts( +"completions-with-fixes", +llvm::cl::desc( +"Enables suggestion of completion items that need additional changes. " +"Like changing an arrow(->) member access to dot(.) member access."), +llvm::cl::init(clangd::CodeCompleteOptions().IncludeFixIts)); + +static llvm::cl::opt EnableFunctionArgSnippets( +"function-arg-placeholders", +llvm::cl::desc("When disabled, completions contain only parentheses for " + "function calls. When enabled, completions also contain " + "placeholders for method parameters."), +llvm::cl::init(clangd::CodeCompleteOptions().EnableFunctionArgSnippets)); + int main(int argc, char *argv[]) { llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); llvm::cl::SetVersionPrinter([](llvm::raw_ostream &OS) { @@ -295,6 +309,8 @@ CCOpts.IncludeIndicator.NoInsert.clear(); } CCOpts.SpeculativeIndexRequest = Opts.StaticIndex; + CCOpts.IncludeFixIts = IncludeFixIts; + CCOpts.EnableFunctionArgSnippets = EnableFunctionArgSnippets; // Initialize and run ClangdLSPServer. ClangdLSPServer LSPServer( Index: clangd/tool/ClangdMain.cpp === --- clangd/tool/ClangdMain.cpp +++ clangd/tool/ClangdMain.cpp @@ -168,6 +168,20 @@ "'compile_commands.json' files")), llvm::cl::init(FilesystemCompileArgs), llvm::cl::Hidden); +static llvm::cl::opt IncludeFixIts( +"completions-with-fixes", +llvm::cl::desc( +"Enables suggestion of completion items that need additional changes. " +"Like changing an arrow(->) member access to dot(.) member access."), +llvm::cl::init(clangd::CodeCompleteOptions().IncludeFixIts)); + +static llvm::cl::opt EnableFunctionArgSnippets( +"function-arg-placeholders", +llvm::cl::desc("When disabled, completions contain only parentheses for " + "function calls. When enabled, completions also contain " + "placeholders for method parameters."), +llvm::cl::init(clangd::CodeCompleteOptions().EnableFunctionArgSnippets)); + int main(int argc, char *argv[]) { llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); llvm::cl::SetVersionPrinter([](llvm::raw_ostream &OS) { @@ -295,6 +309,8 @@ CCOpts.IncludeIndicator.NoInsert.clear(); } CCOpts.SpeculativeIndexRequest = Opts.StaticIndex; + CCOpts.IncludeFixIts = IncludeFixIts; + CCOpts.EnableFunctionArgSnippets = EnableFunctionArgSnippets; // Initialize and run ClangdLSPServer. ClangdLSPServer LSPServer( ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D51747: [clangd] Implement deprecation diagnostics with lower severity.
kadircet added a comment. In https://reviews.llvm.org/D51747#1229066, @sammccall wrote: > In https://reviews.llvm.org/D51747#1228919, @ilya-biryukov wrote: > > > > Most of the value of adding an option is: if someone complains, we can > > > tell them to go away :-) One possible corollary is: we shouldn't add the > > > option until someone complains. I'm not 100% sure about that, though - > > > not totally opposed to an option here. > > > > Any thoughts on tampering with provided compile args in the first place? Is > > it fine for clangd to be opinionated about the warnings we choose to always > > show to the users? > > E.g. I'm a big fan of various uninitialized warnings, but nevertheless > > don't think clangd should force them on everyone. > > > A few thoughts here: > > - does CDB describe user or project preferences? unclear. > - "show this warning for code I build" is a higher bar than "show this > warning for code I edit". So CDB probably enables too few warnings. > - Some warnings play well with -Werror (like uninit warnings), some don't > (like deprecated). -Werror projects often disable interesting warnings. > > I'm not sure we should strictly follow the CDB, but the bar to override it > should probably be high. Maybe the (default) behavior here should be "add > -Wdeprecated -Wno-error=deprecated if -Werror is set"? I agree with checking for -Werror and then providing -Wno-error as well, if -Wdeprecated was not added already. Then keeping it as warnings shouldn't be too much of a problem except the case you mentioned, if user wants to see all diagnostics as a list suddenly they will get deprecations in that list as well :(. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D51747 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D51917: [CodeCompletion] Enable signature help when initializing class/struct/union members.
kadircet updated this revision to Diff 164864. kadircet marked 3 inline comments as done. kadircet added a comment. - Resolve discussions. Repository: rC Clang https://reviews.llvm.org/D51917 Files: include/clang/Sema/Sema.h lib/Parse/ParseDeclCXX.cpp lib/Sema/SemaCodeComplete.cpp lib/Sema/SemaDeclCXX.cpp test/CodeCompletion/ctor-initializer.cpp Index: test/CodeCompletion/ctor-initializer.cpp === --- test/CodeCompletion/ctor-initializer.cpp +++ test/CodeCompletion/ctor-initializer.cpp @@ -64,3 +64,26 @@ // CHECK-CC8: COMPLETION: Pattern : member2(<#args#> int member1, member2; }; + +struct Base2 { + Base2(int); +}; + +struct Composition1 { + Composition1() : b2_elem() {} + // RUN: %clang_cc1 -fsyntax-only -std=c++98 -code-completion-at=%s:73:28 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // RUN: %clang_cc1 -fsyntax-only -std=c++14 -code-completion-at=%s:73:28 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // CHECK-CC9: OVERLOAD: Base2(<#int#>) + // CHECK-CC9: OVERLOAD: Base2(<#const Base2 >) + Composition1(Base2); + Base2 b2_elem; +}; + +struct Composition2 { + Composition2() : c1_elem(Base2(1)) {} + // RUN: %clang_cc1 -fsyntax-only -std=c++98 -code-completion-at=%s:83:34 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // RUN: %clang_cc1 -fsyntax-only -std=c++14 -code-completion-at=%s:83:34 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // RUN: %clang_cc1 -fsyntax-only -std=c++98 -code-completion-at=%s:83:35 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // RUN: %clang_cc1 -fsyntax-only -std=c++14 -code-completion-at=%s:83:35 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + Composition1 c1_elem; +}; Index: lib/Sema/SemaDeclCXX.cpp === --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -3777,6 +3777,22 @@ } +ValueDecl *Sema::tryLookupCtorInitMemberDecl(CXXRecordDecl *ClassDecl, + CXXScopeSpec &SS, + ParsedType TemplateTypeTy, + IdentifierInfo *MemberOrBase) { + if (SS.getScopeRep() || TemplateTypeTy) +return nullptr; + DeclContext::lookup_result Result = ClassDecl->lookup(MemberOrBase); + if (Result.empty()) +return nullptr; + ValueDecl *Member; + if ((Member = dyn_cast(Result.front())) || + (Member = dyn_cast(Result.front( +return Member; + return nullptr; +} + /// Handle a C++ member initializer. MemInitResult Sema::BuildMemInitializer(Decl *ConstructorD, @@ -3820,21 +3836,16 @@ // of a single identifier refers to the class member. A // mem-initializer-id for the hidden base class may be specified // using a qualified name. ] - if (!SS.getScopeRep() && !TemplateTypeTy) { -// Look for a member, first. -DeclContext::lookup_result Result = ClassDecl->lookup(MemberOrBase); -if (!Result.empty()) { - ValueDecl *Member; - if ((Member = dyn_cast(Result.front())) || - (Member = dyn_cast(Result.front( { -if (EllipsisLoc.isValid()) - Diag(EllipsisLoc, diag::err_pack_expansion_member_init) -<< MemberOrBase -<< SourceRange(IdLoc, Init->getSourceRange().getEnd()); - -return BuildMemberInitializer(Member, Init, IdLoc); - } -} + + // Look for a member, first. + if (ValueDecl *Member = tryLookupCtorInitMemberDecl( + ClassDecl, SS, TemplateTypeTy, MemberOrBase)) { +if (EllipsisLoc.isValid()) + Diag(EllipsisLoc, diag::err_pack_expansion_member_init) + << MemberOrBase + << SourceRange(IdLoc, Init->getSourceRange().getEnd()); + +return BuildMemberInitializer(Member, Init, IdLoc); } // It didn't name a member, so see if it names a class. QualType BaseType; Index: lib/Sema/SemaCodeComplete.cpp === --- lib/Sema/SemaCodeComplete.cpp +++ lib/Sema/SemaCodeComplete.cpp @@ -4586,6 +4586,25 @@ return ProduceSignatureHelp(*this, S, Results, Args.size(), OpenParLoc); } +QualType Sema::ProduceCtorInitMemberSignatureHelp( +Scope *S, Decl *ConstructorDecl, CXXScopeSpec SS, ParsedType TemplateTypeTy, +ArrayRef ArgExprs, IdentifierInfo *II, SourceLocation OpenParLoc) { + if (!CodeCompleter) +return QualType(); + + CXXConstructorDecl *Constructor = + dyn_cast(ConstructorDecl); + if (!Constructor) +return QualType(); + // FIXME: Add support for Base class constructors as well. + if (ValueDecl *MemberDecl = tryLookupCtorInitMemberDecl( + Constructor->getParent(), SS, TemplateTypeTy, II)) +return ProduceConstructorSignatureHelp(getCurScope(), MemberDecl->getType(), + MemberDecl->getLocation(), ArgExprs, + OpenParLoc); + return QualType(); +} + vo
[PATCH] D51214: [clangd] Add options to enable/disable fixits and function argument snippets.
kadircet added inline comments. Comment at: clangd/tool/ClangdMain.cpp:197 +static llvm::cl::opt IncludeFixIts( +"include-fixits", ilya-biryukov wrote: > sammccall wrote: > > ilya-biryukov wrote: > > > I wonder if we should make the `IncludeFixIts` option hidden? > > > It currently only works for our YCM integration, VSCode and other clients > > > break. > > why would a user want to turn this on or off? > Ideally, we want to have it always on. > However, all editors interpret the results we return in different ways. This > is a temporary option until we can define how text edits are handled by LSP. > We filed the bugs, will dig them up on Monday. +1 to @ilya-biryukov . We might need to wait for a while until all editors supports additionalTextEdits in a sane way. Comment at: clangd/tool/ClangdMain.cpp:202 +"Like changing an arrow(->) member access to dot(.) member access."), +llvm::cl::init(clangd::CodeCompleteOptions().IncludeFixIts)); + ilya-biryukov wrote: > sammccall wrote: > > ilya-biryukov wrote: > > > Maybe specify the value here explicitly? > > > The defaults for users of the clangd binary (what the option is for) is > > > not necessarily the best default for the `ClangdServer` clients (what the > > > default in the struct is for). > > > More importantly, it's useful to be more straightforward about the > > > defaults we have for the options. > > Not sure I agree here, this is consistent with the other options above. > > It's the other `ClangdServer` clients that are the weirdos, they should > > have to be explicit :-) > > > > The defaults are clear when running with `-help`, which is how users will > > see them. > > The defaults are clear when running with -help, which is how users will see > > them. > Sure, but I would still argue reading the code is simpler without extra > indirection and defaults of the binary are not necessarily the defaults we > use in the APIs. > > But also feel free to keep the code as is, don't think it's terribly > important. Keeping it as it is. Comment at: clangd/tool/ClangdMain.cpp:205 +static llvm::cl::opt EnableFunctionArgSnippets( +"enable-function-arg-snippets", +llvm::cl::desc("Gives snippets for function arguments, when disabled only " ilya-biryukov wrote: > sammccall wrote: > > ilya-biryukov wrote: > > > I wonder if we can infer this setting from the `-completion-style' > > > (`=bundled` implies `enable-function-arg-snippets == false`) > > > @sammccall, WDYT? > > They're not inextricably linked, the main connection is "these options both > > need good signaturehelp support to be really useful". > > But we might want to link them just to cut down on number of options. > > > > I don't have a strong opinion, I don't use `-completion-style=bundled`. Can > > we find a few people who do and ask if they like this setting? > I would (obviously) want these two options to be packaged together whenever I > use `=bundled`. > But I also use VSCode, which has signatureHelp. > > I think @ioeric wanted to try out the `=bundled` completion style. @ioeric, > WDYT? ping on this discussion to @ioeric , but I think linking seems like a good idea. Because it wouldn't be very useful if one already selects a specific overload from completion list. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D51214 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D51917: [CodeCompletion] Enable signature help when initializing class/struct/union members.
kadircet updated this revision to Diff 164866. kadircet added a comment. - Update tests. Repository: rC Clang https://reviews.llvm.org/D51917 Files: include/clang/Sema/Sema.h lib/Parse/ParseDeclCXX.cpp lib/Sema/SemaCodeComplete.cpp lib/Sema/SemaDeclCXX.cpp test/CodeCompletion/ctor-initializer.cpp Index: test/CodeCompletion/ctor-initializer.cpp === --- test/CodeCompletion/ctor-initializer.cpp +++ test/CodeCompletion/ctor-initializer.cpp @@ -64,3 +64,27 @@ // CHECK-CC8: COMPLETION: Pattern : member2(<#args#> int member1, member2; }; + +struct Base2 { + Base2(int); +}; + +struct Composition1 { + Composition1() : b2_elem() {} + // RUN: %clang_cc1 -fsyntax-only -std=c++98 -code-completion-at=%s:73:28 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // RUN: %clang_cc1 -fsyntax-only -std=c++14 -code-completion-at=%s:73:28 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // CHECK-CC9: OVERLOAD: Base2(<#int#>) + // CHECK-CC9: OVERLOAD: Base2(<#const Base2 >) + // CHECK-CC9-NOT: OVERLOAD: Composition1 + Composition1(Base2); + Base2 b2_elem; +}; + +struct Composition2 { + Composition2() : c1_elem(Base2(1)) {} + // RUN: %clang_cc1 -fsyntax-only -std=c++98 -code-completion-at=%s:84:34 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // RUN: %clang_cc1 -fsyntax-only -std=c++14 -code-completion-at=%s:84:34 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // RUN: %clang_cc1 -fsyntax-only -std=c++98 -code-completion-at=%s:84:35 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // RUN: %clang_cc1 -fsyntax-only -std=c++14 -code-completion-at=%s:84:35 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + Composition1 c1_elem; +}; Index: lib/Sema/SemaDeclCXX.cpp === --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -3777,6 +3777,22 @@ } +ValueDecl *Sema::tryLookupCtorInitMemberDecl(CXXRecordDecl *ClassDecl, + CXXScopeSpec &SS, + ParsedType TemplateTypeTy, + IdentifierInfo *MemberOrBase) { + if (SS.getScopeRep() || TemplateTypeTy) +return nullptr; + DeclContext::lookup_result Result = ClassDecl->lookup(MemberOrBase); + if (Result.empty()) +return nullptr; + ValueDecl *Member; + if ((Member = dyn_cast(Result.front())) || + (Member = dyn_cast(Result.front( +return Member; + return nullptr; +} + /// Handle a C++ member initializer. MemInitResult Sema::BuildMemInitializer(Decl *ConstructorD, @@ -3820,21 +3836,16 @@ // of a single identifier refers to the class member. A // mem-initializer-id for the hidden base class may be specified // using a qualified name. ] - if (!SS.getScopeRep() && !TemplateTypeTy) { -// Look for a member, first. -DeclContext::lookup_result Result = ClassDecl->lookup(MemberOrBase); -if (!Result.empty()) { - ValueDecl *Member; - if ((Member = dyn_cast(Result.front())) || - (Member = dyn_cast(Result.front( { -if (EllipsisLoc.isValid()) - Diag(EllipsisLoc, diag::err_pack_expansion_member_init) -<< MemberOrBase -<< SourceRange(IdLoc, Init->getSourceRange().getEnd()); - -return BuildMemberInitializer(Member, Init, IdLoc); - } -} + + // Look for a member, first. + if (ValueDecl *Member = tryLookupCtorInitMemberDecl( + ClassDecl, SS, TemplateTypeTy, MemberOrBase)) { +if (EllipsisLoc.isValid()) + Diag(EllipsisLoc, diag::err_pack_expansion_member_init) + << MemberOrBase + << SourceRange(IdLoc, Init->getSourceRange().getEnd()); + +return BuildMemberInitializer(Member, Init, IdLoc); } // It didn't name a member, so see if it names a class. QualType BaseType; Index: lib/Sema/SemaCodeComplete.cpp === --- lib/Sema/SemaCodeComplete.cpp +++ lib/Sema/SemaCodeComplete.cpp @@ -4586,6 +4586,25 @@ return ProduceSignatureHelp(*this, S, Results, Args.size(), OpenParLoc); } +QualType Sema::ProduceCtorInitMemberSignatureHelp( +Scope *S, Decl *ConstructorDecl, CXXScopeSpec SS, ParsedType TemplateTypeTy, +ArrayRef ArgExprs, IdentifierInfo *II, SourceLocation OpenParLoc) { + if (!CodeCompleter) +return QualType(); + + CXXConstructorDecl *Constructor = + dyn_cast(ConstructorDecl); + if (!Constructor) +return QualType(); + // FIXME: Add support for Base class constructors as well. + if (ValueDecl *MemberDecl = tryLookupCtorInitMemberDecl( + Constructor->getParent(), SS, TemplateTypeTy, II)) +return ProduceConstructorSignatureHelp(getCurScope(), MemberDecl->getType(), + MemberDecl->getLocation(), ArgExprs, + OpenParLoc); + return QualType(); +} + void Sem
[PATCH] D51917: [CodeCompletion] Enable signature help when initializing class/struct/union members.
This revision was automatically updated to reflect the committed changes. Closed by commit rC341949: [CodeCompletion] Enable signature help when initializing class/struct/union… (authored by kadircet, committed by ). Changed prior to commit: https://reviews.llvm.org/D51917?vs=164866&id=164883#toc Repository: rC Clang https://reviews.llvm.org/D51917 Files: include/clang/Sema/Sema.h lib/Parse/ParseDeclCXX.cpp lib/Sema/SemaCodeComplete.cpp lib/Sema/SemaDeclCXX.cpp test/CodeCompletion/ctor-initializer.cpp Index: include/clang/Sema/Sema.h === --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -4568,6 +4568,11 @@ // of a ComparisonCategoryType enumerator. llvm::SmallBitVector FullyCheckedComparisonCategories; + ValueDecl *tryLookupCtorInitMemberDecl(CXXRecordDecl *ClassDecl, + CXXScopeSpec &SS, + ParsedType TemplateTypeTy, + IdentifierInfo *MemberOrBase); + public: /// Lookup the specified comparison category types in the standard /// library, an check the VarDecls possibly returned by the operator<=> @@ -10254,6 +10259,12 @@ SourceLocation Loc, ArrayRef Args, SourceLocation OpenParLoc); + QualType ProduceCtorInitMemberSignatureHelp(Scope *S, Decl *ConstructorDecl, + CXXScopeSpec SS, + ParsedType TemplateTypeTy, + ArrayRef ArgExprs, + IdentifierInfo *II, + SourceLocation OpenParLoc); void CodeCompleteInitializer(Scope *S, Decl *D); void CodeCompleteReturn(Scope *S); void CodeCompleteAfterIf(Scope *S); @@ -10794,7 +10805,6 @@ /// The template function declaration to be late parsed. Decl *D; }; - } // end namespace clang namespace llvm { Index: test/CodeCompletion/ctor-initializer.cpp === --- test/CodeCompletion/ctor-initializer.cpp +++ test/CodeCompletion/ctor-initializer.cpp @@ -64,3 +64,27 @@ // CHECK-CC8: COMPLETION: Pattern : member2(<#args#> int member1, member2; }; + +struct Base2 { + Base2(int); +}; + +struct Composition1 { + Composition1() : b2_elem() {} + // RUN: %clang_cc1 -fsyntax-only -std=c++98 -code-completion-at=%s:73:28 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // RUN: %clang_cc1 -fsyntax-only -std=c++14 -code-completion-at=%s:73:28 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // CHECK-CC9: OVERLOAD: Base2(<#int#>) + // CHECK-CC9: OVERLOAD: Base2(<#const Base2 >) + // CHECK-CC9-NOT: OVERLOAD: Composition1 + Composition1(Base2); + Base2 b2_elem; +}; + +struct Composition2 { + Composition2() : c1_elem(Base2(1)) {} + // RUN: %clang_cc1 -fsyntax-only -std=c++98 -code-completion-at=%s:84:34 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // RUN: %clang_cc1 -fsyntax-only -std=c++14 -code-completion-at=%s:84:34 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // RUN: %clang_cc1 -fsyntax-only -std=c++98 -code-completion-at=%s:84:35 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + // RUN: %clang_cc1 -fsyntax-only -std=c++14 -code-completion-at=%s:84:35 %s -o - | FileCheck -check-prefix=CHECK-CC9 %s + Composition1 c1_elem; +}; Index: lib/Sema/SemaDeclCXX.cpp === --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -3777,6 +3777,22 @@ } +ValueDecl *Sema::tryLookupCtorInitMemberDecl(CXXRecordDecl *ClassDecl, + CXXScopeSpec &SS, + ParsedType TemplateTypeTy, + IdentifierInfo *MemberOrBase) { + if (SS.getScopeRep() || TemplateTypeTy) +return nullptr; + DeclContext::lookup_result Result = ClassDecl->lookup(MemberOrBase); + if (Result.empty()) +return nullptr; + ValueDecl *Member; + if ((Member = dyn_cast(Result.front())) || + (Member = dyn_cast(Result.front( +return Member; + return nullptr; +} + /// Handle a C++ member initializer. MemInitResult Sema::BuildMemInitializer(Decl *ConstructorD, @@ -3820,21 +3836,16 @@ // of a single identifier refers to the class member. A // mem-initializer-id for the hidden base class may be specified // using a qualified name. ] - if (!SS.getScopeRep() && !TemplateTypeTy) { -// Look for a member, first. -DeclContext::lookup_result Result = ClassDecl->lookup(MemberOrBase); -if (!Result.empty()) { - ValueDecl *Member; - if ((Member = dyn_cast(Result.front())) || - (Member = dyn_cast(Result.front( {