[PATCH] D142836: [clangd] Add symbol mappings for `std::experimental::filesystem`

2023-01-29 Thread Younan Zhang via Phabricator via cfe-commits
zyounan created this revision.
Herald added subscribers: kadircet, arphaman.
Herald added a project: All.
zyounan edited the summary of this revision.
zyounan added reviewers: hokein, sammccall, nridge.
zyounan published this revision for review.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.
Herald added projects: clang, clang-tools-extra.

Clangd maintains a symbol map from standard library, in order to prevent
unexpected header/symbol leaks from internal files. (e.g. files under
`bits/` for libstdc++) This symbol map was generated by a python script
that parses pages of offline cppreference archive. The script didn't
handle the case for `std::experimental::`, where most symbols are from
TS. It works well as symbols are directly laid out in the corresponding
header under `experimental` directory for most of time.

However, libstdc++'s implementation split symbols of TS FS into a few
header files located in `experimental/bits`. This would make the code
completion provide internal headers when we simply select the symbols.

This fixes https://github.com/clangd/clangd/issues/1481


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D142836

Files:
  clang-tools-extra/clangd/index/CanonicalIncludes.cpp
  clang-tools-extra/clangd/unittests/CanonicalIncludesTests.cpp
  clang/include/clang/Tooling/Inclusions/TsStdSymbolMap.inc

Index: clang/include/clang/Tooling/Inclusions/TsStdSymbolMap.inc
===
--- /dev/null
+++ clang/include/clang/Tooling/Inclusions/TsStdSymbolMap.inc
@@ -0,0 +1,55 @@
+// FIXME: Add a parser for experimental pages to `clang/tools/include-mapping/cppreference_parser.py`
+
+SYMBOL(absolute, std::experimental::filesystem::, )
+SYMBOL(canonical, std::experimental::filesystem::, )
+SYMBOL(copy, std::experimental::filesystem::, )
+SYMBOL(copy_file, std::experimental::filesystem::, )
+SYMBOL(copy_options, std::experimental::filesystem::, )
+SYMBOL(copy_symlink, std::experimental::filesystem::, )
+SYMBOL(create_directories, std::experimental::filesystem::, )
+SYMBOL(create_directory, std::experimental::filesystem::, )
+SYMBOL(create_directory_symlink, std::experimental::filesystem::, )
+SYMBOL(create_hard_link, std::experimental::filesystem::, )
+SYMBOL(create_symlink, std::experimental::filesystem::, )
+SYMBOL(current_path, std::experimental::filesystem::, )
+SYMBOL(directory_entry, std::experimental::filesystem::, )
+SYMBOL(directory_iterator, std::experimental::filesystem::, )
+SYMBOL(directory_options, std::experimental::filesystem::, )
+SYMBOL(equivalent, std::experimental::filesystem::, )
+SYMBOL(exists, std::experimental::filesystem::, )
+SYMBOL(file_size, std::experimental::filesystem::, )
+SYMBOL(file_status, std::experimental::filesystem::, )
+SYMBOL(file_time_type, std::experimental::filesystem::, )
+SYMBOL(file_type, std::experimental::filesystem::, )
+SYMBOL(filesystem_error, std::experimental::filesystem::, )
+SYMBOL(hard_link_count, std::experimental::filesystem::, )
+SYMBOL(is_block_file, std::experimental::filesystem::, )
+SYMBOL(is_character_file, std::experimental::filesystem::, )
+SYMBOL(is_directory, std::experimental::filesystem::, )
+SYMBOL(is_empty, std::experimental::filesystem::, )
+SYMBOL(is_fifo, std::experimental::filesystem::, )
+SYMBOL(is_other, std::experimental::filesystem::, )
+SYMBOL(is_regular_file, std::experimental::filesystem::, )
+SYMBOL(is_socket, std::experimental::filesystem::, )
+SYMBOL(is_symlink, std::experimental::filesystem::, )
+SYMBOL(last_write_time, std::experimental::filesystem::, )
+SYMBOL(path, std::experimental::filesystem::, )
+SYMBOL(perm_options, std::experimental::filesystem::, )
+SYMBOL(permissions, std::experimental::filesystem::, )
+SYMBOL(perms, std::experimental::filesystem::, )
+SYMBOL(proximate, std::experimental::filesystem::, )
+SYMBOL(read_symlink, std::experimental::filesystem::, )
+SYMBOL(recursive_directory_iterator, std::experimental::filesystem::, )
+SYMBOL(relative, std::experimental::filesystem::, )
+SYMBOL(remove, std::experimental::filesystem::, )
+SYMBOL(remove_all, std::experimental::filesystem::, )
+SYMBOL(rename, std::experimental::filesystem::, )
+SYMBOL(resize_file, std::experimental::filesystem::, )
+SYMBOL(space, std::experimental::filesystem::, )
+SYMBOL(space_info, std::experimental::filesystem::, )
+SYMBOL(status, std::experimental::filesystem::, )
+SYMBOL(status_known, std::experimental::filesystem::, )
+SYMBOL(symlink_status, std::experimental::filesystem::, )
+SYMBOL(temp_directory_path, std::experimental::filesystem::, )
+SYMBOL(u8path, std::experimental::filesystem::, )
+SYMBOL(weakly_canonical, std::experimental::filesystem::, )
Index: clang-tools-extra/clangd/unittests/CanonicalIncludesTests.cpp
===
--- clang-tools-extra/clangd/unittests/CanonicalIncludesTests.cpp
+++ clang-tools-extra/clangd/unittests/CanonicalIncludesTests.cpp
@@ -62,6 +62,23 @@
   

[PATCH] D142836: [clangd] Add symbol mappings for `std::experimental::filesystem`

2023-01-29 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 493081.
zyounan added a comment.

Do not format inc file


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D142836/new/

https://reviews.llvm.org/D142836

Files:
  clang-tools-extra/clangd/index/CanonicalIncludes.cpp
  clang-tools-extra/clangd/unittests/CanonicalIncludesTests.cpp
  clang/include/clang/Tooling/Inclusions/TsStdSymbolMap.inc

Index: clang/include/clang/Tooling/Inclusions/TsStdSymbolMap.inc
===
--- /dev/null
+++ clang/include/clang/Tooling/Inclusions/TsStdSymbolMap.inc
@@ -0,0 +1,57 @@
+// FIXME: Add a parser for experimental pages to `clang/tools/include-mapping/cppreference_parser.py`
+
+// clang-format off
+SYMBOL(absolute, std::experimental::filesystem::, )
+SYMBOL(canonical, std::experimental::filesystem::, )
+SYMBOL(copy, std::experimental::filesystem::, )
+SYMBOL(copy_file, std::experimental::filesystem::, )
+SYMBOL(copy_options, std::experimental::filesystem::, )
+SYMBOL(copy_symlink, std::experimental::filesystem::, )
+SYMBOL(create_directories, std::experimental::filesystem::, )
+SYMBOL(create_directory, std::experimental::filesystem::, )
+SYMBOL(create_directory_symlink, std::experimental::filesystem::, )
+SYMBOL(create_hard_link, std::experimental::filesystem::, )
+SYMBOL(create_symlink, std::experimental::filesystem::, )
+SYMBOL(current_path, std::experimental::filesystem::, )
+SYMBOL(directory_entry, std::experimental::filesystem::, )
+SYMBOL(directory_iterator, std::experimental::filesystem::, )
+SYMBOL(directory_options, std::experimental::filesystem::, )
+SYMBOL(equivalent, std::experimental::filesystem::, )
+SYMBOL(exists, std::experimental::filesystem::, )
+SYMBOL(file_size, std::experimental::filesystem::, )
+SYMBOL(file_status, std::experimental::filesystem::, )
+SYMBOL(file_time_type, std::experimental::filesystem::, )
+SYMBOL(file_type, std::experimental::filesystem::, )
+SYMBOL(filesystem_error, std::experimental::filesystem::, )
+SYMBOL(hard_link_count, std::experimental::filesystem::, )
+SYMBOL(is_block_file, std::experimental::filesystem::, )
+SYMBOL(is_character_file, std::experimental::filesystem::, )
+SYMBOL(is_directory, std::experimental::filesystem::, )
+SYMBOL(is_empty, std::experimental::filesystem::, )
+SYMBOL(is_fifo, std::experimental::filesystem::, )
+SYMBOL(is_other, std::experimental::filesystem::, )
+SYMBOL(is_regular_file, std::experimental::filesystem::, )
+SYMBOL(is_socket, std::experimental::filesystem::, )
+SYMBOL(is_symlink, std::experimental::filesystem::, )
+SYMBOL(last_write_time, std::experimental::filesystem::, )
+SYMBOL(path, std::experimental::filesystem::, )
+SYMBOL(perm_options, std::experimental::filesystem::, )
+SYMBOL(permissions, std::experimental::filesystem::, )
+SYMBOL(perms, std::experimental::filesystem::, )
+SYMBOL(proximate, std::experimental::filesystem::, )
+SYMBOL(read_symlink, std::experimental::filesystem::, )
+SYMBOL(recursive_directory_iterator, std::experimental::filesystem::, )
+SYMBOL(relative, std::experimental::filesystem::, )
+SYMBOL(remove, std::experimental::filesystem::, )
+SYMBOL(remove_all, std::experimental::filesystem::, )
+SYMBOL(rename, std::experimental::filesystem::, )
+SYMBOL(resize_file, std::experimental::filesystem::, )
+SYMBOL(space, std::experimental::filesystem::, )
+SYMBOL(space_info, std::experimental::filesystem::, )
+SYMBOL(status, std::experimental::filesystem::, )
+SYMBOL(status_known, std::experimental::filesystem::, )
+SYMBOL(symlink_status, std::experimental::filesystem::, )
+SYMBOL(temp_directory_path, std::experimental::filesystem::, )
+SYMBOL(u8path, std::experimental::filesystem::, )
+SYMBOL(weakly_canonical, std::experimental::filesystem::, )
+// clang-format on
Index: clang-tools-extra/clangd/unittests/CanonicalIncludesTests.cpp
===
--- clang-tools-extra/clangd/unittests/CanonicalIncludesTests.cpp
+++ clang-tools-extra/clangd/unittests/CanonicalIncludesTests.cpp
@@ -62,6 +62,23 @@
   EXPECT_EQ("", CI.mapHeader(File));
 }
 
+TEST(CanonicalIncludesTest, CXXSymbolsFromTS) {
+  CanonicalIncludes CI;
+  auto Language = LangOptions();
+  Language.CPlusPlus = true;
+  CI.addSystemHeadersMapping(Language);
+
+  EXPECT_EQ("",
+CI.mapSymbol("std::experimental::filesystem::path"));
+  EXPECT_EQ("",
+CI.mapSymbol("std::experimental::filesystem::file_type"));
+  EXPECT_EQ("",
+CI.mapSymbol("std::experimental::filesystem::file_status"));
+  EXPECT_EQ("",
+CI.mapSymbol(
+"std::experimental::filesystem::recursive_directory_iterator"));
+}
+
 TEST(CanonicalIncludesTest, PathMapping) {
   auto InMemFS = llvm::makeIntrusiveRefCnt();
   FileManager Files(FileSystemOptions(), InMemFS);
Index: clang-tools-extra/clangd/index/CanonicalIncludes.cpp
===
--- clang-tools-extra/

[PATCH] D142836: [clangd] Add symbol mappings for `std::experimental::filesystem`

2023-01-29 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 493195.
zyounan added a comment.

Format


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D142836/new/

https://reviews.llvm.org/D142836

Files:
  clang-tools-extra/clangd/index/CanonicalIncludes.cpp
  clang-tools-extra/clangd/unittests/CanonicalIncludesTests.cpp
  clang/include/clang/Tooling/Inclusions/TsStdSymbolMap.inc

Index: clang/include/clang/Tooling/Inclusions/TsStdSymbolMap.inc
===
--- /dev/null
+++ clang/include/clang/Tooling/Inclusions/TsStdSymbolMap.inc
@@ -0,0 +1,58 @@
+// FIXME: Add a parser for experimental pages to
+// `clang/tools/include-mapping/cppreference_parser.py`
+
+// clang-format off
+SYMBOL(absolute, std::experimental::filesystem::, )
+SYMBOL(canonical, std::experimental::filesystem::, )
+SYMBOL(copy, std::experimental::filesystem::, )
+SYMBOL(copy_file, std::experimental::filesystem::, )
+SYMBOL(copy_options, std::experimental::filesystem::, )
+SYMBOL(copy_symlink, std::experimental::filesystem::, )
+SYMBOL(create_directories, std::experimental::filesystem::, )
+SYMBOL(create_directory, std::experimental::filesystem::, )
+SYMBOL(create_directory_symlink, std::experimental::filesystem::, )
+SYMBOL(create_hard_link, std::experimental::filesystem::, )
+SYMBOL(create_symlink, std::experimental::filesystem::, )
+SYMBOL(current_path, std::experimental::filesystem::, )
+SYMBOL(directory_entry, std::experimental::filesystem::, )
+SYMBOL(directory_iterator, std::experimental::filesystem::, )
+SYMBOL(directory_options, std::experimental::filesystem::, )
+SYMBOL(equivalent, std::experimental::filesystem::, )
+SYMBOL(exists, std::experimental::filesystem::, )
+SYMBOL(file_size, std::experimental::filesystem::, )
+SYMBOL(file_status, std::experimental::filesystem::, )
+SYMBOL(file_time_type, std::experimental::filesystem::, )
+SYMBOL(file_type, std::experimental::filesystem::, )
+SYMBOL(filesystem_error, std::experimental::filesystem::, )
+SYMBOL(hard_link_count, std::experimental::filesystem::, )
+SYMBOL(is_block_file, std::experimental::filesystem::, )
+SYMBOL(is_character_file, std::experimental::filesystem::, )
+SYMBOL(is_directory, std::experimental::filesystem::, )
+SYMBOL(is_empty, std::experimental::filesystem::, )
+SYMBOL(is_fifo, std::experimental::filesystem::, )
+SYMBOL(is_other, std::experimental::filesystem::, )
+SYMBOL(is_regular_file, std::experimental::filesystem::, )
+SYMBOL(is_socket, std::experimental::filesystem::, )
+SYMBOL(is_symlink, std::experimental::filesystem::, )
+SYMBOL(last_write_time, std::experimental::filesystem::, )
+SYMBOL(path, std::experimental::filesystem::, )
+SYMBOL(perm_options, std::experimental::filesystem::, )
+SYMBOL(permissions, std::experimental::filesystem::, )
+SYMBOL(perms, std::experimental::filesystem::, )
+SYMBOL(proximate, std::experimental::filesystem::, )
+SYMBOL(read_symlink, std::experimental::filesystem::, )
+SYMBOL(recursive_directory_iterator, std::experimental::filesystem::, )
+SYMBOL(relative, std::experimental::filesystem::, )
+SYMBOL(remove, std::experimental::filesystem::, )
+SYMBOL(remove_all, std::experimental::filesystem::, )
+SYMBOL(rename, std::experimental::filesystem::, )
+SYMBOL(resize_file, std::experimental::filesystem::, )
+SYMBOL(space, std::experimental::filesystem::, )
+SYMBOL(space_info, std::experimental::filesystem::, )
+SYMBOL(status, std::experimental::filesystem::, )
+SYMBOL(status_known, std::experimental::filesystem::, )
+SYMBOL(symlink_status, std::experimental::filesystem::, )
+SYMBOL(temp_directory_path, std::experimental::filesystem::, )
+SYMBOL(u8path, std::experimental::filesystem::, )
+SYMBOL(weakly_canonical, std::experimental::filesystem::, )
+// clang-format on
Index: clang-tools-extra/clangd/unittests/CanonicalIncludesTests.cpp
===
--- clang-tools-extra/clangd/unittests/CanonicalIncludesTests.cpp
+++ clang-tools-extra/clangd/unittests/CanonicalIncludesTests.cpp
@@ -62,6 +62,23 @@
   EXPECT_EQ("", CI.mapHeader(File));
 }
 
+TEST(CanonicalIncludesTest, CXXSymbolsFromTS) {
+  CanonicalIncludes CI;
+  auto Language = LangOptions();
+  Language.CPlusPlus = true;
+  CI.addSystemHeadersMapping(Language);
+
+  EXPECT_EQ("",
+CI.mapSymbol("std::experimental::filesystem::path"));
+  EXPECT_EQ("",
+CI.mapSymbol("std::experimental::filesystem::file_type"));
+  EXPECT_EQ("",
+CI.mapSymbol("std::experimental::filesystem::file_status"));
+  EXPECT_EQ("",
+CI.mapSymbol(
+"std::experimental::filesystem::recursive_directory_iterator"));
+}
+
 TEST(CanonicalIncludesTest, PathMapping) {
   auto InMemFS = llvm::makeIntrusiveRefCnt();
   FileManager Files(FileSystemOptions(), InMemFS);
Index: clang-tools-extra/clangd/index/CanonicalIncludes.cpp
===
--- clang-tools-extra/clangd/index

[PATCH] D142836: [clangd] Add symbol mappings for `std::experimental::filesystem`

2023-01-29 Thread Younan Zhang via Phabricator via cfe-commits
zyounan added a comment.

Another question is that file `clang/Tooling/Inclusions/StdSymbolMap.inc` seems 
to be out-of-date. What's worse, the archive of cppref doesn't always update on 
time 
The latest version from official is published in 2019, while the unofficial 
version is 2022-06.
That means, symbols from C++23, like `std::expected` will be missing from this 
file.

From the aspect of maintenance, shall we consider a more optimal approach to 
keep update?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D142836/new/

https://reviews.llvm.org/D142836

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D142836: [clangd] Add symbol mappings for `std::experimental::filesystem`

2023-01-29 Thread Younan Zhang via Phabricator via cfe-commits
zyounan added a comment.

In D142836#4089721 , @kadircet wrote:

> And to follow up, I definitely see the problem you're facing and it's 
> something we'd like to address as well, just not in the way you proposed.
>
> This falls under the bucket of "we might have symbols missing from our stdlib 
> mappings and should try to compensate for that", e.g. we should probably try 
> disabling include-insertion for such cases where we have a high confidence 
> that the symbol is part of stdlib but we don't have an exact mapping in our 
> symbol database to remedy the issue around inserting "wrong" includes.

Yes, this is another issue I want to address, but you've already pointed out 
that the parser is improving.

The cppref archive page is not always up to date. As of now, the official 
version is still dumped in 2019, that means we're likely missing (partial) 
symbols from C++20/23, e.g. `std::expected`.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D142836/new/

https://reviews.llvm.org/D142836

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D143319: [clangd] Support iwyu pragma: no_include

2023-02-04 Thread Younan Zhang via Phabricator via cfe-commits
zyounan created this revision.
Herald added subscribers: kadircet, arphaman.
Herald added a project: All.
zyounan updated this revision to Diff 494815.
zyounan added a comment.
zyounan updated this revision to Diff 494816.
zyounan added reviewers: hokein, sammccall, kadircet, nridge.
zyounan published this revision for review.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.
Herald added a project: clang-tools-extra.

Remove extra headers


zyounan added a comment.

Update test


This patch is one of the steps trying to optimize experience
of header insertion in code completion.
IWYU supports `no_include` pragma that helps user to get rid
of specified headers in main file.
The patch consists of two parts: Code completion part that
prevent auto insertion if the header to be inserted is under
the guard of `no_include` pragma. The other part is for include
cleaner, which emits diagnostic message pointing out that user
is including `no_include` headers.

A possible workaround for clangd/clangd#1481.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D143319

Files:
  clang-tools-extra/clangd/CodeComplete.cpp
  clang-tools-extra/clangd/Headers.cpp
  clang-tools-extra/clangd/Headers.h
  clang-tools-extra/clangd/IncludeCleaner.cpp
  clang-tools-extra/clangd/IncludeCleaner.h
  clang-tools-extra/clangd/ParsedAST.cpp
  clang-tools-extra/clangd/index/CanonicalIncludes.h
  clang-tools-extra/clangd/unittests/HeadersTests.cpp
  clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp

Index: clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp
===
--- clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp
+++ clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp
@@ -9,6 +9,7 @@
 #include "Annotations.h"
 #include "Config.h"
 #include "IncludeCleaner.h"
+#include "Protocol.h"
 #include "SourceCode.h"
 #include "TestFS.h"
 #include "TestTU.h"
@@ -22,8 +23,10 @@
 namespace clangd {
 namespace {
 
+using ::testing::AllOf;
 using ::testing::ElementsAre;
 using ::testing::ElementsAreArray;
+using ::testing::Field;
 using ::testing::IsEmpty;
 using ::testing::Pointee;
 using ::testing::UnorderedElementsAre;
@@ -611,6 +614,36 @@
   EXPECT_THAT(computeUnusedIncludesExperimental(AST), IsEmpty());
 }
 
+MATCHER_P(message, Message, "") { return arg.Message == Message; }
+MATCHER_P2(range, Start, End, "") {
+  return arg.start == Start && arg.end == End;
+}
+
+TEST(IncludeCleaner, IWYUPragmaNoInclude) {
+  TestTU TU;
+  TU.Code = R"cpp(
+#include "foo.h"
+#include "bar.h"
+// IWYU pragma: no_include "bar.h"
+  )cpp";
+  TU.AdditionalFiles["foo.h"] = guard("");
+  TU.AdditionalFiles["bar.h"] = guard("");
+  ParsedAST AST = TU.build();
+
+  auto Diags = issueNoIncludesDiagnostics(AST, TU.Code);
+  EXPECT_THAT(
+  Diags,
+  UnorderedElementsAre(AllOf(
+  message(
+  "included header 'bar.h' is marked as `no_include` at line 4"),
+  Field(&DiagBase::Range, range(Position{2, 0}, Position{2, 16});
+  ASSERT_TRUE(Diags.size() == 1);
+  EXPECT_THAT(Diags.back().Fixes.size(), 1);
+  ASSERT_TRUE(Diags.back().Fixes.back().Edits.size() == 1);
+  EXPECT_THAT(Diags.back().Fixes.back().Edits.back().range,
+  range(Position{2, 0}, Position{3, 0}));
+}
+
 TEST(IncludeCleaner, NoDiagsForObjC) {
   TestTU TU;
   TU.Code = R"cpp(
Index: clang-tools-extra/clangd/unittests/HeadersTests.cpp
===
--- clang-tools-extra/clangd/unittests/HeadersTests.cpp
+++ clang-tools-extra/clangd/unittests/HeadersTests.cpp
@@ -93,7 +93,8 @@
   // Calculates the include path, or returns "" on error or header should not be
   // inserted.
   std::string calculate(PathRef Original, PathRef Preferred = "",
-const std::vector &Inclusions = {}) {
+const std::vector &Inclusions = {},
+const std::vector &IwyuNoIncludes = {}) {
 Clang = setupClang();
 PreprocessOnlyAction Action;
 EXPECT_TRUE(
@@ -111,6 +112,8 @@
  &Clang->getPreprocessor().getHeaderSearchInfo());
 for (const auto &Inc : Inclusions)
   Inserter.addExisting(Inc);
+for (const auto &Inc : IwyuNoIncludes)
+  Inserter.addNoInclude(Inc);
 auto Inserted = ToHeaderFile(Preferred);
 if (!Inserter.shouldInsertInclude(Original, Inserted))
   return "";
@@ -275,6 +278,29 @@
AllOf(written("\"bar.h\""), hasPragmaKeep(true;
 }
 
+TEST_F(HeadersTest, IWYUPragmaNoInclude) {
+  FS.Files[MainFile] = R"cpp(
+// IWYU pragma: no_include "baz.h"
+#include "foo.h"
+// IWYU pragma: no_include 
+// IWYU pragma: no_include  "headers.hpp" invalid
+// IWYU pragma: no_include no_quotes are considered invalid
+// IWYU pragma: no_include 
+  )cpp";
+  FS.Files["foo.h"] = "";
+
+  auto NI = collectIncludes().IwyuNoIncludes;
+  ASSERT_

[PATCH] D143319: [clangd] Support iwyu pragma: no_include

2023-02-05 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 494911.
zyounan added a comment.
Herald added a subscriber: ormris.

Update tests && Use Preprocessor.LookupFile


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D143319/new/

https://reviews.llvm.org/D143319

Files:
  clang-tools-extra/clangd/CodeComplete.cpp
  clang-tools-extra/clangd/Headers.cpp
  clang-tools-extra/clangd/Headers.h
  clang-tools-extra/clangd/IncludeCleaner.cpp
  clang-tools-extra/clangd/IncludeCleaner.h
  clang-tools-extra/clangd/ParsedAST.cpp
  clang-tools-extra/clangd/index/CanonicalIncludes.h
  clang-tools-extra/clangd/unittests/HeadersTests.cpp
  clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp

Index: clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp
===
--- clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp
+++ clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp
@@ -9,6 +9,7 @@
 #include "Annotations.h"
 #include "Config.h"
 #include "IncludeCleaner.h"
+#include "Protocol.h"
 #include "SourceCode.h"
 #include "TestFS.h"
 #include "TestTU.h"
@@ -22,8 +23,10 @@
 namespace clangd {
 namespace {
 
+using ::testing::AllOf;
 using ::testing::ElementsAre;
 using ::testing::ElementsAreArray;
+using ::testing::Field;
 using ::testing::IsEmpty;
 using ::testing::Pointee;
 using ::testing::UnorderedElementsAre;
@@ -611,6 +614,36 @@
   EXPECT_THAT(computeUnusedIncludesExperimental(AST), IsEmpty());
 }
 
+MATCHER_P(message, Message, "") { return arg.Message == Message; }
+MATCHER_P2(range, Start, End, "") {
+  return arg.start == Start && arg.end == End;
+}
+
+TEST(IncludeCleaner, IWYUPragmaNoInclude) {
+  TestTU TU;
+  TU.Code = R"cpp(
+#include "foo.h"
+#include "bar.h"
+// IWYU pragma: no_include "bar.h"
+  )cpp";
+  TU.AdditionalFiles["foo.h"] = guard("");
+  TU.AdditionalFiles["bar.h"] = guard("");
+  ParsedAST AST = TU.build();
+
+  auto Diags = issueNoIncludesDiagnostics(AST, TU.Code);
+  EXPECT_THAT(
+  Diags,
+  UnorderedElementsAre(AllOf(
+  message(
+  "included header 'bar.h' is marked as `no_include` at line 4"),
+  Field(&DiagBase::Range, range(Position{2, 0}, Position{2, 16});
+  ASSERT_TRUE(Diags.size() == 1);
+  ASSERT_TRUE(Diags.back().Fixes.size() == 1);
+  ASSERT_TRUE(Diags.back().Fixes.back().Edits.size() == 1);
+  EXPECT_THAT(Diags.back().Fixes.back().Edits.back().range,
+  range(Position{2, 0}, Position{3, 0}));
+}
+
 TEST(IncludeCleaner, NoDiagsForObjC) {
   TestTU TU;
   TU.Code = R"cpp(
Index: clang-tools-extra/clangd/unittests/HeadersTests.cpp
===
--- clang-tools-extra/clangd/unittests/HeadersTests.cpp
+++ clang-tools-extra/clangd/unittests/HeadersTests.cpp
@@ -93,7 +93,8 @@
   // Calculates the include path, or returns "" on error or header should not be
   // inserted.
   std::string calculate(PathRef Original, PathRef Preferred = "",
-const std::vector &Inclusions = {}) {
+const std::vector &Inclusions = {},
+const std::vector &IwyuNoIncludes = {}) {
 Clang = setupClang();
 PreprocessOnlyAction Action;
 EXPECT_TRUE(
@@ -111,6 +112,8 @@
  &Clang->getPreprocessor().getHeaderSearchInfo());
 for (const auto &Inc : Inclusions)
   Inserter.addExisting(Inc);
+for (const auto &Inc : IwyuNoIncludes)
+  Inserter.addNoInclude(Inc);
 auto Inserted = ToHeaderFile(Preferred);
 if (!Inserter.shouldInsertInclude(Original, Inserted))
   return "";
@@ -275,6 +278,47 @@
AllOf(written("\"bar.h\""), hasPragmaKeep(true;
 }
 
+TEST_F(HeadersTest, IWYUPragmaNoInclude) {
+  FS.Files[MainFile] = R"cpp(
+// IWYU pragma: no_include "baz.h"
+#include "foo.h"
+// IWYU pragma: no_include 
+// IWYU pragma: no_include  "headers.hpp" are not 
+// IWYU pragma: no_include  "headers.hpp" 
+// IWYU pragma: no_include "multiple"  "invalid"
+// IWYU pragma: no_include no_quotes are considered invalid
+// IWYU pragma: no_include  texts after are ignored
+// IWYU pragma: no_include not starting with quotes  "ignored"
+  )cpp";
+  FS.Files["sub/foo.h"] = "";
+  FS.Files["sub/bar.h"] = "";
+  FS.Files["sub/baz.h"] = "";
+  FS.Files["sub/valid"] = "";
+  FS.Files["sub/invalid"] = "";
+  FS.Files["sub/multiple"] = "";
+  FS.Files["sub/are"] = "";
+  FS.Files["sub/ignored"] = "";
+  FS.Files["sub/headers.hpp"] = "";
+
+  auto NI = collectIncludes().IwyuNoIncludes;
+  ASSERT_TRUE(NI);
+  EXPECT_THAT(*NI,
+  UnorderedElementsAre(
+  AllOf(written("\"baz.h\""),
+resolved("/clangd-test/sub/baz.h"), includeLine(1)),
+  AllOf(written(""), resolved("/clangd-test/sub/bar.h"),
+includeLine(3)),
+  AllOf(written(""), r

[PATCH] D143319: [clangd] Support iwyu pragma: no_include

2023-02-05 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 494921.
zyounan added a comment.

Fix test on windows


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D143319/new/

https://reviews.llvm.org/D143319

Files:
  clang-tools-extra/clangd/CodeComplete.cpp
  clang-tools-extra/clangd/Headers.cpp
  clang-tools-extra/clangd/Headers.h
  clang-tools-extra/clangd/IncludeCleaner.cpp
  clang-tools-extra/clangd/IncludeCleaner.h
  clang-tools-extra/clangd/ParsedAST.cpp
  clang-tools-extra/clangd/index/CanonicalIncludes.h
  clang-tools-extra/clangd/unittests/HeadersTests.cpp
  clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp

Index: clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp
===
--- clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp
+++ clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp
@@ -9,6 +9,7 @@
 #include "Annotations.h"
 #include "Config.h"
 #include "IncludeCleaner.h"
+#include "Protocol.h"
 #include "SourceCode.h"
 #include "TestFS.h"
 #include "TestTU.h"
@@ -22,8 +23,10 @@
 namespace clangd {
 namespace {
 
+using ::testing::AllOf;
 using ::testing::ElementsAre;
 using ::testing::ElementsAreArray;
+using ::testing::Field;
 using ::testing::IsEmpty;
 using ::testing::Pointee;
 using ::testing::UnorderedElementsAre;
@@ -611,6 +614,36 @@
   EXPECT_THAT(computeUnusedIncludesExperimental(AST), IsEmpty());
 }
 
+MATCHER_P(message, Message, "") { return arg.Message == Message; }
+MATCHER_P2(range, Start, End, "") {
+  return arg.start == Start && arg.end == End;
+}
+
+TEST(IncludeCleaner, IWYUPragmaNoInclude) {
+  TestTU TU;
+  TU.Code = R"cpp(
+#include "foo.h"
+#include "bar.h"
+// IWYU pragma: no_include "bar.h"
+  )cpp";
+  TU.AdditionalFiles["foo.h"] = guard("");
+  TU.AdditionalFiles["bar.h"] = guard("");
+  ParsedAST AST = TU.build();
+
+  auto Diags = issueNoIncludesDiagnostics(AST, TU.Code);
+  EXPECT_THAT(
+  Diags,
+  UnorderedElementsAre(AllOf(
+  message(
+  "included header 'bar.h' is marked as `no_include` at line 4"),
+  Field(&DiagBase::Range, range(Position{2, 0}, Position{2, 16});
+  ASSERT_TRUE(Diags.size() == 1);
+  ASSERT_TRUE(Diags.back().Fixes.size() == 1);
+  ASSERT_TRUE(Diags.back().Fixes.back().Edits.size() == 1);
+  EXPECT_THAT(Diags.back().Fixes.back().Edits.back().range,
+  range(Position{2, 0}, Position{3, 0}));
+}
+
 TEST(IncludeCleaner, NoDiagsForObjC) {
   TestTU TU;
   TU.Code = R"cpp(
Index: clang-tools-extra/clangd/unittests/HeadersTests.cpp
===
--- clang-tools-extra/clangd/unittests/HeadersTests.cpp
+++ clang-tools-extra/clangd/unittests/HeadersTests.cpp
@@ -93,7 +93,8 @@
   // Calculates the include path, or returns "" on error or header should not be
   // inserted.
   std::string calculate(PathRef Original, PathRef Preferred = "",
-const std::vector &Inclusions = {}) {
+const std::vector &Inclusions = {},
+const std::vector &IwyuNoIncludes = {}) {
 Clang = setupClang();
 PreprocessOnlyAction Action;
 EXPECT_TRUE(
@@ -111,6 +112,8 @@
  &Clang->getPreprocessor().getHeaderSearchInfo());
 for (const auto &Inc : Inclusions)
   Inserter.addExisting(Inc);
+for (const auto &Inc : IwyuNoIncludes)
+  Inserter.addNoInclude(Inc);
 auto Inserted = ToHeaderFile(Preferred);
 if (!Inserter.shouldInsertInclude(Original, Inserted))
   return "";
@@ -275,6 +278,46 @@
AllOf(written("\"bar.h\""), hasPragmaKeep(true;
 }
 
+TEST_F(HeadersTest, IWYUPragmaNoInclude) {
+  FS.Files[MainFile] = R"cpp(
+// IWYU pragma: no_include "baz.h"
+#include "foo.h"
+// IWYU pragma: no_include 
+// IWYU pragma: no_include  "headers.hpp" are not 
+// IWYU pragma: no_include  "headers.hpp" 
+// IWYU pragma: no_include "multiple"  "invalid"
+// IWYU pragma: no_include no_quotes are considered invalid
+// IWYU pragma: no_include  texts after are ignored
+// IWYU pragma: no_include not starting with quotes  "ignored"
+  )cpp";
+  FS.Files["sub/foo.h"] = "";
+  FS.Files["sub/bar.h"] = "";
+  FS.Files["sub/baz.h"] = "";
+  FS.Files["sub/valid"] = "";
+  FS.Files["sub/invalid"] = "";
+  FS.Files["sub/multiple"] = "";
+  FS.Files["sub/are"] = "";
+  FS.Files["sub/ignored"] = "";
+  FS.Files["sub/headers.hpp"] = "";
+
+  auto NI = collectIncludes().IwyuNoIncludes;
+  ASSERT_TRUE(NI);
+  EXPECT_THAT(*NI, UnorderedElementsAre(
+   AllOf(written("\"baz.h\""),
+ resolved(testPath("sub/baz.h")), includeLine(1)),
+   AllOf(written(""),
+ resolved(testPath("sub/bar.h")), includeLine(3)),
+   AllOf(written(""),
+ resolved(testPath("sub/val

[PATCH] D156605: [clangd][CodeComplete] Improve FunctionCanBeCall

2023-09-28 Thread Younan Zhang via Phabricator via cfe-commits
zyounan marked 3 inline comments as done.
zyounan added a comment.

Thank you guys again for the long and meticulous review! :)

For a quick note, here are points I've excerpted from Nathan's reviews that 
need improvements later:

1. Implement a heuristic that works for function template pointers whose 
template parameters could be deduced from the declaring type. 
https://reviews.llvm.org/D156605#inline-1546819

2. Currently, the deducible template parameters are discarded by default; it 
may be more consistent to put the deduced parameters into an optional chunk as 
well, and let the consumer of the CodeCompletionString decide whether to use 
them. https://reviews.llvm.org/D156605#inline-1548400




Comment at: clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp:594
+Contains(AllOf(named("generic"),
+   signature("(U, V)"),
+   snippetSuffix("<${1:typename T}, ${2:typename U}>";

nridge wrote:
> It seems a bit inconsistent that the signature includes parameters with 
> default arguments in the non-call case, and not in the call case. I guess the 
> reason for this is that in the non-call case, the parameters with defaults 
> become a `CK_Optional` chunk which clangd adds to the signature 
> [here](https://searchfox.org/llvm/rev/4c241a9335c3046e418e1b4afc162bc576c072fd/clang-tools-extra/clangd/CodeCompletionStrings.cpp#213-214),
>  while in the call case the deduced parameters (which include the ones with 
> defaults) are omitted from the completion string altogether.
> 
> It may be more consistent to put the deduced parameters into an optional 
> chunk as well, and let the consumer of the CodeCompletionString decide 
> whether to use them?
> 
> Anyways, that's an idea for the future, no change needed now.
> It seems a bit inconsistent that the signature includes parameters with 
> default arguments in the non-call case, and not in the call case.

Indeed. If we just want consistent behavior (i.e., both get omitted) for 
default parameters, it is easy to fix at the moment. Note that

1) the loop for default template params will run iff the bit vector `Deduced` 
is not empty.

2) the vector would be resized in `Sema::MarkDeducedTemplateParameters` to fit 
the template params, which has been avoided in my patch to emit all template 
params for non-call cases. As a result, `LastDeducibleArgument` would always be 
0 for non-calls, even with default template params.

We can change the `Deduced` to a default initialized N-size bit vector, where N 
is the size of template params. This way, the default params can be omitted in 
the loop as desired (by reducing `LastDeducibleArgument` to limit the range it 
would dump to the CCS chunk later), while non-default params get preserved.

> It may be more consistent to put the deduced parameters into an optional 
> chunk as well, and let the consumer of the CodeCompletionString decide 
> whether to use them?

Sounds reasonable.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156605/new/

https://reviews.llvm.org/D156605

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D156605: [clangd][CodeComplete] Improve FunctionCanBeCall

2023-09-28 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 557441.
zyounan added a comment.

Address nits; discard default template parameters


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156605/new/

https://reviews.llvm.org/D156605

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaCodeComplete.cpp
  clang/lib/Sema/SemaOverload.cpp
  clang/lib/Sema/SemaTemplateDeduction.cpp

Index: clang/lib/Sema/SemaTemplateDeduction.cpp
===
--- clang/lib/Sema/SemaTemplateDeduction.cpp
+++ clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -2239,6 +2239,16 @@
   llvm_unreachable("Invalid Type Class!");
 }
 
+Sema::TemplateDeductionResult Sema::DeduceTemplateArgumentsByTypeMatch(
+Sema &S, TemplateParameterList *TemplateParams, QualType P, QualType A,
+sema::TemplateDeductionInfo &Info,
+SmallVectorImpl &Deduced, unsigned TDF,
+bool PartialOrdering, bool DeducedFromArrayBound) {
+  return ::DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, P, A, Info,
+  Deduced, TDF, PartialOrdering,
+  DeducedFromArrayBound);
+}
+
 static Sema::TemplateDeductionResult
 DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
 const TemplateArgument &P, TemplateArgument A,
Index: clang/lib/Sema/SemaOverload.cpp
===
--- clang/lib/Sema/SemaOverload.cpp
+++ clang/lib/Sema/SemaOverload.cpp
@@ -12460,6 +12460,7 @@
 //   overloaded functions considered.
 FunctionDecl *Specialization = nullptr;
 TemplateDeductionInfo Info(FailedCandidates.getLocation());
+// TargetFunctionType->dump(llvm::errs(), Context);
 if (Sema::TemplateDeductionResult Result
   = S.DeduceTemplateArguments(FunctionTemplate,
   &OvlExplicitTemplateArgs,
Index: clang/lib/Sema/SemaCodeComplete.cpp
===
--- clang/lib/Sema/SemaCodeComplete.cpp
+++ clang/lib/Sema/SemaCodeComplete.cpp
@@ -41,6 +41,7 @@
 #include "clang/Sema/ScopeInfo.h"
 #include "clang/Sema/Sema.h"
 #include "clang/Sema/SemaInternal.h"
+// #include "clang/Sema/Template.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/SmallBitVector.h"
@@ -1463,6 +1464,38 @@
 OverloadSet.Add(Method, Results.size());
   }
 
+#if 0
+  const FunctionTemplateDecl *FTD = nullptr;
+  FTD = dyn_cast(R.Declaration);
+  llvm::errs() << "SCC 0: " << (void *)FTD << " " << PreferredType.isNull()
+   << "\n";
+  if (FTD && PreferredType) {
+auto Pointee = PreferredType->getTypePtr()->getPointeeType();
+llvm::errs() << "SCC 1\n";
+if (!Pointee.isNull()) {
+  llvm::errs() << "SCC 2\n";
+  if (const auto *FT = Pointee->getAs()) {
+llvm::errs() << "SCC 3\n";
+sema::TemplateDeductionInfo Info(SourceLocation{});
+llvm::SmallVector Deduced;
+Deduced.resize(FTD->getTemplateParameters()->size());
+FT->dump();
+if (auto Result = Sema::DeduceTemplateArgumentsByTypeMatch(
+SemaRef, FTD->getTemplateParameters(),
+FTD->getTemplatedDecl()->getType(),
+FT->getCanonicalTypeInternal(), Info, Deduced, 48)) {
+  llvm::errs() << FTD->getNameAsString()
+   << " could not be deduced from enclosing type: "
+   << Result << "\n";
+} else
+  llvm::errs() << FTD->getNameAsString()
+   << " could be deduced from enclosing type"
+   << "\n";
+  }
+}
+  }
+#endif
+
   R.FunctionCanBeCall = canFunctionBeCalled(R.getDeclaration(), BaseExprType);
 
   // Insert this result into the set of results.
Index: clang/include/clang/Sema/Sema.h
===
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -9138,7 +9138,7 @@
 /// a dependent parameter type did not match the corresponding element
 /// of the corresponding argument (when deducing from an initializer list).
 TDK_DeducedMismatchNested,
-/// A non-depnedent component of the parameter did not match the
+/// A non-dependent component of the parameter did not match the
 /// corresponding component of the argument.
 TDK_NonDeducedMismatch,
 /// When performing template argument deduction for a function
@@ -9232,6 +9232,12 @@
   sema::TemplateDeductionInfo &Info,
   bool IsAddressOfFunction = false);
 
+  static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
+  Sema &S, TemplateParameterList *TemplateParams, QualType P, QualType A,
+  sema::TemplateDeductionInfo &Info,
+  SmallVectorImpl &Deduced, unsigned TDF,
+  bool Par

[PATCH] D156605: [clangd][CodeComplete] Improve FunctionCanBeCall

2023-09-28 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 557442.
zyounan added a comment.

Sorry, wrong patch


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156605/new/

https://reviews.llvm.org/D156605

Files:
  clang-tools-extra/clangd/CodeComplete.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.h
  clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
  clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
  clang/lib/Sema/SemaCodeComplete.cpp
  clang/test/CodeCompletion/member-access.cpp
  clang/unittests/Sema/CodeCompleteTest.cpp

Index: clang/unittests/Sema/CodeCompleteTest.cpp
===
--- clang/unittests/Sema/CodeCompleteTest.cpp
+++ clang/unittests/Sema/CodeCompleteTest.cpp
@@ -60,7 +60,10 @@
 for (unsigned I = 0; I < NumResults; ++I) {
   auto R = Results[I];
   if (R.Kind == CodeCompletionResult::RK_Declaration) {
-if (const auto *FD = llvm::dyn_cast(R.getDeclaration())) {
+auto *ND = R.getDeclaration();
+if (auto *Template = llvm::dyn_cast(ND))
+  ND = Template->getTemplatedDecl();
+if (const auto *FD = llvm::dyn_cast(ND)) {
   CompletedFunctionDecl D;
   D.Name = FD->getNameAsString();
   D.CanBeCall = R.FunctionCanBeCall;
@@ -191,6 +194,10 @@
 struct Foo {
   static int staticMethod();
   int method() const;
+  template 
+  T generic(U, V);
+  template 
+  static T staticGeneric();
   Foo() {
 this->$canBeCall^
 $canBeCall^
@@ -199,6 +206,8 @@
 };
 
 struct Derived : Foo {
+  using Foo::method;
+  using Foo::generic;
   Derived() {
 Foo::$canBeCall^
   }
@@ -207,15 +216,29 @@
 struct OtherClass {
   OtherClass() {
 Foo f;
+Derived d;
 f.$canBeCall^
+; // Prevent parsing as 'f.f'
+f.Foo::$canBeCall^
 &Foo::$cannotBeCall^
+;
+d.Foo::$canBeCall^
+;
+d.Derived::$canBeCall^
   }
 };
 
 int main() {
   Foo f;
+  Derived d;
   f.$canBeCall^
+  ; // Prevent parsing as 'f.f'
+  f.Foo::$canBeCall^
   &Foo::$cannotBeCall^
+  ;
+  d.Foo::$canBeCall^
+  ;
+  d.Derived::$canBeCall^
 }
 )cpp");
 
@@ -223,12 +246,16 @@
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("method"), isStatic(false),
 canBeCall(true;
+EXPECT_THAT(Results, Contains(AllOf(named("generic"), isStatic(false),
+canBeCall(true;
   }
 
   for (const auto &P : Code.points("cannotBeCall")) {
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("method"), isStatic(false),
 canBeCall(false;
+EXPECT_THAT(Results, Contains(AllOf(named("generic"), isStatic(false),
+canBeCall(false;
   }
 
   // static method can always be a call
@@ -236,6 +263,8 @@
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("staticMethod"), isStatic(true),
 canBeCall(true;
+EXPECT_THAT(Results, Contains(AllOf(named("staticGeneric"), isStatic(true),
+canBeCall(true;
   }
 }
 
Index: clang/test/CodeCompletion/member-access.cpp
===
--- clang/test/CodeCompletion/member-access.cpp
+++ clang/test/CodeCompletion/member-access.cpp
@@ -341,3 +341,14 @@
   // RUN: %clang_cc1 -fsyntax-only -code-completion-with-fixits -code-completion-at=%s:339:10 %s -o - | FileCheck -check-prefix=CHECK-FIELD-DECLARED-VIA-USING %s
   // CHECK-FIELD-DECLARED-VIA-USING: [#int#]field (requires fix-it: {339:8-339:9} to "->")
 }
+
+namespace function_can_be_call {
+  struct S {
+template 
+T foo(U, V);
+  };
+
+  &S::f
+  // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:351:7 %s -o - | FileCheck -check-prefix=CHECK_FUNCTION_CAN_BE_CALL %s
+  // CHECK_FUNCTION_CAN_BE_CALL: COMPLETION: foo : [#T#]foo<<#typename T#>, <#typename U#>{#, <#typename V#>#}>(<#U#>, <#V#>)
+}
Index: clang/lib/Sema/SemaCodeComplete.cpp
===
--- clang/lib/Sema/SemaCodeComplete.cpp
+++ clang/lib/Sema/SemaCodeComplete.cpp
@@ -310,6 +310,23 @@
   bool isInterestingDecl(const NamedDecl *ND,
  bool &AsNestedNameSpecifier) const;
 
+  /// Decide whether or not a use of function Decl can be a call.
+  ///
+  /// \param ND the function declaration.
+  ///
+  /// \param BaseExprType the object type in a member access expression,
+  /// if any.
+  bool canFunctionBeCalled(const 

[PATCH] D156605: [clangd][CodeComplete] Improve FunctionCanBeCall

2023-09-28 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 557443.
zyounan added a comment.

Fix the CI


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156605/new/

https://reviews.llvm.org/D156605

Files:
  clang-tools-extra/clangd/CodeComplete.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.h
  clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
  clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
  clang/lib/Sema/SemaCodeComplete.cpp
  clang/test/CodeCompletion/member-access.cpp
  clang/unittests/Sema/CodeCompleteTest.cpp

Index: clang/unittests/Sema/CodeCompleteTest.cpp
===
--- clang/unittests/Sema/CodeCompleteTest.cpp
+++ clang/unittests/Sema/CodeCompleteTest.cpp
@@ -60,7 +60,10 @@
 for (unsigned I = 0; I < NumResults; ++I) {
   auto R = Results[I];
   if (R.Kind == CodeCompletionResult::RK_Declaration) {
-if (const auto *FD = llvm::dyn_cast(R.getDeclaration())) {
+auto *ND = R.getDeclaration();
+if (auto *Template = llvm::dyn_cast(ND))
+  ND = Template->getTemplatedDecl();
+if (const auto *FD = llvm::dyn_cast(ND)) {
   CompletedFunctionDecl D;
   D.Name = FD->getNameAsString();
   D.CanBeCall = R.FunctionCanBeCall;
@@ -191,6 +194,10 @@
 struct Foo {
   static int staticMethod();
   int method() const;
+  template 
+  T generic(U, V);
+  template 
+  static T staticGeneric();
   Foo() {
 this->$canBeCall^
 $canBeCall^
@@ -199,6 +206,8 @@
 };
 
 struct Derived : Foo {
+  using Foo::method;
+  using Foo::generic;
   Derived() {
 Foo::$canBeCall^
   }
@@ -207,15 +216,29 @@
 struct OtherClass {
   OtherClass() {
 Foo f;
+Derived d;
 f.$canBeCall^
+; // Prevent parsing as 'f.f'
+f.Foo::$canBeCall^
 &Foo::$cannotBeCall^
+;
+d.Foo::$canBeCall^
+;
+d.Derived::$canBeCall^
   }
 };
 
 int main() {
   Foo f;
+  Derived d;
   f.$canBeCall^
+  ; // Prevent parsing as 'f.f'
+  f.Foo::$canBeCall^
   &Foo::$cannotBeCall^
+  ;
+  d.Foo::$canBeCall^
+  ;
+  d.Derived::$canBeCall^
 }
 )cpp");
 
@@ -223,12 +246,16 @@
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("method"), isStatic(false),
 canBeCall(true;
+EXPECT_THAT(Results, Contains(AllOf(named("generic"), isStatic(false),
+canBeCall(true;
   }
 
   for (const auto &P : Code.points("cannotBeCall")) {
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("method"), isStatic(false),
 canBeCall(false;
+EXPECT_THAT(Results, Contains(AllOf(named("generic"), isStatic(false),
+canBeCall(false;
   }
 
   // static method can always be a call
@@ -236,6 +263,8 @@
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("staticMethod"), isStatic(true),
 canBeCall(true;
+EXPECT_THAT(Results, Contains(AllOf(named("staticGeneric"), isStatic(true),
+canBeCall(true;
   }
 }
 
Index: clang/test/CodeCompletion/member-access.cpp
===
--- clang/test/CodeCompletion/member-access.cpp
+++ clang/test/CodeCompletion/member-access.cpp
@@ -341,3 +341,14 @@
   // RUN: %clang_cc1 -fsyntax-only -code-completion-with-fixits -code-completion-at=%s:339:10 %s -o - | FileCheck -check-prefix=CHECK-FIELD-DECLARED-VIA-USING %s
   // CHECK-FIELD-DECLARED-VIA-USING: [#int#]field (requires fix-it: {339:8-339:9} to "->")
 }
+
+namespace function_can_be_call {
+  struct S {
+template 
+T foo(U, V);
+  };
+
+  &S::f
+  // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:351:7 %s -o - | FileCheck -check-prefix=CHECK_FUNCTION_CAN_BE_CALL %s
+  // CHECK_FUNCTION_CAN_BE_CALL: COMPLETION: foo : [#T#]foo<<#typename T#>, <#typename U#>>(<#U#>, <#V#>)
+}
Index: clang/lib/Sema/SemaCodeComplete.cpp
===
--- clang/lib/Sema/SemaCodeComplete.cpp
+++ clang/lib/Sema/SemaCodeComplete.cpp
@@ -310,6 +310,23 @@
   bool isInterestingDecl(const NamedDecl *ND,
  bool &AsNestedNameSpecifier) const;
 
+  /// Decide whether or not a use of function Decl can be a call.
+  ///
+  /// \param ND the function declaration.
+  ///
+  /// \param BaseExprType the object type in a member access expression,
+  /// if any.
+  bool canFunctionBeCalled(const NamedDecl *ND, QualType Base

[PATCH] D156605: [clangd][CodeComplete] Improve FunctionCanBeCall

2023-09-28 Thread Younan Zhang via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG23ef8bf9c0f3: [clangd][CodeComplete] Improve 
FunctionCanBeCall (authored by zyounan).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156605/new/

https://reviews.llvm.org/D156605

Files:
  clang-tools-extra/clangd/CodeComplete.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.h
  clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
  clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
  clang/lib/Sema/SemaCodeComplete.cpp
  clang/test/CodeCompletion/member-access.cpp
  clang/unittests/Sema/CodeCompleteTest.cpp

Index: clang/unittests/Sema/CodeCompleteTest.cpp
===
--- clang/unittests/Sema/CodeCompleteTest.cpp
+++ clang/unittests/Sema/CodeCompleteTest.cpp
@@ -60,7 +60,10 @@
 for (unsigned I = 0; I < NumResults; ++I) {
   auto R = Results[I];
   if (R.Kind == CodeCompletionResult::RK_Declaration) {
-if (const auto *FD = llvm::dyn_cast(R.getDeclaration())) {
+auto *ND = R.getDeclaration();
+if (auto *Template = llvm::dyn_cast(ND))
+  ND = Template->getTemplatedDecl();
+if (const auto *FD = llvm::dyn_cast(ND)) {
   CompletedFunctionDecl D;
   D.Name = FD->getNameAsString();
   D.CanBeCall = R.FunctionCanBeCall;
@@ -191,6 +194,10 @@
 struct Foo {
   static int staticMethod();
   int method() const;
+  template 
+  T generic(U, V);
+  template 
+  static T staticGeneric();
   Foo() {
 this->$canBeCall^
 $canBeCall^
@@ -199,6 +206,8 @@
 };
 
 struct Derived : Foo {
+  using Foo::method;
+  using Foo::generic;
   Derived() {
 Foo::$canBeCall^
   }
@@ -207,15 +216,29 @@
 struct OtherClass {
   OtherClass() {
 Foo f;
+Derived d;
 f.$canBeCall^
+; // Prevent parsing as 'f.f'
+f.Foo::$canBeCall^
 &Foo::$cannotBeCall^
+;
+d.Foo::$canBeCall^
+;
+d.Derived::$canBeCall^
   }
 };
 
 int main() {
   Foo f;
+  Derived d;
   f.$canBeCall^
+  ; // Prevent parsing as 'f.f'
+  f.Foo::$canBeCall^
   &Foo::$cannotBeCall^
+  ;
+  d.Foo::$canBeCall^
+  ;
+  d.Derived::$canBeCall^
 }
 )cpp");
 
@@ -223,12 +246,16 @@
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("method"), isStatic(false),
 canBeCall(true;
+EXPECT_THAT(Results, Contains(AllOf(named("generic"), isStatic(false),
+canBeCall(true;
   }
 
   for (const auto &P : Code.points("cannotBeCall")) {
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("method"), isStatic(false),
 canBeCall(false;
+EXPECT_THAT(Results, Contains(AllOf(named("generic"), isStatic(false),
+canBeCall(false;
   }
 
   // static method can always be a call
@@ -236,6 +263,8 @@
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("staticMethod"), isStatic(true),
 canBeCall(true;
+EXPECT_THAT(Results, Contains(AllOf(named("staticGeneric"), isStatic(true),
+canBeCall(true;
   }
 }
 
Index: clang/test/CodeCompletion/member-access.cpp
===
--- clang/test/CodeCompletion/member-access.cpp
+++ clang/test/CodeCompletion/member-access.cpp
@@ -341,3 +341,14 @@
   // RUN: %clang_cc1 -fsyntax-only -code-completion-with-fixits -code-completion-at=%s:339:10 %s -o - | FileCheck -check-prefix=CHECK-FIELD-DECLARED-VIA-USING %s
   // CHECK-FIELD-DECLARED-VIA-USING: [#int#]field (requires fix-it: {339:8-339:9} to "->")
 }
+
+namespace function_can_be_call {
+  struct S {
+template 
+T foo(U, V);
+  };
+
+  &S::f
+  // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:351:7 %s -o - | FileCheck -check-prefix=CHECK_FUNCTION_CAN_BE_CALL %s
+  // CHECK_FUNCTION_CAN_BE_CALL: COMPLETION: foo : [#T#]foo<<#typename T#>, <#typename U#>>(<#U#>, <#V#>)
+}
Index: clang/lib/Sema/SemaCodeComplete.cpp
===
--- clang/lib/Sema/SemaCodeComplete.cpp
+++ clang/lib/Sema/SemaCodeComplete.cpp
@@ -310,6 +310,23 @@
   bool isInterestingDecl(const NamedDecl *ND,
  bool &AsNestedNameSpecifier) const;
 
+  /// Decide whether or not a use of function Decl can be a call.
+  ///
+  /// \param ND the function declaration.
+  ///
+  /// \param BaseExprType the object type in a member 

[PATCH] D155370: [CodeComplete] Don't emit parameters when not FunctionCanBeCall

2023-07-23 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 543277.
zyounan added a comment.

Don't change the CCR. Handle these in CreateCodeCompletionString. Emit template 
arguments if possible.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D155370/new/

https://reviews.llvm.org/D155370

Files:
  clang-tools-extra/clangd/CodeComplete.cpp
  clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
  clang/lib/Sema/SemaCodeComplete.cpp
  clang/test/CodeCompletion/member-access.cpp
  clang/test/Index/complete-qualified.cpp
  clang/unittests/Sema/CodeCompleteTest.cpp

Index: clang/unittests/Sema/CodeCompleteTest.cpp
===
--- clang/unittests/Sema/CodeCompleteTest.cpp
+++ clang/unittests/Sema/CodeCompleteTest.cpp
@@ -60,7 +60,10 @@
 for (unsigned I = 0; I < NumResults; ++I) {
   auto R = Results[I];
   if (R.Kind == CodeCompletionResult::RK_Declaration) {
-if (const auto *FD = llvm::dyn_cast(R.getDeclaration())) {
+auto *ND = R.getDeclaration();
+if (auto *Template = llvm::dyn_cast(ND))
+  ND = Template->getTemplatedDecl();
+if (const auto *FD = llvm::dyn_cast(ND)) {
   CompletedFunctionDecl D;
   D.Name = FD->getNameAsString();
   D.CanBeCall = R.FunctionCanBeCall;
@@ -191,6 +194,10 @@
 struct Foo {
   static int staticMethod();
   int method() const;
+  template 
+  void generic(T);
+  template 
+  static T staticGeneric();
   Foo() {
 this->$canBeCall^
 $canBeCall^
@@ -223,12 +230,16 @@
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("method"), isStatic(false),
 canBeCall(true;
+EXPECT_THAT(Results, Contains(AllOf(named("generic"), isStatic(false),
+canBeCall(true;
   }
 
   for (const auto &P : Code.points("cannotBeCall")) {
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("method"), isStatic(false),
 canBeCall(false;
+EXPECT_THAT(Results, Contains(AllOf(named("generic"), isStatic(false),
+canBeCall(false;
   }
 
   // static method can always be a call
@@ -236,6 +247,8 @@
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("staticMethod"), isStatic(true),
 canBeCall(true;
+EXPECT_THAT(Results, Contains(AllOf(named("staticGeneric"), isStatic(true),
+canBeCall(true;
   }
 }
 
Index: clang/test/Index/complete-qualified.cpp
===
--- clang/test/Index/complete-qualified.cpp
+++ clang/test/Index/complete-qualified.cpp
@@ -16,5 +16,5 @@
 // RUN: c-index-test -code-completion-at=%s:14:8 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
 // CHECK-CC1: FieldDecl:{ResultType C}{TypedText c} (35)
 // CHECK-CC1: ClassDecl:{TypedText Foo} (35)
-// CHECK-CC1: CXXMethod:{ResultType Foo &}{TypedText operator=}{LeftParen (}{Placeholder const Foo &}{RightParen )}
-// CHECK-CC1: CXXDestructor:{ResultType void}{TypedText ~Foo}{LeftParen (}{RightParen )} (80)
+// CHECK-CC1: CXXMethod:{ResultType Foo &}{TypedText operator=}
+// CHECK-CC1: CXXDestructor:{ResultType void}{TypedText ~Foo} (80)
Index: clang/test/CodeCompletion/member-access.cpp
===
--- clang/test/CodeCompletion/member-access.cpp
+++ clang/test/CodeCompletion/member-access.cpp
@@ -171,7 +171,7 @@
 template
 void dependentColonColonCompletion() {
   Template::staticFn();
-// CHECK-CC7: function : [#void#]function()
+// CHECK-CC7: function : [#void#]function
 // CHECK-CC7: Nested : Nested
 // CHECK-CC7: o1 : [#BaseTemplate#]o1
 // CHECK-CC7: o2 : [#BaseTemplate#]o2
Index: clang/lib/Sema/SemaCodeComplete.cpp
===
--- clang/lib/Sema/SemaCodeComplete.cpp
+++ clang/lib/Sema/SemaCodeComplete.cpp
@@ -1384,7 +1384,11 @@
   // dot/arrow member access) and we're not inside that class' scope,
   // it can't be a call.
   if (CompletionContext.getKind() == clang::CodeCompletionContext::CCC_Symbol) {
-const auto *Method = dyn_cast(R.getDeclaration());
+const NamedDecl *ND = R.getDeclaration();
+if (const auto *FuncTmpl = dyn_cast(ND)) {
+  ND = FuncTmpl->getTemplatedDecl();
+}
+const auto *Method = dyn_cast(ND);
 if (Method && !Method->isStatic()) {
   // Find the class scope that we're currently in.
   // We could e.g. be inside a lambda, so walk up the DeclContext until we
@@ -3494,6 +3498,9 @@
 AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
   

[PATCH] D155370: [CodeComplete] Don't emit parameters when not FunctionCanBeCall

2023-07-23 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 543280.
zyounan added a comment.

Format


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D155370/new/

https://reviews.llvm.org/D155370

Files:
  clang-tools-extra/clangd/CodeComplete.cpp
  clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
  clang/lib/Sema/SemaCodeComplete.cpp
  clang/test/CodeCompletion/member-access.cpp
  clang/test/Index/complete-qualified.cpp
  clang/unittests/Sema/CodeCompleteTest.cpp

Index: clang/unittests/Sema/CodeCompleteTest.cpp
===
--- clang/unittests/Sema/CodeCompleteTest.cpp
+++ clang/unittests/Sema/CodeCompleteTest.cpp
@@ -60,7 +60,10 @@
 for (unsigned I = 0; I < NumResults; ++I) {
   auto R = Results[I];
   if (R.Kind == CodeCompletionResult::RK_Declaration) {
-if (const auto *FD = llvm::dyn_cast(R.getDeclaration())) {
+auto *ND = R.getDeclaration();
+if (auto *Template = llvm::dyn_cast(ND))
+  ND = Template->getTemplatedDecl();
+if (const auto *FD = llvm::dyn_cast(ND)) {
   CompletedFunctionDecl D;
   D.Name = FD->getNameAsString();
   D.CanBeCall = R.FunctionCanBeCall;
@@ -191,6 +194,10 @@
 struct Foo {
   static int staticMethod();
   int method() const;
+  template 
+  void generic(T);
+  template 
+  static T staticGeneric();
   Foo() {
 this->$canBeCall^
 $canBeCall^
@@ -223,12 +230,16 @@
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("method"), isStatic(false),
 canBeCall(true;
+EXPECT_THAT(Results, Contains(AllOf(named("generic"), isStatic(false),
+canBeCall(true;
   }
 
   for (const auto &P : Code.points("cannotBeCall")) {
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("method"), isStatic(false),
 canBeCall(false;
+EXPECT_THAT(Results, Contains(AllOf(named("generic"), isStatic(false),
+canBeCall(false;
   }
 
   // static method can always be a call
@@ -236,6 +247,8 @@
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("staticMethod"), isStatic(true),
 canBeCall(true;
+EXPECT_THAT(Results, Contains(AllOf(named("staticGeneric"), isStatic(true),
+canBeCall(true;
   }
 }
 
Index: clang/test/Index/complete-qualified.cpp
===
--- clang/test/Index/complete-qualified.cpp
+++ clang/test/Index/complete-qualified.cpp
@@ -16,5 +16,5 @@
 // RUN: c-index-test -code-completion-at=%s:14:8 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
 // CHECK-CC1: FieldDecl:{ResultType C}{TypedText c} (35)
 // CHECK-CC1: ClassDecl:{TypedText Foo} (35)
-// CHECK-CC1: CXXMethod:{ResultType Foo &}{TypedText operator=}{LeftParen (}{Placeholder const Foo &}{RightParen )}
-// CHECK-CC1: CXXDestructor:{ResultType void}{TypedText ~Foo}{LeftParen (}{RightParen )} (80)
+// CHECK-CC1: CXXMethod:{ResultType Foo &}{TypedText operator=}
+// CHECK-CC1: CXXDestructor:{ResultType void}{TypedText ~Foo} (80)
Index: clang/test/CodeCompletion/member-access.cpp
===
--- clang/test/CodeCompletion/member-access.cpp
+++ clang/test/CodeCompletion/member-access.cpp
@@ -171,7 +171,7 @@
 template
 void dependentColonColonCompletion() {
   Template::staticFn();
-// CHECK-CC7: function : [#void#]function()
+// CHECK-CC7: function : [#void#]function
 // CHECK-CC7: Nested : Nested
 // CHECK-CC7: o1 : [#BaseTemplate#]o1
 // CHECK-CC7: o2 : [#BaseTemplate#]o2
Index: clang/lib/Sema/SemaCodeComplete.cpp
===
--- clang/lib/Sema/SemaCodeComplete.cpp
+++ clang/lib/Sema/SemaCodeComplete.cpp
@@ -1384,7 +1384,11 @@
   // dot/arrow member access) and we're not inside that class' scope,
   // it can't be a call.
   if (CompletionContext.getKind() == clang::CodeCompletionContext::CCC_Symbol) {
-const auto *Method = dyn_cast(R.getDeclaration());
+const NamedDecl *ND = R.getDeclaration();
+if (const auto *FuncTmpl = dyn_cast(ND)) {
+  ND = FuncTmpl->getTemplatedDecl();
+}
+const auto *Method = dyn_cast(ND);
 if (Method && !Method->isStatic()) {
   // Find the class scope that we're currently in.
   // We could e.g. be inside a lambda, so walk up the DeclContext until we
@@ -3494,6 +3498,10 @@
 AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
Ctx, Policy);
 AddTypedNameChunk(Ctx, Policy, ND, Result);
+// We don't emit parame

[PATCH] D155370: [CodeComplete] Improve FunctionCanBeCall

2023-07-23 Thread Younan Zhang via Phabricator via cfe-commits
zyounan added a comment.

Thanks for the insightful suggestions!
(Apologies for my late update. Just had a really busy week.)

As suggested, I left the CCR intact and handled these functions in 
`CodeCompletionResult::createCodeCompletionStringForDecl`. I think this 
preserves the Declaration, right? (While I think we //could// get the 
associated Decl if using `RK_Pattern`, however the current approach looks more 
terse to me.)

I also noticed that the previous implementation did not consider function 
templates. For example,

  struct S {
template 
void foo(T);
  
void bar();
  };
  
  &S::bar^ // getting `S::bar`
  &S::foo^ // getting `S::foo(T)`!

This brings a discrepancy, which I have also fixed in this patch. I hope this 
doesn't cause too much inconvenience for the review :)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D155370/new/

https://reviews.llvm.org/D155370

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D155370: [CodeComplete] Improve FunctionCanBeCall

2023-07-25 Thread Younan Zhang via Phabricator via cfe-commits
zyounan added inline comments.



Comment at: clang/lib/Sema/SemaCodeComplete.cpp:1407
 
   R.FunctionCanBeCall =
   CurrentClassScope &&

The current heuristic results in the following:

```
struct Base {
  void foo(int);
};
struct Derived : Base {
  void foo(float);
};

int main() {
  Derived d;
  d.Base::^// FunctionCanBeCall for `foo` is false.
}
```

In situations where it is intended to invoke base member functions hidden by 
subclasses, we shouldn't remove parentheses, IMO.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D155370/new/

https://reviews.llvm.org/D155370

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D156300: [clangd] Avoid unexpected desugaring in isSugaredTemplateParameter

2023-07-26 Thread Younan Zhang via Phabricator via cfe-commits
zyounan created this revision.
zyounan added a reviewer: nridge.
Herald added subscribers: kadircet, arphaman.
Herald added a project: All.
zyounan requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.
Herald added a project: clang-tools-extra.

This is a follow-up to D151785 , addressing 
https://github.com/clangd/clangd/issues/1703.

The previous approach of peeling pointer types during a traversal
using getPointeeType might have produced unexpected results; since
the method would implicitly desugar the type if the type being passed
in could not be cast to a Pointer-like Type.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D156300

Files:
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -81,11 +81,13 @@
 }
 
 template 
-void assertHints(InlayHintKind Kind, llvm::StringRef AnnotatedSource,
- ExpectedHints... Expected) {
+void assertHintsWithHeader(InlayHintKind Kind, llvm::StringRef AnnotatedSource,
+   llvm::StringRef HeaderContent,
+   ExpectedHints... Expected) {
   Annotations Source(AnnotatedSource);
   TestTU TU = TestTU::withCode(Source.code());
   TU.ExtraArgs.push_back("-std=c++20");
+  TU.HeaderCode = HeaderContent;
   auto AST = TU.build();
 
   EXPECT_THAT(hintsOfKind(AST, Kind),
@@ -96,6 +98,12 @@
   EXPECT_THAT(inlayHints(AST, std::nullopt), IsEmpty());
 }
 
+template 
+void assertHints(InlayHintKind Kind, llvm::StringRef AnnotatedSource,
+ ExpectedHints... Expected) {
+  return assertHintsWithHeader(Kind, AnnotatedSource, "", std::move(Expected)...);
+}
+
 // Hack to allow expression-statements operating on parameter packs in C++14.
 template  void ignore(T &&...) {}
 
@@ -1421,8 +1429,7 @@
 }
 
 TEST(TypeHints, SubstTemplateParameterAliases) {
-  assertTypeHints(
-  R"cpp(
+  llvm::StringRef Header = R"cpp(
   template  struct allocator {};
 
   template 
@@ -1455,9 +1462,34 @@
 
 T elements[10];
   };
+  )cpp";
+
+  llvm::StringRef VectorIntPtr = R"cpp(
+vector array;
+auto $no_modifier[[x]] = array[3];
+auto* $ptr_modifier[[ptr]] = &array[3];
+auto& $ref_modifier[[ref]] = array[3];
+auto& $at[[immutable]] = array.at(3);
+
+auto $data[[data]] = array.data();
+auto $allocator[[alloc]] = array.get_allocator();
+auto $size[[size]] = array.size();
+auto $begin[[begin]] = array.begin();
+auto $end[[end]] = array.end();
+  )cpp";
+
+  assertHintsWithHeader(
+  InlayHintKind::Type, VectorIntPtr, Header,
+  ExpectedHint{": int *", "no_modifier"},
+  ExpectedHint{": int **", "ptr_modifier"},
+  ExpectedHint{": int *&", "ref_modifier"},
+  ExpectedHint{": int *const &", "at"}, ExpectedHint{": int **", "data"},
+  ExpectedHint{": allocator", "allocator"},
+  ExpectedHint{": size_type", "size"}, ExpectedHint{": iterator", "begin"},
+  ExpectedHint{": non_template_iterator", "end"});
 
+  llvm::StringRef VectorInt = R"cpp(
   vector array;
-
   auto $no_modifier[[by_value]] = array[3];
   auto* $ptr_modifier[[ptr]] = &array[3];
   auto& $ref_modifier[[ref]] = array[3];
@@ -1468,8 +1500,19 @@
   auto $size[[size]] = array.size();
   auto $begin[[begin]] = array.begin();
   auto $end[[end]] = array.end();
+  )cpp";
 
+  assertHintsWithHeader(
+  InlayHintKind::Type, VectorInt, Header,
+  ExpectedHint{": int", "no_modifier"},
+  ExpectedHint{": int *", "ptr_modifier"},
+  ExpectedHint{": int &", "ref_modifier"},
+  ExpectedHint{": const int &", "at"}, ExpectedHint{": int *", "data"},
+  ExpectedHint{": allocator", "allocator"},
+  ExpectedHint{": size_type", "size"}, ExpectedHint{": iterator", "begin"},
+  ExpectedHint{": non_template_iterator", "end"});
 
+  llvm::StringRef TypeAlias = R"cpp(
   // If the type alias is not of substituted template parameter type,
   // do not show desugared type.
   using VeryLongLongTypeName = my_iterator;
@@ -1484,16 +1527,11 @@
   using static_vector = basic_static_vector>;
 
   auto $vector_name[[vec]] = static_vector();
-  )cpp",
-  ExpectedHint{": int", "no_modifier"},
-  ExpectedHint{": int *", "ptr_modifier"},
-  ExpectedHint{": int &", "ref_modifier"},
-  ExpectedHint{": const int &", "at"}, ExpectedHint{": int *", "data"},
-  ExpectedHint{": allocator", "allocator"},
-  ExpectedHint{": size_type", "size"}, ExpectedHint{": iterator", "begin"},
-  ExpectedHint{": non_template_iterator", "end"},
-  ExpectedHint{": Short", "short_name"},
-  ExpectedHint{": static_vector", "vector_name"});
+  )cpp";
+
+  assertHintsWithHeader(InlayHintKind::Type, TypeAlia

[PATCH] D156300: [clangd] Avoid unexpected desugaring in isSugaredTemplateParameter

2023-07-26 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 544252.
zyounan added a comment.

Format


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156300/new/

https://reviews.llvm.org/D156300

Files:
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -81,11 +81,13 @@
 }
 
 template 
-void assertHints(InlayHintKind Kind, llvm::StringRef AnnotatedSource,
- ExpectedHints... Expected) {
+void assertHintsWithHeader(InlayHintKind Kind, llvm::StringRef AnnotatedSource,
+   llvm::StringRef HeaderContent,
+   ExpectedHints... Expected) {
   Annotations Source(AnnotatedSource);
   TestTU TU = TestTU::withCode(Source.code());
   TU.ExtraArgs.push_back("-std=c++20");
+  TU.HeaderCode = HeaderContent;
   auto AST = TU.build();
 
   EXPECT_THAT(hintsOfKind(AST, Kind),
@@ -96,6 +98,13 @@
   EXPECT_THAT(inlayHints(AST, std::nullopt), IsEmpty());
 }
 
+template 
+void assertHints(InlayHintKind Kind, llvm::StringRef AnnotatedSource,
+ ExpectedHints... Expected) {
+  return assertHintsWithHeader(Kind, AnnotatedSource, "",
+   std::move(Expected)...);
+}
+
 // Hack to allow expression-statements operating on parameter packs in C++14.
 template  void ignore(T &&...) {}
 
@@ -1421,8 +1430,7 @@
 }
 
 TEST(TypeHints, SubstTemplateParameterAliases) {
-  assertTypeHints(
-  R"cpp(
+  llvm::StringRef Header = R"cpp(
   template  struct allocator {};
 
   template 
@@ -1455,9 +1463,34 @@
 
 T elements[10];
   };
+  )cpp";
+
+  llvm::StringRef VectorIntPtr = R"cpp(
+vector array;
+auto $no_modifier[[x]] = array[3];
+auto* $ptr_modifier[[ptr]] = &array[3];
+auto& $ref_modifier[[ref]] = array[3];
+auto& $at[[immutable]] = array.at(3);
+
+auto $data[[data]] = array.data();
+auto $allocator[[alloc]] = array.get_allocator();
+auto $size[[size]] = array.size();
+auto $begin[[begin]] = array.begin();
+auto $end[[end]] = array.end();
+  )cpp";
+
+  assertHintsWithHeader(
+  InlayHintKind::Type, VectorIntPtr, Header,
+  ExpectedHint{": int *", "no_modifier"},
+  ExpectedHint{": int **", "ptr_modifier"},
+  ExpectedHint{": int *&", "ref_modifier"},
+  ExpectedHint{": int *const &", "at"}, ExpectedHint{": int **", "data"},
+  ExpectedHint{": allocator", "allocator"},
+  ExpectedHint{": size_type", "size"}, ExpectedHint{": iterator", "begin"},
+  ExpectedHint{": non_template_iterator", "end"});
 
+  llvm::StringRef VectorInt = R"cpp(
   vector array;
-
   auto $no_modifier[[by_value]] = array[3];
   auto* $ptr_modifier[[ptr]] = &array[3];
   auto& $ref_modifier[[ref]] = array[3];
@@ -1468,8 +1501,19 @@
   auto $size[[size]] = array.size();
   auto $begin[[begin]] = array.begin();
   auto $end[[end]] = array.end();
+  )cpp";
 
+  assertHintsWithHeader(
+  InlayHintKind::Type, VectorInt, Header,
+  ExpectedHint{": int", "no_modifier"},
+  ExpectedHint{": int *", "ptr_modifier"},
+  ExpectedHint{": int &", "ref_modifier"},
+  ExpectedHint{": const int &", "at"}, ExpectedHint{": int *", "data"},
+  ExpectedHint{": allocator", "allocator"},
+  ExpectedHint{": size_type", "size"}, ExpectedHint{": iterator", "begin"},
+  ExpectedHint{": non_template_iterator", "end"});
 
+  llvm::StringRef TypeAlias = R"cpp(
   // If the type alias is not of substituted template parameter type,
   // do not show desugared type.
   using VeryLongLongTypeName = my_iterator;
@@ -1484,16 +1528,11 @@
   using static_vector = basic_static_vector>;
 
   auto $vector_name[[vec]] = static_vector();
-  )cpp",
-  ExpectedHint{": int", "no_modifier"},
-  ExpectedHint{": int *", "ptr_modifier"},
-  ExpectedHint{": int &", "ref_modifier"},
-  ExpectedHint{": const int &", "at"}, ExpectedHint{": int *", "data"},
-  ExpectedHint{": allocator", "allocator"},
-  ExpectedHint{": size_type", "size"}, ExpectedHint{": iterator", "begin"},
-  ExpectedHint{": non_template_iterator", "end"},
-  ExpectedHint{": Short", "short_name"},
-  ExpectedHint{": static_vector", "vector_name"});
+  )cpp";
+
+  assertHintsWithHeader(InlayHintKind::Type, TypeAlias, Header,
+ExpectedHint{": Short", "short_name"},
+ExpectedHint{": static_vector", "vector_name"});
 }
 
 TEST(DesignatorHints, Basic) {
Index: clang-tools-extra/clangd/InlayHints.cpp
===
--- clang-tools-extra/clangd/InlayHints.cpp
+++ clang-tools-extra/clangd/InlayHints.cpp
@@ -199,18 +199,45 @@
 // Neither `PointerType` nor `ReferenceType` is considered as sugared

[PATCH] D158061: [clang] Construct ExprRequirement with SubstitutionDiagnostic on SubstFailure

2023-08-16 Thread Younan Zhang via Phabricator via cfe-commits
zyounan created this revision.
zyounan added reviewers: saar.raz, erichkeane, ilya-biryukov, aaron.ballman.
Herald added a subscriber: kadircet.
Herald added a project: All.
zyounan published this revision for review.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

We're expecting a SubstitutionDiagnostic in diagnoseUnsatisfiedRequirement
if the status of ExprRequirement is SubstFailure. Previously, the Requirement
was created with Expr on SubstFailure by mistake, which could lead to the
assertion failure in the subsequent diagnosis.

Fixes https://github.com/clangd/clangd/issues/1726
Fixes https://github.com/llvm/llvm-project/issues/64723
Fixes https://github.com/llvm/llvm-project/issues/64172

In addition, this patch also fixes an invalid test from D129499 
.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D158061

Files:
  clang/include/clang/AST/ExprConcepts.h
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
  clang/test/SemaCXX/concept-fatal-error.cpp

Index: clang/test/SemaCXX/concept-fatal-error.cpp
===
--- clang/test/SemaCXX/concept-fatal-error.cpp
+++ clang/test/SemaCXX/concept-fatal-error.cpp
@@ -1,4 +1,4 @@
-// RUN: not %clang_cc1 -fsyntax-only -std=c++20 -ferror-limit 1 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++20 -ferror-limit 1 -verify %s
 
 template 
 concept f = requires { 42; };
@@ -6,5 +6,5 @@
   // The missing semicolon will trigger an error and -ferror-limit=1 will make it fatal
   // We test that we do not crash in such cases (#55401)
   int i = requires { { i } f } // expected-error {{expected ';' at end of declaration list}}
-   // expected-error@* {{too many errros emitted}}
+   // expected-error@* {{too many errors emitted}}
 };
Index: clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s
+
+template  class normal_iterator {};
+
+template  struct is_convertible {};
+
+template 
+inline constexpr bool is_convertible_v = is_convertible::value; // #1
+
+// expected-error@#1 {{no member named 'value' in 'is_convertible'}}
+
+template 
+concept convertible_to = is_convertible_v; // expected-note 0+{{}}
+template 
+  requires requires(IteratorL lhs, IteratorR rhs) { // expected-note 0+{{}}
+{ lhs == rhs } -> convertible_to; // #2
+  }
+constexpr bool compare(normal_iterator lhs, normal_iterator rhs) {
+  return false;
+}
+
+// We don't know exactly the substituted type for `lhs == rhs`, thus a placeholder 'expr-type' is emitted.
+// expected-note@#2 {{'convertible_to'}}
+
+// Consume remaining notes/errors.
+// expected-note@* 0+{{}}
+// expected-error@* 0+{{}}
+class Object;
+
+void function() {
+  normal_iterator begin, end;
+  compare(begin, end);
+}
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2276,9 +2276,9 @@
   getPackIndex(Pack), Arg, TL.getNameLoc());
 }
 
-template
 static concepts::Requirement::SubstitutionDiagnostic *
-createSubstDiag(Sema &S, TemplateDeductionInfo &Info, EntityPrinter Printer) {
+createSubstDiag(Sema &S, TemplateDeductionInfo &Info,
+concepts::EntityPrinter Printer) {
   SmallString<128> Message;
   SourceLocation ErrorLoc;
   if (Info.hasSFINAEDiagnostic()) {
@@ -2302,6 +2302,19 @@
   StringRef(MessageBuf, Message.size())};
 }
 
+concepts::Requirement::SubstitutionDiagnostic *
+concepts::createSubstDiagAt(Sema &S, SourceLocation Location,
+EntityPrinter Printer) {
+  SmallString<128> Entity;
+  llvm::raw_svector_ostream OS(Entity);
+  Printer(OS);
+  char *EntityBuf = new (S.Context) char[Entity.size()];
+  llvm::copy(Entity, EntityBuf);
+  return new (S.Context) concepts::Requirement::SubstitutionDiagnostic{
+  /*SubstitutedEntity=*/StringRef(EntityBuf, Entity.size()),
+  /*DiagLoc=*/Location, /*DiagMessage=*/StringRef()};
+}
+
 ExprResult TemplateInstantiator::TransformRequiresTypeParams(
 SourceLocation KWLoc, SourceLocation RBraceLoc, const RequiresExpr *RE,
 RequiresExprBodyDecl *Body, ArrayRef Params,
Index: clang/lib/Sema/SemaExprCXX.cpp
===
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -19,6 +19,7 @@
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprConcepts.h"
 #include "clang/AST/ExprObjC.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/Type.

[PATCH] D158061: [clang] Construct ExprRequirement with SubstitutionDiagnostic on SubstFailure

2023-08-16 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 550683.
zyounan added a comment.

Rebase and format


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158061/new/

https://reviews.llvm.org/D158061

Files:
  clang/include/clang/AST/ExprConcepts.h
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
  clang/test/SemaCXX/concept-fatal-error.cpp

Index: clang/test/SemaCXX/concept-fatal-error.cpp
===
--- clang/test/SemaCXX/concept-fatal-error.cpp
+++ clang/test/SemaCXX/concept-fatal-error.cpp
@@ -1,4 +1,4 @@
-// RUN: not %clang_cc1 -fsyntax-only -std=c++20 -ferror-limit 1 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++20 -ferror-limit 1 -verify %s
 
 template 
 concept f = requires { 42; };
@@ -6,5 +6,5 @@
   // The missing semicolon will trigger an error and -ferror-limit=1 will make it fatal
   // We test that we do not crash in such cases (#55401)
   int i = requires { { i } f } // expected-error {{expected ';' at end of declaration list}}
-   // expected-error@* {{too many errros emitted}}
+   // expected-error@* {{too many errors emitted}}
 };
Index: clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s
+
+template  class normal_iterator {};
+
+template  struct is_convertible {};
+
+template 
+inline constexpr bool is_convertible_v = is_convertible::value; // #1
+
+// expected-error@#1 {{no member named 'value' in 'is_convertible'}}
+
+template 
+concept convertible_to = is_convertible_v; // expected-note 0+{{}}
+template 
+  requires requires(IteratorL lhs, IteratorR rhs) { // expected-note 0+{{}}
+{ lhs == rhs } -> convertible_to; // #2
+  }
+constexpr bool compare(normal_iterator lhs, normal_iterator rhs) {
+  return false;
+}
+
+// We don't know exactly the substituted type for `lhs == rhs`, thus a placeholder 'expr-type' is emitted.
+// expected-note@#2 {{'convertible_to'}}
+
+// Consume remaining notes/errors.
+// expected-note@* 0+{{}}
+// expected-error@* 0+{{}}
+class Object;
+
+void function() {
+  normal_iterator begin, end;
+  compare(begin, end);
+}
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2271,9 +2271,9 @@
   getPackIndex(Pack), Arg, TL.getNameLoc());
 }
 
-template
 static concepts::Requirement::SubstitutionDiagnostic *
-createSubstDiag(Sema &S, TemplateDeductionInfo &Info, EntityPrinter Printer) {
+createSubstDiag(Sema &S, TemplateDeductionInfo &Info,
+concepts::EntityPrinter Printer) {
   SmallString<128> Message;
   SourceLocation ErrorLoc;
   if (Info.hasSFINAEDiagnostic()) {
@@ -2297,6 +2297,19 @@
   StringRef(MessageBuf, Message.size())};
 }
 
+concepts::Requirement::SubstitutionDiagnostic *
+concepts::createSubstDiagAt(Sema &S, SourceLocation Location,
+EntityPrinter Printer) {
+  SmallString<128> Entity;
+  llvm::raw_svector_ostream OS(Entity);
+  Printer(OS);
+  char *EntityBuf = new (S.Context) char[Entity.size()];
+  llvm::copy(Entity, EntityBuf);
+  return new (S.Context) concepts::Requirement::SubstitutionDiagnostic{
+  /*SubstitutedEntity=*/StringRef(EntityBuf, Entity.size()),
+  /*DiagLoc=*/Location, /*DiagMessage=*/StringRef()};
+}
+
 ExprResult TemplateInstantiator::TransformRequiresTypeParams(
 SourceLocation KWLoc, SourceLocation RBraceLoc, const RequiresExpr *RE,
 RequiresExprBodyDecl *Body, ArrayRef Params,
Index: clang/lib/Sema/SemaExprCXX.cpp
===
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -19,6 +19,7 @@
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprConcepts.h"
 #include "clang/AST/ExprObjC.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/Type.h"
@@ -9078,12 +9079,18 @@
 SubstExpr(TC->getImmediatelyDeclaredConstraint(), MLTAL);
 if (Constraint.isInvalid()) {
   Status = concepts::ExprRequirement::SS_ExprSubstitutionFailure;
-} else {
-  SubstitutedConstraintExpr =
-  cast(Constraint.get());
-  if (!SubstitutedConstraintExpr->isSatisfied())
-Status = concepts::ExprRequirement::SS_ConstraintsNotSatisfied;
-}
+  return new (Context) concepts::ExprRequirement(
+  concepts::createSubstDiagAt(*this, IDC->getExprLoc(),
+  [IDC, this](llvm::raw_ostream &OS) {
+IDC->printPretty(O

[PATCH] D158061: [clang] Construct ExprRequirement with SubstitutionDiagnostic on SubstFailure

2023-08-16 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 550713.
zyounan added a comment.

Adapt to D157554 


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158061/new/

https://reviews.llvm.org/D158061

Files:
  clang/include/clang/AST/ExprConcepts.h
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
  clang/test/SemaCXX/concept-fatal-error.cpp

Index: clang/test/SemaCXX/concept-fatal-error.cpp
===
--- clang/test/SemaCXX/concept-fatal-error.cpp
+++ clang/test/SemaCXX/concept-fatal-error.cpp
@@ -1,4 +1,4 @@
-// RUN: not %clang_cc1 -fsyntax-only -std=c++20 -ferror-limit 1 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++20 -ferror-limit 1 -verify %s
 
 template 
 concept f = requires { 42; };
@@ -6,5 +6,5 @@
   // The missing semicolon will trigger an error and -ferror-limit=1 will make it fatal
   // We test that we do not crash in such cases (#55401)
   int i = requires { { i } f } // expected-error {{expected ';' at end of declaration list}}
-   // expected-error@* {{too many errros emitted}}
+   // expected-error@* {{too many errors emitted}}
 };
Index: clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s
+
+template  class normal_iterator {};
+
+template  struct is_convertible {};
+
+template 
+inline constexpr bool is_convertible_v = is_convertible::value; // #1
+
+// expected-error@#1 {{no member named 'value' in 'is_convertible'}}
+
+template 
+concept convertible_to = is_convertible_v; // expected-note 0+{{}}
+template 
+  requires requires(IteratorL lhs, IteratorR rhs) { // expected-note 0+{{}}
+{ lhs == rhs } -> convertible_to; // #2
+  }
+constexpr bool compare(normal_iterator lhs, normal_iterator rhs) {
+  return false;
+}
+
+// We don't know exactly the substituted type for `lhs == rhs`, thus a placeholder 'expr-type' is emitted.
+// expected-note@#2 {{'convertible_to'}}
+
+// Consume remaining notes/errors.
+// expected-note@* 0+{{}}
+// expected-error@* 0+{{}}
+class Object;
+
+void function() {
+  normal_iterator begin, end;
+  compare(begin, end);
+}
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2271,9 +2271,9 @@
   getPackIndex(Pack), Arg, TL.getNameLoc());
 }
 
-template
 static concepts::Requirement::SubstitutionDiagnostic *
-createSubstDiag(Sema &S, TemplateDeductionInfo &Info, EntityPrinter Printer) {
+createSubstDiag(Sema &S, TemplateDeductionInfo &Info,
+concepts::EntityPrinter Printer) {
   SmallString<128> Message;
   SourceLocation ErrorLoc;
   if (Info.hasSFINAEDiagnostic()) {
@@ -2297,6 +2297,19 @@
   StringRef(MessageBuf, Message.size())};
 }
 
+concepts::Requirement::SubstitutionDiagnostic *
+concepts::createSubstDiagAt(Sema &S, SourceLocation Location,
+EntityPrinter Printer) {
+  SmallString<128> Entity;
+  llvm::raw_svector_ostream OS(Entity);
+  Printer(OS);
+  char *EntityBuf = new (S.Context) char[Entity.size()];
+  llvm::copy(Entity, EntityBuf);
+  return new (S.Context) concepts::Requirement::SubstitutionDiagnostic{
+  /*SubstitutedEntity=*/StringRef(EntityBuf, Entity.size()),
+  /*DiagLoc=*/Location, /*DiagMessage=*/StringRef()};
+}
+
 ExprResult TemplateInstantiator::TransformRequiresTypeParams(
 SourceLocation KWLoc, SourceLocation RBraceLoc, const RequiresExpr *RE,
 RequiresExprBodyDecl *Body, ArrayRef Params,
Index: clang/lib/Sema/SemaExprCXX.cpp
===
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -19,6 +19,7 @@
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprConcepts.h"
 #include "clang/AST/ExprObjC.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/Type.h"
@@ -9074,16 +9075,23 @@
 MLTAL.addOuterRetainedLevels(TPL->getDepth());
 const TypeConstraint *TC = Param->getTypeConstraint();
 assert(TC && "Type Constraint cannot be null here");
-ExprResult Constraint =
-SubstExpr(TC->getImmediatelyDeclaredConstraint(), MLTAL);
+auto *IDC = TC->getImmediatelyDeclaredConstraint();
+assert(IDC && "ImmediatelyDeclaredConstraint can't be null here.");
+ExprResult Constraint = SubstExpr(IDC, MLTAL);
 if (Constraint.isInvalid()) {
   Status = concepts::ExprRequirement::SS_ExprSubstitutionFailure;
-} else {
-  SubstitutedConstraintExpr =
-

[PATCH] D158061: [clang] Construct ExprRequirement with SubstitutionDiagnostic on SubstFailure

2023-08-16 Thread Younan Zhang via Phabricator via cfe-commits
zyounan added inline comments.



Comment at: clang/lib/Sema/SemaExprCXX.cpp:9079
+auto *IDC = TC->getImmediatelyDeclaredConstraint();
+assert(IDC && "ImmediatelyDeclaredConstraint can't be null here.");
+ExprResult Constraint = SubstExpr(IDC, MLTAL);

I'm adding another assertion here following up on D157554: If IDC is nullptr 
somehow, we will fall into the cast statement in the else block and crash 
anyway.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158061/new/

https://reviews.llvm.org/D158061

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D156605: [clangd][CodeComplete] Improve FunctionCanBeCall

2023-08-19 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 551723.
zyounan marked 14 inline comments as done.
zyounan added a comment.

Address many comments.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156605/new/

https://reviews.llvm.org/D156605

Files:
  clang-tools-extra/clangd/CodeComplete.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.h
  clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
  clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
  clang/lib/Sema/SemaCodeComplete.cpp
  clang/test/CodeCompletion/member-access.cpp
  clang/unittests/Sema/CodeCompleteTest.cpp

Index: clang/unittests/Sema/CodeCompleteTest.cpp
===
--- clang/unittests/Sema/CodeCompleteTest.cpp
+++ clang/unittests/Sema/CodeCompleteTest.cpp
@@ -60,7 +60,10 @@
 for (unsigned I = 0; I < NumResults; ++I) {
   auto R = Results[I];
   if (R.Kind == CodeCompletionResult::RK_Declaration) {
-if (const auto *FD = llvm::dyn_cast(R.getDeclaration())) {
+auto *ND = R.getDeclaration();
+if (auto *Template = llvm::dyn_cast(ND))
+  ND = Template->getTemplatedDecl();
+if (const auto *FD = llvm::dyn_cast(ND)) {
   CompletedFunctionDecl D;
   D.Name = FD->getNameAsString();
   D.CanBeCall = R.FunctionCanBeCall;
@@ -191,6 +194,10 @@
 struct Foo {
   static int staticMethod();
   int method() const;
+  template 
+  void generic(U);
+  template 
+  static T staticGeneric();
   Foo() {
 this->$canBeCall^
 $canBeCall^
@@ -199,6 +206,8 @@
 };
 
 struct Derived : Foo {
+  using Foo::method;
+  using Foo::generic;
   Derived() {
 Foo::$canBeCall^
   }
@@ -207,15 +216,29 @@
 struct OtherClass {
   OtherClass() {
 Foo f;
+Derived d;
 f.$canBeCall^
+; // Prevent parsing as 'f.f'
+f.Foo::$canBeCall^
 &Foo::$cannotBeCall^
+;
+d.Foo::$canBeCall^
+;
+d.Derived::$canBeCall^
   }
 };
 
 int main() {
   Foo f;
+  Derived d;
   f.$canBeCall^
+  ; // Prevent parsing as 'f.f'
+  f.Foo::$canBeCall^
   &Foo::$cannotBeCall^
+  ;
+  d.Foo::$canBeCall^
+  ;
+  d.Derived::$canBeCall^
 }
 )cpp");
 
@@ -223,12 +246,16 @@
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("method"), isStatic(false),
 canBeCall(true;
+EXPECT_THAT(Results, Contains(AllOf(named("generic"), isStatic(false),
+canBeCall(true;
   }
 
   for (const auto &P : Code.points("cannotBeCall")) {
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("method"), isStatic(false),
 canBeCall(false;
+EXPECT_THAT(Results, Contains(AllOf(named("generic"), isStatic(false),
+canBeCall(false;
   }
 
   // static method can always be a call
@@ -236,6 +263,8 @@
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("staticMethod"), isStatic(true),
 canBeCall(true;
+EXPECT_THAT(Results, Contains(AllOf(named("staticGeneric"), isStatic(true),
+canBeCall(true;
   }
 }
 
Index: clang/test/CodeCompletion/member-access.cpp
===
--- clang/test/CodeCompletion/member-access.cpp
+++ clang/test/CodeCompletion/member-access.cpp
@@ -341,3 +341,14 @@
   // RUN: %clang_cc1 -fsyntax-only -code-completion-with-fixits -code-completion-at=%s:339:10 %s -o - | FileCheck -check-prefix=CHECK-FIELD-DECLARED-VIA-USING %s
   // CHECK-FIELD-DECLARED-VIA-USING: [#int#]field (requires fix-it: {339:8-339:9} to "->")
 }
+
+namespace function_can_be_call {
+  struct S {
+template 
+V foo(T, U);
+  };
+
+  &S::f
+  // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:351:7 %s -o - | FileCheck -check-prefix=CHECK_FUNCTION_CAN_BE_CALL %s
+  // CHECK_FUNCTION_CAN_BE_CALL: COMPLETION: foo : [#V#]foo<<#typename T#>, <#typename U#>{#, <#typename V#>#}>(<#T#>, <#U#>)
+}
Index: clang/lib/Sema/SemaCodeComplete.cpp
===
--- clang/lib/Sema/SemaCodeComplete.cpp
+++ clang/lib/Sema/SemaCodeComplete.cpp
@@ -338,8 +338,11 @@
   ///
   /// \param InBaseClass whether the result was found in a base
   /// class of the searched context.
+  ///
+  /// \param BaseExprType the type of expression that precedes the "." or "->"
+  /// in a member access expression.
   void AddResult(Result R, DeclContext *CurContext, NamedDecl *Hiding,
-   

[PATCH] D156605: [clangd][CodeComplete] Improve FunctionCanBeCall

2023-08-19 Thread Younan Zhang via Phabricator via cfe-commits
zyounan added a comment.

Thanks for Sam and Nathan's thorough review! I've updated, and please take 
another look.
(Apologize for churning on weekends, but I don't have chunk time during the 
week.)




Comment at: clang-tools-extra/clangd/CodeCompletionStrings.cpp:258
 case CodeCompletionString::CK_RightParen:
+  if (DropFunctionArguments &&
+  ResultKind == CodeCompletionResult::RK_Declaration)

sammccall wrote:
> nridge wrote:
> > It looks like we are assuming two things:
> > 
> >  1. Any LeftParen in an RK_Declaration starts a function argument list
> >  2. Everything that comes after the function argument list can be discarded
> > 
> > I think these assumptions are fine to make, but let's be explicit about 
> > them in a comment
> Agree, but also I think the code could reflect this more directly:
>  - this should trigger only for CK_LeftParen, not CK_RightParen
> 
> Rather than redirecting output to a different string by reassigning the 
> param, I think it would be a bit more direct to have
> 
> ```
> optional TruncateSnippetAt;
> ...
> case CK_LeftBracket:
>   if (DropFunctionArguments && ... && !TruncateSnippetAt)
> TruncateSnippetAt = Snippet->size();
> ...
> if (TruncateSnippetAt)
>   Snippet->resize(*TruncateSnippetAt);
> }
> ```
> 
> (though still not totally clear)
> It looks like we are assuming two things

Honestly, I don't quite prefer this assumption. However, we have lost some of 
the semantics e.g., the structure of a call expression within this function, 
and unfortunately it's not trivial to pass these out from clang. :-(

> (though still not totally clear)

Yeah. I imagine a clearer way would be separating the calculation for 
`Signature` and `Snippet`, and we could bail out early for `Snippet`. But I'm 
afraid that making so many adjustments to `getSignature` for such a small 
feature is inappropriate.

Assuming the left parenthesis is the beginning of a call might be sufficient 
for the time being, and let's leave the refactoring to subsequent patches.




Comment at: clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp:580
 auto Results = completions(TU, P, /*IndexSymbols*/ {}, Opts);
 EXPECT_THAT(Results.Completions,
 Contains(AllOf(named("method"), snippetSuffix("";

nridge wrote:
> Since you're updating this test anyways, could you add `signature()` matchers 
> for the non-template cases as well please?
Of course!



Comment at: clang/lib/Sema/SemaCodeComplete.cpp:345
   void AddResult(Result R, DeclContext *CurContext, NamedDecl *Hiding,
- bool InBaseClass);
+ bool InBaseClass, QualType BaseType);
 

nridge wrote:
> The word "base" is a bit overloaded in this signature; in the parameter 
> `InBaseClass` it refers to inheritance, but in `BaseType` it refers to the 
> base expression of a `MemberExpr`.
> 
> Maybe we can name the new parameter `BaseExprType` to avoid confusion?
Makes sense to me. Thanks for the correction.



Comment at: clang/lib/Sema/SemaCodeComplete.cpp:1285
 Result.ShadowDecl = Using;
 AddResult(Result, CurContext, Hiding);
 return;

nridge wrote:
> Should we propagate `BaseType` into this recursive call?
Yes. And thanks for spotting this. I added another test case reflecting it.



Comment at: clang/lib/Sema/SemaCodeComplete.cpp:1387
 
-  // When completing a non-static member function (and not via
-  // dot/arrow member access) and we're not inside that class' scope,
-  // it can't be a call.
+  // Decide whether or not a non-static member function can be a call.
   if (CompletionContext.getKind() == clang::CodeCompletionContext::CCC_Symbol) 
{

sammccall wrote:
> This is confusing: the `CCC_Symbol` test is part of the specific heuristics 
> being used (it's the "not via dot/arrow member access" part, right?) but 
> you've moved the comment explaining what it does.
> 
> Also this function is just getting too long, and we're inlining more 
> complicated control flow here.
> Can we extract a function?
> 
> ```
> const auto *Method = ...;
> if (Method & !Method->isStatic()) {
>   R.FunctionCanBeCall = canMethodBeCalled(...);
> }
> ```
> it's the "not via dot/arrow member access" part

(Sorry for being unaware of the historical context). But I think `CCC_Symbol` 
should mean "we're completing a name such as a function or type name" per its 
comment. The heuristic for dot/arrow member access actually lies on the next 
line, i.e., if the completing decl is a CXXMethodDecl.

> Can we extract a function?

Sure. 



Comment at: clang/lib/Sema/SemaCodeComplete.cpp:1425
+R.FunctionCanBeCall =
+MaybeDerived == MaybeBase || 
MaybeDerived->isDerivedFrom(MaybeBase);
+  }

nridge wrote:
> Is there any situation where `MaybeDerived == MaybeBase || 
> MaybeDerived-

[PATCH] D158061: [clang] Construct ExprRequirement with SubstitutionDiagnostic on SubstFailure

2023-08-19 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 551726.
zyounan added a comment.

Add release note


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158061/new/

https://reviews.llvm.org/D158061

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/AST/ExprConcepts.h
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
  clang/test/SemaCXX/concept-fatal-error.cpp

Index: clang/test/SemaCXX/concept-fatal-error.cpp
===
--- clang/test/SemaCXX/concept-fatal-error.cpp
+++ clang/test/SemaCXX/concept-fatal-error.cpp
@@ -1,4 +1,4 @@
-// RUN: not %clang_cc1 -fsyntax-only -std=c++20 -ferror-limit 1 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++20 -ferror-limit 1 -verify %s
 
 template 
 concept f = requires { 42; };
@@ -6,5 +6,5 @@
   // The missing semicolon will trigger an error and -ferror-limit=1 will make it fatal
   // We test that we do not crash in such cases (#55401)
   int i = requires { { i } f } // expected-error {{expected ';' at end of declaration list}}
-   // expected-error@* {{too many errros emitted}}
+   // expected-error@* {{too many errors emitted}}
 };
Index: clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s
+
+template  class normal_iterator {};
+
+template  struct is_convertible {};
+
+template 
+inline constexpr bool is_convertible_v = is_convertible::value; // #1
+
+// expected-error@#1 {{no member named 'value' in 'is_convertible'}}
+
+template 
+concept convertible_to = is_convertible_v; // expected-note 0+{{}}
+template 
+  requires requires(IteratorL lhs, IteratorR rhs) { // expected-note 0+{{}}
+{ lhs == rhs } -> convertible_to; // #2
+  }
+constexpr bool compare(normal_iterator lhs, normal_iterator rhs) {
+  return false;
+}
+
+// We don't know exactly the substituted type for `lhs == rhs`, thus a placeholder 'expr-type' is emitted.
+// expected-note@#2 {{'convertible_to'}}
+
+// Consume remaining notes/errors.
+// expected-note@* 0+{{}}
+// expected-error@* 0+{{}}
+class Object;
+
+void function() {
+  normal_iterator begin, end;
+  compare(begin, end);
+}
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2271,9 +2271,9 @@
   getPackIndex(Pack), Arg, TL.getNameLoc());
 }
 
-template
 static concepts::Requirement::SubstitutionDiagnostic *
-createSubstDiag(Sema &S, TemplateDeductionInfo &Info, EntityPrinter Printer) {
+createSubstDiag(Sema &S, TemplateDeductionInfo &Info,
+concepts::EntityPrinter Printer) {
   SmallString<128> Message;
   SourceLocation ErrorLoc;
   if (Info.hasSFINAEDiagnostic()) {
@@ -2297,6 +2297,19 @@
   StringRef(MessageBuf, Message.size())};
 }
 
+concepts::Requirement::SubstitutionDiagnostic *
+concepts::createSubstDiagAt(Sema &S, SourceLocation Location,
+EntityPrinter Printer) {
+  SmallString<128> Entity;
+  llvm::raw_svector_ostream OS(Entity);
+  Printer(OS);
+  char *EntityBuf = new (S.Context) char[Entity.size()];
+  llvm::copy(Entity, EntityBuf);
+  return new (S.Context) concepts::Requirement::SubstitutionDiagnostic{
+  /*SubstitutedEntity=*/StringRef(EntityBuf, Entity.size()),
+  /*DiagLoc=*/Location, /*DiagMessage=*/StringRef()};
+}
+
 ExprResult TemplateInstantiator::TransformRequiresTypeParams(
 SourceLocation KWLoc, SourceLocation RBraceLoc, const RequiresExpr *RE,
 RequiresExprBodyDecl *Body, ArrayRef Params,
Index: clang/lib/Sema/SemaExprCXX.cpp
===
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -19,6 +19,7 @@
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprConcepts.h"
 #include "clang/AST/ExprObjC.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/Type.h"
@@ -9074,16 +9075,23 @@
 MLTAL.addOuterRetainedLevels(TPL->getDepth());
 const TypeConstraint *TC = Param->getTypeConstraint();
 assert(TC && "Type Constraint cannot be null here");
-ExprResult Constraint =
-SubstExpr(TC->getImmediatelyDeclaredConstraint(), MLTAL);
+auto *IDC = TC->getImmediatelyDeclaredConstraint();
+assert(IDC && "ImmediatelyDeclaredConstraint can't be null here.");
+ExprResult Constraint = SubstExpr(IDC, MLTAL);
 if (Constraint.isInvalid()) {
   Status = concepts::ExprRequirement::SS_ExprSubstitutionFailure;
-} else {
-  SubstitutedConstraintExpr =
-  cas

[PATCH] D158061: [clang] Construct ExprRequirement with SubstitutionDiagnostic on SubstFailure

2023-08-19 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 551728.
zyounan added a comment.

Rebase and Remove the stray status


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158061/new/

https://reviews.llvm.org/D158061

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/AST/ExprConcepts.h
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
  clang/test/SemaCXX/concept-fatal-error.cpp

Index: clang/test/SemaCXX/concept-fatal-error.cpp
===
--- clang/test/SemaCXX/concept-fatal-error.cpp
+++ clang/test/SemaCXX/concept-fatal-error.cpp
@@ -1,4 +1,4 @@
-// RUN: not %clang_cc1 -fsyntax-only -std=c++20 -ferror-limit 1 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++20 -ferror-limit 1 -verify %s
 
 template 
 concept f = requires { 42; };
@@ -6,5 +6,5 @@
   // The missing semicolon will trigger an error and -ferror-limit=1 will make it fatal
   // We test that we do not crash in such cases (#55401)
   int i = requires { { i } f } // expected-error {{expected ';' at end of declaration list}}
-   // expected-error@* {{too many errros emitted}}
+   // expected-error@* {{too many errors emitted}}
 };
Index: clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s
+
+template  class normal_iterator {};
+
+template  struct is_convertible {};
+
+template 
+inline constexpr bool is_convertible_v = is_convertible::value; // #1
+
+// expected-error@#1 {{no member named 'value' in 'is_convertible'}}
+
+template 
+concept convertible_to = is_convertible_v; // expected-note 0+{{}}
+template 
+  requires requires(IteratorL lhs, IteratorR rhs) { // expected-note 0+{{}}
+{ lhs == rhs } -> convertible_to; // #2
+  }
+constexpr bool compare(normal_iterator lhs, normal_iterator rhs) {
+  return false;
+}
+
+// We don't know exactly the substituted type for `lhs == rhs`, thus a placeholder 'expr-type' is emitted.
+// expected-note@#2 {{'convertible_to'}}
+
+// Consume remaining notes/errors.
+// expected-note@* 0+{{}}
+// expected-error@* 0+{{}}
+class Object;
+
+void function() {
+  normal_iterator begin, end;
+  compare(begin, end);
+}
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2271,9 +2271,9 @@
   getPackIndex(Pack), Arg, TL.getNameLoc());
 }
 
-template
 static concepts::Requirement::SubstitutionDiagnostic *
-createSubstDiag(Sema &S, TemplateDeductionInfo &Info, EntityPrinter Printer) {
+createSubstDiag(Sema &S, TemplateDeductionInfo &Info,
+concepts::EntityPrinter Printer) {
   SmallString<128> Message;
   SourceLocation ErrorLoc;
   if (Info.hasSFINAEDiagnostic()) {
@@ -2297,6 +2297,19 @@
   StringRef(MessageBuf, Message.size())};
 }
 
+concepts::Requirement::SubstitutionDiagnostic *
+concepts::createSubstDiagAt(Sema &S, SourceLocation Location,
+EntityPrinter Printer) {
+  SmallString<128> Entity;
+  llvm::raw_svector_ostream OS(Entity);
+  Printer(OS);
+  char *EntityBuf = new (S.Context) char[Entity.size()];
+  llvm::copy(Entity, EntityBuf);
+  return new (S.Context) concepts::Requirement::SubstitutionDiagnostic{
+  /*SubstitutedEntity=*/StringRef(EntityBuf, Entity.size()),
+  /*DiagLoc=*/Location, /*DiagMessage=*/StringRef()};
+}
+
 ExprResult TemplateInstantiator::TransformRequiresTypeParams(
 SourceLocation KWLoc, SourceLocation RBraceLoc, const RequiresExpr *RE,
 RequiresExprBodyDecl *Body, ArrayRef Params,
Index: clang/lib/Sema/SemaExprCXX.cpp
===
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -19,6 +19,7 @@
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprConcepts.h"
 #include "clang/AST/ExprObjC.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/Type.h"
@@ -9074,16 +9075,22 @@
 MLTAL.addOuterRetainedLevels(TPL->getDepth());
 const TypeConstraint *TC = Param->getTypeConstraint();
 assert(TC && "Type Constraint cannot be null here");
-ExprResult Constraint =
-SubstExpr(TC->getImmediatelyDeclaredConstraint(), MLTAL);
+auto *IDC = TC->getImmediatelyDeclaredConstraint();
+assert(IDC && "ImmediatelyDeclaredConstraint can't be null here.");
+ExprResult Constraint = SubstExpr(IDC, MLTAL);
 if (Constraint.isInvalid()) {
-  Status = concepts::ExprRequirement::SS_ExprSubstitutionFailure;
-} else {
-  SubstitutedConstraintExp

[PATCH] D156605: [clangd][CodeComplete] Improve FunctionCanBeCall

2023-08-19 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 551730.
zyounan added a comment.

Fix the bool expression.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156605/new/

https://reviews.llvm.org/D156605

Files:
  clang-tools-extra/clangd/CodeComplete.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.h
  clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
  clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
  clang/lib/Sema/SemaCodeComplete.cpp
  clang/test/CodeCompletion/member-access.cpp
  clang/unittests/Sema/CodeCompleteTest.cpp

Index: clang/unittests/Sema/CodeCompleteTest.cpp
===
--- clang/unittests/Sema/CodeCompleteTest.cpp
+++ clang/unittests/Sema/CodeCompleteTest.cpp
@@ -60,7 +60,10 @@
 for (unsigned I = 0; I < NumResults; ++I) {
   auto R = Results[I];
   if (R.Kind == CodeCompletionResult::RK_Declaration) {
-if (const auto *FD = llvm::dyn_cast(R.getDeclaration())) {
+auto *ND = R.getDeclaration();
+if (auto *Template = llvm::dyn_cast(ND))
+  ND = Template->getTemplatedDecl();
+if (const auto *FD = llvm::dyn_cast(ND)) {
   CompletedFunctionDecl D;
   D.Name = FD->getNameAsString();
   D.CanBeCall = R.FunctionCanBeCall;
@@ -191,6 +194,10 @@
 struct Foo {
   static int staticMethod();
   int method() const;
+  template 
+  void generic(U);
+  template 
+  static T staticGeneric();
   Foo() {
 this->$canBeCall^
 $canBeCall^
@@ -199,6 +206,8 @@
 };
 
 struct Derived : Foo {
+  using Foo::method;
+  using Foo::generic;
   Derived() {
 Foo::$canBeCall^
   }
@@ -207,15 +216,29 @@
 struct OtherClass {
   OtherClass() {
 Foo f;
+Derived d;
 f.$canBeCall^
+; // Prevent parsing as 'f.f'
+f.Foo::$canBeCall^
 &Foo::$cannotBeCall^
+;
+d.Foo::$canBeCall^
+;
+d.Derived::$canBeCall^
   }
 };
 
 int main() {
   Foo f;
+  Derived d;
   f.$canBeCall^
+  ; // Prevent parsing as 'f.f'
+  f.Foo::$canBeCall^
   &Foo::$cannotBeCall^
+  ;
+  d.Foo::$canBeCall^
+  ;
+  d.Derived::$canBeCall^
 }
 )cpp");
 
@@ -223,12 +246,16 @@
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("method"), isStatic(false),
 canBeCall(true;
+EXPECT_THAT(Results, Contains(AllOf(named("generic"), isStatic(false),
+canBeCall(true;
   }
 
   for (const auto &P : Code.points("cannotBeCall")) {
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("method"), isStatic(false),
 canBeCall(false;
+EXPECT_THAT(Results, Contains(AllOf(named("generic"), isStatic(false),
+canBeCall(false;
   }
 
   // static method can always be a call
@@ -236,6 +263,8 @@
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("staticMethod"), isStatic(true),
 canBeCall(true;
+EXPECT_THAT(Results, Contains(AllOf(named("staticGeneric"), isStatic(true),
+canBeCall(true;
   }
 }
 
Index: clang/test/CodeCompletion/member-access.cpp
===
--- clang/test/CodeCompletion/member-access.cpp
+++ clang/test/CodeCompletion/member-access.cpp
@@ -341,3 +341,14 @@
   // RUN: %clang_cc1 -fsyntax-only -code-completion-with-fixits -code-completion-at=%s:339:10 %s -o - | FileCheck -check-prefix=CHECK-FIELD-DECLARED-VIA-USING %s
   // CHECK-FIELD-DECLARED-VIA-USING: [#int#]field (requires fix-it: {339:8-339:9} to "->")
 }
+
+namespace function_can_be_call {
+  struct S {
+template 
+V foo(T, U);
+  };
+
+  &S::f
+  // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:351:7 %s -o - | FileCheck -check-prefix=CHECK_FUNCTION_CAN_BE_CALL %s
+  // CHECK_FUNCTION_CAN_BE_CALL: COMPLETION: foo : [#V#]foo<<#typename T#>, <#typename U#>{#, <#typename V#>#}>(<#T#>, <#U#>)
+}
Index: clang/lib/Sema/SemaCodeComplete.cpp
===
--- clang/lib/Sema/SemaCodeComplete.cpp
+++ clang/lib/Sema/SemaCodeComplete.cpp
@@ -338,8 +338,11 @@
   ///
   /// \param InBaseClass whether the result was found in a base
   /// class of the searched context.
+  ///
+  /// \param BaseExprType the type of expression that precedes the "." or "->"
+  /// in a member access expression.
   void AddResult(Result R, DeclContext *CurContext, NamedDecl *Hiding,
- bool InBaseClass);
+   

[PATCH] D156605: [clangd][CodeComplete] Improve FunctionCanBeCall

2023-08-19 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 551736.
zyounan added a comment.

Sorry, forgot to update tests :(


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156605/new/

https://reviews.llvm.org/D156605

Files:
  clang-tools-extra/clangd/CodeComplete.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.h
  clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
  clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
  clang/lib/Sema/SemaCodeComplete.cpp
  clang/test/CodeCompletion/member-access.cpp
  clang/unittests/Sema/CodeCompleteTest.cpp

Index: clang/unittests/Sema/CodeCompleteTest.cpp
===
--- clang/unittests/Sema/CodeCompleteTest.cpp
+++ clang/unittests/Sema/CodeCompleteTest.cpp
@@ -60,7 +60,10 @@
 for (unsigned I = 0; I < NumResults; ++I) {
   auto R = Results[I];
   if (R.Kind == CodeCompletionResult::RK_Declaration) {
-if (const auto *FD = llvm::dyn_cast(R.getDeclaration())) {
+auto *ND = R.getDeclaration();
+if (auto *Template = llvm::dyn_cast(ND))
+  ND = Template->getTemplatedDecl();
+if (const auto *FD = llvm::dyn_cast(ND)) {
   CompletedFunctionDecl D;
   D.Name = FD->getNameAsString();
   D.CanBeCall = R.FunctionCanBeCall;
@@ -191,6 +194,10 @@
 struct Foo {
   static int staticMethod();
   int method() const;
+  template 
+  void generic(U);
+  template 
+  static T staticGeneric();
   Foo() {
 this->$canBeCall^
 $canBeCall^
@@ -199,6 +206,8 @@
 };
 
 struct Derived : Foo {
+  using Foo::method;
+  using Foo::generic;
   Derived() {
 Foo::$canBeCall^
   }
@@ -207,15 +216,29 @@
 struct OtherClass {
   OtherClass() {
 Foo f;
+Derived d;
 f.$canBeCall^
+; // Prevent parsing as 'f.f'
+f.Foo::$canBeCall^
 &Foo::$cannotBeCall^
+;
+d.Foo::$canBeCall^
+;
+d.Derived::$canBeCall^
   }
 };
 
 int main() {
   Foo f;
+  Derived d;
   f.$canBeCall^
+  ; // Prevent parsing as 'f.f'
+  f.Foo::$canBeCall^
   &Foo::$cannotBeCall^
+  ;
+  d.Foo::$canBeCall^
+  ;
+  d.Derived::$canBeCall^
 }
 )cpp");
 
@@ -223,12 +246,16 @@
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("method"), isStatic(false),
 canBeCall(true;
+EXPECT_THAT(Results, Contains(AllOf(named("generic"), isStatic(false),
+canBeCall(true;
   }
 
   for (const auto &P : Code.points("cannotBeCall")) {
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("method"), isStatic(false),
 canBeCall(false;
+EXPECT_THAT(Results, Contains(AllOf(named("generic"), isStatic(false),
+canBeCall(false;
   }
 
   // static method can always be a call
@@ -236,6 +263,8 @@
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("staticMethod"), isStatic(true),
 canBeCall(true;
+EXPECT_THAT(Results, Contains(AllOf(named("staticGeneric"), isStatic(true),
+canBeCall(true;
   }
 }
 
Index: clang/test/CodeCompletion/member-access.cpp
===
--- clang/test/CodeCompletion/member-access.cpp
+++ clang/test/CodeCompletion/member-access.cpp
@@ -341,3 +341,14 @@
   // RUN: %clang_cc1 -fsyntax-only -code-completion-with-fixits -code-completion-at=%s:339:10 %s -o - | FileCheck -check-prefix=CHECK-FIELD-DECLARED-VIA-USING %s
   // CHECK-FIELD-DECLARED-VIA-USING: [#int#]field (requires fix-it: {339:8-339:9} to "->")
 }
+
+namespace function_can_be_call {
+  struct S {
+template 
+V foo(T, U);
+  };
+
+  &S::f
+  // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:351:7 %s -o - | FileCheck -check-prefix=CHECK_FUNCTION_CAN_BE_CALL %s
+  // CHECK_FUNCTION_CAN_BE_CALL: COMPLETION: foo : [#V#]foo<<#typename T#>, <#typename U#>{#, <#typename V#>#}>(<#T#>, <#U#>)
+}
Index: clang/lib/Sema/SemaCodeComplete.cpp
===
--- clang/lib/Sema/SemaCodeComplete.cpp
+++ clang/lib/Sema/SemaCodeComplete.cpp
@@ -338,8 +338,11 @@
   ///
   /// \param InBaseClass whether the result was found in a base
   /// class of the searched context.
+  ///
+  /// \param BaseExprType the type of expression that precedes the "." or "->"
+  /// in a member access expression.
   void AddResult(Result R, DeclContext *CurContext, NamedDecl *Hiding,
- bool InBaseClass);

[PATCH] D156300: [clangd] Avoid unexpected desugaring in isSugaredTemplateParameter

2023-07-29 Thread Younan Zhang via Phabricator via cfe-commits
zyounan added a comment.

Ping~


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156300/new/

https://reviews.llvm.org/D156300

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D156300: [clangd] Avoid unexpected desugaring in isSugaredTemplateParameter

2023-07-29 Thread Younan Zhang via Phabricator via cfe-commits
zyounan added a comment.

Oops, my apologies for bothering you. Thanks again for the explanation and your 
dedication!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156300/new/

https://reviews.llvm.org/D156300

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D156605: [CodeComplete] Mark 'Derived().Base::foo()' CanBeCall

2023-07-29 Thread Younan Zhang via Phabricator via cfe-commits
zyounan created this revision.
zyounan added reviewers: sammccall, nridge, hokein.
Herald added subscribers: kadircet, arphaman.
Herald added a project: All.
zyounan published this revision for review.
Herald added projects: clang, clang-tools-extra.
Herald added a subscriber: cfe-commits.

This resolves https://reviews.llvm.org/D155370#4531274.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D156605

Files:
  clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
  clang/lib/Sema/SemaCodeComplete.cpp
  clang/unittests/Sema/CodeCompleteTest.cpp

Index: clang/unittests/Sema/CodeCompleteTest.cpp
===
--- clang/unittests/Sema/CodeCompleteTest.cpp
+++ clang/unittests/Sema/CodeCompleteTest.cpp
@@ -214,15 +214,25 @@
 struct OtherClass {
   OtherClass() {
 Foo f;
+Derived d;
 f.$canBeCall^
+; // Prevent parsing as 'f.f'
+f.Foo::$canBeCall^
 &Foo::$cannotBeCall^
+;
+d.Foo::$canBeCall^
   }
 };
 
 int main() {
   Foo f;
+  Derived d;
   f.$canBeCall^
+  ; // Prevent parsing as 'f.f'
+  f.Foo::$canBeCall^
   &Foo::$cannotBeCall^
+  ;
+  d.Foo::$canBeCall^
 }
 )cpp");
 
Index: clang/lib/Sema/SemaCodeComplete.cpp
===
--- clang/lib/Sema/SemaCodeComplete.cpp
+++ clang/lib/Sema/SemaCodeComplete.cpp
@@ -338,8 +338,11 @@
   ///
   /// \param InBaseClass whether the result was found in a base
   /// class of the searched context.
+  ///
+  /// \param BaseType the type of expression that precedes the "." or "->"
+  /// in a member access expression.
   void AddResult(Result R, DeclContext *CurContext, NamedDecl *Hiding,
- bool InBaseClass);
+ bool InBaseClass, QualType BaseType);
 
   /// Add a new non-declaration result to this result set.
   void AddResult(Result R);
@@ -1262,7 +1265,8 @@
 }
 
 void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
-  NamedDecl *Hiding, bool InBaseClass = false) {
+  NamedDecl *Hiding, bool InBaseClass = false,
+  QualType BaseType = QualType()) {
   if (R.Kind != Result::RK_Declaration) {
 // For non-declaration results, just add the result.
 Results.push_back(R);
@@ -1380,9 +1384,7 @@
 OverloadSet.Add(Method, Results.size());
   }
 
-  // When completing a non-static member function (and not via
-  // dot/arrow member access) and we're not inside that class' scope,
-  // it can't be a call.
+  // Decide whether or not a non-static member function can be a call.
   if (CompletionContext.getKind() == clang::CodeCompletionContext::CCC_Symbol) {
 const NamedDecl *ND = R.getDeclaration();
 if (const auto *FuncTmpl = dyn_cast(ND)) {
@@ -1404,10 +1406,24 @@
 return nullptr;
   }();
 
+  // When completing a non-static member function (and not via
+  // dot/arrow member access) and we're not inside that class' scope,
+  // it can't be a call.
   R.FunctionCanBeCall =
   CurrentClassScope &&
   (CurrentClassScope == Method->getParent() ||
CurrentClassScope->isDerivedFrom(Method->getParent()));
+
+  // If the member access "." or "->" is followed by a qualified Id and the
+  // object type is derived from or the same as that of the Id, then
+  // the candidate functions should be perceived as calls.
+  if (const CXXRecordDecl *MaybeDerived = nullptr;
+  !BaseType.isNull() &&
+  (MaybeDerived = BaseType->getAsCXXRecordDecl())) {
+auto *MaybeBase = Method->getParent();
+R.FunctionCanBeCall =
+MaybeDerived == MaybeBase || MaybeDerived->isDerivedFrom(MaybeBase);
+  }
 }
   }
 
@@ -1683,7 +1699,7 @@
  bool InBaseClass) override {
 ResultBuilder::Result Result(ND, Results.getBasePriority(ND), nullptr,
  false, IsAccessible(ND, Ctx), FixIts);
-Results.AddResult(Result, InitialLookupCtx, Hiding, InBaseClass);
+Results.AddResult(Result, InitialLookupCtx, Hiding, InBaseClass, BaseType);
   }
 
   void EnteredContext(DeclContext *Ctx) override {
Index: clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
===
--- clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -552,15 +552,25 @@
   struct OtherClass {
 OtherClass() {
   Foo f;
+  Derived d;
   f.$canBeCall^
+  ; // Prevent parsing as 'f.f'
+  f.Foo::$canBeCall^
   &Foo::$canNotBeCall^
+  ;
+  d.Foo::$canBeCall^
 }
   };
 
   int main() {
 Foo f;
+Derived d;
 f.$canBeCall^
+; // Prevent parsing as 'f.f'

[PATCH] D155370: [CodeComplete] Improve FunctionCanBeCall

2023-07-29 Thread Younan Zhang via Phabricator via cfe-commits
zyounan added inline comments.



Comment at: clang/lib/Sema/SemaCodeComplete.cpp:1407
 
   R.FunctionCanBeCall =
   CurrentClassScope &&

zyounan wrote:
> The current heuristic results in the following:
> 
> ```
> struct Base {
>   void foo(int);
> };
> struct Derived : Base {
>   void foo(float);
> };
> 
> int main() {
>   Derived d;
>   d.Base::^// FunctionCanBeCall for `foo` is false.
> }
> ```
> 
> In situations where it is intended to invoke base member functions hidden by 
> subclasses, we shouldn't remove parentheses, IMO.
D156605 to address this.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D155370/new/

https://reviews.llvm.org/D155370

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D156300: [clangd] Avoid unexpected desugaring in isSugaredTemplateParameter

2023-07-31 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 545920.
zyounan marked 2 inline comments as done.
zyounan added a comment.
Herald added a project: clang.

Update


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156300/new/

https://reviews.llvm.org/D156300

Files:
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp
  clang/lib/Sema/SemaCodeComplete.cpp
  clang/unittests/Sema/CodeCompleteTest.cpp

Index: clang/unittests/Sema/CodeCompleteTest.cpp
===
--- clang/unittests/Sema/CodeCompleteTest.cpp
+++ clang/unittests/Sema/CodeCompleteTest.cpp
@@ -214,15 +214,25 @@
 struct OtherClass {
   OtherClass() {
 Foo f;
+Derived d;
 f.$canBeCall^
+; // Prevent parsing as 'f.f'
+f.Foo::$canBeCall^
 &Foo::$cannotBeCall^
+;
+d.Foo::$canBeCall^
   }
 };
 
 int main() {
   Foo f;
+  Derived d;
   f.$canBeCall^
+  ; // Prevent parsing as 'f.f'
+  f.Foo::$canBeCall^
   &Foo::$cannotBeCall^
+  ;
+  d.Foo::$canBeCall^
 }
 )cpp");
 
Index: clang/lib/Sema/SemaCodeComplete.cpp
===
--- clang/lib/Sema/SemaCodeComplete.cpp
+++ clang/lib/Sema/SemaCodeComplete.cpp
@@ -338,8 +338,11 @@
   ///
   /// \param InBaseClass whether the result was found in a base
   /// class of the searched context.
+  ///
+  /// \param BaseType the type of expression that precedes the "." or "->"
+  /// in a member access expression.
   void AddResult(Result R, DeclContext *CurContext, NamedDecl *Hiding,
- bool InBaseClass);
+ bool InBaseClass, QualType BaseType);
 
   /// Add a new non-declaration result to this result set.
   void AddResult(Result R);
@@ -1262,7 +1265,8 @@
 }
 
 void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
-  NamedDecl *Hiding, bool InBaseClass = false) {
+  NamedDecl *Hiding, bool InBaseClass = false,
+  QualType BaseType = QualType()) {
   if (R.Kind != Result::RK_Declaration) {
 // For non-declaration results, just add the result.
 Results.push_back(R);
@@ -1380,9 +1384,7 @@
 OverloadSet.Add(Method, Results.size());
   }
 
-  // When completing a non-static member function (and not via
-  // dot/arrow member access) and we're not inside that class' scope,
-  // it can't be a call.
+  // Decide whether or not a non-static member function can be a call.
   if (CompletionContext.getKind() == clang::CodeCompletionContext::CCC_Symbol) {
 const NamedDecl *ND = R.getDeclaration();
 if (const auto *FuncTmpl = dyn_cast(ND)) {
@@ -1404,10 +1406,24 @@
 return nullptr;
   }();
 
+  // When completing a non-static member function (and not via
+  // dot/arrow member access) and we're not inside that class' scope,
+  // it can't be a call.
   R.FunctionCanBeCall =
   CurrentClassScope &&
   (CurrentClassScope == Method->getParent() ||
CurrentClassScope->isDerivedFrom(Method->getParent()));
+
+  // If the member access "." or "->" is followed by a qualified Id and the
+  // object type is derived from or the same as that of the Id, then
+  // the candidate functions should be perceived as calls.
+  if (const CXXRecordDecl *MaybeDerived = nullptr;
+  !BaseType.isNull() &&
+  (MaybeDerived = BaseType->getAsCXXRecordDecl())) {
+auto *MaybeBase = Method->getParent();
+R.FunctionCanBeCall =
+MaybeDerived == MaybeBase || MaybeDerived->isDerivedFrom(MaybeBase);
+  }
 }
   }
 
@@ -1683,7 +1699,7 @@
  bool InBaseClass) override {
 ResultBuilder::Result Result(ND, Results.getBasePriority(ND), nullptr,
  false, IsAccessible(ND, Ctx), FixIts);
-Results.AddResult(Result, InitialLookupCtx, Hiding, InBaseClass);
+Results.AddResult(Result, InitialLookupCtx, Hiding, InBaseClass, BaseType);
   }
 
   void EnteredContext(DeclContext *Ctx) override {
Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -81,11 +81,13 @@
 }
 
 template 
-void assertHints(InlayHintKind Kind, llvm::StringRef AnnotatedSource,
- ExpectedHints... Expected) {
+void assertHintsWithHeader(InlayHintKind Kind, llvm::StringRef AnnotatedSource,
+   llvm::StringRef HeaderContent,
+   ExpectedHints... Expected) {
   Annotations Source(AnnotatedSource);
   TestTU TU = TestTU::withCode(Source.code());
   TU.ExtraArgs.push_back

[PATCH] D156300: [clangd] Avoid unexpected desugaring in isSugaredTemplateParameter

2023-07-31 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 545922.
zyounan added a comment.

Fix the chaos in the previous update


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156300/new/

https://reviews.llvm.org/D156300

Files:
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -81,11 +81,13 @@
 }
 
 template 
-void assertHints(InlayHintKind Kind, llvm::StringRef AnnotatedSource,
- ExpectedHints... Expected) {
+void assertHintsWithHeader(InlayHintKind Kind, llvm::StringRef AnnotatedSource,
+   llvm::StringRef HeaderContent,
+   ExpectedHints... Expected) {
   Annotations Source(AnnotatedSource);
   TestTU TU = TestTU::withCode(Source.code());
   TU.ExtraArgs.push_back("-std=c++20");
+  TU.HeaderCode = HeaderContent;
   auto AST = TU.build();
 
   EXPECT_THAT(hintsOfKind(AST, Kind),
@@ -96,6 +98,13 @@
   EXPECT_THAT(inlayHints(AST, std::nullopt), IsEmpty());
 }
 
+template 
+void assertHints(InlayHintKind Kind, llvm::StringRef AnnotatedSource,
+ ExpectedHints... Expected) {
+  return assertHintsWithHeader(Kind, AnnotatedSource, "",
+   std::move(Expected)...);
+}
+
 // Hack to allow expression-statements operating on parameter packs in C++14.
 template  void ignore(T &&...) {}
 
@@ -1421,8 +1430,7 @@
 }
 
 TEST(TypeHints, SubstTemplateParameterAliases) {
-  assertTypeHints(
-  R"cpp(
+  llvm::StringRef Header = R"cpp(
   template  struct allocator {};
 
   template 
@@ -1455,9 +1463,34 @@
 
 T elements[10];
   };
+  )cpp";
+
+  llvm::StringRef VectorIntPtr = R"cpp(
+vector array;
+auto $no_modifier[[x]] = array[3];
+auto* $ptr_modifier[[ptr]] = &array[3];
+auto& $ref_modifier[[ref]] = array[3];
+auto& $at[[immutable]] = array.at(3);
+
+auto $data[[data]] = array.data();
+auto $allocator[[alloc]] = array.get_allocator();
+auto $size[[size]] = array.size();
+auto $begin[[begin]] = array.begin();
+auto $end[[end]] = array.end();
+  )cpp";
+
+  assertHintsWithHeader(
+  InlayHintKind::Type, VectorIntPtr, Header,
+  ExpectedHint{": int *", "no_modifier"},
+  ExpectedHint{": int **", "ptr_modifier"},
+  ExpectedHint{": int *&", "ref_modifier"},
+  ExpectedHint{": int *const &", "at"}, ExpectedHint{": int **", "data"},
+  ExpectedHint{": allocator", "allocator"},
+  ExpectedHint{": size_type", "size"}, ExpectedHint{": iterator", "begin"},
+  ExpectedHint{": non_template_iterator", "end"});
 
+  llvm::StringRef VectorInt = R"cpp(
   vector array;
-
   auto $no_modifier[[by_value]] = array[3];
   auto* $ptr_modifier[[ptr]] = &array[3];
   auto& $ref_modifier[[ref]] = array[3];
@@ -1468,8 +1501,19 @@
   auto $size[[size]] = array.size();
   auto $begin[[begin]] = array.begin();
   auto $end[[end]] = array.end();
+  )cpp";
 
+  assertHintsWithHeader(
+  InlayHintKind::Type, VectorInt, Header,
+  ExpectedHint{": int", "no_modifier"},
+  ExpectedHint{": int *", "ptr_modifier"},
+  ExpectedHint{": int &", "ref_modifier"},
+  ExpectedHint{": const int &", "at"}, ExpectedHint{": int *", "data"},
+  ExpectedHint{": allocator", "allocator"},
+  ExpectedHint{": size_type", "size"}, ExpectedHint{": iterator", "begin"},
+  ExpectedHint{": non_template_iterator", "end"});
 
+  llvm::StringRef TypeAlias = R"cpp(
   // If the type alias is not of substituted template parameter type,
   // do not show desugared type.
   using VeryLongLongTypeName = my_iterator;
@@ -1484,16 +1528,11 @@
   using static_vector = basic_static_vector>;
 
   auto $vector_name[[vec]] = static_vector();
-  )cpp",
-  ExpectedHint{": int", "no_modifier"},
-  ExpectedHint{": int *", "ptr_modifier"},
-  ExpectedHint{": int &", "ref_modifier"},
-  ExpectedHint{": const int &", "at"}, ExpectedHint{": int *", "data"},
-  ExpectedHint{": allocator", "allocator"},
-  ExpectedHint{": size_type", "size"}, ExpectedHint{": iterator", "begin"},
-  ExpectedHint{": non_template_iterator", "end"},
-  ExpectedHint{": Short", "short_name"},
-  ExpectedHint{": static_vector", "vector_name"});
+  )cpp";
+
+  assertHintsWithHeader(InlayHintKind::Type, TypeAlias, Header,
+ExpectedHint{": Short", "short_name"},
+ExpectedHint{": static_vector", "vector_name"});
 }
 
 TEST(DesignatorHints, Basic) {
Index: clang-tools-extra/clangd/InlayHints.cpp
===
--- clang-tools-extra/clangd/InlayHints.cpp
+++ clang-tools-extra/clangd/InlayHints.cpp
@@ -195,22 +195,47 @@
 // Determines if any intermediate type in de

[PATCH] D156300: [clangd] Avoid unexpected desugaring in isSugaredTemplateParameter

2023-07-31 Thread Younan Zhang via Phabricator via cfe-commits
zyounan added a comment.

Sorry, looks like I messed up with the commits before. Fixed it now.




Comment at: clang-tools-extra/clangd/InlayHints.cpp:207
+
+  // This is a bit tricky: we traverse the type structure and find whether or
+  // not a type in the desugaring process is of SubstTemplateTypeParmType.

nridge wrote:
> Nice find, this is indeed pretty tricky. I remember running into a similar 
> issue before in https://reviews.llvm.org/D124690#inline-1205484.
Cool. That looks far more intricate and I should take some time to understand 
the context. Thanks for the reference :)



Comment at: clang-tools-extra/clangd/unittests/InlayHintTests.cpp:1432
 
 TEST(TypeHints, SubstTemplateParameterAliases) {
+  llvm::StringRef Header = R"cpp(

I feel like this test is becoming clunky: The validations here require an 
invented class template `vector` which I think should be better placed in a 
header; however, in the remaining snippet, it seems that I'm testing too many 
hints in one `assertHint` call. Should I split these cases into different 
snippets, or we just leave them as-is at the moment?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156300/new/

https://reviews.llvm.org/D156300

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D155370: [CodeComplete] Improve FunctionCanBeCall

2023-08-01 Thread Younan Zhang via Phabricator via cfe-commits
zyounan added a comment.

In D155370#4545763 , @nridge wrote:

> (e.g. maybe you're looking for one with a particular parameter type).

I understand the second point that it'd be nice to offer the user a chance to 
see the arguments in order to help decide if the function is appropriate -- 
although in the context where `CanBeCall=false`, arguments don't disambiguate 
against the overloads, so we'd end up with the same function name after 
selecting the candidate. (An explicit cast may be required to perform overload 
resolution if necessary 
, but that 
should occur before the completion point `&ClassName::Prefix^`.)

OTOH, we don't present arguments for overloads in the candidates:

F28542806: image.png 

(At least for VSCode, I'm not sure if others behave the same.)

So, I don't think it is that important to retain the `Signature`. Any thoughts?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D155370/new/

https://reviews.llvm.org/D155370

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D156300: [clangd] Avoid unexpected desugaring in isSugaredTemplateParameter

2023-08-01 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 546007.
zyounan added a comment.

.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156300/new/

https://reviews.llvm.org/D156300

Files:
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -84,11 +84,13 @@
 }
 
 template 
-void assertHints(InlayHintKind Kind, llvm::StringRef AnnotatedSource,
- ExpectedHints... Expected) {
+void assertHintsWithHeader(InlayHintKind Kind, llvm::StringRef AnnotatedSource,
+   llvm::StringRef HeaderContent,
+   ExpectedHints... Expected) {
   Annotations Source(AnnotatedSource);
   TestTU TU = TestTU::withCode(Source.code());
   TU.ExtraArgs.push_back("-std=c++20");
+  TU.HeaderCode = HeaderContent;
   auto AST = TU.build();
 
   EXPECT_THAT(hintsOfKind(AST, Kind),
@@ -99,6 +101,13 @@
   EXPECT_THAT(inlayHints(AST, std::nullopt), IsEmpty());
 }
 
+template 
+void assertHints(InlayHintKind Kind, llvm::StringRef AnnotatedSource,
+ ExpectedHints... Expected) {
+  return assertHintsWithHeader(Kind, AnnotatedSource, "",
+   std::move(Expected)...);
+}
+
 // Hack to allow expression-statements operating on parameter packs in C++14.
 template  void ignore(T &&...) {}
 
@@ -1433,8 +1442,7 @@
 }
 
 TEST(TypeHints, SubstTemplateParameterAliases) {
-  assertTypeHints(
-  R"cpp(
+  llvm::StringRef Header = R"cpp(
   template  struct allocator {};
 
   template 
@@ -1467,9 +1475,34 @@
 
 T elements[10];
   };
+  )cpp";
 
-  vector array;
+  llvm::StringRef VectorIntPtr = R"cpp(
+vector array;
+auto $no_modifier[[x]] = array[3];
+auto* $ptr_modifier[[ptr]] = &array[3];
+auto& $ref_modifier[[ref]] = array[3];
+auto& $at[[immutable]] = array.at(3);
+
+auto $data[[data]] = array.data();
+auto $allocator[[alloc]] = array.get_allocator();
+auto $size[[size]] = array.size();
+auto $begin[[begin]] = array.begin();
+auto $end[[end]] = array.end();
+  )cpp";
+
+  assertHintsWithHeader(
+  InlayHintKind::Type, VectorIntPtr, Header,
+  ExpectedHint{": int *", "no_modifier"},
+  ExpectedHint{": int **", "ptr_modifier"},
+  ExpectedHint{": int *&", "ref_modifier"},
+  ExpectedHint{": int *const &", "at"}, ExpectedHint{": int **", "data"},
+  ExpectedHint{": allocator", "allocator"},
+  ExpectedHint{": size_type", "size"}, ExpectedHint{": iterator", "begin"},
+  ExpectedHint{": non_template_iterator", "end"});
 
+  llvm::StringRef VectorInt = R"cpp(
+  vector array;
   auto $no_modifier[[by_value]] = array[3];
   auto* $ptr_modifier[[ptr]] = &array[3];
   auto& $ref_modifier[[ref]] = array[3];
@@ -1480,8 +1513,19 @@
   auto $size[[size]] = array.size();
   auto $begin[[begin]] = array.begin();
   auto $end[[end]] = array.end();
+  )cpp";
 
+  assertHintsWithHeader(
+  InlayHintKind::Type, VectorInt, Header,
+  ExpectedHint{": int", "no_modifier"},
+  ExpectedHint{": int *", "ptr_modifier"},
+  ExpectedHint{": int &", "ref_modifier"},
+  ExpectedHint{": const int &", "at"}, ExpectedHint{": int *", "data"},
+  ExpectedHint{": allocator", "allocator"},
+  ExpectedHint{": size_type", "size"}, ExpectedHint{": iterator", "begin"},
+  ExpectedHint{": non_template_iterator", "end"});
 
+  llvm::StringRef TypeAlias = R"cpp(
   // If the type alias is not of substituted template parameter type,
   // do not show desugared type.
   using VeryLongLongTypeName = my_iterator;
@@ -1496,16 +1540,11 @@
   using static_vector = basic_static_vector>;
 
   auto $vector_name[[vec]] = static_vector();
-  )cpp",
-  ExpectedHint{": int", "no_modifier"},
-  ExpectedHint{": int *", "ptr_modifier"},
-  ExpectedHint{": int &", "ref_modifier"},
-  ExpectedHint{": const int &", "at"}, ExpectedHint{": int *", "data"},
-  ExpectedHint{": allocator", "allocator"},
-  ExpectedHint{": size_type", "size"}, ExpectedHint{": iterator", "begin"},
-  ExpectedHint{": non_template_iterator", "end"},
-  ExpectedHint{": Short", "short_name"},
-  ExpectedHint{": static_vector", "vector_name"});
+  )cpp";
+
+  assertHintsWithHeader(InlayHintKind::Type, TypeAlias, Header,
+ExpectedHint{": Short", "short_name"},
+ExpectedHint{": static_vector", "vector_name"});
 }
 
 TEST(DesignatorHints, Basic) {
Index: clang-tools-extra/clangd/InlayHints.cpp
===
--- clang-tools-extra/clangd/InlayHints.cpp
+++ clang-tools-extra/clangd/InlayHints.cpp
@@ -405,22 +405,47 @@
 // Determines if any intermediate type in desugaring QualType Q

[PATCH] D156300: [clangd] Avoid unexpected desugaring in isSugaredTemplateParameter

2023-08-01 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 546008.
zyounan added a comment.

Final update


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156300/new/

https://reviews.llvm.org/D156300

Files:
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -84,11 +84,13 @@
 }
 
 template 
-void assertHints(InlayHintKind Kind, llvm::StringRef AnnotatedSource,
- ExpectedHints... Expected) {
+void assertHintsWithHeader(InlayHintKind Kind, llvm::StringRef AnnotatedSource,
+   llvm::StringRef HeaderContent,
+   ExpectedHints... Expected) {
   Annotations Source(AnnotatedSource);
   TestTU TU = TestTU::withCode(Source.code());
   TU.ExtraArgs.push_back("-std=c++20");
+  TU.HeaderCode = HeaderContent;
   auto AST = TU.build();
 
   EXPECT_THAT(hintsOfKind(AST, Kind),
@@ -99,6 +101,13 @@
   EXPECT_THAT(inlayHints(AST, std::nullopt), IsEmpty());
 }
 
+template 
+void assertHints(InlayHintKind Kind, llvm::StringRef AnnotatedSource,
+ ExpectedHints... Expected) {
+  return assertHintsWithHeader(Kind, AnnotatedSource, "",
+   std::move(Expected)...);
+}
+
 // Hack to allow expression-statements operating on parameter packs in C++14.
 template  void ignore(T &&...) {}
 
@@ -1433,8 +1442,7 @@
 }
 
 TEST(TypeHints, SubstTemplateParameterAliases) {
-  assertTypeHints(
-  R"cpp(
+  llvm::StringRef Header = R"cpp(
   template  struct allocator {};
 
   template 
@@ -1467,9 +1475,34 @@
 
 T elements[10];
   };
+  )cpp";
 
-  vector array;
+  llvm::StringRef VectorIntPtr = R"cpp(
+vector array;
+auto $no_modifier[[x]] = array[3];
+auto* $ptr_modifier[[ptr]] = &array[3];
+auto& $ref_modifier[[ref]] = array[3];
+auto& $at[[immutable]] = array.at(3);
+
+auto $data[[data]] = array.data();
+auto $allocator[[alloc]] = array.get_allocator();
+auto $size[[size]] = array.size();
+auto $begin[[begin]] = array.begin();
+auto $end[[end]] = array.end();
+  )cpp";
+
+  assertHintsWithHeader(
+  InlayHintKind::Type, VectorIntPtr, Header,
+  ExpectedHint{": int *", "no_modifier"},
+  ExpectedHint{": int **", "ptr_modifier"},
+  ExpectedHint{": int *&", "ref_modifier"},
+  ExpectedHint{": int *const &", "at"}, ExpectedHint{": int **", "data"},
+  ExpectedHint{": allocator", "allocator"},
+  ExpectedHint{": size_type", "size"}, ExpectedHint{": iterator", "begin"},
+  ExpectedHint{": non_template_iterator", "end"});
 
+  llvm::StringRef VectorInt = R"cpp(
+  vector array;
   auto $no_modifier[[by_value]] = array[3];
   auto* $ptr_modifier[[ptr]] = &array[3];
   auto& $ref_modifier[[ref]] = array[3];
@@ -1480,8 +1513,19 @@
   auto $size[[size]] = array.size();
   auto $begin[[begin]] = array.begin();
   auto $end[[end]] = array.end();
+  )cpp";
 
+  assertHintsWithHeader(
+  InlayHintKind::Type, VectorInt, Header,
+  ExpectedHint{": int", "no_modifier"},
+  ExpectedHint{": int *", "ptr_modifier"},
+  ExpectedHint{": int &", "ref_modifier"},
+  ExpectedHint{": const int &", "at"}, ExpectedHint{": int *", "data"},
+  ExpectedHint{": allocator", "allocator"},
+  ExpectedHint{": size_type", "size"}, ExpectedHint{": iterator", "begin"},
+  ExpectedHint{": non_template_iterator", "end"});
 
+  llvm::StringRef TypeAlias = R"cpp(
   // If the type alias is not of substituted template parameter type,
   // do not show desugared type.
   using VeryLongLongTypeName = my_iterator;
@@ -1496,16 +1540,11 @@
   using static_vector = basic_static_vector>;
 
   auto $vector_name[[vec]] = static_vector();
-  )cpp",
-  ExpectedHint{": int", "no_modifier"},
-  ExpectedHint{": int *", "ptr_modifier"},
-  ExpectedHint{": int &", "ref_modifier"},
-  ExpectedHint{": const int &", "at"}, ExpectedHint{": int *", "data"},
-  ExpectedHint{": allocator", "allocator"},
-  ExpectedHint{": size_type", "size"}, ExpectedHint{": iterator", "begin"},
-  ExpectedHint{": non_template_iterator", "end"},
-  ExpectedHint{": Short", "short_name"},
-  ExpectedHint{": static_vector", "vector_name"});
+  )cpp";
+
+  assertHintsWithHeader(InlayHintKind::Type, TypeAlias, Header,
+ExpectedHint{": Short", "short_name"},
+ExpectedHint{": static_vector", "vector_name"});
 }
 
 TEST(DesignatorHints, Basic) {
Index: clang-tools-extra/clangd/InlayHints.cpp
===
--- clang-tools-extra/clangd/InlayHints.cpp
+++ clang-tools-extra/clangd/InlayHints.cpp
@@ -405,22 +405,47 @@
 // Determines if any intermediate type in desugaring

[PATCH] D156300: [clangd] Avoid unexpected desugaring in isSugaredTemplateParameter

2023-08-01 Thread Younan Zhang via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rGb1193c13a5f9: [clangd] Avoid unexpected desugaring in 
isSugaredTemplateParameter (authored by zyounan).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156300/new/

https://reviews.llvm.org/D156300

Files:
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -84,11 +84,13 @@
 }
 
 template 
-void assertHints(InlayHintKind Kind, llvm::StringRef AnnotatedSource,
- ExpectedHints... Expected) {
+void assertHintsWithHeader(InlayHintKind Kind, llvm::StringRef AnnotatedSource,
+   llvm::StringRef HeaderContent,
+   ExpectedHints... Expected) {
   Annotations Source(AnnotatedSource);
   TestTU TU = TestTU::withCode(Source.code());
   TU.ExtraArgs.push_back("-std=c++20");
+  TU.HeaderCode = HeaderContent;
   auto AST = TU.build();
 
   EXPECT_THAT(hintsOfKind(AST, Kind),
@@ -99,6 +101,13 @@
   EXPECT_THAT(inlayHints(AST, std::nullopt), IsEmpty());
 }
 
+template 
+void assertHints(InlayHintKind Kind, llvm::StringRef AnnotatedSource,
+ ExpectedHints... Expected) {
+  return assertHintsWithHeader(Kind, AnnotatedSource, "",
+   std::move(Expected)...);
+}
+
 // Hack to allow expression-statements operating on parameter packs in C++14.
 template  void ignore(T &&...) {}
 
@@ -1433,8 +1442,7 @@
 }
 
 TEST(TypeHints, SubstTemplateParameterAliases) {
-  assertTypeHints(
-  R"cpp(
+  llvm::StringRef Header = R"cpp(
   template  struct allocator {};
 
   template 
@@ -1467,9 +1475,34 @@
 
 T elements[10];
   };
+  )cpp";
 
-  vector array;
+  llvm::StringRef VectorIntPtr = R"cpp(
+vector array;
+auto $no_modifier[[x]] = array[3];
+auto* $ptr_modifier[[ptr]] = &array[3];
+auto& $ref_modifier[[ref]] = array[3];
+auto& $at[[immutable]] = array.at(3);
+
+auto $data[[data]] = array.data();
+auto $allocator[[alloc]] = array.get_allocator();
+auto $size[[size]] = array.size();
+auto $begin[[begin]] = array.begin();
+auto $end[[end]] = array.end();
+  )cpp";
+
+  assertHintsWithHeader(
+  InlayHintKind::Type, VectorIntPtr, Header,
+  ExpectedHint{": int *", "no_modifier"},
+  ExpectedHint{": int **", "ptr_modifier"},
+  ExpectedHint{": int *&", "ref_modifier"},
+  ExpectedHint{": int *const &", "at"}, ExpectedHint{": int **", "data"},
+  ExpectedHint{": allocator", "allocator"},
+  ExpectedHint{": size_type", "size"}, ExpectedHint{": iterator", "begin"},
+  ExpectedHint{": non_template_iterator", "end"});
 
+  llvm::StringRef VectorInt = R"cpp(
+  vector array;
   auto $no_modifier[[by_value]] = array[3];
   auto* $ptr_modifier[[ptr]] = &array[3];
   auto& $ref_modifier[[ref]] = array[3];
@@ -1480,8 +1513,19 @@
   auto $size[[size]] = array.size();
   auto $begin[[begin]] = array.begin();
   auto $end[[end]] = array.end();
+  )cpp";
 
+  assertHintsWithHeader(
+  InlayHintKind::Type, VectorInt, Header,
+  ExpectedHint{": int", "no_modifier"},
+  ExpectedHint{": int *", "ptr_modifier"},
+  ExpectedHint{": int &", "ref_modifier"},
+  ExpectedHint{": const int &", "at"}, ExpectedHint{": int *", "data"},
+  ExpectedHint{": allocator", "allocator"},
+  ExpectedHint{": size_type", "size"}, ExpectedHint{": iterator", "begin"},
+  ExpectedHint{": non_template_iterator", "end"});
 
+  llvm::StringRef TypeAlias = R"cpp(
   // If the type alias is not of substituted template parameter type,
   // do not show desugared type.
   using VeryLongLongTypeName = my_iterator;
@@ -1496,16 +1540,11 @@
   using static_vector = basic_static_vector>;
 
   auto $vector_name[[vec]] = static_vector();
-  )cpp",
-  ExpectedHint{": int", "no_modifier"},
-  ExpectedHint{": int *", "ptr_modifier"},
-  ExpectedHint{": int &", "ref_modifier"},
-  ExpectedHint{": const int &", "at"}, ExpectedHint{": int *", "data"},
-  ExpectedHint{": allocator", "allocator"},
-  ExpectedHint{": size_type", "size"}, ExpectedHint{": iterator", "begin"},
-  ExpectedHint{": non_template_iterator", "end"},
-  ExpectedHint{": Short", "short_name"},
-  ExpectedHint{": static_vector", "vector_name"});
+  )cpp";
+
+  assertHintsWithHeader(InlayHintKind::Type, TypeAlias, Header,
+ExpectedHint{": Short", "short_name"},
+ExpectedHint{": static_vector", "vector_name"});
 }
 
 TEST(DesignatorHints, Basic) {
Index: clang-tools-extra/clangd/InlayHints.cpp
===

[PATCH] D155370: [CodeComplete] Improve FunctionCanBeCall

2023-08-03 Thread Younan Zhang via Phabricator via cfe-commits
zyounan planned changes to this revision.
zyounan added a comment.

In D155370#4552967 , @nridge wrote:

> I was thinking of functions with different names (with a common prefix) and 
> different signatures, where the signature could be a useful piece of 
> information in addition to the name to help you choose the right one.

Ah, that makes sense! Honestly, I've never thought the signature could assist 
such a scenario.

> Note, we have a flag that affects this, `--completion-style=detailed`.

Thanks. Just learned this flag.

Apart from the `Signature`, I still have two improvements for `CanBeCall`. I 
think it's better to close this review and merge these two changes into one 
patch.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D155370/new/

https://reviews.llvm.org/D155370

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D156605: [CodeComplete] Mark 'Derived().Base::foo()' CanBeCall

2023-08-06 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 547566.
zyounan added a comment.

Merge changes with function templates from D155370 



Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156605/new/

https://reviews.llvm.org/D156605

Files:
  clang-tools-extra/clangd/CodeComplete.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.h
  clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
  clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
  clang/lib/Sema/SemaCodeComplete.cpp
  clang/test/CodeCompletion/member-access.cpp
  clang/unittests/Sema/CodeCompleteTest.cpp

Index: clang/unittests/Sema/CodeCompleteTest.cpp
===
--- clang/unittests/Sema/CodeCompleteTest.cpp
+++ clang/unittests/Sema/CodeCompleteTest.cpp
@@ -60,7 +60,10 @@
 for (unsigned I = 0; I < NumResults; ++I) {
   auto R = Results[I];
   if (R.Kind == CodeCompletionResult::RK_Declaration) {
-if (const auto *FD = llvm::dyn_cast(R.getDeclaration())) {
+auto *ND = R.getDeclaration();
+if (auto *Template = llvm::dyn_cast(ND))
+  ND = Template->getTemplatedDecl();
+if (const auto *FD = llvm::dyn_cast(ND)) {
   CompletedFunctionDecl D;
   D.Name = FD->getNameAsString();
   D.CanBeCall = R.FunctionCanBeCall;
@@ -191,6 +194,10 @@
 struct Foo {
   static int staticMethod();
   int method() const;
+  template 
+  void generic(T);
+  template 
+  static T staticGeneric();
   Foo() {
 this->$canBeCall^
 $canBeCall^
@@ -207,15 +214,25 @@
 struct OtherClass {
   OtherClass() {
 Foo f;
+Derived d;
 f.$canBeCall^
+; // Prevent parsing as 'f.f'
+f.Foo::$canBeCall^
 &Foo::$cannotBeCall^
+;
+d.Foo::$canBeCall^
   }
 };
 
 int main() {
   Foo f;
+  Derived d;
   f.$canBeCall^
+  ; // Prevent parsing as 'f.f'
+  f.Foo::$canBeCall^
   &Foo::$cannotBeCall^
+  ;
+  d.Foo::$canBeCall^
 }
 )cpp");
 
@@ -223,12 +240,16 @@
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("method"), isStatic(false),
 canBeCall(true;
+EXPECT_THAT(Results, Contains(AllOf(named("generic"), isStatic(false),
+canBeCall(true;
   }
 
   for (const auto &P : Code.points("cannotBeCall")) {
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("method"), isStatic(false),
 canBeCall(false;
+EXPECT_THAT(Results, Contains(AllOf(named("generic"), isStatic(false),
+canBeCall(false;
   }
 
   // static method can always be a call
@@ -236,6 +257,8 @@
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("staticMethod"), isStatic(true),
 canBeCall(true;
+EXPECT_THAT(Results, Contains(AllOf(named("staticGeneric"), isStatic(true),
+canBeCall(true;
   }
 }
 
Index: clang/test/CodeCompletion/member-access.cpp
===
--- clang/test/CodeCompletion/member-access.cpp
+++ clang/test/CodeCompletion/member-access.cpp
@@ -341,3 +341,14 @@
   // RUN: %clang_cc1 -fsyntax-only -code-completion-with-fixits -code-completion-at=%s:339:10 %s -o - | FileCheck -check-prefix=CHECK-FIELD-DECLARED-VIA-USING %s
   // CHECK-FIELD-DECLARED-VIA-USING: [#int#]field (requires fix-it: {339:8-339:9} to "->")
 }
+
+namespace function_can_be_call {
+  struct S {
+template 
+V foo(T, U);
+  };
+
+  &S::f
+  // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:351:7 %s -o - | FileCheck -check-prefix=CHECK_FUNCTION_CAN_BE_CALL %s
+  // CHECK_FUNCTION_CAN_BE_CALL: COMPLETION: foo : [#V#]foo<<#typename T#>, <#typename U#>{#, <#typename V#>#}>(<#T#>, <#U#>)
+}
Index: clang/lib/Sema/SemaCodeComplete.cpp
===
--- clang/lib/Sema/SemaCodeComplete.cpp
+++ clang/lib/Sema/SemaCodeComplete.cpp
@@ -338,8 +338,11 @@
   ///
   /// \param InBaseClass whether the result was found in a base
   /// class of the searched context.
+  ///
+  /// \param BaseType the type of expression that precedes the "." or "->"
+  /// in a member access expression.
   void AddResult(Result R, DeclContext *CurContext, NamedDecl *Hiding,
- bool InBaseClass);
+ bool InBaseClass, QualType BaseType);
 
   /// Add a new non-declaration result to this result set.
   void AddResult(Result R);
@@ -1262,7 +1265,8 @@
 }
 
 void ResultBuilder::Ad

[PATCH] D155370: [CodeComplete] Improve FunctionCanBeCall

2023-08-06 Thread Younan Zhang via Phabricator via cfe-commits
zyounan abandoned this revision.
zyounan added a comment.

Closing this in favor of D156605 .


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D155370/new/

https://reviews.llvm.org/D155370

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D156605: [clangd][CodeComplete] Improve FunctionCanBeCall

2023-08-06 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 547569.
zyounan added a comment.

Trigger the build


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156605/new/

https://reviews.llvm.org/D156605

Files:
  clang-tools-extra/clangd/CodeComplete.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.h
  clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
  clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
  clang/lib/Sema/SemaCodeComplete.cpp
  clang/test/CodeCompletion/member-access.cpp
  clang/unittests/Sema/CodeCompleteTest.cpp

Index: clang/unittests/Sema/CodeCompleteTest.cpp
===
--- clang/unittests/Sema/CodeCompleteTest.cpp
+++ clang/unittests/Sema/CodeCompleteTest.cpp
@@ -60,7 +60,10 @@
 for (unsigned I = 0; I < NumResults; ++I) {
   auto R = Results[I];
   if (R.Kind == CodeCompletionResult::RK_Declaration) {
-if (const auto *FD = llvm::dyn_cast(R.getDeclaration())) {
+auto *ND = R.getDeclaration();
+if (auto *Template = llvm::dyn_cast(ND))
+  ND = Template->getTemplatedDecl();
+if (const auto *FD = llvm::dyn_cast(ND)) {
   CompletedFunctionDecl D;
   D.Name = FD->getNameAsString();
   D.CanBeCall = R.FunctionCanBeCall;
@@ -191,6 +194,10 @@
 struct Foo {
   static int staticMethod();
   int method() const;
+  template 
+  void generic(T);
+  template 
+  static T staticGeneric();
   Foo() {
 this->$canBeCall^
 $canBeCall^
@@ -207,15 +214,25 @@
 struct OtherClass {
   OtherClass() {
 Foo f;
+Derived d;
 f.$canBeCall^
+; // Prevent parsing as 'f.f'
+f.Foo::$canBeCall^
 &Foo::$cannotBeCall^
+;
+d.Foo::$canBeCall^
   }
 };
 
 int main() {
   Foo f;
+  Derived d;
   f.$canBeCall^
+  ; // Prevent parsing as 'f.f'
+  f.Foo::$canBeCall^
   &Foo::$cannotBeCall^
+  ;
+  d.Foo::$canBeCall^
 }
 )cpp");
 
@@ -223,12 +240,16 @@
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("method"), isStatic(false),
 canBeCall(true;
+EXPECT_THAT(Results, Contains(AllOf(named("generic"), isStatic(false),
+canBeCall(true;
   }
 
   for (const auto &P : Code.points("cannotBeCall")) {
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("method"), isStatic(false),
 canBeCall(false;
+EXPECT_THAT(Results, Contains(AllOf(named("generic"), isStatic(false),
+canBeCall(false;
   }
 
   // static method can always be a call
@@ -236,6 +257,8 @@
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("staticMethod"), isStatic(true),
 canBeCall(true;
+EXPECT_THAT(Results, Contains(AllOf(named("staticGeneric"), isStatic(true),
+canBeCall(true;
   }
 }
 
Index: clang/test/CodeCompletion/member-access.cpp
===
--- clang/test/CodeCompletion/member-access.cpp
+++ clang/test/CodeCompletion/member-access.cpp
@@ -341,3 +341,14 @@
   // RUN: %clang_cc1 -fsyntax-only -code-completion-with-fixits -code-completion-at=%s:339:10 %s -o - | FileCheck -check-prefix=CHECK-FIELD-DECLARED-VIA-USING %s
   // CHECK-FIELD-DECLARED-VIA-USING: [#int#]field (requires fix-it: {339:8-339:9} to "->")
 }
+
+namespace function_can_be_call {
+  struct S {
+template 
+V foo(T, U);
+  };
+
+  &S::f
+  // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:351:7 %s -o - | FileCheck -check-prefix=CHECK_FUNCTION_CAN_BE_CALL %s
+  // CHECK_FUNCTION_CAN_BE_CALL: COMPLETION: foo : [#V#]foo<<#typename T#>, <#typename U#>{#, <#typename V#>#}>(<#T#>, <#U#>)
+}
Index: clang/lib/Sema/SemaCodeComplete.cpp
===
--- clang/lib/Sema/SemaCodeComplete.cpp
+++ clang/lib/Sema/SemaCodeComplete.cpp
@@ -338,8 +338,11 @@
   ///
   /// \param InBaseClass whether the result was found in a base
   /// class of the searched context.
+  ///
+  /// \param BaseType the type of expression that precedes the "." or "->"
+  /// in a member access expression.
   void AddResult(Result R, DeclContext *CurContext, NamedDecl *Hiding,
- bool InBaseClass);
+ bool InBaseClass, QualType BaseType);
 
   /// Add a new non-declaration result to this result set.
   void AddResult(Result R);
@@ -1262,7 +1265,8 @@
 }
 
 void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
- 

[PATCH] D158926: [clangd] Show parameter hints for operator()

2023-09-09 Thread Younan Zhang via Phabricator via cfe-commits
zyounan marked 2 inline comments as done.
zyounan added inline comments.



Comment at: clang-tools-extra/clangd/InlayHints.cpp:626
+  Method && Method->isInstance())
+Args = Args.drop_front(1);
+processCall(Callee, Args);

nridge wrote:
> Huh, that's an interesting inconsistency between CXXMemberCallExpr and 
> CXXOperatorCallExpr (that one include th implied object argument in getArgs() 
> and the other doesn't)
> 
> As always, thank you for writing thorough tests that give us confidence we're 
> doing the right thing :)
I'm glad to hear that! Thank you.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158926/new/

https://reviews.llvm.org/D158926

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158926: [clangd] Show parameter hints for operator()

2023-09-09 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 556358.
zyounan marked an inline comment as done.
zyounan added a comment.

Address a nit comment


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158926/new/

https://reviews.llvm.org/D158926

Files:
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -89,7 +89,7 @@
ExpectedHints... Expected) {
   Annotations Source(AnnotatedSource);
   TestTU TU = TestTU::withCode(Source.code());
-  TU.ExtraArgs.push_back("-std=c++20");
+  TU.ExtraArgs.push_back("-std=c++23");
   TU.HeaderCode = HeaderContent;
   auto AST = TU.build();
 
@@ -807,6 +807,42 @@
   )cpp");
 }
 
+TEST(ParameterHints, FunctionCallOperator) {
+  assertParameterHints(R"cpp(
+struct W {
+  void operator()(int x);
+};
+struct S : W {
+  using W::operator();
+  static void operator()(int x, int y);
+};
+void bar() {
+  auto l1 = [](int x) {};
+  auto l2 = [](int x) static {};
+
+  S s;
+  s($1[[1]]);
+  s.operator()($2[[1]]);
+  s.operator()($3[[1]], $4[[2]]);
+  S::operator()($5[[1]], $6[[2]]);
+
+  l1($7[[1]]);
+  l1.operator()($8[[1]]);
+  l2($9[[1]]);
+  l2.operator()($10[[1]]);
+
+  void (*ptr)(int a, int b) = &S::operator();
+  ptr($11[[1]], $12[[2]]);
+}
+  )cpp",
+   ExpectedHint{"x: ", "1"}, ExpectedHint{"x: ", "2"},
+   ExpectedHint{"x: ", "3"}, ExpectedHint{"y: ", "4"},
+   ExpectedHint{"x: ", "5"}, ExpectedHint{"y: ", "6"},
+   ExpectedHint{"x: ", "7"}, ExpectedHint{"x: ", "8"},
+   ExpectedHint{"x: ", "9"}, ExpectedHint{"x: ", "10"},
+   ExpectedHint{"a: ", "11"}, ExpectedHint{"b: ", "12"});
+}
+
 TEST(ParameterHints, Macros) {
   // Handling of macros depends on where the call's argument list comes from.
 
Index: clang-tools-extra/clangd/InlayHints.cpp
===
--- clang-tools-extra/clangd/InlayHints.cpp
+++ clang-tools-extra/clangd/InlayHints.cpp
@@ -586,11 +586,13 @@
 if (!Cfg.InlayHints.Parameters)
   return true;
 
-// Do not show parameter hints for operator calls written using operator
-// syntax or user-defined literals. (Among other reasons, the resulting
+bool IsFunctor = isFunctionObjectCallExpr(E);
+// Do not show parameter hints for user-defined literals or
+// operator calls except for operator(). (Among other reasons, the resulting
 // hints can look awkward, e.g. the expression can itself be a function
 // argument and then we'd get two hints side by side).
-if (isa(E) || isa(E))
+if ((isa(E) && !IsFunctor) ||
+isa(E))
   return true;
 
 auto CalleeDecls = Resolver->resolveCalleeOfCallExpr(E);
@@ -607,7 +609,22 @@
 else
   return true;
 
-processCall(Callee, {E->getArgs(), E->getNumArgs()});
+// N4868 [over.call.object]p3 says,
+// The argument list submitted to overload resolution consists of the
+// argument expressions present in the function call syntax preceded by the
+// implied object argument (E).
+//
+// However, we don't have the implied object argument for static
+// operator() per clang::Sema::BuildCallToObjectOfClassType.
+llvm::ArrayRef Args = {E->getArgs(), E->getNumArgs()};
+if (IsFunctor)
+  // We don't have the implied object argument through
+  // a function pointer either.
+  if (const CXXMethodDecl *Method =
+  dyn_cast_or_null(Callee.Decl);
+  Method && Method->isInstance())
+Args = Args.drop_front(1);
+processCall(Callee, Args);
 return true;
   }
 
@@ -1203,6 +1220,12 @@
 return Range{HintStart, HintEnd};
   }
 
+  static bool isFunctionObjectCallExpr(CallExpr *E) noexcept {
+if (auto *CallExpr = dyn_cast(E))
+  return CallExpr->getOperator() == OverloadedOperatorKind::OO_Call;
+return false;
+  }
+
   std::vector &Results;
   ASTContext &AST;
   const syntax::TokenBuffer &Tokens;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D156605: [clangd][CodeComplete] Improve FunctionCanBeCall

2023-09-09 Thread Younan Zhang via Phabricator via cfe-commits
zyounan added inline comments.



Comment at: clang/lib/Sema/SemaCodeComplete.cpp:3577
   // containing all of the arguments up to the first deducible argument.
+  // Or, if this isn't a call, emit all the template arguments
+  // to disambiguate the (potential) overloads.

nridge wrote:
> zyounan wrote:
> > nridge wrote:
> > > 1. If this is not a call, we can avoid running the 
> > > `Sema::MarkDeducedTemplateParameters` operation altogether.
> > > 
> > > 2. A future improvement we could consider: if this is not a call, try to 
> > > detect cases where the template parameters can be deduced from the 
> > > surrounding context (["Deducing template arguments taking the address of 
> > > a function template "](https://eel.is/c++draft/temp.deduct.funcaddr)). 
> > > Maybe add a FIXME for this?
> > > avoid running the Sema::MarkDeducedTemplateParameters operation altogether
> > 
> > I think doing so could cause too many adjustments to the flow, and I'm 
> > afraid that the `Sema::MarkDeducedTemplateParameters` would be required 
> > again when we decide to implement point 2.
> > 
> > I'm adding a FIXME anyway but leave the first intact. However, I'd be happy 
> > to rearrange the logic flow if you insist.
> I realized there's actually an open question here: if `FunctionCanBeCall == 
> false`, do we want to include **all** the template parameters, or just the 
> non-deducible ones?
> 
> Let's consider an example:
> 
> ```
> class Foo {
>   template 
>   T convertTo(U from);
> };
> 
> void bar() {
>   Foo::^
> }
> ```
> 
> Here, `U` can be deduced but `T` cannot.
> 
> The current behaviour is to complete `convertTo`. That seems appropriate 
> for a **call**, since `U` will be deduced from the call. But since this is 
> not a call, wouldn't it be  better to complete `convertTo`?
> But since this is not a call, wouldn't it be better to complete convertTo U>?

(Ugh, this is exactly this patch's initial intention, but how...?)

Oh, I made a mistake here: I presumed `LastDeducibleArgument` would always be 0 
if we're in a non-callable context, but this is wrong! This variable is 
calculated based on the function parameters, which ought to be equal to the 
number of template parameters deducible in function parameters.

( I used to duplicate this `if` block for the `!FunctionCanBeCall` case but 
finally, I merged these two erroneously. :-( )


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156605/new/

https://reviews.llvm.org/D156605

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158926: [clangd] Show parameter hints for operator()

2023-09-10 Thread Younan Zhang via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGcbd6ac6165e6: [clangd] Show parameter hints for operator() 
(authored by zyounan).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158926/new/

https://reviews.llvm.org/D158926

Files:
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -89,7 +89,7 @@
ExpectedHints... Expected) {
   Annotations Source(AnnotatedSource);
   TestTU TU = TestTU::withCode(Source.code());
-  TU.ExtraArgs.push_back("-std=c++20");
+  TU.ExtraArgs.push_back("-std=c++23");
   TU.HeaderCode = HeaderContent;
   auto AST = TU.build();
 
@@ -807,6 +807,42 @@
   )cpp");
 }
 
+TEST(ParameterHints, FunctionCallOperator) {
+  assertParameterHints(R"cpp(
+struct W {
+  void operator()(int x);
+};
+struct S : W {
+  using W::operator();
+  static void operator()(int x, int y);
+};
+void bar() {
+  auto l1 = [](int x) {};
+  auto l2 = [](int x) static {};
+
+  S s;
+  s($1[[1]]);
+  s.operator()($2[[1]]);
+  s.operator()($3[[1]], $4[[2]]);
+  S::operator()($5[[1]], $6[[2]]);
+
+  l1($7[[1]]);
+  l1.operator()($8[[1]]);
+  l2($9[[1]]);
+  l2.operator()($10[[1]]);
+
+  void (*ptr)(int a, int b) = &S::operator();
+  ptr($11[[1]], $12[[2]]);
+}
+  )cpp",
+   ExpectedHint{"x: ", "1"}, ExpectedHint{"x: ", "2"},
+   ExpectedHint{"x: ", "3"}, ExpectedHint{"y: ", "4"},
+   ExpectedHint{"x: ", "5"}, ExpectedHint{"y: ", "6"},
+   ExpectedHint{"x: ", "7"}, ExpectedHint{"x: ", "8"},
+   ExpectedHint{"x: ", "9"}, ExpectedHint{"x: ", "10"},
+   ExpectedHint{"a: ", "11"}, ExpectedHint{"b: ", "12"});
+}
+
 TEST(ParameterHints, Macros) {
   // Handling of macros depends on where the call's argument list comes from.
 
Index: clang-tools-extra/clangd/InlayHints.cpp
===
--- clang-tools-extra/clangd/InlayHints.cpp
+++ clang-tools-extra/clangd/InlayHints.cpp
@@ -586,11 +586,13 @@
 if (!Cfg.InlayHints.Parameters)
   return true;
 
-// Do not show parameter hints for operator calls written using operator
-// syntax or user-defined literals. (Among other reasons, the resulting
+bool IsFunctor = isFunctionObjectCallExpr(E);
+// Do not show parameter hints for user-defined literals or
+// operator calls except for operator(). (Among other reasons, the resulting
 // hints can look awkward, e.g. the expression can itself be a function
 // argument and then we'd get two hints side by side).
-if (isa(E) || isa(E))
+if ((isa(E) && !IsFunctor) ||
+isa(E))
   return true;
 
 auto CalleeDecls = Resolver->resolveCalleeOfCallExpr(E);
@@ -607,7 +609,22 @@
 else
   return true;
 
-processCall(Callee, {E->getArgs(), E->getNumArgs()});
+// N4868 [over.call.object]p3 says,
+// The argument list submitted to overload resolution consists of the
+// argument expressions present in the function call syntax preceded by the
+// implied object argument (E).
+//
+// However, we don't have the implied object argument for static
+// operator() per clang::Sema::BuildCallToObjectOfClassType.
+llvm::ArrayRef Args = {E->getArgs(), E->getNumArgs()};
+if (IsFunctor)
+  // We don't have the implied object argument through
+  // a function pointer either.
+  if (const CXXMethodDecl *Method =
+  dyn_cast_or_null(Callee.Decl);
+  Method && Method->isInstance())
+Args = Args.drop_front(1);
+processCall(Callee, Args);
 return true;
   }
 
@@ -1203,6 +1220,12 @@
 return Range{HintStart, HintEnd};
   }
 
+  static bool isFunctionObjectCallExpr(CallExpr *E) noexcept {
+if (auto *CallExpr = dyn_cast(E))
+  return CallExpr->getOperator() == OverloadedOperatorKind::OO_Call;
+return false;
+  }
+
   std::vector &Results;
   ASTContext &AST;
   const syntax::TokenBuffer &Tokens;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D156605: [clangd][CodeComplete] Improve FunctionCanBeCall

2023-09-17 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 556909.
zyounan marked 2 inline comments as done.
zyounan added a comment.

Address comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156605/new/

https://reviews.llvm.org/D156605

Files:
  clang-tools-extra/clangd/CodeComplete.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.h
  clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
  clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
  clang/lib/Sema/SemaCodeComplete.cpp
  clang/test/CodeCompletion/member-access.cpp
  clang/unittests/Sema/CodeCompleteTest.cpp

Index: clang/unittests/Sema/CodeCompleteTest.cpp
===
--- clang/unittests/Sema/CodeCompleteTest.cpp
+++ clang/unittests/Sema/CodeCompleteTest.cpp
@@ -60,7 +60,10 @@
 for (unsigned I = 0; I < NumResults; ++I) {
   auto R = Results[I];
   if (R.Kind == CodeCompletionResult::RK_Declaration) {
-if (const auto *FD = llvm::dyn_cast(R.getDeclaration())) {
+auto *ND = R.getDeclaration();
+if (auto *Template = llvm::dyn_cast(ND))
+  ND = Template->getTemplatedDecl();
+if (const auto *FD = llvm::dyn_cast(ND)) {
   CompletedFunctionDecl D;
   D.Name = FD->getNameAsString();
   D.CanBeCall = R.FunctionCanBeCall;
@@ -191,6 +194,10 @@
 struct Foo {
   static int staticMethod();
   int method() const;
+  template 
+  T generic(U, V);
+  template 
+  static T staticGeneric();
   Foo() {
 this->$canBeCall^
 $canBeCall^
@@ -199,6 +206,8 @@
 };
 
 struct Derived : Foo {
+  using Foo::method;
+  using Foo::generic;
   Derived() {
 Foo::$canBeCall^
   }
@@ -207,15 +216,29 @@
 struct OtherClass {
   OtherClass() {
 Foo f;
+Derived d;
 f.$canBeCall^
+; // Prevent parsing as 'f.f'
+f.Foo::$canBeCall^
 &Foo::$cannotBeCall^
+;
+d.Foo::$canBeCall^
+;
+d.Derived::$canBeCall^
   }
 };
 
 int main() {
   Foo f;
+  Derived d;
   f.$canBeCall^
+  ; // Prevent parsing as 'f.f'
+  f.Foo::$canBeCall^
   &Foo::$cannotBeCall^
+  ;
+  d.Foo::$canBeCall^
+  ;
+  d.Derived::$canBeCall^
 }
 )cpp");
 
@@ -223,12 +246,16 @@
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("method"), isStatic(false),
 canBeCall(true;
+EXPECT_THAT(Results, Contains(AllOf(named("generic"), isStatic(false),
+canBeCall(true;
   }
 
   for (const auto &P : Code.points("cannotBeCall")) {
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("method"), isStatic(false),
 canBeCall(false;
+EXPECT_THAT(Results, Contains(AllOf(named("generic"), isStatic(false),
+canBeCall(false;
   }
 
   // static method can always be a call
@@ -236,6 +263,8 @@
 auto Results = CollectCompletedFunctions(Code.code(), P);
 EXPECT_THAT(Results, Contains(AllOf(named("staticMethod"), isStatic(true),
 canBeCall(true;
+EXPECT_THAT(Results, Contains(AllOf(named("staticGeneric"), isStatic(true),
+canBeCall(true;
   }
 }
 
Index: clang/test/CodeCompletion/member-access.cpp
===
--- clang/test/CodeCompletion/member-access.cpp
+++ clang/test/CodeCompletion/member-access.cpp
@@ -341,3 +341,14 @@
   // RUN: %clang_cc1 -fsyntax-only -code-completion-with-fixits -code-completion-at=%s:339:10 %s -o - | FileCheck -check-prefix=CHECK-FIELD-DECLARED-VIA-USING %s
   // CHECK-FIELD-DECLARED-VIA-USING: [#int#]field (requires fix-it: {339:8-339:9} to "->")
 }
+
+namespace function_can_be_call {
+  struct S {
+template 
+T foo(U, V);
+  };
+
+  &S::f
+  // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:351:7 %s -o - | FileCheck -check-prefix=CHECK_FUNCTION_CAN_BE_CALL %s
+  // CHECK_FUNCTION_CAN_BE_CALL: COMPLETION: foo : [#T#]foo<<#typename T#>, <#typename U#>{#, <#typename V#>#}>(<#U#>, <#V#>)
+}
Index: clang/lib/Sema/SemaCodeComplete.cpp
===
--- clang/lib/Sema/SemaCodeComplete.cpp
+++ clang/lib/Sema/SemaCodeComplete.cpp
@@ -310,6 +310,23 @@
   bool isInterestingDecl(const NamedDecl *ND,
  bool &AsNestedNameSpecifier) const;
 
+  /// Decide whether or not a use of function Decl can be a call.
+  ///
+  /// \param ND the function declaration.
+  ///
+  /// \param BaseExprType the object type in a member access expression,
+  /// if

[PATCH] D156605: [clangd][CodeComplete] Improve FunctionCanBeCall

2023-09-17 Thread Younan Zhang via Phabricator via cfe-commits
zyounan added a comment.

Thank you Nathan for your constructive opinions! I've updated this patch again, 
hopefully this becomes better.




Comment at: clang/lib/Sema/SemaCodeComplete.cpp:1387
 
-  // When completing a non-static member function (and not via
-  // dot/arrow member access) and we're not inside that class' scope,
-  // it can't be a call.
+  // Decide whether or not a non-static member function can be a call.
   if (CompletionContext.getKind() == clang::CodeCompletionContext::CCC_Symbol) 
{

nridge wrote:
> zyounan wrote:
> > sammccall wrote:
> > > This is confusing: the `CCC_Symbol` test is part of the specific 
> > > heuristics being used (it's the "not via dot/arrow member access" part, 
> > > right?) but you've moved the comment explaining what it does.
> > > 
> > > Also this function is just getting too long, and we're inlining more 
> > > complicated control flow here.
> > > Can we extract a function?
> > > 
> > > ```
> > > const auto *Method = ...;
> > > if (Method & !Method->isStatic()) {
> > >   R.FunctionCanBeCall = canMethodBeCalled(...);
> > > }
> > > ```
> > > it's the "not via dot/arrow member access" part
> > 
> > (Sorry for being unaware of the historical context). But I think 
> > `CCC_Symbol` should mean "we're completing a name such as a function or 
> > type name" per its comment. The heuristic for dot/arrow member access 
> > actually lies on the next line, i.e., if the completing decl is a 
> > CXXMethodDecl.
> > 
> > > Can we extract a function?
> > 
> > Sure. 
> The check for `CompletionContext.getKind()` is in fact a part of the 
> heuristic:
> 
>  * for `f.method`, the kind is `CCC_DotMemberAccess`
>  * for `f->method`, the kind is `CCC_ArrowMemberAccess`
>  * for `f.Foo::method` and `f->Foo::method`, the kind is `CCC_Symbol`
> 
> (I realize that's a bit inconsistent. Maybe the `f.Foo::` and `f->Foo::` 
> cases should be using `DotMemberAccess` and `ArrowMemberAccess` as well? 
> Anyways, that's a pre-existing issue.)
> 
> So, the `if (CompletionContext.getKind() == 
> clang::CodeCompletionContext::CCC_Symbol)` check is what currently makes sure 
> that in the `f.method` and `f->method` cases, we just keep `FunctionCanBeCall 
> = true` without having to check any context or expression type.
> 
> I think it may be clearest to move this entire `if` block into the new 
> function (whose name can be generalized to `canBeCall` or similar), and here 
> just unconditionally set `R.FunctionCanBeCall = canBeCall(CompletionContext, 
> /* other things */)`.
> I think it may be clearest to move this entire if block into the new function

Nice suggestion. I'll take it.



Comment at: clang/lib/Sema/SemaCodeComplete.cpp:3577
   // containing all of the arguments up to the first deducible argument.
+  // Or, if this isn't a call, emit all the template arguments
+  // to disambiguate the (potential) overloads.

zyounan wrote:
> nridge wrote:
> > zyounan wrote:
> > > nridge wrote:
> > > > 1. If this is not a call, we can avoid running the 
> > > > `Sema::MarkDeducedTemplateParameters` operation altogether.
> > > > 
> > > > 2. A future improvement we could consider: if this is not a call, try 
> > > > to detect cases where the template parameters can be deduced from the 
> > > > surrounding context (["Deducing template arguments taking the address 
> > > > of a function template 
> > > > "](https://eel.is/c++draft/temp.deduct.funcaddr)). Maybe add a FIXME 
> > > > for this?
> > > > avoid running the Sema::MarkDeducedTemplateParameters operation 
> > > > altogether
> > > 
> > > I think doing so could cause too many adjustments to the flow, and I'm 
> > > afraid that the `Sema::MarkDeducedTemplateParameters` would be required 
> > > again when we decide to implement point 2.
> > > 
> > > I'm adding a FIXME anyway but leave the first intact. However, I'd be 
> > > happy to rearrange the logic flow if you insist.
> > I realized there's actually an open question here: if `FunctionCanBeCall == 
> > false`, do we want to include **all** the template parameters, or just the 
> > non-deducible ones?
> > 
> > Let's consider an example:
> > 
> > ```
> > class Foo {
> >   template 
> >   T convertTo(U from);
> > };
> > 
> > void bar() {
> >   Foo::^
> > }
> > ```
> > 
> > Here, `U` can be deduced but `T` cannot.
> > 
> > The current behaviour is to complete `convertTo`. That seems appropriate 
> > for a **call**, since `U` will be deduced from the call. But since this is 
> > not a call, wouldn't it be  better to complete `convertTo`?
> > But since this is not a call, wouldn't it be better to complete 
> > convertTo?
> 
> (Ugh, this is exactly this patch's initial intention, but how...?)
> 
> Oh, I made a mistake here: I presumed `LastDeducibleArgument` would always be 
> 0 if we're in a non-callable context, but this is wrong! This variable is 
> calculated based on the function parameters, which ought to be equal

[PATCH] D155370: [CodeComplete] Don't emit parameters when not FunctionCanBeCall

2023-07-15 Thread Younan Zhang via Phabricator via cfe-commits
zyounan created this revision.
zyounan added reviewers: nridge, tom-anders, sammccall.
Herald added subscribers: kadircet, arphaman.
Herald added a project: All.
zyounan added a comment.
zyounan updated this revision to Diff 540687.
zyounan published this revision for review.
Herald added projects: clang, clang-tools-extra.
Herald added a subscriber: cfe-commits.

Changing the code completion string to `RK_Pattern` makes the completion 
clearer, in a way that showing candidates with signatures in the completion 
items if `FunctionCanBeCall` while a mere name otherwise.

F28256820: image.png 

F28256841: image.png 

(Comparing to that we always show signatures even if no parameters are produced 
when hit the item.)

F28256859: image.png  -> F28256863: 
image.png 

---

P.S. Despite the fact that I changed many associated tests, I still hope people 
don't rely on the former behavior so that this patch could be marked as NFC. :D

I discovered that patch when trying to figure out why clangd doesn't complete 
function parameters for members in global scope while it produces parameters 
when I'm inside a call expression. Regard to the heuristic itself, it's 
currently a bit inconvenient that I have to switch headers and sources back and 
forth and do copy-pastes when I'm writing member function definitions outside 
of a class. I think we could be more lenient here e.g., don't set the flag on 
if we're in the global scope. What do you guys think? (I'm working on another 
follow-up patch to address this, although it is not strightforward to tell 
which scope the building Declarator is in inside Sema. )


zyounan added a comment.

Format


This tries to avoid extra calculations in D137040 
.

In that patch the extra completion strings were dropped at the client
site, after function parameters became available, to implement the
heuristic. However, we can make the process a bit more terse. In the
context where a call isn't required, we could teach the Sema to emit
the completion string without additional parameters by changing the Decl
to a Pattern with the function name.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D155370

Files:
  clang-tools-extra/clangd/CodeComplete.cpp
  clang/lib/Sema/SemaCodeComplete.cpp
  clang/test/CodeCompletion/member-access.cpp
  clang/test/Index/complete-qualified.cpp
  clang/unittests/Sema/CodeCompleteTest.cpp

Index: clang/unittests/Sema/CodeCompleteTest.cpp
===
--- clang/unittests/Sema/CodeCompleteTest.cpp
+++ clang/unittests/Sema/CodeCompleteTest.cpp
@@ -59,14 +59,12 @@
   unsigned NumResults) override {
 for (unsigned I = 0; I < NumResults; ++I) {
   auto R = Results[I];
-  if (R.Kind == CodeCompletionResult::RK_Declaration) {
-if (const auto *FD = llvm::dyn_cast(R.getDeclaration())) {
-  CompletedFunctionDecl D;
-  D.Name = FD->getNameAsString();
-  D.CanBeCall = R.FunctionCanBeCall;
-  D.IsStatic = FD->isStatic();
-  CompletedFuncDecls.emplace_back(std::move(D));
-}
+  if (const auto *FD = llvm::dyn_cast(R.getDeclaration())) {
+CompletedFunctionDecl D;
+D.Name = FD->getNameAsString();
+D.CanBeCall = R.FunctionCanBeCall;
+D.IsStatic = FD->isStatic();
+CompletedFuncDecls.emplace_back(std::move(D));
   }
 }
   }
Index: clang/test/Index/complete-qualified.cpp
===
--- clang/test/Index/complete-qualified.cpp
+++ clang/test/Index/complete-qualified.cpp
@@ -16,5 +16,6 @@
 // RUN: c-index-test -code-completion-at=%s:14:8 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
 // CHECK-CC1: FieldDecl:{ResultType C}{TypedText c} (35)
 // CHECK-CC1: ClassDecl:{TypedText Foo} (35)
-// CHECK-CC1: CXXMethod:{ResultType Foo &}{TypedText operator=}{LeftParen (}{Placeholder const Foo &}{RightParen )}
-// CHECK-CC1: CXXDestructor:{ResultType void}{TypedText ~Foo}{LeftParen (}{RightParen )} (80)
+// CHECK-CC1: CXXMethod:{TypedText operator=} (50)
+// CHECK-CC1: CXXMethod:{TypedText operator=} (50)
+// CHECK-CC1: CXXMethod:{TypedText ~Foo} (50)
Index: clang/test/CodeCompletion/member-access.cpp
===
--- clang/test/CodeCompletion/member-access.cpp
+++ clang/test/CodeCompletion/member-access.cpp
@@ -171,7 +171,7 @@
 template
 void dependentColonColonCompletion() {
   Template::staticFn();
-// CHECK-CC7: function : [#void#]function()
+// CHECK-CC7: Pattern : function
 // CHECK-CC7: Nested : Nested
 // CHECK-CC7: o1 : [#BaseTemplate#]o1
 // CHECK-CC7: o2 : [#BaseTemplate#]o2
Index: clang/lib/Sema/SemaCodeComplete.cpp

[PATCH] D158926: [clangd] Show parameter hints for operator()

2023-08-26 Thread Younan Zhang via Phabricator via cfe-commits
zyounan created this revision.
zyounan added a reviewer: nridge.
Herald added subscribers: kadircet, arphaman.
Herald added a project: All.
zyounan requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.
Herald added a project: clang-tools-extra.

Closes https://github.com/clangd/clangd/issues/1742


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D158926

Files:
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -89,7 +89,7 @@
ExpectedHints... Expected) {
   Annotations Source(AnnotatedSource);
   TestTU TU = TestTU::withCode(Source.code());
-  TU.ExtraArgs.push_back("-std=c++20");
+  TU.ExtraArgs.push_back("-std=c++23");
   TU.HeaderCode = HeaderContent;
   auto AST = TU.build();
 
@@ -807,6 +807,42 @@
   )cpp");
 }
 
+TEST(ParameterHints, FunctionCallOperator) {
+  assertParameterHints(R"cpp(
+struct W {
+  void operator()(int x);
+};
+struct S : W {
+  using W::operator();
+  static void operator()(int x, int y);
+};
+void bar() {
+  auto l1 = [](int x) {};
+  auto l2 = [](int x) static {};
+
+  S s;
+  s($1[[1]]);
+  s.operator()($2[[1]]);
+  s.operator()($3[[1]], $4[[2]]);
+  S::operator()($5[[1]], $6[[2]]);
+
+  l1($7[[1]]);
+  l1.operator()($8[[1]]);
+  l2($9[[1]]);
+  l2.operator()($10[[1]]);
+
+  void (*ptr)(int a, int b) = &S::operator();
+  ptr($11[[1]], $12[[2]]);
+}
+  )cpp",
+   ExpectedHint{"x: ", "1"}, ExpectedHint{"x: ", "2"},
+   ExpectedHint{"x: ", "3"}, ExpectedHint{"y: ", "4"},
+   ExpectedHint{"x: ", "5"}, ExpectedHint{"y: ", "6"},
+   ExpectedHint{"x: ", "7"}, ExpectedHint{"x: ", "8"},
+   ExpectedHint{"x: ", "9"}, ExpectedHint{"x: ", "10"},
+   ExpectedHint{"a: ", "11"}, ExpectedHint{"b: ", "12"});
+}
+
 TEST(ParameterHints, Macros) {
   // Handling of macros depends on where the call's argument list comes from.
 
Index: clang-tools-extra/clangd/InlayHints.cpp
===
--- clang-tools-extra/clangd/InlayHints.cpp
+++ clang-tools-extra/clangd/InlayHints.cpp
@@ -586,11 +586,13 @@
 if (!Cfg.InlayHints.Parameters)
   return true;
 
-// Do not show parameter hints for operator calls written using operator
-// syntax or user-defined literals. (Among other reasons, the resulting
+bool IsFunctor = isFunctionObjectCallExpr(E);
+// Do not show parameter hints for user-defined literals or
+// operator calls except for operator(). (Among other reasons, the resulting
 // hints can look awkward, e.g. the expression can itself be a function
 // argument and then we'd get two hints side by side).
-if (isa(E) || isa(E))
+if ((isa(E) && !IsFunctor) ||
+isa(E))
   return true;
 
 auto CalleeDecls = Resolver->resolveCalleeOfCallExpr(E);
@@ -607,7 +609,22 @@
 else
   return true;
 
-processCall(Callee, {E->getArgs(), E->getNumArgs()});
+// N4868 [over.call.object]p3 says,
+// The argument list submitted to overload resolution consists of the
+// argument expressions present in the function call syntax preceded by the
+// implied object argument (E).
+//
+// However, we don't have the implied object argument for static
+// operator() per clang::Sema::BuildCallToObjectOfClassType.
+llvm::ArrayRef Args = {E->getArgs(), E->getNumArgs()};
+if (IsFunctor)
+  // We don't have the implied object argument through
+  // a function pointer either.
+  if (const CXXMethodDecl *Method =
+  dyn_cast_or_null(Callee.Decl);
+  Method && Method->isInstance())
+Args = Args.drop_front(1);
+processCall(Callee, Args);
 return true;
   }
 
@@ -1202,6 +1219,12 @@
 return Range{HintStart, HintEnd};
   }
 
+  bool isFunctionObjectCallExpr(CallExpr *E) const noexcept {
+if (auto *CallExpr = dyn_cast(E))
+  return CallExpr->getOperator() == OverloadedOperatorKind::OO_Call;
+return false;
+  }
+
   std::vector &Results;
   ASTContext &AST;
   const syntax::TokenBuffer &Tokens;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D156605: [clangd][CodeComplete] Improve FunctionCanBeCall

2023-08-26 Thread Younan Zhang via Phabricator via cfe-commits
zyounan added a comment.

Gently ping~


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156605/new/

https://reviews.llvm.org/D156605

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158061: [clang] Construct ExprRequirement with SubstitutionDiagnostic on SubstFailure

2023-08-26 Thread Younan Zhang via Phabricator via cfe-commits
zyounan added a comment.

Gently ping~


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158061/new/

https://reviews.llvm.org/D158061

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158967: [clangd] Record the stack bottom before building AST

2023-08-28 Thread Younan Zhang via Phabricator via cfe-commits
zyounan created this revision.
zyounan added reviewers: sammccall, nridge.
Herald added subscribers: kadircet, arphaman.
Herald added a project: All.
zyounan requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.
Herald added a project: clang-tools-extra.

`clang::runWithSufficientStackSpace` requires the address of the
initial stack bottom to prevent potential stack overflows.

Fixes https://github.com/clangd/clangd/issues/1745.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D158967

Files:
  clang-tools-extra/clangd/ParsedAST.cpp
  clang-tools-extra/clangd/test/infinite-instantiation.test


Index: clang-tools-extra/clangd/test/infinite-instantiation.test
===
--- /dev/null
+++ clang-tools-extra/clangd/test/infinite-instantiation.test
@@ -0,0 +1,13 @@
+// RUN: cp %s %t.cpp
+// RUN: not clangd -check=%t.cpp 2>&1 | FileCheck -strict-whitespace %s
+
+// CHECK: [template_recursion_depth_exceeded]
+
+template 
+constexpr int f(T... args) {
+  return f(0, args...);
+}
+
+int main() {
+  auto i = f();
+}
Index: clang-tools-extra/clangd/ParsedAST.cpp
===
--- clang-tools-extra/clangd/ParsedAST.cpp
+++ clang-tools-extra/clangd/ParsedAST.cpp
@@ -44,6 +44,7 @@
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Stack.h"
 #include "clang/Basic/TokenKinds.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/CompilerInvocation.h"
@@ -388,6 +389,7 @@
  std::unique_ptr CI,
  llvm::ArrayRef CompilerInvocationDiags,
  std::shared_ptr Preamble) {
+  clang::noteBottomOfStack();
   trace::Span Tracer("BuildAST");
   SPAN_ATTACH(Tracer, "File", Filename);
 


Index: clang-tools-extra/clangd/test/infinite-instantiation.test
===
--- /dev/null
+++ clang-tools-extra/clangd/test/infinite-instantiation.test
@@ -0,0 +1,13 @@
+// RUN: cp %s %t.cpp
+// RUN: not clangd -check=%t.cpp 2>&1 | FileCheck -strict-whitespace %s
+
+// CHECK: [template_recursion_depth_exceeded]
+
+template 
+constexpr int f(T... args) {
+  return f(0, args...);
+}
+
+int main() {
+  auto i = f();
+}
Index: clang-tools-extra/clangd/ParsedAST.cpp
===
--- clang-tools-extra/clangd/ParsedAST.cpp
+++ clang-tools-extra/clangd/ParsedAST.cpp
@@ -44,6 +44,7 @@
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Stack.h"
 #include "clang/Basic/TokenKinds.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/CompilerInvocation.h"
@@ -388,6 +389,7 @@
  std::unique_ptr CI,
  llvm::ArrayRef CompilerInvocationDiags,
  std::shared_ptr Preamble) {
+  clang::noteBottomOfStack();
   trace::Span Tracer("BuildAST");
   SPAN_ATTACH(Tracer, "File", Filename);
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158967: [clangd] Record the stack bottom before building AST

2023-08-28 Thread Younan Zhang via Phabricator via cfe-commits
zyounan added a comment.

> `clang::ParseAST` or `ASTFrontendAction::ExecuteAction` look like good 
> candidates to me.

We had already placed the initialization in ASTFrontendAction::ExecuteAction 
,
 but we don't have such if we prefer invoking the action outside the libclang. 
(Just as what we're doing now at the clangd site.)

I'm not 100% sure if `clang::ParseAST` is appropriate since this might cause a 
side effect to the global state. Would this break the encapsulation hierarchy?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158967/new/

https://reviews.llvm.org/D158967

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158967: [clangd] Record the stack bottom before building AST

2023-08-28 Thread Younan Zhang via Phabricator via cfe-commits
zyounan added a subscriber: rsmith.
zyounan added a comment.

Thanks for the reply. And I understand (and agree with) the point that it's 
better to solve this problem once and for all.

> Currently the code in CompilerInstance::ExecuteAction seems to acknowledge 
> that there should be a fallback. I'm suggesting to move this fallback down to 
> a function that actually runs parsing.

One thing I'm afraid of is, that there are/were some compatible reasons that 
made us decide not to insert this call at `ASTFrontendAction::ExecuteAction` 
nor `clang::ParseAST`. (I didn't see the explanation in D66361 
. Richard, could you kindly explain why? 
@rsmith)

> That's `CompilerInstance::ExecuteAction`

Sorry for my mistake. I thought placing that in `CompilerInstance` was enough 
for most tools since it's less likely for developers to invoke the 
FrontendAction on their own, and for "advanced" users (like clangd) who'd like 
to control every step handling the AST, maybe it's fine to give them the 
opportunity to decide if it should crash on infinite recursion?

However, creating such a discrepancy doesn't make much sense. I'm happy to move 
this call to libclang if this won't break many things.

> Could you clarify what kind of encapsulation would it break?

(That's just my spitballing, please don't mind. :)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158967/new/

https://reviews.llvm.org/D158967

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158967: [clangd] Record the stack bottom before building AST

2023-08-28 Thread Younan Zhang via Phabricator via cfe-commits
zyounan added a comment.

> According to documentation of noteBottomOfStack, those should be tied to 
> thread creation, i.e. main and AsyncTaskRunner are two most common entry 
> points for threads that do parsing.

Yeah, I was about to put this call there. But they both boil down to the single 
`ParsedAST::build()`, right? (Admittedly, this breaks the "encapsulation" if we 
say 'the build process for AST should not bring any other side effects besides 
the AST itself', and this doesn't adhere to the document that it should be 
created at the beginning of the thread/program.)

> Currently the code in CompilerInstance::ExecuteAction seems to acknowledge 
> that there should be a fallback. I'm suggesting to move this fallback down to 
> a function that actually runs parsing.

Upon the implementation, the result will be more accurate if it occurs earlier 
before diving into parsing. Maybe we can do both, that put this call at clangd 
site and libclang's `ASTFrontendAction::ExecuteAction`?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158967/new/

https://reviews.llvm.org/D158967

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158967: [clangd] Record the stack bottom before building AST

2023-08-29 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 554279.
zyounan added a comment.
Herald added a project: clang.

Adopt the comments.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158967/new/

https://reviews.llvm.org/D158967

Files:
  clang-tools-extra/clangd/ParsedAST.cpp
  clang-tools-extra/clangd/support/Threading.cpp
  clang-tools-extra/clangd/test/infinite-instantiation.test
  clang-tools-extra/clangd/tool/Check.cpp
  clang/lib/Frontend/FrontendAction.cpp

Index: clang/lib/Frontend/FrontendAction.cpp
===
--- clang/lib/Frontend/FrontendAction.cpp
+++ clang/lib/Frontend/FrontendAction.cpp
@@ -15,6 +15,7 @@
 #include "clang/Basic/FileEntry.h"
 #include "clang/Basic/LangStandard.h"
 #include "clang/Basic/Sarif.h"
+#include "clang/Basic/Stack.h"
 #include "clang/Frontend/ASTUnit.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendDiagnostic.h"
@@ -1054,6 +1055,11 @@
 }
 
 llvm::Error FrontendAction::Execute() {
+  // This is a fallback: If the client forgets to invoke this, we mark the
+  // current stack as the bottom. Though not optimal, this could help prevent
+  // stack overflow during deep recursion.
+  clang::noteBottomOfStack();
+
   CompilerInstance &CI = getCompilerInstance();
 
   if (CI.hasFrontendTimer()) {
Index: clang-tools-extra/clangd/tool/Check.cpp
===
--- clang-tools-extra/clangd/tool/Check.cpp
+++ clang-tools-extra/clangd/tool/Check.cpp
@@ -57,6 +57,7 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/LLVM.h"
+#include "clang/Basic/Stack.h"
 #include "clang/Format/Format.h"
 #include "clang/Frontend/CompilerInvocation.h"
 #include "clang/Tooling/CompilationDatabase.h"
@@ -441,6 +442,7 @@
 
 bool check(llvm::StringRef File, const ThreadsafeFS &TFS,
const ClangdLSPServer::Options &Opts) {
+  clang::noteBottomOfStack();
   std::optional LineRange;
   if (!CheckFileLines.empty()) {
 uint32_t Begin = 0, End = std::numeric_limits::max();
Index: clang-tools-extra/clangd/test/infinite-instantiation.test
===
--- /dev/null
+++ clang-tools-extra/clangd/test/infinite-instantiation.test
@@ -0,0 +1,13 @@
+// RUN: cp %s %t.cpp
+// RUN: not clangd -check=%t.cpp 2>&1 | FileCheck -strict-whitespace %s
+
+// CHECK: [template_recursion_depth_exceeded]
+
+template 
+constexpr int f(T... args) {
+  return f(0, args...);
+}
+
+int main() {
+  auto i = f();
+}
Index: clang-tools-extra/clangd/support/Threading.cpp
===
--- clang-tools-extra/clangd/support/Threading.cpp
+++ clang-tools-extra/clangd/support/Threading.cpp
@@ -8,6 +8,7 @@
 
 #include "support/Threading.h"
 #include "support/Trace.h"
+#include "clang/Basic/Stack.h"
 #include "llvm/ADT/ScopeExit.h"
 #include "llvm/Support/Threading.h"
 #include "llvm/Support/thread.h"
@@ -98,6 +99,9 @@
   auto Task = [Name = Name.str(), Action = std::move(Action),
Cleanup = std::move(CleanupTask)]() mutable {
 llvm::set_thread_name(Name);
+// Mark the bottom of the stack for clang to be aware of the stack usage and
+// prevent stack overflow.
+clang::noteBottomOfStack();
 Action();
 // Make sure function stored by ThreadFunc is destroyed before Cleanup runs.
 Action = nullptr;
Index: clang-tools-extra/clangd/ParsedAST.cpp
===
--- clang-tools-extra/clangd/ParsedAST.cpp
+++ clang-tools-extra/clangd/ParsedAST.cpp
@@ -44,6 +44,7 @@
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Stack.h"
 #include "clang/Basic/TokenKinds.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/CompilerInvocation.h"
@@ -388,6 +389,7 @@
  std::unique_ptr CI,
  llvm::ArrayRef CompilerInvocationDiags,
  std::shared_ptr Preamble) {
+  clang::noteBottomOfStack();
   trace::Span Tracer("BuildAST");
   SPAN_ATTACH(Tracer, "File", Filename);
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158967: [clangd] Record the stack bottom before building AST

2023-08-29 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 554283.
zyounan added a comment.

.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158967/new/

https://reviews.llvm.org/D158967

Files:
  clang-tools-extra/clangd/ParsedAST.cpp
  clang-tools-extra/clangd/support/Threading.cpp
  clang-tools-extra/clangd/test/infinite-instantiation.test
  clang-tools-extra/clangd/tool/Check.cpp
  clang/lib/Frontend/FrontendAction.cpp

Index: clang/lib/Frontend/FrontendAction.cpp
===
--- clang/lib/Frontend/FrontendAction.cpp
+++ clang/lib/Frontend/FrontendAction.cpp
@@ -15,6 +15,7 @@
 #include "clang/Basic/FileEntry.h"
 #include "clang/Basic/LangStandard.h"
 #include "clang/Basic/Sarif.h"
+#include "clang/Basic/Stack.h"
 #include "clang/Frontend/ASTUnit.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendDiagnostic.h"
@@ -1155,6 +1156,10 @@
   CompilerInstance &CI = getCompilerInstance();
   if (!CI.hasPreprocessor())
 return;
+  // This is a fallback: If the client forgets to invoke this, we mark the
+  // current stack as the bottom. Though not optimal, this could help prevent
+  // stack overflow during deep recursion.
+  clang::noteBottomOfStack();
 
   // FIXME: Move the truncation aspect of this into Sema, we delayed this till
   // here so the source manager would be initialized.
Index: clang-tools-extra/clangd/tool/Check.cpp
===
--- clang-tools-extra/clangd/tool/Check.cpp
+++ clang-tools-extra/clangd/tool/Check.cpp
@@ -57,6 +57,7 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/LLVM.h"
+#include "clang/Basic/Stack.h"
 #include "clang/Format/Format.h"
 #include "clang/Frontend/CompilerInvocation.h"
 #include "clang/Tooling/CompilationDatabase.h"
@@ -441,6 +442,7 @@
 
 bool check(llvm::StringRef File, const ThreadsafeFS &TFS,
const ClangdLSPServer::Options &Opts) {
+  clang::noteBottomOfStack();
   std::optional LineRange;
   if (!CheckFileLines.empty()) {
 uint32_t Begin = 0, End = std::numeric_limits::max();
Index: clang-tools-extra/clangd/test/infinite-instantiation.test
===
--- /dev/null
+++ clang-tools-extra/clangd/test/infinite-instantiation.test
@@ -0,0 +1,13 @@
+// RUN: cp %s %t.cpp
+// RUN: not clangd -check=%t.cpp 2>&1 | FileCheck -strict-whitespace %s
+
+// CHECK: [template_recursion_depth_exceeded]
+
+template 
+constexpr int f(T... args) {
+  return f(0, args...);
+}
+
+int main() {
+  auto i = f();
+}
Index: clang-tools-extra/clangd/support/Threading.cpp
===
--- clang-tools-extra/clangd/support/Threading.cpp
+++ clang-tools-extra/clangd/support/Threading.cpp
@@ -8,6 +8,7 @@
 
 #include "support/Threading.h"
 #include "support/Trace.h"
+#include "clang/Basic/Stack.h"
 #include "llvm/ADT/ScopeExit.h"
 #include "llvm/Support/Threading.h"
 #include "llvm/Support/thread.h"
@@ -98,6 +99,9 @@
   auto Task = [Name = Name.str(), Action = std::move(Action),
Cleanup = std::move(CleanupTask)]() mutable {
 llvm::set_thread_name(Name);
+// Mark the bottom of the stack for clang to be aware of the stack usage and
+// prevent stack overflow.
+clang::noteBottomOfStack();
 Action();
 // Make sure function stored by ThreadFunc is destroyed before Cleanup runs.
 Action = nullptr;
Index: clang-tools-extra/clangd/ParsedAST.cpp
===
--- clang-tools-extra/clangd/ParsedAST.cpp
+++ clang-tools-extra/clangd/ParsedAST.cpp
@@ -44,6 +44,7 @@
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Stack.h"
 #include "clang/Basic/TokenKinds.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/CompilerInvocation.h"
@@ -388,6 +389,7 @@
  std::unique_ptr CI,
  llvm::ArrayRef CompilerInvocationDiags,
  std::shared_ptr Preamble) {
+  clang::noteBottomOfStack();
   trace::Span Tracer("BuildAST");
   SPAN_ATTACH(Tracer, "File", Filename);
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158967: [clang][clangd] Ensure the stack bottom before building AST

2023-08-29 Thread Younan Zhang via Phabricator via cfe-commits
zyounan added a comment.

@ilya-biryukov I've updated the patch following your suggestion. PTAL, thanks!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158967/new/

https://reviews.llvm.org/D158967

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158967: [clang][clangd] Ensure the stack bottom before building AST

2023-08-29 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 554285.
zyounan added a comment.

Oops, something went wrong accidently.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158967/new/

https://reviews.llvm.org/D158967

Files:
  clang-tools-extra/clangd/support/Threading.cpp
  clang-tools-extra/clangd/test/infinite-instantiation.test
  clang-tools-extra/clangd/tool/Check.cpp
  clang/lib/Frontend/FrontendAction.cpp


Index: clang/lib/Frontend/FrontendAction.cpp
===
--- clang/lib/Frontend/FrontendAction.cpp
+++ clang/lib/Frontend/FrontendAction.cpp
@@ -15,6 +15,7 @@
 #include "clang/Basic/FileEntry.h"
 #include "clang/Basic/LangStandard.h"
 #include "clang/Basic/Sarif.h"
+#include "clang/Basic/Stack.h"
 #include "clang/Frontend/ASTUnit.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendDiagnostic.h"
@@ -1155,6 +1156,10 @@
   CompilerInstance &CI = getCompilerInstance();
   if (!CI.hasPreprocessor())
 return;
+  // This is a fallback: If the client forgets to invoke this, we mark the
+  // current stack as the bottom. Though not optimal, this could help prevent
+  // stack overflow during deep recursion.
+  clang::noteBottomOfStack();
 
   // FIXME: Move the truncation aspect of this into Sema, we delayed this till
   // here so the source manager would be initialized.
Index: clang-tools-extra/clangd/tool/Check.cpp
===
--- clang-tools-extra/clangd/tool/Check.cpp
+++ clang-tools-extra/clangd/tool/Check.cpp
@@ -57,6 +57,7 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/LLVM.h"
+#include "clang/Basic/Stack.h"
 #include "clang/Format/Format.h"
 #include "clang/Frontend/CompilerInvocation.h"
 #include "clang/Tooling/CompilationDatabase.h"
@@ -441,6 +442,7 @@
 
 bool check(llvm::StringRef File, const ThreadsafeFS &TFS,
const ClangdLSPServer::Options &Opts) {
+  clang::noteBottomOfStack();
   std::optional LineRange;
   if (!CheckFileLines.empty()) {
 uint32_t Begin = 0, End = std::numeric_limits::max();
Index: clang-tools-extra/clangd/test/infinite-instantiation.test
===
--- /dev/null
+++ clang-tools-extra/clangd/test/infinite-instantiation.test
@@ -0,0 +1,13 @@
+// RUN: cp %s %t.cpp
+// RUN: not clangd -check=%t.cpp 2>&1 | FileCheck -strict-whitespace %s
+
+// CHECK: [template_recursion_depth_exceeded]
+
+template 
+constexpr int f(T... args) {
+  return f(0, args...);
+}
+
+int main() {
+  auto i = f();
+}
Index: clang-tools-extra/clangd/support/Threading.cpp
===
--- clang-tools-extra/clangd/support/Threading.cpp
+++ clang-tools-extra/clangd/support/Threading.cpp
@@ -8,6 +8,7 @@
 
 #include "support/Threading.h"
 #include "support/Trace.h"
+#include "clang/Basic/Stack.h"
 #include "llvm/ADT/ScopeExit.h"
 #include "llvm/Support/Threading.h"
 #include "llvm/Support/thread.h"
@@ -98,6 +99,9 @@
   auto Task = [Name = Name.str(), Action = std::move(Action),
Cleanup = std::move(CleanupTask)]() mutable {
 llvm::set_thread_name(Name);
+// Mark the bottom of the stack for clang to be aware of the stack usage 
and
+// prevent stack overflow.
+clang::noteBottomOfStack();
 Action();
 // Make sure function stored by ThreadFunc is destroyed before Cleanup 
runs.
 Action = nullptr;


Index: clang/lib/Frontend/FrontendAction.cpp
===
--- clang/lib/Frontend/FrontendAction.cpp
+++ clang/lib/Frontend/FrontendAction.cpp
@@ -15,6 +15,7 @@
 #include "clang/Basic/FileEntry.h"
 #include "clang/Basic/LangStandard.h"
 #include "clang/Basic/Sarif.h"
+#include "clang/Basic/Stack.h"
 #include "clang/Frontend/ASTUnit.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendDiagnostic.h"
@@ -1155,6 +1156,10 @@
   CompilerInstance &CI = getCompilerInstance();
   if (!CI.hasPreprocessor())
 return;
+  // This is a fallback: If the client forgets to invoke this, we mark the
+  // current stack as the bottom. Though not optimal, this could help prevent
+  // stack overflow during deep recursion.
+  clang::noteBottomOfStack();
 
   // FIXME: Move the truncation aspect of this into Sema, we delayed this till
   // here so the source manager would be initialized.
Index: clang-tools-extra/clangd/tool/Check.cpp
===
--- clang-tools-extra/clangd/tool/Check.cpp
+++ clang-tools-extra/clangd/tool/Check.cpp
@@ -57,6 +57,7 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/LLVM.h"
+#include "clang/Basic/Stack.h"
 #include "clang/Format/Format.h"
 #include "clang/Frontend/CompilerInvocation.h"
 #include "clang/Tooling/CompilationData

[PATCH] D158967: [clang][clangd] Ensure the stack bottom before building AST

2023-08-30 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 554674.
zyounan marked an inline comment as done.
zyounan added a comment.

Address comment


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158967/new/

https://reviews.llvm.org/D158967

Files:
  clang-tools-extra/clangd/support/Threading.cpp
  clang-tools-extra/clangd/test/infinite-instantiation.test
  clang-tools-extra/clangd/tool/ClangdMain.cpp
  clang/lib/Frontend/FrontendAction.cpp


Index: clang/lib/Frontend/FrontendAction.cpp
===
--- clang/lib/Frontend/FrontendAction.cpp
+++ clang/lib/Frontend/FrontendAction.cpp
@@ -15,6 +15,7 @@
 #include "clang/Basic/FileEntry.h"
 #include "clang/Basic/LangStandard.h"
 #include "clang/Basic/Sarif.h"
+#include "clang/Basic/Stack.h"
 #include "clang/Frontend/ASTUnit.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendDiagnostic.h"
@@ -1155,6 +1156,10 @@
   CompilerInstance &CI = getCompilerInstance();
   if (!CI.hasPreprocessor())
 return;
+  // This is a fallback: If the client forgets to invoke this, we mark the
+  // current stack as the bottom. Though not optimal, this could help prevent
+  // stack overflow during deep recursion.
+  clang::noteBottomOfStack();
 
   // FIXME: Move the truncation aspect of this into Sema, we delayed this till
   // here so the source manager would be initialized.
Index: clang-tools-extra/clangd/tool/ClangdMain.cpp
===
--- clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -29,6 +29,7 @@
 #include "support/ThreadCrashReporter.h"
 #include "support/ThreadsafeFS.h"
 #include "support/Trace.h"
+#include "clang/Basic/Stack.h"
 #include "clang/Format/Format.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringRef.h"
@@ -710,6 +711,9 @@
 };
 
 int clangdMain(int argc, char *argv[]) {
+  // Clang could run on the main thread. e.g., when the flag '-check' or 
'-sync'
+  // is enabled.
+  clang::noteBottomOfStack();
   llvm::InitializeAllTargetInfos();
   llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
   llvm::sys::AddSignalHandler(
Index: clang-tools-extra/clangd/test/infinite-instantiation.test
===
--- /dev/null
+++ clang-tools-extra/clangd/test/infinite-instantiation.test
@@ -0,0 +1,13 @@
+// RUN: cp %s %t.cpp
+// RUN: not clangd -check=%t.cpp 2>&1 | FileCheck -strict-whitespace %s
+
+// CHECK: [template_recursion_depth_exceeded]
+
+template 
+constexpr int f(T... args) {
+  return f(0, args...);
+}
+
+int main() {
+  auto i = f();
+}
Index: clang-tools-extra/clangd/support/Threading.cpp
===
--- clang-tools-extra/clangd/support/Threading.cpp
+++ clang-tools-extra/clangd/support/Threading.cpp
@@ -8,6 +8,7 @@
 
 #include "support/Threading.h"
 #include "support/Trace.h"
+#include "clang/Basic/Stack.h"
 #include "llvm/ADT/ScopeExit.h"
 #include "llvm/Support/Threading.h"
 #include "llvm/Support/thread.h"
@@ -98,6 +99,9 @@
   auto Task = [Name = Name.str(), Action = std::move(Action),
Cleanup = std::move(CleanupTask)]() mutable {
 llvm::set_thread_name(Name);
+// Mark the bottom of the stack for clang to be aware of the stack usage 
and
+// prevent stack overflow.
+clang::noteBottomOfStack();
 Action();
 // Make sure function stored by ThreadFunc is destroyed before Cleanup 
runs.
 Action = nullptr;


Index: clang/lib/Frontend/FrontendAction.cpp
===
--- clang/lib/Frontend/FrontendAction.cpp
+++ clang/lib/Frontend/FrontendAction.cpp
@@ -15,6 +15,7 @@
 #include "clang/Basic/FileEntry.h"
 #include "clang/Basic/LangStandard.h"
 #include "clang/Basic/Sarif.h"
+#include "clang/Basic/Stack.h"
 #include "clang/Frontend/ASTUnit.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendDiagnostic.h"
@@ -1155,6 +1156,10 @@
   CompilerInstance &CI = getCompilerInstance();
   if (!CI.hasPreprocessor())
 return;
+  // This is a fallback: If the client forgets to invoke this, we mark the
+  // current stack as the bottom. Though not optimal, this could help prevent
+  // stack overflow during deep recursion.
+  clang::noteBottomOfStack();
 
   // FIXME: Move the truncation aspect of this into Sema, we delayed this till
   // here so the source manager would be initialized.
Index: clang-tools-extra/clangd/tool/ClangdMain.cpp
===
--- clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -29,6 +29,7 @@
 #include "support/ThreadCrashReporter.h"
 #include "support/ThreadsafeFS.h"
 #include "support/Trace.h"
+#include "clang/Basic/Stack.h"
 #include "clang/Format/Format.h"
 #include "llvm/ADT/S

[PATCH] D158967: [clang][clangd] Ensure the stack bottom before building AST

2023-08-30 Thread Younan Zhang via Phabricator via cfe-commits
zyounan added a comment.

Thanks again for Richard and Sam's comments!

(I didn't add another lit test for asynchronous case since it essentially works 
the same as the synchronous one. Hope this isn't harmful.)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158967/new/

https://reviews.llvm.org/D158967

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158061: [clang] Construct ExprRequirement with SubstitutionDiagnostic on SubstFailure

2023-08-31 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 554914.
zyounan marked an inline comment as done.
zyounan added a comment.

Expand diagnostics in the test.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158061/new/

https://reviews.llvm.org/D158061

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/AST/ExprConcepts.h
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
  clang/test/SemaCXX/concept-fatal-error.cpp

Index: clang/test/SemaCXX/concept-fatal-error.cpp
===
--- clang/test/SemaCXX/concept-fatal-error.cpp
+++ clang/test/SemaCXX/concept-fatal-error.cpp
@@ -1,4 +1,4 @@
-// RUN: not %clang_cc1 -fsyntax-only -std=c++20 -ferror-limit 1 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++20 -ferror-limit 1 -verify %s
 
 template 
 concept f = requires { 42; };
@@ -6,5 +6,5 @@
   // The missing semicolon will trigger an error and -ferror-limit=1 will make it fatal
   // We test that we do not crash in such cases (#55401)
   int i = requires { { i } f } // expected-error {{expected ';' at end of declaration list}}
-   // expected-error@* {{too many errros emitted}}
+   // expected-error@* {{too many errors emitted}}
 };
Index: clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s
+
+template  class normal_iterator {};
+
+template  struct is_convertible {};
+
+template 
+inline constexpr bool is_convertible_v = is_convertible::value; // #1
+
+template 
+concept convertible_to = is_convertible_v; // #2
+
+template 
+  requires requires(IteratorL lhs, IteratorR rhs) { // #3
+{ lhs == rhs } -> convertible_to; // #4
+  }
+constexpr bool compare(normal_iterator lhs, normal_iterator rhs) { // #5
+  return false;
+}
+
+class Object;
+
+void function() {
+  normal_iterator begin, end;
+  compare(begin, end); // #6
+}
+
+// expected-error@#1 {{no member named 'value' in 'is_convertible'}}
+
+// expected-note@#2 {{in instantiation of variable template specialization 'is_convertible_v' requested here}}
+// expected-note@#2 {{substituting template arguments into constraint expression here}}
+// expected-note@#4 {{checking the satisfaction of concept 'convertible_to'}}
+// expected-note@#3 {{substituting template arguments into constraint expression here}}
+// expected-note@#6 {{checking constraint satisfaction for template 'compare'}}
+// expected-note@#6 {{in instantiation of function template specialization 'compare' requested here}}
+
+// expected-error@#6 {{no matching function for call to 'compare'}}
+
+// expected-note@#5 {{candidate template ignored: constraints not satisfied [with IteratorL = Object *, IteratorR = Object *]}}
+// We don't know exactly the substituted type for `lhs == rhs`, thus a placeholder 'expr-type' is emitted.
+// expected-note@#4 {{because 'convertible_to' would be invalid}}
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2271,9 +2271,9 @@
   getPackIndex(Pack), Arg, TL.getNameLoc());
 }
 
-template
 static concepts::Requirement::SubstitutionDiagnostic *
-createSubstDiag(Sema &S, TemplateDeductionInfo &Info, EntityPrinter Printer) {
+createSubstDiag(Sema &S, TemplateDeductionInfo &Info,
+concepts::EntityPrinter Printer) {
   SmallString<128> Message;
   SourceLocation ErrorLoc;
   if (Info.hasSFINAEDiagnostic()) {
@@ -2297,6 +2297,19 @@
   StringRef(MessageBuf, Message.size())};
 }
 
+concepts::Requirement::SubstitutionDiagnostic *
+concepts::createSubstDiagAt(Sema &S, SourceLocation Location,
+EntityPrinter Printer) {
+  SmallString<128> Entity;
+  llvm::raw_svector_ostream OS(Entity);
+  Printer(OS);
+  char *EntityBuf = new (S.Context) char[Entity.size()];
+  llvm::copy(Entity, EntityBuf);
+  return new (S.Context) concepts::Requirement::SubstitutionDiagnostic{
+  /*SubstitutedEntity=*/StringRef(EntityBuf, Entity.size()),
+  /*DiagLoc=*/Location, /*DiagMessage=*/StringRef()};
+}
+
 ExprResult TemplateInstantiator::TransformRequiresTypeParams(
 SourceLocation KWLoc, SourceLocation RBraceLoc, const RequiresExpr *RE,
 RequiresExprBodyDecl *Body, ArrayRef Params,
Index: clang/lib/Sema/SemaExprCXX.cpp
===
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -19,6 +19,7 @@
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprConcepts.h"
 #include "clang/AST/Ex

[PATCH] D158061: [clang] Construct ExprRequirement with SubstitutionDiagnostic on SubstFailure

2023-08-31 Thread Younan Zhang via Phabricator via cfe-commits
zyounan added a comment.

Thanks for the review!




Comment at: clang/test/SemaCXX/concept-crash-on-diagnostic.cpp:26
+// Consume remaining notes/errors.
+// expected-note@* 0+{{}}
+// expected-error@* 0+{{}}

erichkeane wrote:
> Please don't do this, actually write out the remaining diagnostics.  Same 
> with the notes above.
> 
> Additionally, please use the 'bookmark' feature of verify-consumer to make 
> sure the diagnostics/notes are in proper order (which makes it easier to 
> figure out when reviewing).
Thanks for reminding me. Will do that.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158061/new/

https://reviews.llvm.org/D158061

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158061: [clang] Construct ExprRequirement with SubstitutionDiagnostic on SubstFailure

2023-08-31 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 554919.
zyounan added a comment.

Rebase to main


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158061/new/

https://reviews.llvm.org/D158061

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/AST/ExprConcepts.h
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
  clang/test/SemaCXX/concept-fatal-error.cpp

Index: clang/test/SemaCXX/concept-fatal-error.cpp
===
--- clang/test/SemaCXX/concept-fatal-error.cpp
+++ clang/test/SemaCXX/concept-fatal-error.cpp
@@ -1,4 +1,4 @@
-// RUN: not %clang_cc1 -fsyntax-only -std=c++20 -ferror-limit 1 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++20 -ferror-limit 1 -verify %s
 
 template 
 concept f = requires { 42; };
@@ -6,5 +6,5 @@
   // The missing semicolon will trigger an error and -ferror-limit=1 will make it fatal
   // We test that we do not crash in such cases (#55401)
   int i = requires { { i } f } // expected-error {{expected ';' at end of declaration list}}
-   // expected-error@* {{too many errros emitted}}
+   // expected-error@* {{too many errors emitted}}
 };
Index: clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s
+
+template  class normal_iterator {};
+
+template  struct is_convertible {};
+
+template 
+inline constexpr bool is_convertible_v = is_convertible::value; // #1
+
+template 
+concept convertible_to = is_convertible_v; // #2
+
+template 
+  requires requires(IteratorL lhs, IteratorR rhs) { // #3
+{ lhs == rhs } -> convertible_to; // #4
+  }
+constexpr bool compare(normal_iterator lhs, normal_iterator rhs) { // #5
+  return false;
+}
+
+class Object;
+
+void function() {
+  normal_iterator begin, end;
+  compare(begin, end); // #6
+}
+
+// expected-error@#1 {{no member named 'value' in 'is_convertible'}}
+
+// expected-note@#2 {{in instantiation of variable template specialization 'is_convertible_v' requested here}}
+// expected-note@#2 {{substituting template arguments into constraint expression here}}
+// expected-note@#4 {{checking the satisfaction of concept 'convertible_to'}}
+// expected-note@#3 {{substituting template arguments into constraint expression here}}
+// expected-note@#6 {{checking constraint satisfaction for template 'compare'}}
+// expected-note@#6 {{in instantiation of function template specialization 'compare' requested here}}
+
+// expected-error@#6 {{no matching function for call to 'compare'}}
+
+// expected-note@#5 {{candidate template ignored: constraints not satisfied [with IteratorL = Object *, IteratorR = Object *]}}
+// We don't know exactly the substituted type for `lhs == rhs`, thus a placeholder 'expr-type' is emitted.
+// expected-note@#4 {{because 'convertible_to' would be invalid}}
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2271,9 +2271,9 @@
   getPackIndex(Pack), Arg, TL.getNameLoc());
 }
 
-template
 static concepts::Requirement::SubstitutionDiagnostic *
-createSubstDiag(Sema &S, TemplateDeductionInfo &Info, EntityPrinter Printer) {
+createSubstDiag(Sema &S, TemplateDeductionInfo &Info,
+concepts::EntityPrinter Printer) {
   SmallString<128> Message;
   SourceLocation ErrorLoc;
   if (Info.hasSFINAEDiagnostic()) {
@@ -2297,6 +2297,19 @@
   StringRef(MessageBuf, Message.size())};
 }
 
+concepts::Requirement::SubstitutionDiagnostic *
+concepts::createSubstDiagAt(Sema &S, SourceLocation Location,
+EntityPrinter Printer) {
+  SmallString<128> Entity;
+  llvm::raw_svector_ostream OS(Entity);
+  Printer(OS);
+  char *EntityBuf = new (S.Context) char[Entity.size()];
+  llvm::copy(Entity, EntityBuf);
+  return new (S.Context) concepts::Requirement::SubstitutionDiagnostic{
+  /*SubstitutedEntity=*/StringRef(EntityBuf, Entity.size()),
+  /*DiagLoc=*/Location, /*DiagMessage=*/StringRef()};
+}
+
 ExprResult TemplateInstantiator::TransformRequiresTypeParams(
 SourceLocation KWLoc, SourceLocation RBraceLoc, const RequiresExpr *RE,
 RequiresExprBodyDecl *Body, ArrayRef Params,
Index: clang/lib/Sema/SemaExprCXX.cpp
===
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -19,6 +19,7 @@
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprConcepts.h"
 #include "clang/AST/ExprObjC.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #inc

[PATCH] D158061: [clang] Construct ExprRequirement with SubstitutionDiagnostic on SubstFailure

2023-08-31 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 555277.
zyounan marked an inline comment as done.
zyounan added a comment.

Address one last nit comment.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158061/new/

https://reviews.llvm.org/D158061

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/AST/ExprConcepts.h
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
  clang/test/SemaCXX/concept-fatal-error.cpp

Index: clang/test/SemaCXX/concept-fatal-error.cpp
===
--- clang/test/SemaCXX/concept-fatal-error.cpp
+++ clang/test/SemaCXX/concept-fatal-error.cpp
@@ -1,4 +1,4 @@
-// RUN: not %clang_cc1 -fsyntax-only -std=c++20 -ferror-limit 1 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++20 -ferror-limit 1 -verify %s
 
 template 
 concept f = requires { 42; };
@@ -6,5 +6,5 @@
   // The missing semicolon will trigger an error and -ferror-limit=1 will make it fatal
   // We test that we do not crash in such cases (#55401)
   int i = requires { { i } f } // expected-error {{expected ';' at end of declaration list}}
-   // expected-error@* {{too many errros emitted}}
+   // expected-error@* {{too many errors emitted}}
 };
Index: clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s
+
+template  class normal_iterator {};
+
+template  struct is_convertible {};
+
+template 
+inline constexpr bool is_convertible_v = is_convertible::value; // expected-error {{no member named 'value' in 'is_convertible'}}
+
+template 
+concept convertible_to = is_convertible_v; // #1
+
+template 
+  requires requires(IteratorL lhs, IteratorR rhs) { // #2
+{ lhs == rhs } -> convertible_to; // #3
+  }
+constexpr bool compare(normal_iterator lhs, normal_iterator rhs) { // #4
+  return false;
+}
+
+class Object;
+
+void function() {
+  normal_iterator begin, end;
+  compare(begin, end); // expected-error {{no matching function for call to 'compare'}} #5
+}
+
+// expected-note@#1 {{in instantiation of variable template specialization 'is_convertible_v' requested here}}
+// expected-note@#1 {{substituting template arguments into constraint expression here}}
+// expected-note@#3 {{checking the satisfaction of concept 'convertible_to'}}
+// expected-note@#2 {{substituting template arguments into constraint expression here}}
+// expected-note@#5 {{checking constraint satisfaction for template 'compare'}}
+// expected-note@#5 {{in instantiation of function template specialization 'compare' requested here}}
+
+// expected-note@#4 {{candidate template ignored: constraints not satisfied [with IteratorL = Object *, IteratorR = Object *]}}
+// We don't know exactly the substituted type for `lhs == rhs`, thus a placeholder 'expr-type' is emitted.
+// expected-note@#3 {{because 'convertible_to' would be invalid}}
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2271,9 +2271,9 @@
   getPackIndex(Pack), Arg, TL.getNameLoc());
 }
 
-template
 static concepts::Requirement::SubstitutionDiagnostic *
-createSubstDiag(Sema &S, TemplateDeductionInfo &Info, EntityPrinter Printer) {
+createSubstDiag(Sema &S, TemplateDeductionInfo &Info,
+concepts::EntityPrinter Printer) {
   SmallString<128> Message;
   SourceLocation ErrorLoc;
   if (Info.hasSFINAEDiagnostic()) {
@@ -2297,6 +2297,19 @@
   StringRef(MessageBuf, Message.size())};
 }
 
+concepts::Requirement::SubstitutionDiagnostic *
+concepts::createSubstDiagAt(Sema &S, SourceLocation Location,
+EntityPrinter Printer) {
+  SmallString<128> Entity;
+  llvm::raw_svector_ostream OS(Entity);
+  Printer(OS);
+  char *EntityBuf = new (S.Context) char[Entity.size()];
+  llvm::copy(Entity, EntityBuf);
+  return new (S.Context) concepts::Requirement::SubstitutionDiagnostic{
+  /*SubstitutedEntity=*/StringRef(EntityBuf, Entity.size()),
+  /*DiagLoc=*/Location, /*DiagMessage=*/StringRef()};
+}
+
 ExprResult TemplateInstantiator::TransformRequiresTypeParams(
 SourceLocation KWLoc, SourceLocation RBraceLoc, const RequiresExpr *RE,
 RequiresExprBodyDecl *Body, ArrayRef Params,
Index: clang/lib/Sema/SemaExprCXX.cpp
===
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -19,6 +19,7 @@
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprConcepts.h"
 #include "clang/AST/ExprObjC.h"
 #include "cl

[PATCH] D158061: [clang] Construct ExprRequirement with SubstitutionDiagnostic on SubstFailure

2023-08-31 Thread Younan Zhang via Phabricator via cfe-commits
zyounan marked an inline comment as done.
zyounan added a comment.

Thanks again for the review!




Comment at: clang/test/SemaCXX/concept-crash-on-diagnostic.cpp:28
+
+// expected-error@#1 {{no member named 'value' in 'is_convertible'}}
+

erichkeane wrote:
> So I typically don't do the 'error' with a bookmark, just put the 'error' 
> next to the line that causes the error, and bookmark the note.  It makes it 
> easier to read.
Good suggestion!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158061/new/

https://reviews.llvm.org/D158061

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158061: [clang] Construct ExprRequirement with SubstitutionDiagnostic on SubstFailure

2023-09-01 Thread Younan Zhang via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG2fd01d75a863: [clang] Construct ExprRequirement with 
SubstitutionDiagnostic on SubstFailure (authored by zyounan).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158061/new/

https://reviews.llvm.org/D158061

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/AST/ExprConcepts.h
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
  clang/test/SemaCXX/concept-fatal-error.cpp

Index: clang/test/SemaCXX/concept-fatal-error.cpp
===
--- clang/test/SemaCXX/concept-fatal-error.cpp
+++ clang/test/SemaCXX/concept-fatal-error.cpp
@@ -1,4 +1,4 @@
-// RUN: not %clang_cc1 -fsyntax-only -std=c++20 -ferror-limit 1 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++20 -ferror-limit 1 -verify %s
 
 template 
 concept f = requires { 42; };
@@ -6,5 +6,5 @@
   // The missing semicolon will trigger an error and -ferror-limit=1 will make it fatal
   // We test that we do not crash in such cases (#55401)
   int i = requires { { i } f } // expected-error {{expected ';' at end of declaration list}}
-   // expected-error@* {{too many errros emitted}}
+   // expected-error@* {{too many errors emitted}}
 };
Index: clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s
+
+template  class normal_iterator {};
+
+template  struct is_convertible {};
+
+template 
+inline constexpr bool is_convertible_v = is_convertible::value; // expected-error {{no member named 'value' in 'is_convertible'}}
+
+template 
+concept convertible_to = is_convertible_v; // #1
+
+template 
+  requires requires(IteratorL lhs, IteratorR rhs) { // #2
+{ lhs == rhs } -> convertible_to; // #3
+  }
+constexpr bool compare(normal_iterator lhs, normal_iterator rhs) { // #4
+  return false;
+}
+
+class Object;
+
+void function() {
+  normal_iterator begin, end;
+  compare(begin, end); // expected-error {{no matching function for call to 'compare'}} #5
+}
+
+// expected-note@#1 {{in instantiation of variable template specialization 'is_convertible_v' requested here}}
+// expected-note@#1 {{substituting template arguments into constraint expression here}}
+// expected-note@#3 {{checking the satisfaction of concept 'convertible_to'}}
+// expected-note@#2 {{substituting template arguments into constraint expression here}}
+// expected-note@#5 {{checking constraint satisfaction for template 'compare'}}
+// expected-note@#5 {{in instantiation of function template specialization 'compare' requested here}}
+
+// expected-note@#4 {{candidate template ignored: constraints not satisfied [with IteratorL = Object *, IteratorR = Object *]}}
+// We don't know exactly the substituted type for `lhs == rhs`, thus a placeholder 'expr-type' is emitted.
+// expected-note@#3 {{because 'convertible_to' would be invalid}}
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2271,9 +2271,9 @@
   getPackIndex(Pack), Arg, TL.getNameLoc());
 }
 
-template
 static concepts::Requirement::SubstitutionDiagnostic *
-createSubstDiag(Sema &S, TemplateDeductionInfo &Info, EntityPrinter Printer) {
+createSubstDiag(Sema &S, TemplateDeductionInfo &Info,
+concepts::EntityPrinter Printer) {
   SmallString<128> Message;
   SourceLocation ErrorLoc;
   if (Info.hasSFINAEDiagnostic()) {
@@ -2297,6 +2297,19 @@
   StringRef(MessageBuf, Message.size())};
 }
 
+concepts::Requirement::SubstitutionDiagnostic *
+concepts::createSubstDiagAt(Sema &S, SourceLocation Location,
+EntityPrinter Printer) {
+  SmallString<128> Entity;
+  llvm::raw_svector_ostream OS(Entity);
+  Printer(OS);
+  char *EntityBuf = new (S.Context) char[Entity.size()];
+  llvm::copy(Entity, EntityBuf);
+  return new (S.Context) concepts::Requirement::SubstitutionDiagnostic{
+  /*SubstitutedEntity=*/StringRef(EntityBuf, Entity.size()),
+  /*DiagLoc=*/Location, /*DiagMessage=*/StringRef()};
+}
+
 ExprResult TemplateInstantiator::TransformRequiresTypeParams(
 SourceLocation KWLoc, SourceLocation RBraceLoc, const RequiresExpr *RE,
 RequiresExprBodyDecl *Body, ArrayRef Params,
Index: clang/lib/Sema/SemaExprCXX.cpp
===
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -19,6 +19,7 @@
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/AS

[PATCH] D158967: [clang][clangd] Ensure the stack bottom before building AST

2023-09-01 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 555356.
zyounan added a comment.
Herald added a subscriber: javed.absar.

Disperse the call over clangd tasks


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158967/new/

https://reviews.llvm.org/D158967

Files:
  clang-tools-extra/clangd/ClangdServer.cpp
  clang-tools-extra/clangd/TUScheduler.cpp
  clang-tools-extra/clangd/index/Background.cpp
  clang-tools-extra/clangd/support/Threading.cpp
  clang-tools-extra/clangd/test/infinite-instantiation.test
  clang-tools-extra/clangd/tool/ClangdMain.cpp
  clang/lib/Frontend/FrontendAction.cpp

Index: clang/lib/Frontend/FrontendAction.cpp
===
--- clang/lib/Frontend/FrontendAction.cpp
+++ clang/lib/Frontend/FrontendAction.cpp
@@ -15,6 +15,7 @@
 #include "clang/Basic/FileEntry.h"
 #include "clang/Basic/LangStandard.h"
 #include "clang/Basic/Sarif.h"
+#include "clang/Basic/Stack.h"
 #include "clang/Frontend/ASTUnit.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendDiagnostic.h"
@@ -1155,6 +1156,10 @@
   CompilerInstance &CI = getCompilerInstance();
   if (!CI.hasPreprocessor())
 return;
+  // This is a fallback: If the client forgets to invoke this, we mark the
+  // current stack as the bottom. Though not optimal, this could help prevent
+  // stack overflow during deep recursion.
+  clang::noteBottomOfStack();
 
   // FIXME: Move the truncation aspect of this into Sema, we delayed this till
   // here so the source manager would be initialized.
Index: clang-tools-extra/clangd/tool/ClangdMain.cpp
===
--- clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -29,6 +29,7 @@
 #include "support/ThreadCrashReporter.h"
 #include "support/ThreadsafeFS.h"
 #include "support/Trace.h"
+#include "clang/Basic/Stack.h"
 #include "clang/Format/Format.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringRef.h"
@@ -710,6 +711,9 @@
 };
 
 int clangdMain(int argc, char *argv[]) {
+  // Clang could run on the main thread. e.g., when the flag '-check' or '-sync'
+  // is enabled.
+  clang::noteBottomOfStack();
   llvm::InitializeAllTargetInfos();
   llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
   llvm::sys::AddSignalHandler(
Index: clang-tools-extra/clangd/test/infinite-instantiation.test
===
--- /dev/null
+++ clang-tools-extra/clangd/test/infinite-instantiation.test
@@ -0,0 +1,13 @@
+// RUN: cp %s %t.cpp
+// RUN: not clangd -check=%t.cpp 2>&1 | FileCheck -strict-whitespace %s
+
+// CHECK: [template_recursion_depth_exceeded]
+
+template 
+constexpr int f(T... args) {
+  return f(0, args...);
+}
+
+int main() {
+  auto i = f();
+}
Index: clang-tools-extra/clangd/support/Threading.cpp
===
--- clang-tools-extra/clangd/support/Threading.cpp
+++ clang-tools-extra/clangd/support/Threading.cpp
@@ -8,6 +8,7 @@
 
 #include "support/Threading.h"
 #include "support/Trace.h"
+#include "clang/Basic/Stack.h"
 #include "llvm/ADT/ScopeExit.h"
 #include "llvm/Support/Threading.h"
 #include "llvm/Support/thread.h"
Index: clang-tools-extra/clangd/index/Background.cpp
===
--- clang-tools-extra/clangd/index/Background.cpp
+++ clang-tools-extra/clangd/index/Background.cpp
@@ -30,6 +30,7 @@
 #include "support/Trace.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Stack.h"
 #include "clang/Frontend/FrontendAction.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseSet.h"
@@ -108,6 +109,7 @@
   for (unsigned I = 0; I < Opts.ThreadPoolSize; ++I) {
 ThreadPool.runAsync("background-worker-" + llvm::Twine(I + 1),
 [this, Ctx(Context::current().clone())]() mutable {
+  clang::noteBottomOfStack();
   WithContext BGContext(std::move(Ctx));
   Queue.work([&] { Rebuilder.idle(); });
 });
Index: clang-tools-extra/clangd/TUScheduler.cpp
===
--- clang-tools-extra/clangd/TUScheduler.cpp
+++ clang-tools-extra/clangd/TUScheduler.cpp
@@ -63,6 +63,7 @@
 #include "support/ThreadCrashReporter.h"
 #include "support/Threading.h"
 #include "support/Trace.h"
+#include "clang/Basic/Stack.h"
 #include "clang/Frontend/CompilerInvocation.h"
 #include "clang/Tooling/CompilationDatabase.h"
 #include "llvm/ADT/FunctionExtras.h"
@@ -464,6 +465,10 @@
   }
 
   void run() {
+// We mark the current as the stack bottom so that clang running on this
+// thread can notice the stack usage and prevent stack overflow with best
+// efforts. Same applies to other calls thoughout clangd.
+clang:

[PATCH] D158967: [clang][clangd] Ensure the stack bottom before building AST

2023-09-01 Thread Younan Zhang via Phabricator via cfe-commits
zyounan added a comment.

Thanks! I hope I'm getting things right. Specifically,

1. `UpdateIndexCallbacks::indexStdlib()::Task` in `ClangdServer.cpp`
2. `PreambleThread::run()`, `ASTWorker::run()` and 
`TUScheduler::runWithPreamble()::Task` in `TUScheduler.cpp`
3. The lambda of `runAsync` in `BackgroundIndex::BackgroundIndex()` in 
`index/Background.cpp`.




Comment at: clang-tools-extra/clangd/support/Threading.cpp:102
 llvm::set_thread_name(Name);
+// Mark the bottom of the stack for clang to be aware of the stack usage 
and
+// prevent stack overflow.

sammccall wrote:
> ugh, I forgot: this function is part of clangBasic (which is not small!) and 
> clangdSupport shouldn't depend on clang at all.
> 
> I'm afraid the easiest fix is to move this to the tasks in the relevant 
> callsites:
> - indexStdlib() in ClangdServer.cpp
> - ASTWorker::run(), PreambleWorker::run(), TUScheduler::runWithPreamble() in 
> TUScheduler.cpp
> - BackgroundIndex() in index/Background.cpp
> 
> (I guess principled thing would be to make noteBottomOfStack() part of llvm 
> Support, but that seems complicated)
Ah, I've never noticed clangdSupport is independent of clang.

> (I guess principled thing would be to make noteBottomOfStack() part of llvm 
> Support, but that seems complicated)

Agreed. And I think it requires an RFC before we have that migrate to 
llvmSupport.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158967/new/

https://reviews.llvm.org/D158967

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D158967: [clang][clangd] Ensure the stack bottom before building AST

2023-09-02 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 77.
zyounan marked an inline comment as done.
zyounan added a comment.

Remove the stray header


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158967/new/

https://reviews.llvm.org/D158967

Files:
  clang-tools-extra/clangd/ClangdServer.cpp
  clang-tools-extra/clangd/TUScheduler.cpp
  clang-tools-extra/clangd/index/Background.cpp
  clang-tools-extra/clangd/test/infinite-instantiation.test
  clang-tools-extra/clangd/tool/ClangdMain.cpp
  clang/lib/Frontend/FrontendAction.cpp

Index: clang/lib/Frontend/FrontendAction.cpp
===
--- clang/lib/Frontend/FrontendAction.cpp
+++ clang/lib/Frontend/FrontendAction.cpp
@@ -15,6 +15,7 @@
 #include "clang/Basic/FileEntry.h"
 #include "clang/Basic/LangStandard.h"
 #include "clang/Basic/Sarif.h"
+#include "clang/Basic/Stack.h"
 #include "clang/Frontend/ASTUnit.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendDiagnostic.h"
@@ -1155,6 +1156,10 @@
   CompilerInstance &CI = getCompilerInstance();
   if (!CI.hasPreprocessor())
 return;
+  // This is a fallback: If the client forgets to invoke this, we mark the
+  // current stack as the bottom. Though not optimal, this could help prevent
+  // stack overflow during deep recursion.
+  clang::noteBottomOfStack();
 
   // FIXME: Move the truncation aspect of this into Sema, we delayed this till
   // here so the source manager would be initialized.
Index: clang-tools-extra/clangd/tool/ClangdMain.cpp
===
--- clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -29,6 +29,7 @@
 #include "support/ThreadCrashReporter.h"
 #include "support/ThreadsafeFS.h"
 #include "support/Trace.h"
+#include "clang/Basic/Stack.h"
 #include "clang/Format/Format.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringRef.h"
@@ -710,6 +711,9 @@
 };
 
 int clangdMain(int argc, char *argv[]) {
+  // Clang could run on the main thread. e.g., when the flag '-check' or '-sync'
+  // is enabled.
+  clang::noteBottomOfStack();
   llvm::InitializeAllTargetInfos();
   llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
   llvm::sys::AddSignalHandler(
Index: clang-tools-extra/clangd/test/infinite-instantiation.test
===
--- /dev/null
+++ clang-tools-extra/clangd/test/infinite-instantiation.test
@@ -0,0 +1,13 @@
+// RUN: cp %s %t.cpp
+// RUN: not clangd -check=%t.cpp 2>&1 | FileCheck -strict-whitespace %s
+
+// CHECK: [template_recursion_depth_exceeded]
+
+template 
+constexpr int f(T... args) {
+  return f(0, args...);
+}
+
+int main() {
+  auto i = f();
+}
Index: clang-tools-extra/clangd/index/Background.cpp
===
--- clang-tools-extra/clangd/index/Background.cpp
+++ clang-tools-extra/clangd/index/Background.cpp
@@ -30,6 +30,7 @@
 #include "support/Trace.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Stack.h"
 #include "clang/Frontend/FrontendAction.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseSet.h"
@@ -108,6 +109,7 @@
   for (unsigned I = 0; I < Opts.ThreadPoolSize; ++I) {
 ThreadPool.runAsync("background-worker-" + llvm::Twine(I + 1),
 [this, Ctx(Context::current().clone())]() mutable {
+  clang::noteBottomOfStack();
   WithContext BGContext(std::move(Ctx));
   Queue.work([&] { Rebuilder.idle(); });
 });
Index: clang-tools-extra/clangd/TUScheduler.cpp
===
--- clang-tools-extra/clangd/TUScheduler.cpp
+++ clang-tools-extra/clangd/TUScheduler.cpp
@@ -63,6 +63,7 @@
 #include "support/ThreadCrashReporter.h"
 #include "support/Threading.h"
 #include "support/Trace.h"
+#include "clang/Basic/Stack.h"
 #include "clang/Frontend/CompilerInvocation.h"
 #include "clang/Tooling/CompilationDatabase.h"
 #include "llvm/ADT/FunctionExtras.h"
@@ -464,6 +465,10 @@
   }
 
   void run() {
+// We mark the current as the stack bottom so that clang running on this
+// thread can notice the stack usage and prevent stack overflow with best
+// efforts. Same applies to other calls thoughout clangd.
+clang::noteBottomOfStack();
 while (true) {
   std::optional Throttle;
   {
@@ -1383,6 +1388,7 @@
 }
 
 void ASTWorker::run() {
+  clang::noteBottomOfStack();
   while (true) {
 {
   std::unique_lock Lock(Mutex);
@@ -1777,6 +1783,7 @@
Ctx = Context::current().derive(FileBeingProcessed,
std::string(File)),
Action = std::move(Action), this]() mutable {
+clang::noteBottomOfStack();
 ThreadCrashR

[PATCH] D158967: [clang][clangd] Ensure the stack bottom before building AST

2023-09-02 Thread Younan Zhang via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rGe257c0a91906: [clang][clangd] Ensure the stack bottom before 
building AST (authored by zyounan).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158967/new/

https://reviews.llvm.org/D158967

Files:
  clang-tools-extra/clangd/ClangdServer.cpp
  clang-tools-extra/clangd/TUScheduler.cpp
  clang-tools-extra/clangd/index/Background.cpp
  clang-tools-extra/clangd/test/infinite-instantiation.test
  clang-tools-extra/clangd/tool/ClangdMain.cpp
  clang/lib/Frontend/FrontendAction.cpp

Index: clang/lib/Frontend/FrontendAction.cpp
===
--- clang/lib/Frontend/FrontendAction.cpp
+++ clang/lib/Frontend/FrontendAction.cpp
@@ -15,6 +15,7 @@
 #include "clang/Basic/FileEntry.h"
 #include "clang/Basic/LangStandard.h"
 #include "clang/Basic/Sarif.h"
+#include "clang/Basic/Stack.h"
 #include "clang/Frontend/ASTUnit.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendDiagnostic.h"
@@ -1155,6 +1156,10 @@
   CompilerInstance &CI = getCompilerInstance();
   if (!CI.hasPreprocessor())
 return;
+  // This is a fallback: If the client forgets to invoke this, we mark the
+  // current stack as the bottom. Though not optimal, this could help prevent
+  // stack overflow during deep recursion.
+  clang::noteBottomOfStack();
 
   // FIXME: Move the truncation aspect of this into Sema, we delayed this till
   // here so the source manager would be initialized.
Index: clang-tools-extra/clangd/tool/ClangdMain.cpp
===
--- clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -29,6 +29,7 @@
 #include "support/ThreadCrashReporter.h"
 #include "support/ThreadsafeFS.h"
 #include "support/Trace.h"
+#include "clang/Basic/Stack.h"
 #include "clang/Format/Format.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringRef.h"
@@ -710,6 +711,9 @@
 };
 
 int clangdMain(int argc, char *argv[]) {
+  // Clang could run on the main thread. e.g., when the flag '-check' or '-sync'
+  // is enabled.
+  clang::noteBottomOfStack();
   llvm::InitializeAllTargetInfos();
   llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
   llvm::sys::AddSignalHandler(
Index: clang-tools-extra/clangd/test/infinite-instantiation.test
===
--- /dev/null
+++ clang-tools-extra/clangd/test/infinite-instantiation.test
@@ -0,0 +1,13 @@
+// RUN: cp %s %t.cpp
+// RUN: not clangd -check=%t.cpp 2>&1 | FileCheck -strict-whitespace %s
+
+// CHECK: [template_recursion_depth_exceeded]
+
+template 
+constexpr int f(T... args) {
+  return f(0, args...);
+}
+
+int main() {
+  auto i = f();
+}
Index: clang-tools-extra/clangd/index/Background.cpp
===
--- clang-tools-extra/clangd/index/Background.cpp
+++ clang-tools-extra/clangd/index/Background.cpp
@@ -30,6 +30,7 @@
 #include "support/Trace.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Stack.h"
 #include "clang/Frontend/FrontendAction.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseSet.h"
@@ -108,6 +109,7 @@
   for (unsigned I = 0; I < Opts.ThreadPoolSize; ++I) {
 ThreadPool.runAsync("background-worker-" + llvm::Twine(I + 1),
 [this, Ctx(Context::current().clone())]() mutable {
+  clang::noteBottomOfStack();
   WithContext BGContext(std::move(Ctx));
   Queue.work([&] { Rebuilder.idle(); });
 });
Index: clang-tools-extra/clangd/TUScheduler.cpp
===
--- clang-tools-extra/clangd/TUScheduler.cpp
+++ clang-tools-extra/clangd/TUScheduler.cpp
@@ -63,6 +63,7 @@
 #include "support/ThreadCrashReporter.h"
 #include "support/Threading.h"
 #include "support/Trace.h"
+#include "clang/Basic/Stack.h"
 #include "clang/Frontend/CompilerInvocation.h"
 #include "clang/Tooling/CompilationDatabase.h"
 #include "llvm/ADT/FunctionExtras.h"
@@ -464,6 +465,10 @@
   }
 
   void run() {
+// We mark the current as the stack bottom so that clang running on this
+// thread can notice the stack usage and prevent stack overflow with best
+// efforts. Same applies to other calls thoughout clangd.
+clang::noteBottomOfStack();
 while (true) {
   std::optional Throttle;
   {
@@ -1383,6 +1388,7 @@
 }
 
 void ASTWorker::run() {
+  clang::noteBottomOfStack();
   while (true) {
 {
   std::unique_lock Lock(Mutex);
@@ -1777,6 +1783,7 @@
Ctx = Context::current().derive(FileBeingProcessed,
std::string(File)),

[PATCH] D145319: [clangd] Refine logic on $0 in completion snippets

2023-03-15 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 505420.
zyounan marked 3 inline comments as done.
zyounan added a comment.

Address comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145319/new/

https://reviews.llvm.org/D145319

Files:
  clang-tools-extra/clangd/CodeComplete.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.h
  clang-tools-extra/clangd/index/SymbolCollector.cpp
  clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
  clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp

Index: clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
===
--- clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
+++ clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
@@ -24,11 +24,13 @@
 
 protected:
   void computeSignature(const CodeCompletionString &CCS,
-bool CompletingPattern = false) {
+CodeCompletionResult::ResultKind ResultKind =
+CodeCompletionResult::ResultKind::RK_Declaration) {
 Signature.clear();
 Snippet.clear();
-getSignature(CCS, &Signature, &Snippet, /*RequiredQualifier=*/nullptr,
- CompletingPattern);
+getSignature(CCS, &Signature, &Snippet, ResultKind,
+ /*CursorKind=*/CXCursorKind::CXCursor_NotImplemented,
+ /*RequiredQualifiers=*/nullptr);
   }
 
   std::shared_ptr Allocator;
@@ -145,11 +147,12 @@
 Builder.AddChunk(CodeCompletionString::CK_SemiColon);
 return *Builder.TakeString();
   };
-  computeSignature(MakeCCS(), /*CompletingPattern=*/false);
+  computeSignature(MakeCCS());
   EXPECT_EQ(Snippet, " ${1:name} = ${2:target};");
 
   // When completing a pattern, the last placeholder holds the cursor position.
-  computeSignature(MakeCCS(), /*CompletingPattern=*/true);
+  computeSignature(MakeCCS(),
+   /*ResultKind=*/CodeCompletionResult::ResultKind::RK_Pattern);
   EXPECT_EQ(Snippet, " ${1:name} = $0;");
 }
 
Index: clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
===
--- clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -3450,6 +3450,22 @@
   EXPECT_THAT(Results.Completions,
   Contains(AllOf(named("while_foo"),
  snippetSuffix("(${1:int a}, ${2:int b})";
+
+  Results = completions(R"cpp(
+struct Base {
+  Base(int a, int b) {}
+};
+
+struct Derived : Base {
+  Derived() : Base^
+};
+  )cpp",
+/*IndexSymbols=*/{}, Options);
+  // Constructors from base classes are a kind of pattern that shouldn't end
+  // with $0.
+  EXPECT_THAT(Results.Completions,
+  Contains(AllOf(named("Base"),
+ snippetSuffix("(${1:int a}, ${2:int b})";
 }
 
 TEST(CompletionTest, WorksWithNullType) {
Index: clang-tools-extra/clangd/index/SymbolCollector.cpp
===
--- clang-tools-extra/clangd/index/SymbolCollector.cpp
+++ clang-tools-extra/clangd/index/SymbolCollector.cpp
@@ -756,7 +756,8 @@
   *PP, *CompletionAllocator, *CompletionTUInfo);
   std::string Signature;
   std::string SnippetSuffix;
-  getSignature(*CCS, &Signature, &SnippetSuffix);
+  getSignature(*CCS, &Signature, &SnippetSuffix, SymbolCompletion.Kind,
+   SymbolCompletion.CursorKind);
   S.Signature = Signature;
   S.CompletionSnippetSuffix = SnippetSuffix;
 
@@ -933,7 +934,8 @@
   S.Documentation = Documentation;
   std::string Signature;
   std::string SnippetSuffix;
-  getSignature(*CCS, &Signature, &SnippetSuffix);
+  getSignature(*CCS, &Signature, &SnippetSuffix, SymbolCompletion.Kind,
+   SymbolCompletion.CursorKind);
   S.Signature = Signature;
   S.CompletionSnippetSuffix = SnippetSuffix;
   std::string ReturnType = getReturnType(*CCS);
Index: clang-tools-extra/clangd/CodeCompletionStrings.h
===
--- clang-tools-extra/clangd/CodeCompletionStrings.h
+++ clang-tools-extra/clangd/CodeCompletionStrings.h
@@ -42,12 +42,15 @@
 /// If set, RequiredQualifiers is the text that must be typed before the name.
 /// e.g "Base::" when calling a base class member function that's hidden.
 ///
-/// When \p CompletingPattern is true, the last placeholder will be of the form
-/// ${0:…}, indicating the cursor should stay there.
+/// When \p ResultKind is RK_Pattern, the last placeholder will be $0,
+/// indicating the cursor should stay there.
+/// Note that for certain \p CursorKind like \p CXCursor_Constructor, $0 won't
+/// be emitted in order to avoid overlapping normal parameters.
 void getSignature(const CodeCompletionString &CCS, std::string *Signature

[PATCH] D145319: [clangd] Refine logic on $0 in completion snippets

2023-03-15 Thread Younan Zhang via Phabricator via cfe-commits
zyounan added a comment.

Updated now. Thank you again for your patient review. :)




Comment at: clang-tools-extra/clangd/CodeCompletionStrings.cpp:213
   ++SnippetArg;
-  if (SnippetArg == CursorSnippetArg) {
+  if (ShouldPatchPlaceholder0 && SnippetArg == CursorSnippetArg) {
 // We'd like to make $0 a placeholder too, but vscode does not support

nridge wrote:
> I realized the first part of the condition is now redundant: if 
> `ShouldPatchPlaceholder0 == false`, then `CursorSnippetArg` will have value 
> `std::numeric_limits::max()` and `SnippetArg == CursorSnippetArg` 
> will never be true.
Aha, yes. Almost forget that.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145319/new/

https://reviews.llvm.org/D145319

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D145319: [clangd] Refine logic on $0 in completion snippets

2023-03-17 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 506001.
zyounan marked an inline comment as done.
zyounan added a comment.

Add description to shouldPatchPlaceholder0


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145319/new/

https://reviews.llvm.org/D145319

Files:
  clang-tools-extra/clangd/CodeComplete.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.h
  clang-tools-extra/clangd/index/SymbolCollector.cpp
  clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
  clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp

Index: clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
===
--- clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
+++ clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
@@ -24,11 +24,13 @@
 
 protected:
   void computeSignature(const CodeCompletionString &CCS,
-bool CompletingPattern = false) {
+CodeCompletionResult::ResultKind ResultKind =
+CodeCompletionResult::ResultKind::RK_Declaration) {
 Signature.clear();
 Snippet.clear();
-getSignature(CCS, &Signature, &Snippet, /*RequiredQualifier=*/nullptr,
- CompletingPattern);
+getSignature(CCS, &Signature, &Snippet, ResultKind,
+ /*CursorKind=*/CXCursorKind::CXCursor_NotImplemented,
+ /*RequiredQualifiers=*/nullptr);
   }
 
   std::shared_ptr Allocator;
@@ -145,11 +147,12 @@
 Builder.AddChunk(CodeCompletionString::CK_SemiColon);
 return *Builder.TakeString();
   };
-  computeSignature(MakeCCS(), /*CompletingPattern=*/false);
+  computeSignature(MakeCCS());
   EXPECT_EQ(Snippet, " ${1:name} = ${2:target};");
 
   // When completing a pattern, the last placeholder holds the cursor position.
-  computeSignature(MakeCCS(), /*CompletingPattern=*/true);
+  computeSignature(MakeCCS(),
+   /*ResultKind=*/CodeCompletionResult::ResultKind::RK_Pattern);
   EXPECT_EQ(Snippet, " ${1:name} = $0;");
 }
 
Index: clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
===
--- clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -3450,6 +3450,22 @@
   EXPECT_THAT(Results.Completions,
   Contains(AllOf(named("while_foo"),
  snippetSuffix("(${1:int a}, ${2:int b})";
+
+  Results = completions(R"cpp(
+struct Base {
+  Base(int a, int b) {}
+};
+
+struct Derived : Base {
+  Derived() : Base^
+};
+  )cpp",
+/*IndexSymbols=*/{}, Options);
+  // Constructors from base classes are a kind of pattern that shouldn't end
+  // with $0.
+  EXPECT_THAT(Results.Completions,
+  Contains(AllOf(named("Base"),
+ snippetSuffix("(${1:int a}, ${2:int b})";
 }
 
 TEST(CompletionTest, WorksWithNullType) {
Index: clang-tools-extra/clangd/index/SymbolCollector.cpp
===
--- clang-tools-extra/clangd/index/SymbolCollector.cpp
+++ clang-tools-extra/clangd/index/SymbolCollector.cpp
@@ -756,7 +756,8 @@
   *PP, *CompletionAllocator, *CompletionTUInfo);
   std::string Signature;
   std::string SnippetSuffix;
-  getSignature(*CCS, &Signature, &SnippetSuffix);
+  getSignature(*CCS, &Signature, &SnippetSuffix, SymbolCompletion.Kind,
+   SymbolCompletion.CursorKind);
   S.Signature = Signature;
   S.CompletionSnippetSuffix = SnippetSuffix;
 
@@ -933,7 +934,8 @@
   S.Documentation = Documentation;
   std::string Signature;
   std::string SnippetSuffix;
-  getSignature(*CCS, &Signature, &SnippetSuffix);
+  getSignature(*CCS, &Signature, &SnippetSuffix, SymbolCompletion.Kind,
+   SymbolCompletion.CursorKind);
   S.Signature = Signature;
   S.CompletionSnippetSuffix = SnippetSuffix;
   std::string ReturnType = getReturnType(*CCS);
Index: clang-tools-extra/clangd/CodeCompletionStrings.h
===
--- clang-tools-extra/clangd/CodeCompletionStrings.h
+++ clang-tools-extra/clangd/CodeCompletionStrings.h
@@ -42,12 +42,15 @@
 /// If set, RequiredQualifiers is the text that must be typed before the name.
 /// e.g "Base::" when calling a base class member function that's hidden.
 ///
-/// When \p CompletingPattern is true, the last placeholder will be of the form
-/// ${0:…}, indicating the cursor should stay there.
+/// When \p ResultKind is RK_Pattern, the last placeholder will be $0,
+/// indicating the cursor should stay there.
+/// Note that for certain \p CursorKind like \p CXCursor_Constructor, $0 won't
+/// be emitted in order to avoid overlapping normal parameters.
 void getSignature(const CodeCompletionString &C

[PATCH] D145319: [clangd] Refine logic on $0 in completion snippets

2023-03-17 Thread Younan Zhang via Phabricator via cfe-commits
zyounan added inline comments.



Comment at: clang-tools-extra/clangd/CodeCompletionStrings.cpp:60
 
+bool shouldPatchPlaceholder0(CodeCompletionResult::ResultKind ResultKind,
+ CXCursorKind CursorKind) {

nridge wrote:
> nit: let's add a short comment to describe the function, such as:
> 
> ```
> // Determine whether the completion string should be patched
> // to replace the last placeholder with $0
> ```
Sure!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145319/new/

https://reviews.llvm.org/D145319

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D145319: [clangd] Refine logic on $0 in completion snippets

2023-03-17 Thread Younan Zhang via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG138adb098032: [clangd] Refine logic on $0 in completion 
snippets (authored by zyounan).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145319/new/

https://reviews.llvm.org/D145319

Files:
  clang-tools-extra/clangd/CodeComplete.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.h
  clang-tools-extra/clangd/index/SymbolCollector.cpp
  clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
  clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp

Index: clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
===
--- clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
+++ clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
@@ -24,11 +24,13 @@
 
 protected:
   void computeSignature(const CodeCompletionString &CCS,
-bool CompletingPattern = false) {
+CodeCompletionResult::ResultKind ResultKind =
+CodeCompletionResult::ResultKind::RK_Declaration) {
 Signature.clear();
 Snippet.clear();
-getSignature(CCS, &Signature, &Snippet, /*RequiredQualifier=*/nullptr,
- CompletingPattern);
+getSignature(CCS, &Signature, &Snippet, ResultKind,
+ /*CursorKind=*/CXCursorKind::CXCursor_NotImplemented,
+ /*RequiredQualifiers=*/nullptr);
   }
 
   std::shared_ptr Allocator;
@@ -145,11 +147,12 @@
 Builder.AddChunk(CodeCompletionString::CK_SemiColon);
 return *Builder.TakeString();
   };
-  computeSignature(MakeCCS(), /*CompletingPattern=*/false);
+  computeSignature(MakeCCS());
   EXPECT_EQ(Snippet, " ${1:name} = ${2:target};");
 
   // When completing a pattern, the last placeholder holds the cursor position.
-  computeSignature(MakeCCS(), /*CompletingPattern=*/true);
+  computeSignature(MakeCCS(),
+   /*ResultKind=*/CodeCompletionResult::ResultKind::RK_Pattern);
   EXPECT_EQ(Snippet, " ${1:name} = $0;");
 }
 
Index: clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
===
--- clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -3450,6 +3450,22 @@
   EXPECT_THAT(Results.Completions,
   Contains(AllOf(named("while_foo"),
  snippetSuffix("(${1:int a}, ${2:int b})";
+
+  Results = completions(R"cpp(
+struct Base {
+  Base(int a, int b) {}
+};
+
+struct Derived : Base {
+  Derived() : Base^
+};
+  )cpp",
+/*IndexSymbols=*/{}, Options);
+  // Constructors from base classes are a kind of pattern that shouldn't end
+  // with $0.
+  EXPECT_THAT(Results.Completions,
+  Contains(AllOf(named("Base"),
+ snippetSuffix("(${1:int a}, ${2:int b})";
 }
 
 TEST(CompletionTest, WorksWithNullType) {
Index: clang-tools-extra/clangd/index/SymbolCollector.cpp
===
--- clang-tools-extra/clangd/index/SymbolCollector.cpp
+++ clang-tools-extra/clangd/index/SymbolCollector.cpp
@@ -756,7 +756,8 @@
   *PP, *CompletionAllocator, *CompletionTUInfo);
   std::string Signature;
   std::string SnippetSuffix;
-  getSignature(*CCS, &Signature, &SnippetSuffix);
+  getSignature(*CCS, &Signature, &SnippetSuffix, SymbolCompletion.Kind,
+   SymbolCompletion.CursorKind);
   S.Signature = Signature;
   S.CompletionSnippetSuffix = SnippetSuffix;
 
@@ -933,7 +934,8 @@
   S.Documentation = Documentation;
   std::string Signature;
   std::string SnippetSuffix;
-  getSignature(*CCS, &Signature, &SnippetSuffix);
+  getSignature(*CCS, &Signature, &SnippetSuffix, SymbolCompletion.Kind,
+   SymbolCompletion.CursorKind);
   S.Signature = Signature;
   S.CompletionSnippetSuffix = SnippetSuffix;
   std::string ReturnType = getReturnType(*CCS);
Index: clang-tools-extra/clangd/CodeCompletionStrings.h
===
--- clang-tools-extra/clangd/CodeCompletionStrings.h
+++ clang-tools-extra/clangd/CodeCompletionStrings.h
@@ -42,12 +42,15 @@
 /// If set, RequiredQualifiers is the text that must be typed before the name.
 /// e.g "Base::" when calling a base class member function that's hidden.
 ///
-/// When \p CompletingPattern is true, the last placeholder will be of the form
-/// ${0:…}, indicating the cursor should stay there.
+/// When \p ResultKind is RK_Pattern, the last placeholder will be $0,
+/// indicating the cursor should stay there.
+/// Note that for certain \p CursorKind like \p CXCursor_Constructor, $0 won't
+/// be emitted in order to avoid overlapping normal parameters.
 void getSignature(const

[PATCH] D146874: [clangd] Fix a hover crash on unsigned 64bit value

2023-03-25 Thread Younan Zhang via Phabricator via cfe-commits
zyounan created this revision.
Herald added subscribers: kadircet, arphaman.
Herald added a project: All.
zyounan requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.
Herald added a project: clang-tools-extra.

This patch adapts to D140059 , which makes an 
assumption that the
caller of `APSInt::getExtValue` promises no narrowing conversion
happens, i.e., from signed int64 to unsigned int64.

It also fixes clangd/clangd#1557.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D146874

Files:
  clang-tools-extra/clangd/Hover.cpp
  clang-tools-extra/clangd/unittests/HoverTests.cpp


Index: clang-tools-extra/clangd/unittests/HoverTests.cpp
===
--- clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -2947,6 +2947,15 @@
 getHover(AST, P, format::getLLVMStyle(), nullptr);
 }
 
+TEST(Hover, NoCrashAPInt64) {
+  Annotations T(R"cpp(
+constexpr unsigned long value = -1; // wrap around
+void foo() { va$1^lue; }
+  )cpp");
+  auto AST = TestTU::withCode(T.code()).build();
+  getHover(AST, T.point("1"), format::getLLVMStyle(), nullptr);
+}
+
 TEST(Hover, DocsFromMostSpecial) {
   Annotations T(R"cpp(
   // doc1
Index: clang-tools-extra/clangd/Hover.cpp
===
--- clang-tools-extra/clangd/Hover.cpp
+++ clang-tools-extra/clangd/Hover.cpp
@@ -395,7 +395,7 @@
 // -2=> 0xfffe
 // -2^32 => 0xfffe
 static llvm::FormattedNumber printHex(const llvm::APSInt &V) {
-  uint64_t Bits = V.getExtValue();
+  uint64_t Bits = V.getZExtValue();
   if (V.isNegative() && V.getSignificantBits() <= 32)
 return llvm::format_hex(uint32_t(Bits), 0);
   return llvm::format_hex(Bits, 0);


Index: clang-tools-extra/clangd/unittests/HoverTests.cpp
===
--- clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -2947,6 +2947,15 @@
 getHover(AST, P, format::getLLVMStyle(), nullptr);
 }
 
+TEST(Hover, NoCrashAPInt64) {
+  Annotations T(R"cpp(
+constexpr unsigned long value = -1; // wrap around
+void foo() { va$1^lue; }
+  )cpp");
+  auto AST = TestTU::withCode(T.code()).build();
+  getHover(AST, T.point("1"), format::getLLVMStyle(), nullptr);
+}
+
 TEST(Hover, DocsFromMostSpecial) {
   Annotations T(R"cpp(
   // doc1
Index: clang-tools-extra/clangd/Hover.cpp
===
--- clang-tools-extra/clangd/Hover.cpp
+++ clang-tools-extra/clangd/Hover.cpp
@@ -395,7 +395,7 @@
 // -2=> 0xfffe
 // -2^32 => 0xfffe
 static llvm::FormattedNumber printHex(const llvm::APSInt &V) {
-  uint64_t Bits = V.getExtValue();
+  uint64_t Bits = V.getZExtValue();
   if (V.isNegative() && V.getSignificantBits() <= 32)
 return llvm::format_hex(uint32_t(Bits), 0);
   return llvm::format_hex(Bits, 0);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D146874: [clangd] Fix a hover crash on unsigned 64bit value

2023-03-25 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 508316.
zyounan added a comment.

Fix comment


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D146874/new/

https://reviews.llvm.org/D146874

Files:
  clang-tools-extra/clangd/Hover.cpp
  clang-tools-extra/clangd/unittests/HoverTests.cpp


Index: clang-tools-extra/clangd/unittests/HoverTests.cpp
===
--- clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -2947,6 +2947,15 @@
 getHover(AST, P, format::getLLVMStyle(), nullptr);
 }
 
+TEST(Hover, NoCrashAPInt64) {
+  Annotations T(R"cpp(
+constexpr unsigned long value = -1; // wrap around
+void foo() { va$1^lue; }
+  )cpp");
+  auto AST = TestTU::withCode(T.code()).build();
+  getHover(AST, T.point("1"), format::getLLVMStyle(), nullptr);
+}
+
 TEST(Hover, DocsFromMostSpecial) {
   Annotations T(R"cpp(
   // doc1
Index: clang-tools-extra/clangd/Hover.cpp
===
--- clang-tools-extra/clangd/Hover.cpp
+++ clang-tools-extra/clangd/Hover.cpp
@@ -393,9 +393,9 @@
 // 100   => 0x64
 // Negative numbers are sign-extended to 32/64 bits
 // -2=> 0xfffe
-// -2^32 => 0xfffe
+// -2^32 => 0x
 static llvm::FormattedNumber printHex(const llvm::APSInt &V) {
-  uint64_t Bits = V.getExtValue();
+  uint64_t Bits = V.getZExtValue();
   if (V.isNegative() && V.getSignificantBits() <= 32)
 return llvm::format_hex(uint32_t(Bits), 0);
   return llvm::format_hex(Bits, 0);


Index: clang-tools-extra/clangd/unittests/HoverTests.cpp
===
--- clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -2947,6 +2947,15 @@
 getHover(AST, P, format::getLLVMStyle(), nullptr);
 }
 
+TEST(Hover, NoCrashAPInt64) {
+  Annotations T(R"cpp(
+constexpr unsigned long value = -1; // wrap around
+void foo() { va$1^lue; }
+  )cpp");
+  auto AST = TestTU::withCode(T.code()).build();
+  getHover(AST, T.point("1"), format::getLLVMStyle(), nullptr);
+}
+
 TEST(Hover, DocsFromMostSpecial) {
   Annotations T(R"cpp(
   // doc1
Index: clang-tools-extra/clangd/Hover.cpp
===
--- clang-tools-extra/clangd/Hover.cpp
+++ clang-tools-extra/clangd/Hover.cpp
@@ -393,9 +393,9 @@
 // 100   => 0x64
 // Negative numbers are sign-extended to 32/64 bits
 // -2=> 0xfffe
-// -2^32 => 0xfffe
+// -2^32 => 0x
 static llvm::FormattedNumber printHex(const llvm::APSInt &V) {
-  uint64_t Bits = V.getExtValue();
+  uint64_t Bits = V.getZExtValue();
   if (V.isNegative() && V.getSignificantBits() <= 32)
 return llvm::format_hex(uint32_t(Bits), 0);
   return llvm::format_hex(Bits, 0);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D146874: [clangd] Fix a hover crash on unsigned 64bit value

2023-03-26 Thread Younan Zhang via Phabricator via cfe-commits
zyounan marked 2 inline comments as done.
zyounan added a comment.

Thank you!




Comment at: clang-tools-extra/clangd/Hover.cpp:396
 // -2=> 0xfffe
-// -2^32 => 0xfffe
+// -2^32 => 0x
 static llvm::FormattedNumber printHex(const llvm::APSInt &V) {

nridge wrote:
> Just to make sure I'm not missing anything: this comment change is just 
> fixing a pre-existing mistake in the comment (-2^32 was already printed as 
> 0x), right? i.e. this patch doesn't change how any number is 
> printed
No, the patch doesn't change the behavior of the function.  
`0xfffe` actually stands for `-(2**32 + 1)`. :D


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D146874/new/

https://reviews.llvm.org/D146874

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D146874: [clangd] Fix a hover crash on unsigned 64bit value

2023-03-26 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 508401.
zyounan marked an inline comment as done.
zyounan added a comment.

Address comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D146874/new/

https://reviews.llvm.org/D146874

Files:
  clang-tools-extra/clangd/Hover.cpp
  clang-tools-extra/clangd/unittests/HoverTests.cpp


Index: clang-tools-extra/clangd/unittests/HoverTests.cpp
===
--- clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -2947,6 +2947,15 @@
 getHover(AST, P, format::getLLVMStyle(), nullptr);
 }
 
+TEST(Hover, NoCrashAPInt64) {
+  Annotations T(R"cpp(
+constexpr unsigned long value = -1; // wrap around
+void foo() { va^lue; }
+  )cpp");
+  auto AST = TestTU::withCode(T.code()).build();
+  getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
+}
+
 TEST(Hover, DocsFromMostSpecial) {
   Annotations T(R"cpp(
   // doc1
Index: clang-tools-extra/clangd/Hover.cpp
===
--- clang-tools-extra/clangd/Hover.cpp
+++ clang-tools-extra/clangd/Hover.cpp
@@ -393,9 +393,9 @@
 // 100   => 0x64
 // Negative numbers are sign-extended to 32/64 bits
 // -2=> 0xfffe
-// -2^32 => 0xfffe
+// -2^32 => 0x
 static llvm::FormattedNumber printHex(const llvm::APSInt &V) {
-  uint64_t Bits = V.getExtValue();
+  uint64_t Bits = V.getZExtValue();
   if (V.isNegative() && V.getSignificantBits() <= 32)
 return llvm::format_hex(uint32_t(Bits), 0);
   return llvm::format_hex(Bits, 0);


Index: clang-tools-extra/clangd/unittests/HoverTests.cpp
===
--- clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -2947,6 +2947,15 @@
 getHover(AST, P, format::getLLVMStyle(), nullptr);
 }
 
+TEST(Hover, NoCrashAPInt64) {
+  Annotations T(R"cpp(
+constexpr unsigned long value = -1; // wrap around
+void foo() { va^lue; }
+  )cpp");
+  auto AST = TestTU::withCode(T.code()).build();
+  getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
+}
+
 TEST(Hover, DocsFromMostSpecial) {
   Annotations T(R"cpp(
   // doc1
Index: clang-tools-extra/clangd/Hover.cpp
===
--- clang-tools-extra/clangd/Hover.cpp
+++ clang-tools-extra/clangd/Hover.cpp
@@ -393,9 +393,9 @@
 // 100   => 0x64
 // Negative numbers are sign-extended to 32/64 bits
 // -2=> 0xfffe
-// -2^32 => 0xfffe
+// -2^32 => 0x
 static llvm::FormattedNumber printHex(const llvm::APSInt &V) {
-  uint64_t Bits = V.getExtValue();
+  uint64_t Bits = V.getZExtValue();
   if (V.isNegative() && V.getSignificantBits() <= 32)
 return llvm::format_hex(uint32_t(Bits), 0);
   return llvm::format_hex(Bits, 0);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D146874: [clangd] Fix a hover crash on unsigned 64bit value

2023-03-26 Thread Younan Zhang via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG0b103edf5b2c: [clangd] Fix a hover crash on unsigned 64bit 
value (authored by zyounan).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D146874/new/

https://reviews.llvm.org/D146874

Files:
  clang-tools-extra/clangd/Hover.cpp
  clang-tools-extra/clangd/unittests/HoverTests.cpp


Index: clang-tools-extra/clangd/unittests/HoverTests.cpp
===
--- clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -3045,6 +3045,15 @@
 getHover(AST, P, format::getLLVMStyle(), nullptr);
 }
 
+TEST(Hover, NoCrashAPInt64) {
+  Annotations T(R"cpp(
+constexpr unsigned long value = -1; // wrap around
+void foo() { va^lue; }
+  )cpp");
+  auto AST = TestTU::withCode(T.code()).build();
+  getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
+}
+
 TEST(Hover, DocsFromMostSpecial) {
   Annotations T(R"cpp(
   // doc1
Index: clang-tools-extra/clangd/Hover.cpp
===
--- clang-tools-extra/clangd/Hover.cpp
+++ clang-tools-extra/clangd/Hover.cpp
@@ -400,9 +400,9 @@
 // 100   => 0x64
 // Negative numbers are sign-extended to 32/64 bits
 // -2=> 0xfffe
-// -2^32 => 0xfffe
+// -2^32 => 0x
 static llvm::FormattedNumber printHex(const llvm::APSInt &V) {
-  uint64_t Bits = V.getExtValue();
+  uint64_t Bits = V.getZExtValue();
   if (V.isNegative() && V.getSignificantBits() <= 32)
 return llvm::format_hex(uint32_t(Bits), 0);
   return llvm::format_hex(Bits, 0);


Index: clang-tools-extra/clangd/unittests/HoverTests.cpp
===
--- clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -3045,6 +3045,15 @@
 getHover(AST, P, format::getLLVMStyle(), nullptr);
 }
 
+TEST(Hover, NoCrashAPInt64) {
+  Annotations T(R"cpp(
+constexpr unsigned long value = -1; // wrap around
+void foo() { va^lue; }
+  )cpp");
+  auto AST = TestTU::withCode(T.code()).build();
+  getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
+}
+
 TEST(Hover, DocsFromMostSpecial) {
   Annotations T(R"cpp(
   // doc1
Index: clang-tools-extra/clangd/Hover.cpp
===
--- clang-tools-extra/clangd/Hover.cpp
+++ clang-tools-extra/clangd/Hover.cpp
@@ -400,9 +400,9 @@
 // 100   => 0x64
 // Negative numbers are sign-extended to 32/64 bits
 // -2=> 0xfffe
-// -2^32 => 0xfffe
+// -2^32 => 0x
 static llvm::FormattedNumber printHex(const llvm::APSInt &V) {
-  uint64_t Bits = V.getExtValue();
+  uint64_t Bits = V.getZExtValue();
   if (V.isNegative() && V.getSignificantBits() <= 32)
 return llvm::format_hex(uint32_t(Bits), 0);
   return llvm::format_hex(Bits, 0);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D144074: [clangd] Hide inlay hints when using a macro as a calling argument that with a param comment

2023-02-25 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 500387.
zyounan marked an inline comment as done.
zyounan added a comment.

Address the comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D144074/new/

https://reviews.llvm.org/D144074

Files:
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp


Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -1050,9 +1050,15 @@
 void bar() {
   foo(/*param*/42);
   foo( /* param = */ 42);
+#define X 42
+#define Y X
+#define Z(...) Y
+  foo(/*param=*/Z(a));
+  foo($macro[[Z(a)]]);
   foo(/* the answer */$param[[42]]);
 }
   )cpp",
+   ExpectedHint{"param: ", "macro"},
ExpectedHint{"param: ", "param"});
 }
 
Index: clang-tools-extra/clangd/InlayHints.cpp
===
--- clang-tools-extra/clangd/InlayHints.cpp
+++ clang-tools-extra/clangd/InlayHints.cpp
@@ -516,8 +516,8 @@
   // at the end.
   bool isPrecededByParamNameComment(const Expr *E, StringRef ParamName) {
 auto &SM = AST.getSourceManager();
-auto ExprStartLoc = SM.getTopMacroCallerLoc(E->getBeginLoc());
-auto Decomposed = SM.getDecomposedLoc(ExprStartLoc);
+auto ExpansionLoc = SM.getFileLoc(E->getBeginLoc());
+auto Decomposed = SM.getDecomposedLoc(ExpansionLoc);
 if (Decomposed.first != MainFileID)
   return false;
 


Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -1050,9 +1050,15 @@
 void bar() {
   foo(/*param*/42);
   foo( /* param = */ 42);
+#define X 42
+#define Y X
+#define Z(...) Y
+  foo(/*param=*/Z(a));
+  foo($macro[[Z(a)]]);
   foo(/* the answer */$param[[42]]);
 }
   )cpp",
+   ExpectedHint{"param: ", "macro"},
ExpectedHint{"param: ", "param"});
 }
 
Index: clang-tools-extra/clangd/InlayHints.cpp
===
--- clang-tools-extra/clangd/InlayHints.cpp
+++ clang-tools-extra/clangd/InlayHints.cpp
@@ -516,8 +516,8 @@
   // at the end.
   bool isPrecededByParamNameComment(const Expr *E, StringRef ParamName) {
 auto &SM = AST.getSourceManager();
-auto ExprStartLoc = SM.getTopMacroCallerLoc(E->getBeginLoc());
-auto Decomposed = SM.getDecomposedLoc(ExprStartLoc);
+auto ExpansionLoc = SM.getFileLoc(E->getBeginLoc());
+auto Decomposed = SM.getDecomposedLoc(ExpansionLoc);
 if (Decomposed.first != MainFileID)
   return false;
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D144074: [clangd] Hide inlay hints when using a macro as a calling argument that with a param comment

2023-02-25 Thread Younan Zhang via Phabricator via cfe-commits
zyounan added inline comments.



Comment at: clang-tools-extra/clangd/InlayHints.cpp:520
 auto ExprStartLoc = SM.getTopMacroCallerLoc(E->getBeginLoc());
-auto Decomposed = SM.getDecomposedLoc(ExprStartLoc);
+auto Decomposed = SM.getDecomposedExpansionLoc(ExprStartLoc);
 if (Decomposed.first != MainFileID)

nridge wrote:
> I admit I struggle with this spelling/expansion loc stuff. But having spent a 
> bit of time reading the implementations of these functions, would I be 
> correct to say that another, perhaps easier to follow, way to express the 
> same thing would be:
> 
> ```
> auto Decomposed = SM.getDecomposedLoc(SM.getFileLoc(E->getBeginLoc()));
> ```
> 
> ?
Yes, indeed. `SM.getFileLoc` performs exactly the same function as 
`getTopMacroCallerLoc` and `getDecomposedExpansionLoc`: 
If Loc is a FileID, just return Loc. 
In another case it falls into a loop until the result is a FileID: First obtain 
the "top macro caller" location, then the beginning expansion location.



Comment at: clang-tools-extra/clangd/InlayHints.cpp:521
+auto Decomposed = SM.getDecomposedExpansionLoc(ExprStartLoc);
 if (Decomposed.first != MainFileID)
   return false;

nridge wrote:
> zyounan wrote:
> > stupid question: I was suspicious with this check that when would 
> > `Decomposed.first` not being the same as MainFileID? Should the 
> > "top-caller" of the macro always be in main file? I didn't find a case that 
> > differs, except when `getDecomposedLoc` provides wrong FileID.
> I tried adding an assertion in this early-return branch, and it tripped in 
> `ParameterHints.IncludeAtNonGlobalScope`.
> 
> The code there is:
> 
> ```
>   Annotations FooInc(R"cpp(
> void bar() { foo(42); }
>   )cpp");
>   Annotations FooCC(R"cpp(
> struct S {
>   void foo(int param);
>   #include "foo.inc"
> };
>   )cpp");
> ```
> 
> so I guess the decomposed loc there is a file loc, but not in the main file 
> (but rather in `foo.inc`).
Ah, I see. Thanks!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D144074/new/

https://reviews.llvm.org/D144074

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D144074: [clangd] Hide inlay hints when using a macro as a calling argument that with a param comment

2023-02-25 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 500388.
zyounan added a comment.

Update


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D144074/new/

https://reviews.llvm.org/D144074

Files:
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp


Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -1050,9 +1050,15 @@
 void bar() {
   foo(/*param*/42);
   foo( /* param = */ 42);
+#define X 42
+#define Y X
+#define Z(...) Y
+  foo(/*param=*/Z(a));
+  foo($macro[[Z(a)]]);
   foo(/* the answer */$param[[42]]);
 }
   )cpp",
+   ExpectedHint{"param: ", "macro"},
ExpectedHint{"param: ", "param"});
 }
 
Index: clang-tools-extra/clangd/InlayHints.cpp
===
--- clang-tools-extra/clangd/InlayHints.cpp
+++ clang-tools-extra/clangd/InlayHints.cpp
@@ -516,8 +516,8 @@
   // at the end.
   bool isPrecededByParamNameComment(const Expr *E, StringRef ParamName) {
 auto &SM = AST.getSourceManager();
-auto ExprStartLoc = SM.getTopMacroCallerLoc(E->getBeginLoc());
-auto Decomposed = SM.getDecomposedLoc(ExprStartLoc);
+auto FileLoc = SM.getFileLoc(E->getBeginLoc());
+auto Decomposed = SM.getDecomposedLoc(FileLoc);
 if (Decomposed.first != MainFileID)
   return false;
 


Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -1050,9 +1050,15 @@
 void bar() {
   foo(/*param*/42);
   foo( /* param = */ 42);
+#define X 42
+#define Y X
+#define Z(...) Y
+  foo(/*param=*/Z(a));
+  foo($macro[[Z(a)]]);
   foo(/* the answer */$param[[42]]);
 }
   )cpp",
+   ExpectedHint{"param: ", "macro"},
ExpectedHint{"param: ", "param"});
 }
 
Index: clang-tools-extra/clangd/InlayHints.cpp
===
--- clang-tools-extra/clangd/InlayHints.cpp
+++ clang-tools-extra/clangd/InlayHints.cpp
@@ -516,8 +516,8 @@
   // at the end.
   bool isPrecededByParamNameComment(const Expr *E, StringRef ParamName) {
 auto &SM = AST.getSourceManager();
-auto ExprStartLoc = SM.getTopMacroCallerLoc(E->getBeginLoc());
-auto Decomposed = SM.getDecomposedLoc(ExprStartLoc);
+auto FileLoc = SM.getFileLoc(E->getBeginLoc());
+auto Decomposed = SM.getDecomposedLoc(FileLoc);
 if (Decomposed.first != MainFileID)
   return false;
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D144074: [clangd] Hide inlay hints when using a macro as a calling argument that with a param comment

2023-02-26 Thread Younan Zhang via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGcb2d04d41e47: [clangd] Hide inlay hints when using a macro 
as a calling argument that with a… (authored by zyounan).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D144074/new/

https://reviews.llvm.org/D144074

Files:
  clang-tools-extra/clangd/InlayHints.cpp
  clang-tools-extra/clangd/unittests/InlayHintTests.cpp


Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -1050,9 +1050,15 @@
 void bar() {
   foo(/*param*/42);
   foo( /* param = */ 42);
+#define X 42
+#define Y X
+#define Z(...) Y
+  foo(/*param=*/Z(a));
+  foo($macro[[Z(a)]]);
   foo(/* the answer */$param[[42]]);
 }
   )cpp",
+   ExpectedHint{"param: ", "macro"},
ExpectedHint{"param: ", "param"});
 }
 
Index: clang-tools-extra/clangd/InlayHints.cpp
===
--- clang-tools-extra/clangd/InlayHints.cpp
+++ clang-tools-extra/clangd/InlayHints.cpp
@@ -516,8 +516,8 @@
   // at the end.
   bool isPrecededByParamNameComment(const Expr *E, StringRef ParamName) {
 auto &SM = AST.getSourceManager();
-auto ExprStartLoc = SM.getTopMacroCallerLoc(E->getBeginLoc());
-auto Decomposed = SM.getDecomposedLoc(ExprStartLoc);
+auto FileLoc = SM.getFileLoc(E->getBeginLoc());
+auto Decomposed = SM.getDecomposedLoc(FileLoc);
 if (Decomposed.first != MainFileID)
   return false;
 


Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp
===
--- clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -1050,9 +1050,15 @@
 void bar() {
   foo(/*param*/42);
   foo( /* param = */ 42);
+#define X 42
+#define Y X
+#define Z(...) Y
+  foo(/*param=*/Z(a));
+  foo($macro[[Z(a)]]);
   foo(/* the answer */$param[[42]]);
 }
   )cpp",
+   ExpectedHint{"param: ", "macro"},
ExpectedHint{"param: ", "param"});
 }
 
Index: clang-tools-extra/clangd/InlayHints.cpp
===
--- clang-tools-extra/clangd/InlayHints.cpp
+++ clang-tools-extra/clangd/InlayHints.cpp
@@ -516,8 +516,8 @@
   // at the end.
   bool isPrecededByParamNameComment(const Expr *E, StringRef ParamName) {
 auto &SM = AST.getSourceManager();
-auto ExprStartLoc = SM.getTopMacroCallerLoc(E->getBeginLoc());
-auto Decomposed = SM.getDecomposedLoc(ExprStartLoc);
+auto FileLoc = SM.getFileLoc(E->getBeginLoc());
+auto Decomposed = SM.getDecomposedLoc(FileLoc);
 if (Decomposed.first != MainFileID)
   return false;
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D145319: [clangd] Refine logic on $0 in completion snippets

2023-03-05 Thread Younan Zhang via Phabricator via cfe-commits
zyounan created this revision.
Herald added subscribers: kadircet, arphaman.
Herald added a project: All.
zyounan added reviewers: nridge, kadircet.
zyounan published this revision for review.
zyounan added inline comments.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.
Herald added a project: clang-tools-extra.



Comment at: clang-tools-extra/clangd/CodeCompletionStrings.cpp:130
+  return false;
+return true;
+  }();

I was cringed that if we should refine the logic based on `CursorKind`: It is 
from libclang; The meaning is sometimes kind of opaque (to me, I don't know it 
very clearly TBH) like `CXCursor_NotImplemented`...


We have a workaround from D128621  that makes 
$0 no longer being
a placeholder to conform a vscode feature. However, we have to
refine the logic as it may suppress the last parameter placeholder
for constructor of base class because not all patterns of completion
are compound statements.

This fixes clangd/clangd#1479


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D145319

Files:
  clang-tools-extra/clangd/CodeComplete.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.h
  clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp

Index: clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
===
--- clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -3450,6 +3450,22 @@
   EXPECT_THAT(Results.Completions,
   Contains(AllOf(named("while_foo"),
  snippetSuffix("(${1:int a}, ${2:int b})";
+
+  Results = completions(R"cpp(
+struct Base {
+  Base(int a, int b) {}
+};
+
+struct Derived : Base {
+  Derived() : Base^
+};
+  )cpp",
+/*IndexSymbols=*/{}, Options);
+  // Constructors from base classes are a kind of pattern that shouldn't end
+  // with $0.
+  EXPECT_THAT(Results.Completions,
+  Contains(AllOf(named("Base"),
+ snippetSuffix("(${1:int a}, ${2:int b})";
 }
 
 TEST(CompletionTest, WorksWithNullType) {
Index: clang-tools-extra/clangd/CodeCompletionStrings.h
===
--- clang-tools-extra/clangd/CodeCompletionStrings.h
+++ clang-tools-extra/clangd/CodeCompletionStrings.h
@@ -47,7 +47,8 @@
 void getSignature(const CodeCompletionString &CCS, std::string *Signature,
   std::string *Snippet,
   std::string *RequiredQualifiers = nullptr,
-  bool CompletingPattern = false);
+  bool CompletingPattern = false,
+  const CodeCompletionResult *CCR = nullptr);
 
 /// Assembles formatted documentation for a completion result. This includes
 /// documentation comments and other relevant information like annotations.
Index: clang-tools-extra/clangd/CodeCompletionStrings.cpp
===
--- clang-tools-extra/clangd/CodeCompletionStrings.cpp
+++ clang-tools-extra/clangd/CodeCompletionStrings.cpp
@@ -7,6 +7,7 @@
 //===--===//
 
 #include "CodeCompletionStrings.h"
+#include "clang-c/Index.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/RawCommentList.h"
 #include "clang/Basic/SourceManager.h"
@@ -96,7 +97,7 @@
 
 void getSignature(const CodeCompletionString &CCS, std::string *Signature,
   std::string *Snippet, std::string *RequiredQualifiers,
-  bool CompletingPattern) {
+  bool CompletingPattern, const CodeCompletionResult *CCR) {
   // Placeholder with this index will be ${0:…} to mark final cursor position.
   // Usually we do not add $0, so the cursor is placed at end of completed text.
   unsigned CursorSnippetArg = std::numeric_limits::max();
@@ -111,6 +112,23 @@
   return C.Kind == CodeCompletionString::CK_Placeholder;
 });
   }
+  // If the result kind of CCR is `RK_Pattern`, it doesn't always mean we're
+  // completing a chunk of statements.  Constructors defined in base class, for
+  // example, are considered as a type of pattern, with the cursor type set to
+  // CXCursor_Constructor.
+  // We have to discriminate these cases manually in order to avoid providing
+  // incorrect placeholder `$0` which should have been a normal parameter.
+  bool ShouldPatchPlaceholder0 = CompletingPattern && [CCR] {
+if (!CCR)
+  return true;
+// The process of CCR construction employs `clang::getCursorKindForDecl` to
+// obtain cursor kind for Decls, otherwise CursorKind would be set by
+// constructor. Note that the default value is CXCursor_NotImplemented.
+if (CCR->CursorKind == CXCursorKind::CXCursor_Constructor ||

[PATCH] D145319: [clangd] Refine logic on $0 in completion snippets

2023-03-09 Thread Younan Zhang via Phabricator via cfe-commits
zyounan added a comment.

Ping :)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145319/new/

https://reviews.llvm.org/D145319

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D145319: [clangd] Refine logic on $0 in completion snippets

2023-03-13 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 504947.
zyounan marked 3 inline comments as done.
zyounan added a comment.

Address the comments. Revise parameters of `getSignature` to avoid passing CCR


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145319/new/

https://reviews.llvm.org/D145319

Files:
  clang-tools-extra/clangd/CodeComplete.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.h
  clang-tools-extra/clangd/index/SymbolCollector.cpp
  clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
  clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp

Index: clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
===
--- clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
+++ clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
@@ -27,8 +27,16 @@
 bool CompletingPattern = false) {
 Signature.clear();
 Snippet.clear();
-getSignature(CCS, &Signature, &Snippet, /*RequiredQualifier=*/nullptr,
- CompletingPattern);
+// Note that `getSignature` uses CursorKind to identify if we shouldn't
+// complete $0 for certain patterns, such as constructors. Passing
+// CXCursor_NotImplemented to circumvent that logic, thus the behavior of
+// this function matches that before https://reviews.llvm.org/D145319.
+getSignature(CCS, &Signature, &Snippet,
+ CompletingPattern
+ ? CodeCompletionResult::ResultKind::RK_Pattern
+ : CodeCompletionResult::ResultKind::RK_Declaration,
+ CXCursorKind::CXCursor_NotImplemented,
+ /*RequiredQualifiers=*/nullptr);
   }
 
   std::shared_ptr Allocator;
Index: clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
===
--- clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -3450,6 +3450,22 @@
   EXPECT_THAT(Results.Completions,
   Contains(AllOf(named("while_foo"),
  snippetSuffix("(${1:int a}, ${2:int b})";
+
+  Results = completions(R"cpp(
+struct Base {
+  Base(int a, int b) {}
+};
+
+struct Derived : Base {
+  Derived() : Base^
+};
+  )cpp",
+/*IndexSymbols=*/{}, Options);
+  // Constructors from base classes are a kind of pattern that shouldn't end
+  // with $0.
+  EXPECT_THAT(Results.Completions,
+  Contains(AllOf(named("Base"),
+ snippetSuffix("(${1:int a}, ${2:int b})";
 }
 
 TEST(CompletionTest, WorksWithNullType) {
Index: clang-tools-extra/clangd/index/SymbolCollector.cpp
===
--- clang-tools-extra/clangd/index/SymbolCollector.cpp
+++ clang-tools-extra/clangd/index/SymbolCollector.cpp
@@ -756,7 +756,8 @@
   *PP, *CompletionAllocator, *CompletionTUInfo);
   std::string Signature;
   std::string SnippetSuffix;
-  getSignature(*CCS, &Signature, &SnippetSuffix);
+  getSignature(*CCS, &Signature, &SnippetSuffix, SymbolCompletion.Kind,
+   SymbolCompletion.CursorKind);
   S.Signature = Signature;
   S.CompletionSnippetSuffix = SnippetSuffix;
 
@@ -933,7 +934,8 @@
   S.Documentation = Documentation;
   std::string Signature;
   std::string SnippetSuffix;
-  getSignature(*CCS, &Signature, &SnippetSuffix);
+  getSignature(*CCS, &Signature, &SnippetSuffix, SymbolCompletion.Kind,
+   SymbolCompletion.CursorKind);
   S.Signature = Signature;
   S.CompletionSnippetSuffix = SnippetSuffix;
   std::string ReturnType = getReturnType(*CCS);
Index: clang-tools-extra/clangd/CodeCompletionStrings.h
===
--- clang-tools-extra/clangd/CodeCompletionStrings.h
+++ clang-tools-extra/clangd/CodeCompletionStrings.h
@@ -46,8 +46,9 @@
 /// ${0:…}, indicating the cursor should stay there.
 void getSignature(const CodeCompletionString &CCS, std::string *Signature,
   std::string *Snippet,
-  std::string *RequiredQualifiers = nullptr,
-  bool CompletingPattern = false);
+  CodeCompletionResult::ResultKind ResultKind,
+  CXCursorKind CursorKind,
+  std::string *RequiredQualifiers = nullptr);
 
 /// Assembles formatted documentation for a completion result. This includes
 /// documentation comments and other relevant information like annotations.
Index: clang-tools-extra/clangd/CodeCompletionStrings.cpp
===
--- clang-tools-extra/clangd/CodeCompletionStrings.cpp
+++ clang-tools-extra/clangd/CodeCompletionStrings.cpp
@@ -7,6 +7,7 @@
 //===-

[PATCH] D145319: [clangd] Refine logic on $0 in completion snippets

2023-03-13 Thread Younan Zhang via Phabricator via cfe-commits
zyounan added inline comments.



Comment at: clang-tools-extra/clangd/CodeComplete.cpp:441
   getSignature(*SemaCCS, &S.Signature, &S.SnippetSuffix,
-   &Completion.RequiredQualifier, IsPattern);
+   &Completion.RequiredQualifier, IsPattern, C.SemaResult);
   if (!C.SemaResult->FunctionCanBeCall)

nridge wrote:
> Since we are now passing in the entire `C.SemaResult`, can we remove the 
> `CompletingPattern` parameter, and compute that boolean inside the function 
> instead?
Revise the parameters of `getSignature` to circumvent CCR now -- Tests for 
CodeCompletionStrings do not construct any CCR and I don't think it necessary 
to add that logic.



Comment at: clang-tools-extra/clangd/CodeCompletionStrings.cpp:104
   unsigned CursorSnippetArg = std::numeric_limits::max();
   if (CompletingPattern) {
 // In patterns, it's best to place the cursor at the last placeholder, to

nridge wrote:
> Can we move this check after the declaration of `ShouldPatchPlaceholder0`, 
> and change the condition to `if (ShouldPatchPlaceholder0)`?
> 
> (And at the usage site, swap the operands to `if (ShouldPatchPlaceholder0 && 
> SnippetArg == CursorSnippetArg)`?)
> 
> This would avoid doing the count_if when not necessary.
Nice catch! thanks!



Comment at: clang-tools-extra/clangd/CodeCompletionStrings.cpp:130
+  return false;
+return true;
+  }();

nridge wrote:
> zyounan wrote:
> > I was cringed that if we should refine the logic based on `CursorKind`: It 
> > is from libclang; The meaning is sometimes kind of opaque (to me, I don't 
> > know it very clearly TBH) like `CXCursor_NotImplemented`...
> It does seem like a layering violation that a libSema interface 
> (CodeCompletionResult) uses a libclang type (CXCursorKind), but that's a 
> pre-existing issue.
> It does seem like a layering violation that a libSema interface 
> (CodeCompletionResult) uses a libclang type (CXCursorKind), but that's a 
> pre-existing issue.





Comment at: clang-tools-extra/clangd/CodeCompletionStrings.cpp:130
+  return false;
+return true;
+  }();

zyounan wrote:
> nridge wrote:
> > zyounan wrote:
> > > I was cringed that if we should refine the logic based on `CursorKind`: 
> > > It is from libclang; The meaning is sometimes kind of opaque (to me, I 
> > > don't know it very clearly TBH) like `CXCursor_NotImplemented`...
> > It does seem like a layering violation that a libSema interface 
> > (CodeCompletionResult) uses a libclang type (CXCursorKind), but that's a 
> > pre-existing issue.
> > It does seem like a layering violation that a libSema interface 
> > (CodeCompletionResult) uses a libclang type (CXCursorKind), but that's a 
> > pre-existing issue.
> 
> 
Thanks for clarifying.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145319/new/

https://reviews.llvm.org/D145319

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D145319: [clangd] Refine logic on $0 in completion snippets

2023-03-13 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 504950.
zyounan added a comment.

Update doxygen comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145319/new/

https://reviews.llvm.org/D145319

Files:
  clang-tools-extra/clangd/CodeComplete.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.h
  clang-tools-extra/clangd/index/SymbolCollector.cpp
  clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
  clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp

Index: clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
===
--- clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
+++ clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
@@ -27,8 +27,16 @@
 bool CompletingPattern = false) {
 Signature.clear();
 Snippet.clear();
-getSignature(CCS, &Signature, &Snippet, /*RequiredQualifier=*/nullptr,
- CompletingPattern);
+// Note that `getSignature` uses CursorKind to identify if we shouldn't
+// complete $0 for certain patterns, such as constructors. Passing
+// CXCursor_NotImplemented to circumvent that logic, thus the behavior of
+// this function matches that before https://reviews.llvm.org/D145319.
+getSignature(CCS, &Signature, &Snippet,
+ CompletingPattern
+ ? CodeCompletionResult::ResultKind::RK_Pattern
+ : CodeCompletionResult::ResultKind::RK_Declaration,
+ CXCursorKind::CXCursor_NotImplemented,
+ /*RequiredQualifiers=*/nullptr);
   }
 
   std::shared_ptr Allocator;
Index: clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
===
--- clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -3450,6 +3450,22 @@
   EXPECT_THAT(Results.Completions,
   Contains(AllOf(named("while_foo"),
  snippetSuffix("(${1:int a}, ${2:int b})";
+
+  Results = completions(R"cpp(
+struct Base {
+  Base(int a, int b) {}
+};
+
+struct Derived : Base {
+  Derived() : Base^
+};
+  )cpp",
+/*IndexSymbols=*/{}, Options);
+  // Constructors from base classes are a kind of pattern that shouldn't end
+  // with $0.
+  EXPECT_THAT(Results.Completions,
+  Contains(AllOf(named("Base"),
+ snippetSuffix("(${1:int a}, ${2:int b})";
 }
 
 TEST(CompletionTest, WorksWithNullType) {
Index: clang-tools-extra/clangd/index/SymbolCollector.cpp
===
--- clang-tools-extra/clangd/index/SymbolCollector.cpp
+++ clang-tools-extra/clangd/index/SymbolCollector.cpp
@@ -756,7 +756,8 @@
   *PP, *CompletionAllocator, *CompletionTUInfo);
   std::string Signature;
   std::string SnippetSuffix;
-  getSignature(*CCS, &Signature, &SnippetSuffix);
+  getSignature(*CCS, &Signature, &SnippetSuffix, SymbolCompletion.Kind,
+   SymbolCompletion.CursorKind);
   S.Signature = Signature;
   S.CompletionSnippetSuffix = SnippetSuffix;
 
@@ -933,7 +934,8 @@
   S.Documentation = Documentation;
   std::string Signature;
   std::string SnippetSuffix;
-  getSignature(*CCS, &Signature, &SnippetSuffix);
+  getSignature(*CCS, &Signature, &SnippetSuffix, SymbolCompletion.Kind,
+   SymbolCompletion.CursorKind);
   S.Signature = Signature;
   S.CompletionSnippetSuffix = SnippetSuffix;
   std::string ReturnType = getReturnType(*CCS);
Index: clang-tools-extra/clangd/CodeCompletionStrings.h
===
--- clang-tools-extra/clangd/CodeCompletionStrings.h
+++ clang-tools-extra/clangd/CodeCompletionStrings.h
@@ -42,12 +42,15 @@
 /// If set, RequiredQualifiers is the text that must be typed before the name.
 /// e.g "Base::" when calling a base class member function that's hidden.
 ///
-/// When \p CompletingPattern is true, the last placeholder will be of the form
-/// ${0:…}, indicating the cursor should stay there.
+/// When \p ResultKind is RK_Pattern, the last placeholder will be $0,
+/// indicating the cursor should stay there.
+/// Note that for certain \p CursorKind like \p CXCursor_Constructor, $0 won't
+/// be emitted in order to avoid overlapping normal parameters.
 void getSignature(const CodeCompletionString &CCS, std::string *Signature,
   std::string *Snippet,
-  std::string *RequiredQualifiers = nullptr,
-  bool CompletingPattern = false);
+  CodeCompletionResult::ResultKind ResultKind,
+  CXCursorKind CursorKind,
+  std::string *RequiredQualifiers = nullptr);
 
 /// Assembles formatted documentation for a 

[PATCH] D145319: [clangd] Refine logic on $0 in completion snippets

2023-03-13 Thread Younan Zhang via Phabricator via cfe-commits
zyounan added inline comments.



Comment at: clang-tools-extra/clangd/CodeCompletionStrings.h:45
 ///
 /// When \p CompletingPattern is true, the last placeholder will be of the form
 /// ${0:…}, indicating the cursor should stay there.

Sorry, I forget to revise the comments :(


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145319/new/

https://reviews.llvm.org/D145319

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D153724: [clang] Fix a crash on invalid destructor

2023-06-25 Thread Younan Zhang via Phabricator via cfe-commits
zyounan created this revision.
zyounan added reviewers: royjacobson, aaron.ballman, erichkeane, shafik.
Herald added a project: All.
zyounan requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

This is a follow-up patch to D126194  in 
order to
fix https://github.com/llvm/llvm-project/issues/63503.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D153724

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/test/SemaCXX/virtuals.cpp


Index: clang/test/SemaCXX/virtuals.cpp
===
--- clang/test/SemaCXX/virtuals.cpp
+++ clang/test/SemaCXX/virtuals.cpp
@@ -52,6 +52,19 @@
   };
 }
 
+namespace issue63503 {
+struct Base {
+  virtual ~Base() = default;
+};
+
+struct Derived final : Base {
+  using Base::Base;
+  virtual ~Derived() = defaul; // #62
+} do_not_crash;
+// expected-error@#62 {{initializer on function does not look like a 
pure-specifier}}
+// expected-error@#62 {{use of undeclared identifier 'defaul'}}
+}
+
 namespace VirtualFriend {
   // DR (filed but no number yet): reject meaningless pure-specifier on a 
friend declaration.
   struct A { virtual int f(); };
Index: clang/lib/Sema/SemaDeclCXX.cpp
===
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -15807,7 +15807,11 @@
 return;
 
   CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl);
-
+  // The result of `LookupDestructor` might be nullptr if the destructor is
+  // invalid, in which case it is not marked as `IsEligibleOrSelected` and
+  // will not be selected by `CXXRecordDecl::getDestructor()`.
+  if (!Destructor)
+return;
   // If this is an array, we'll require the destructor during initialization, 
so
   // we can skip over this. We still want to emit exit-time destructor warnings
   // though.
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -521,21 +521,23 @@
   (`#50534 `_).
 - CallExpr built for C error-recovery now is always type-dependent. Fixes a
   crash when we encounter a unresolved TypoExpr during diagnostic emission.
-  (`#50244 _`).
+  (`#50244 `_).
 - Apply ``-fmacro-prefix-map`` to anonymous tags in template arguments
   (`#63219 `_).
 - Clang now properly diagnoses format string mismatches involving scoped
   enumeration types. A scoped enumeration type is not promoted to an integer
   type by the default argument promotions, and thus this is UB. Clang's
   behavior now matches GCC's behavior in C++.
-  (`#38717 _`).
+  (`#38717 `_).
 - Fixed a failing assertion when implicitly defining a function within a GNU
   statement expression that appears outside of a function block scope. The
   assertion was benign outside of asserts builds and would only fire in C.
-  (`#48579 _`).
+  (`#48579 `_).
 - Fixed a failing assertion when applying an attribute to an anonymous union.
   The assertion was benign outside of asserts builds and would only fire in 
C++.
-  (`#48512 _`).
+  (`#48512 `_).
+- Fixed a failing assertion when parsing incomplete destructor.
+  (`#63503 `_)
 
 Bug Fixes to Compiler Builtins
 ^^


Index: clang/test/SemaCXX/virtuals.cpp
===
--- clang/test/SemaCXX/virtuals.cpp
+++ clang/test/SemaCXX/virtuals.cpp
@@ -52,6 +52,19 @@
   };
 }
 
+namespace issue63503 {
+struct Base {
+  virtual ~Base() = default;
+};
+
+struct Derived final : Base {
+  using Base::Base;
+  virtual ~Derived() = defaul; // #62
+} do_not_crash;
+// expected-error@#62 {{initializer on function does not look like a pure-specifier}}
+// expected-error@#62 {{use of undeclared identifier 'defaul'}}
+}
+
 namespace VirtualFriend {
   // DR (filed but no number yet): reject meaningless pure-specifier on a friend declaration.
   struct A { virtual int f(); };
Index: clang/lib/Sema/SemaDeclCXX.cpp
===
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -15807,7 +15807,11 @@
 return;
 
   CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl);
-
+  // The result of `LookupDestructor` might be nullptr if the dest

[PATCH] D153724: [clang] Fix a crash on invalid destructor

2023-06-25 Thread Younan Zhang via Phabricator via cfe-commits
zyounan added inline comments.



Comment at: clang/docs/ReleaseNotes.rst:524
   crash when we encounter a unresolved TypoExpr during diagnostic emission.
-  (`#50244 _`).
+  (`#50244 `_).
 - Apply ``-fmacro-prefix-map`` to anonymous tags in template arguments

These underscores are not placed correctly so I revised them as well. Hope you 
don't mind. :)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D153724/new/

https://reviews.llvm.org/D153724

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D153724: [clang] Fix a crash on invalid destructor

2023-06-25 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 534359.
zyounan added a comment.

And this


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D153724/new/

https://reviews.llvm.org/D153724

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/test/SemaCXX/virtuals.cpp


Index: clang/test/SemaCXX/virtuals.cpp
===
--- clang/test/SemaCXX/virtuals.cpp
+++ clang/test/SemaCXX/virtuals.cpp
@@ -52,6 +52,19 @@
   };
 }
 
+namespace issue63503 {
+struct Base {
+  virtual ~Base() = default;
+};
+
+struct Derived final : Base {
+  using Base::Base;
+  virtual ~Derived() = defaul; // #62
+} do_not_crash;
+// expected-error@#62 {{initializer on function does not look like a 
pure-specifier}}
+// expected-error@#62 {{use of undeclared identifier 'defaul'}}
+}
+
 namespace VirtualFriend {
   // DR (filed but no number yet): reject meaningless pure-specifier on a 
friend declaration.
   struct A { virtual int f(); };
Index: clang/lib/Sema/SemaDeclCXX.cpp
===
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -15807,7 +15807,11 @@
 return;
 
   CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl);
-
+  // The result of `LookupDestructor` might be nullptr if the destructor is
+  // invalid, in which case it is not marked as `IsEligibleOrSelected` and
+  // will not be selected by `CXXRecordDecl::getDestructor()`.
+  if (!Destructor)
+return;
   // If this is an array, we'll require the destructor during initialization, 
so
   // we can skip over this. We still want to emit exit-time destructor warnings
   // though.
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -469,7 +469,7 @@
 - Fix crash when redefining a variable with an invalid type again with an
   invalid type. (`#62447 `_)
 - Fix a stack overflow issue when evaluating ``consteval`` default arguments.
-  (`#60082` `_)
+  (`#60082 `_)
 - Fix the assertion hit when generating code for global variable initializer of
   _BitInt(1) type.
   (`#62207 `_)
@@ -521,21 +521,23 @@
   (`#50534 `_).
 - CallExpr built for C error-recovery now is always type-dependent. Fixes a
   crash when we encounter a unresolved TypoExpr during diagnostic emission.
-  (`#50244 _`).
+  (`#50244 `_).
 - Apply ``-fmacro-prefix-map`` to anonymous tags in template arguments
   (`#63219 `_).
 - Clang now properly diagnoses format string mismatches involving scoped
   enumeration types. A scoped enumeration type is not promoted to an integer
   type by the default argument promotions, and thus this is UB. Clang's
   behavior now matches GCC's behavior in C++.
-  (`#38717 _`).
+  (`#38717 `_).
 - Fixed a failing assertion when implicitly defining a function within a GNU
   statement expression that appears outside of a function block scope. The
   assertion was benign outside of asserts builds and would only fire in C.
-  (`#48579 _`).
+  (`#48579 `_).
 - Fixed a failing assertion when applying an attribute to an anonymous union.
   The assertion was benign outside of asserts builds and would only fire in 
C++.
-  (`#48512 _`).
+  (`#48512 `_).
+- Fixed a failing assertion when parsing incomplete destructor.
+  (`#63503 `_)
 
 Bug Fixes to Compiler Builtins
 ^^


Index: clang/test/SemaCXX/virtuals.cpp
===
--- clang/test/SemaCXX/virtuals.cpp
+++ clang/test/SemaCXX/virtuals.cpp
@@ -52,6 +52,19 @@
   };
 }
 
+namespace issue63503 {
+struct Base {
+  virtual ~Base() = default;
+};
+
+struct Derived final : Base {
+  using Base::Base;
+  virtual ~Derived() = defaul; // #62
+} do_not_crash;
+// expected-error@#62 {{initializer on function does not look like a pure-specifier}}
+// expected-error@#62 {{use of undeclared identifier 'defaul'}}
+}
+
 namespace VirtualFriend {
   // DR (filed but no number yet): reject meaningless pure-specifier on a friend declaration.
   struct A { virtual int f(); };
Index: clang/lib/Sema/SemaDeclC

[PATCH] D153724: [clang] Fix a crash on invalid destructor

2023-06-25 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 534362.
zyounan added a comment.

Typo


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D153724/new/

https://reviews.llvm.org/D153724

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/test/SemaCXX/virtuals.cpp


Index: clang/test/SemaCXX/virtuals.cpp
===
--- clang/test/SemaCXX/virtuals.cpp
+++ clang/test/SemaCXX/virtuals.cpp
@@ -52,6 +52,19 @@
   };
 }
 
+namespace issue63503 {
+struct Base {
+  virtual ~Base() = default;
+};
+
+struct Derived final : Base {
+  using Base::Base;
+  virtual ~Derived() = defaul; // #62
+} do_not_crash;
+// expected-error@#62 {{initializer on function does not look like a 
pure-specifier}}
+// expected-error@#62 {{use of undeclared identifier 'defaul'}}
+}
+
 namespace VirtualFriend {
   // DR (filed but no number yet): reject meaningless pure-specifier on a 
friend declaration.
   struct A { virtual int f(); };
Index: clang/lib/Sema/SemaDeclCXX.cpp
===
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -15807,7 +15807,11 @@
 return;
 
   CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl);
-
+  // The result of `LookupDestructor` might be nullptr if the destructor is
+  // invalid, in which case it is marked as `IneligibleOrNotSelected` and
+  // will not be selected by `CXXRecordDecl::getDestructor()`.
+  if (!Destructor)
+return;
   // If this is an array, we'll require the destructor during initialization, 
so
   // we can skip over this. We still want to emit exit-time destructor warnings
   // though.
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -469,7 +469,7 @@
 - Fix crash when redefining a variable with an invalid type again with an
   invalid type. (`#62447 `_)
 - Fix a stack overflow issue when evaluating ``consteval`` default arguments.
-  (`#60082` `_)
+  (`#60082 `_)
 - Fix the assertion hit when generating code for global variable initializer of
   _BitInt(1) type.
   (`#62207 `_)
@@ -521,21 +521,23 @@
   (`#50534 `_).
 - CallExpr built for C error-recovery now is always type-dependent. Fixes a
   crash when we encounter a unresolved TypoExpr during diagnostic emission.
-  (`#50244 _`).
+  (`#50244 `_).
 - Apply ``-fmacro-prefix-map`` to anonymous tags in template arguments
   (`#63219 `_).
 - Clang now properly diagnoses format string mismatches involving scoped
   enumeration types. A scoped enumeration type is not promoted to an integer
   type by the default argument promotions, and thus this is UB. Clang's
   behavior now matches GCC's behavior in C++.
-  (`#38717 _`).
+  (`#38717 `_).
 - Fixed a failing assertion when implicitly defining a function within a GNU
   statement expression that appears outside of a function block scope. The
   assertion was benign outside of asserts builds and would only fire in C.
-  (`#48579 _`).
+  (`#48579 `_).
 - Fixed a failing assertion when applying an attribute to an anonymous union.
   The assertion was benign outside of asserts builds and would only fire in 
C++.
-  (`#48512 _`).
+  (`#48512 `_).
+- Fixed a failing assertion when parsing incomplete destructor.
+  (`#63503 `_)
 
 Bug Fixes to Compiler Builtins
 ^^


Index: clang/test/SemaCXX/virtuals.cpp
===
--- clang/test/SemaCXX/virtuals.cpp
+++ clang/test/SemaCXX/virtuals.cpp
@@ -52,6 +52,19 @@
   };
 }
 
+namespace issue63503 {
+struct Base {
+  virtual ~Base() = default;
+};
+
+struct Derived final : Base {
+  using Base::Base;
+  virtual ~Derived() = defaul; // #62
+} do_not_crash;
+// expected-error@#62 {{initializer on function does not look like a pure-specifier}}
+// expected-error@#62 {{use of undeclared identifier 'defaul'}}
+}
+
 namespace VirtualFriend {
   // DR (filed but no number yet): reject meaningless pure-specifier on a friend declaration.
   struct A { virtual int f(); };
Index: clang/lib/Sema/SemaDeclCXX.cp

[PATCH] D153724: [clang] Fix a crash on invalid destructor

2023-06-25 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 534386.
zyounan added a comment.

Simplify test case


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D153724/new/

https://reviews.llvm.org/D153724

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/test/SemaCXX/virtuals.cpp


Index: clang/test/SemaCXX/virtuals.cpp
===
--- clang/test/SemaCXX/virtuals.cpp
+++ clang/test/SemaCXX/virtuals.cpp
@@ -52,6 +52,18 @@
   };
 }
 
+namespace issue63503 {
+struct Base {
+  virtual ~Base() = default;
+};
+
+struct Derived final : Base {
+  virtual ~Derived() = defaul; // #62
+} do_not_crash;
+// expected-error@#62 {{initializer on function does not look like a 
pure-specifier}}
+// expected-error@#62 {{use of undeclared identifier 'defaul'}}
+}
+
 namespace VirtualFriend {
   // DR (filed but no number yet): reject meaningless pure-specifier on a 
friend declaration.
   struct A { virtual int f(); };
Index: clang/lib/Sema/SemaDeclCXX.cpp
===
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -15807,7 +15807,11 @@
 return;
 
   CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl);
-
+  // The result of `LookupDestructor` might be nullptr if the destructor is
+  // invalid, in which case it is marked as `IneligibleOrNotSelected` and
+  // will not be selected by `CXXRecordDecl::getDestructor()`.
+  if (!Destructor)
+return;
   // If this is an array, we'll require the destructor during initialization, 
so
   // we can skip over this. We still want to emit exit-time destructor warnings
   // though.
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -469,7 +469,7 @@
 - Fix crash when redefining a variable with an invalid type again with an
   invalid type. (`#62447 `_)
 - Fix a stack overflow issue when evaluating ``consteval`` default arguments.
-  (`#60082` `_)
+  (`#60082 `_)
 - Fix the assertion hit when generating code for global variable initializer of
   _BitInt(1) type.
   (`#62207 `_)
@@ -521,21 +521,23 @@
   (`#50534 `_).
 - CallExpr built for C error-recovery now is always type-dependent. Fixes a
   crash when we encounter a unresolved TypoExpr during diagnostic emission.
-  (`#50244 _`).
+  (`#50244 `_).
 - Apply ``-fmacro-prefix-map`` to anonymous tags in template arguments
   (`#63219 `_).
 - Clang now properly diagnoses format string mismatches involving scoped
   enumeration types. A scoped enumeration type is not promoted to an integer
   type by the default argument promotions, and thus this is UB. Clang's
   behavior now matches GCC's behavior in C++.
-  (`#38717 _`).
+  (`#38717 `_).
 - Fixed a failing assertion when implicitly defining a function within a GNU
   statement expression that appears outside of a function block scope. The
   assertion was benign outside of asserts builds and would only fire in C.
-  (`#48579 _`).
+  (`#48579 `_).
 - Fixed a failing assertion when applying an attribute to an anonymous union.
   The assertion was benign outside of asserts builds and would only fire in 
C++.
-  (`#48512 _`).
+  (`#48512 `_).
+- Fixed a failing assertion when parsing incomplete destructor.
+  (`#63503 `_)
 
 Bug Fixes to Compiler Builtins
 ^^


Index: clang/test/SemaCXX/virtuals.cpp
===
--- clang/test/SemaCXX/virtuals.cpp
+++ clang/test/SemaCXX/virtuals.cpp
@@ -52,6 +52,18 @@
   };
 }
 
+namespace issue63503 {
+struct Base {
+  virtual ~Base() = default;
+};
+
+struct Derived final : Base {
+  virtual ~Derived() = defaul; // #62
+} do_not_crash;
+// expected-error@#62 {{initializer on function does not look like a pure-specifier}}
+// expected-error@#62 {{use of undeclared identifier 'defaul'}}
+}
+
 namespace VirtualFriend {
   // DR (filed but no number yet): reject meaningless pure-specifier on a friend declaration.
   struct A { virtual int f(); };
Index: clang/lib/Sema/SemaDeclCXX.cpp
==

[PATCH] D153724: [clang] Fix a crash on invalid destructor

2023-06-25 Thread Younan Zhang via Phabricator via cfe-commits
zyounan updated this revision to Diff 534387.
zyounan added a comment.

.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D153724/new/

https://reviews.llvm.org/D153724

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/test/SemaCXX/virtuals.cpp


Index: clang/test/SemaCXX/virtuals.cpp
===
--- clang/test/SemaCXX/virtuals.cpp
+++ clang/test/SemaCXX/virtuals.cpp
@@ -52,6 +52,18 @@
   };
 }
 
+namespace issue63503 {
+struct Base {
+  virtual ~Base() = default;
+};
+
+struct Derived final : Base {
+  virtual ~Derived() = defaul; // #default
+} do_not_crash;
+// expected-error@#default {{initializer on function does not look like a 
pure-specifier}}
+// expected-error@#default {{use of undeclared identifier 'defaul'}}
+}
+
 namespace VirtualFriend {
   // DR (filed but no number yet): reject meaningless pure-specifier on a 
friend declaration.
   struct A { virtual int f(); };
Index: clang/lib/Sema/SemaDeclCXX.cpp
===
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -15807,7 +15807,11 @@
 return;
 
   CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl);
-
+  // The result of `LookupDestructor` might be nullptr if the destructor is
+  // invalid, in which case it is marked as `IneligibleOrNotSelected` and
+  // will not be selected by `CXXRecordDecl::getDestructor()`.
+  if (!Destructor)
+return;
   // If this is an array, we'll require the destructor during initialization, 
so
   // we can skip over this. We still want to emit exit-time destructor warnings
   // though.
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -469,7 +469,7 @@
 - Fix crash when redefining a variable with an invalid type again with an
   invalid type. (`#62447 `_)
 - Fix a stack overflow issue when evaluating ``consteval`` default arguments.
-  (`#60082` `_)
+  (`#60082 `_)
 - Fix the assertion hit when generating code for global variable initializer of
   _BitInt(1) type.
   (`#62207 `_)
@@ -521,21 +521,23 @@
   (`#50534 `_).
 - CallExpr built for C error-recovery now is always type-dependent. Fixes a
   crash when we encounter a unresolved TypoExpr during diagnostic emission.
-  (`#50244 _`).
+  (`#50244 `_).
 - Apply ``-fmacro-prefix-map`` to anonymous tags in template arguments
   (`#63219 `_).
 - Clang now properly diagnoses format string mismatches involving scoped
   enumeration types. A scoped enumeration type is not promoted to an integer
   type by the default argument promotions, and thus this is UB. Clang's
   behavior now matches GCC's behavior in C++.
-  (`#38717 _`).
+  (`#38717 `_).
 - Fixed a failing assertion when implicitly defining a function within a GNU
   statement expression that appears outside of a function block scope. The
   assertion was benign outside of asserts builds and would only fire in C.
-  (`#48579 _`).
+  (`#48579 `_).
 - Fixed a failing assertion when applying an attribute to an anonymous union.
   The assertion was benign outside of asserts builds and would only fire in 
C++.
-  (`#48512 _`).
+  (`#48512 `_).
+- Fixed a failing assertion when parsing incomplete destructor.
+  (`#63503 `_)
 
 Bug Fixes to Compiler Builtins
 ^^


Index: clang/test/SemaCXX/virtuals.cpp
===
--- clang/test/SemaCXX/virtuals.cpp
+++ clang/test/SemaCXX/virtuals.cpp
@@ -52,6 +52,18 @@
   };
 }
 
+namespace issue63503 {
+struct Base {
+  virtual ~Base() = default;
+};
+
+struct Derived final : Base {
+  virtual ~Derived() = defaul; // #default
+} do_not_crash;
+// expected-error@#default {{initializer on function does not look like a pure-specifier}}
+// expected-error@#default {{use of undeclared identifier 'defaul'}}
+}
+
 namespace VirtualFriend {
   // DR (filed but no number yet): reject meaningless pure-specifier on a friend declaration.
   struct A { virtual int f(); };
Index: clang/lib/Sema/SemaDeclCXX.cpp
=

  1   2   >