[PATCH] D51311: (WIP) Type hierarchy

2018-08-29 Thread Simon Marchi via Phabricator via cfe-commits
simark added inline comments.



Comment at: clangd/Protocol.h:891
+
+  std::vector Parents;
+

ilya-biryukov wrote:
> What is the proposal to add children (i.e. overriden methods) to the 
> hierarchy?
> This seems like a place where we might want to have multiple requests from 
> the clients when expanding the nodes.
In my prototype, I fetch the whole parent hierarchy in a single request.  In 
the proposal at

  https://github.com/Microsoft/vscode-languageserver-node/pull/346

it has been suggested to only fetch one level at the time, and have the client 
issue as many request as it wants (until possibly getting the whole hierarchy). 
 I don't know what the protocol will end up like. 



Comment at: clangd/ProtocolHandlers.cpp:70
   Register("textDocument/hover", ::onHover);
+  Register("textDocument/typeHierarchy", ::onTypeHierarchy);
   Register("textDocument/documentSymbol", 
::onDocumentSymbol);

kadircet wrote:
> LSP doesn't have such an entry, maybe we should use [[ 
> https://microsoft.github.io/language-server-protocol/specification#workspace_executeCommand
>  | workspace/executeCommand ]]. WDYT @ilya-biryukov 
I don't intend to merge this patch before the protocol actually defines the way 
to get type hierarchy.  So this will be updated to reflect what the protocol 
will actually define.



Comment at: clangd/XRefs.cpp:669
+  const CXXMethodDecl *Candidate) {
+  // FIXME: How do I determine if Method overrides Candidate?
+

ilya-biryukov wrote:
> kadircet wrote:
> > ilya-biryukov wrote:
> > > simark wrote:
> > > > kadircet wrote:
> > > > > https://github.com/llvm-mirror/clang/blob/master/lib/Sema/SemaDecl.cpp
> > > > > 
> > > > > you can check this sample, which simply traverses all base classes 
> > > > > and gets methods with the same name, then checks whether one is 
> > > > > overload of the other. If it they are not overloads then one in the 
> > > > > base classes gets overriden by the other.
> > > > > 
> > > > > 
> > > > > Another approach could be to search for one method in others 
> > > > > overriden_methods.
> > > > > 
> > > > > But they are both inefficient, I would suggest calling these 
> > > > > functions only when one of them is defined in the base class of other 
> > > > > then you can just check for name equality and not being an overload.
> > > > > https://github.com/llvm-mirror/clang/blob/master/lib/Sema/SemaDecl.cpp
> > > > 
> > > > Did you mean to link to a particular line?
> > > > 
> > > > > you can check this sample, which simply traverses all base classes 
> > > > > and gets methods with the same name, then checks whether one is 
> > > > > overload of the other. If it they are not overloads then one in the 
> > > > > base classes gets overriden by the other.
> > > > 
> > > > > Another approach could be to search for one method in others 
> > > > > overriden_methods.
> > > > 
> > > > I have tried using `overriden_methods`, but it only contains methods 
> > > > marked virtual.  For this feature, I would like to consider non-virtual 
> > > > methods too.
> > > > 
> > > > > But they are both inefficient, I would suggest calling these 
> > > > > functions only when one of them is defined in the base class of other 
> > > > > then you can just check for name equality and not being an overload.
> > > > 
> > > > I am not sure I understand, but maybe it will be clearer when I will 
> > > > see the sample.
> > > See the code that actually computes a list for `override_methods()`: 
> > > Sema::AddOverriddenMethods.
> > > Did you mean to link to a particular line?
> > 
> > 
> > Yeah sorry, I was trying to link the function ilya mentioned.
> > https://github.com/llvm-mirror/clang/blob/master/lib/Sema/SemaDecl.cpp#L7615
> > 
> > Since you also mentioned checking non-virtual method as well you might 
> > wanna look at 
> > https://github.com/llvm-mirror/clang/blob/master/lib/Sema/SemaDecl.cpp#L7555
> >  as well.
> > 
> > Also I got the chance to look the rest of the patch, as I mentioned above 
> > you are already checking two methods iff one lies in the others base 
> > classes. So you can simply check for name equality and not being an 
> > overload case.
> Also wanted to bring up what @sammccall already mentioned on clangd-dev: we 
> probably shouldn't show methods that hide base methods rather than override 
> the virtual base methods (at least, by default).
> 
> Those might be useful, but unless we can have a clear UI indicator of whether 
> a method is overriding a virtual base method or is hiding some other method, 
> it would to add more confusion than benefit IMO.
> Also I got the chance to look the rest of the patch, as I mentioned above you 
> are already checking two methods iff one lies in the others base classes. So 
> you can simply check for name equality and not being an overload case.

To check for an overload case, you would use `Sema::IsOverload`?  

[PATCH] D51311: (WIP) Type hierarchy

2018-08-29 Thread Ilya Biryukov via Phabricator via cfe-commits
ilya-biryukov added a subscriber: sammccall.
ilya-biryukov added inline comments.



Comment at: clangd/XRefs.cpp:669
+  const CXXMethodDecl *Candidate) {
+  // FIXME: How do I determine if Method overrides Candidate?
+

kadircet wrote:
> ilya-biryukov wrote:
> > simark wrote:
> > > kadircet wrote:
> > > > https://github.com/llvm-mirror/clang/blob/master/lib/Sema/SemaDecl.cpp
> > > > 
> > > > you can check this sample, which simply traverses all base classes and 
> > > > gets methods with the same name, then checks whether one is overload of 
> > > > the other. If it they are not overloads then one in the base classes 
> > > > gets overriden by the other.
> > > > 
> > > > 
> > > > Another approach could be to search for one method in others 
> > > > overriden_methods.
> > > > 
> > > > But they are both inefficient, I would suggest calling these functions 
> > > > only when one of them is defined in the base class of other then you 
> > > > can just check for name equality and not being an overload.
> > > > https://github.com/llvm-mirror/clang/blob/master/lib/Sema/SemaDecl.cpp
> > > 
> > > Did you mean to link to a particular line?
> > > 
> > > > you can check this sample, which simply traverses all base classes and 
> > > > gets methods with the same name, then checks whether one is overload of 
> > > > the other. If it they are not overloads then one in the base classes 
> > > > gets overriden by the other.
> > > 
> > > > Another approach could be to search for one method in others 
> > > > overriden_methods.
> > > 
> > > I have tried using `overriden_methods`, but it only contains methods 
> > > marked virtual.  For this feature, I would like to consider non-virtual 
> > > methods too.
> > > 
> > > > But they are both inefficient, I would suggest calling these functions 
> > > > only when one of them is defined in the base class of other then you 
> > > > can just check for name equality and not being an overload.
> > > 
> > > I am not sure I understand, but maybe it will be clearer when I will see 
> > > the sample.
> > See the code that actually computes a list for `override_methods()`: 
> > Sema::AddOverriddenMethods.
> > Did you mean to link to a particular line?
> 
> 
> Yeah sorry, I was trying to link the function ilya mentioned.
> https://github.com/llvm-mirror/clang/blob/master/lib/Sema/SemaDecl.cpp#L7615
> 
> Since you also mentioned checking non-virtual method as well you might wanna 
> look at 
> https://github.com/llvm-mirror/clang/blob/master/lib/Sema/SemaDecl.cpp#L7555 
> as well.
> 
> Also I got the chance to look the rest of the patch, as I mentioned above you 
> are already checking two methods iff one lies in the others base classes. So 
> you can simply check for name equality and not being an overload case.
Also wanted to bring up what @sammccall already mentioned on clangd-dev: we 
probably shouldn't show methods that hide base methods rather than override the 
virtual base methods (at least, by default).

Those might be useful, but unless we can have a clear UI indicator of whether a 
method is overriding a virtual base method or is hiding some other method, it 
would to add more confusion than benefit IMO.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D51311



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


[PATCH] D51311: (WIP) Type hierarchy

2018-08-28 Thread Kadir Cetinkaya via Phabricator via cfe-commits
kadircet added inline comments.



Comment at: clangd/ProtocolHandlers.cpp:70
   Register("textDocument/hover", ::onHover);
+  Register("textDocument/typeHierarchy", ::onTypeHierarchy);
   Register("textDocument/documentSymbol", 
::onDocumentSymbol);

LSP doesn't have such an entry, maybe we should use [[ 
https://microsoft.github.io/language-server-protocol/specification#workspace_executeCommand
 | workspace/executeCommand ]]. WDYT @ilya-biryukov 



Comment at: clangd/XRefs.cpp:669
+  const CXXMethodDecl *Candidate) {
+  // FIXME: How do I determine if Method overrides Candidate?
+

ilya-biryukov wrote:
> simark wrote:
> > kadircet wrote:
> > > https://github.com/llvm-mirror/clang/blob/master/lib/Sema/SemaDecl.cpp
> > > 
> > > you can check this sample, which simply traverses all base classes and 
> > > gets methods with the same name, then checks whether one is overload of 
> > > the other. If it they are not overloads then one in the base classes gets 
> > > overriden by the other.
> > > 
> > > 
> > > Another approach could be to search for one method in others 
> > > overriden_methods.
> > > 
> > > But they are both inefficient, I would suggest calling these functions 
> > > only when one of them is defined in the base class of other then you can 
> > > just check for name equality and not being an overload.
> > > https://github.com/llvm-mirror/clang/blob/master/lib/Sema/SemaDecl.cpp
> > 
> > Did you mean to link to a particular line?
> > 
> > > you can check this sample, which simply traverses all base classes and 
> > > gets methods with the same name, then checks whether one is overload of 
> > > the other. If it they are not overloads then one in the base classes gets 
> > > overriden by the other.
> > 
> > > Another approach could be to search for one method in others 
> > > overriden_methods.
> > 
> > I have tried using `overriden_methods`, but it only contains methods marked 
> > virtual.  For this feature, I would like to consider non-virtual methods 
> > too.
> > 
> > > But they are both inefficient, I would suggest calling these functions 
> > > only when one of them is defined in the base class of other then you can 
> > > just check for name equality and not being an overload.
> > 
> > I am not sure I understand, but maybe it will be clearer when I will see 
> > the sample.
> See the code that actually computes a list for `override_methods()`: 
> Sema::AddOverriddenMethods.
> Did you mean to link to a particular line?


Yeah sorry, I was trying to link the function ilya mentioned.
https://github.com/llvm-mirror/clang/blob/master/lib/Sema/SemaDecl.cpp#L7615

Since you also mentioned checking non-virtual method as well you might wanna 
look at 
https://github.com/llvm-mirror/clang/blob/master/lib/Sema/SemaDecl.cpp#L7555 as 
well.

Also I got the chance to look the rest of the patch, as I mentioned above you 
are already checking two methods iff one lies in the others base classes. So 
you can simply check for name equality and not being an overload case.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D51311



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


[PATCH] D51311: (WIP) Type hierarchy

2018-08-28 Thread Ilya Biryukov via Phabricator via cfe-commits
ilya-biryukov added a comment.

Thanks for looking into this. Would be cool to get this supported after the 
proposal is finalized.




Comment at: clangd/Protocol.h:891
+
+  std::vector Parents;
+

What is the proposal to add children (i.e. overriden methods) to the hierarchy?
This seems like a place where we might want to have multiple requests from the 
clients when expanding the nodes.



Comment at: clangd/XRefs.cpp:669
+  const CXXMethodDecl *Candidate) {
+  // FIXME: How do I determine if Method overrides Candidate?
+

simark wrote:
> kadircet wrote:
> > https://github.com/llvm-mirror/clang/blob/master/lib/Sema/SemaDecl.cpp
> > 
> > you can check this sample, which simply traverses all base classes and gets 
> > methods with the same name, then checks whether one is overload of the 
> > other. If it they are not overloads then one in the base classes gets 
> > overriden by the other.
> > 
> > 
> > Another approach could be to search for one method in others 
> > overriden_methods.
> > 
> > But they are both inefficient, I would suggest calling these functions only 
> > when one of them is defined in the base class of other then you can just 
> > check for name equality and not being an overload.
> > https://github.com/llvm-mirror/clang/blob/master/lib/Sema/SemaDecl.cpp
> 
> Did you mean to link to a particular line?
> 
> > you can check this sample, which simply traverses all base classes and gets 
> > methods with the same name, then checks whether one is overload of the 
> > other. If it they are not overloads then one in the base classes gets 
> > overriden by the other.
> 
> > Another approach could be to search for one method in others 
> > overriden_methods.
> 
> I have tried using `overriden_methods`, but it only contains methods marked 
> virtual.  For this feature, I would like to consider non-virtual methods too.
> 
> > But they are both inefficient, I would suggest calling these functions only 
> > when one of them is defined in the base class of other then you can just 
> > check for name equality and not being an overload.
> 
> I am not sure I understand, but maybe it will be clearer when I will see the 
> sample.
See the code that actually computes a list for `override_methods()`: 
Sema::AddOverriddenMethods.



Comment at: clangd/XRefs.cpp:732
+// If this is a variable, use the type of the variable.
+CXXRD = VD->getType().getTypePtr()->getAsCXXRecordDecl();
+  } else if (Method) {

Why special-case the variables? Maybe just return empty results for consistency 
with other use-cases (typedefs, etc)?



Comment at: clangd/XRefs.cpp:741
+  if (CXXRD)
+return getTypeHierarchy(CXXRD, Method, SourceMgr);
+

Maybe also return all base types for classes?


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D51311



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


[PATCH] D51311: (WIP) Type hierarchy

2018-08-28 Thread Simon Marchi via Phabricator via cfe-commits
simark added inline comments.



Comment at: clangd/Protocol.h:889
+  // Does this node implement the method targeted by the request?
+  bool DeclaresMethod;
+

kadircet wrote:
> I think comment and the name is in contradiction here, do you mean 
> DefinesMethod?
Actually I think the comment is wrong.  Even if we only see a declaration of 
the method, it's enough to say that this type has its own version of the method.



Comment at: clangd/XRefs.cpp:669
+  const CXXMethodDecl *Candidate) {
+  // FIXME: How do I determine if Method overrides Candidate?
+

kadircet wrote:
> https://github.com/llvm-mirror/clang/blob/master/lib/Sema/SemaDecl.cpp
> 
> you can check this sample, which simply traverses all base classes and gets 
> methods with the same name, then checks whether one is overload of the other. 
> If it they are not overloads then one in the base classes gets overriden by 
> the other.
> 
> 
> Another approach could be to search for one method in others 
> overriden_methods.
> 
> But they are both inefficient, I would suggest calling these functions only 
> when one of them is defined in the base class of other then you can just 
> check for name equality and not being an overload.
> https://github.com/llvm-mirror/clang/blob/master/lib/Sema/SemaDecl.cpp

Did you mean to link to a particular line?

> you can check this sample, which simply traverses all base classes and gets 
> methods with the same name, then checks whether one is overload of the other. 
> If it they are not overloads then one in the base classes gets overriden by 
> the other.

> Another approach could be to search for one method in others 
> overriden_methods.

I have tried using `overriden_methods`, but it only contains methods marked 
virtual.  For this feature, I would like to consider non-virtual methods too.

> But they are both inefficient, I would suggest calling these functions only 
> when one of them is defined in the base class of other then you can just 
> check for name equality and not being an overload.

I am not sure I understand, but maybe it will be clearer when I will see the 
sample.



Comment at: clangd/XRefs.cpp:693
+
+std::cerr << " >>> A parent is " << ParentDecl->getName().str()
+  << std::endl;

kadircet wrote:
> If you plan to keep it for later debugging info, consider using {d,v}log
Yes of course :)


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D51311



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


[PATCH] D51311: (WIP) Type hierarchy

2018-08-27 Thread Kadir Cetinkaya via Phabricator via cfe-commits
kadircet added inline comments.



Comment at: clangd/Protocol.h:889
+  // Does this node implement the method targeted by the request?
+  bool DeclaresMethod;
+

I think comment and the name is in contradiction here, do you mean 
DefinesMethod?



Comment at: clangd/XRefs.cpp:669
+  const CXXMethodDecl *Candidate) {
+  // FIXME: How do I determine if Method overrides Candidate?
+

https://github.com/llvm-mirror/clang/blob/master/lib/Sema/SemaDecl.cpp

you can check this sample, which simply traverses all base classes and gets 
methods with the same name, then checks whether one is overload of the other. 
If it they are not overloads then one in the base classes gets overriden by the 
other.


Another approach could be to search for one method in others overriden_methods.

But they are both inefficient, I would suggest calling these functions only 
when one of them is defined in the base class of other then you can just check 
for name equality and not being an overload.



Comment at: clangd/XRefs.cpp:693
+
+std::cerr << " >>> A parent is " << ParentDecl->getName().str()
+  << std::endl;

If you plan to keep it for later debugging info, consider using {d,v}log



Comment at: unittests/clangd/XRefsTests.cpp:1075
+$ParentDef^struct Parent
+{
+  int a;

NIT: Maybe format test code as well.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D51311



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


[PATCH] D51311: (WIP) Type hierarchy

2018-08-27 Thread Simon Marchi via Phabricator via cfe-commits
simark created this revision.
Herald added subscribers: cfe-commits, kadircet, arphaman, jkorous, ioeric, 
ilya-biryukov.

This is a work in progress patch to support an eventual "get type
hierarchy" request that does not exist in the LSP today.  I only plan to
support getting parent types (i.e. base classes) for now, because it
doesn't require touching the index.  Finding child classes would come
later.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D51311

Files:
  clangd/ClangdLSPServer.cpp
  clangd/ClangdLSPServer.h
  clangd/ClangdServer.cpp
  clangd/ClangdServer.h
  clangd/Protocol.cpp
  clangd/Protocol.h
  clangd/ProtocolHandlers.cpp
  clangd/ProtocolHandlers.h
  clangd/XRefs.cpp
  clangd/XRefs.h
  unittests/clangd/XRefsTests.cpp

Index: unittests/clangd/XRefsTests.cpp
===
--- unittests/clangd/XRefsTests.cpp
+++ unittests/clangd/XRefsTests.cpp
@@ -27,6 +27,7 @@
 
 namespace {
 using testing::ElementsAre;
+using testing::Eq;
 using testing::Field;
 using testing::IsEmpty;
 using testing::Matcher;
@@ -1068,6 +1069,166 @@
   ElementsAre(Location{FooCppUri, FooWithoutHeader.range()}));
 }
 
+TEST(TypeHierarchy, SimpleInheritanceOnTypeOrVariable) {
+  Annotations Source(R"cpp(
+$ParentDef^struct Parent
+{
+  int a;
+};
+
+$Child1Def^struct Child1 : Parent
+{
+  int b;
+};
+
+struct Ch$p1^ild2 : Child1
+{
+  int c;
+};
+
+struct Child3 : Child2
+{
+  int d;
+};
+
+int main()
+{
+  Ch$p2^ild2 ch$p3^ild2;
+
+  parent.a = 1;
+  ch$p4^ild2.c = 1;
+}
+)cpp");
+
+  TestTU TU = TestTU::withCode(Source.code());
+  auto AST = TU.build();
+
+  llvm::Optional Result;
+
+  TypeHierarchy ExpectedResult{{TypeHierarchyResult{
+  "Child1",
+  Source.point("Child1Def"),
+  false,
+  {TypeHierarchyResult{"Parent", Source.point("ParentDef"), false, {}};
+
+  for (auto Pt : {"p1", "p2", "p3", "p4"}) {
+Result = getTypeHierarchy(AST, Source.point(Pt));
+ASSERT_TRUE(bool(Result));
+EXPECT_THAT(*Result, Eq(ExpectedResult));
+  }
+}
+
+TEST(TypeHierarchy, MultipleInheritanceOnTypeOrVariable) {
+  Annotations Source(R"cpp(
+$Parent1Def^struct Parent1
+{
+  int a;
+};
+
+$Parent2Def^struct Parent2
+{
+  int b;
+};
+
+$Parent3Def^struct Parent3 : Parent2
+{
+  int c;
+};
+
+struct Ch$c1^ild : Parent1, Parent3
+{
+  int d;
+};
+
+int main()
+{
+  Ch$c2^ild  ch$c3^ild;
+
+  ch$c4^ild.a = 1;
+}
+)cpp");
+
+  TestTU TU = TestTU::withCode(Source.code());
+  auto AST = TU.build();
+
+  llvm::Optional Result;
+  TypeHierarchy ExpectedResult{{
+  TypeHierarchyResult{"Parent1", Source.point("Parent1Def"), false, {}},
+  TypeHierarchyResult{
+  "Parent3",
+  Source.point("Parent3Def"),
+  false,
+  {TypeHierarchyResult{
+  "Parent2", Source.point("Parent2Def"), false, {,
+  }};
+
+  for (auto Pt : {"c1", "c2", "c3", "c4"}) {
+Result = getTypeHierarchy(AST, Source.point(Pt));
+ASSERT_TRUE(bool(Result));
+EXPECT_THAT(*Result, Eq(ExpectedResult));
+  }
+}
+
+TEST(TypeHierarchy, OnMethod) {
+  Annotations Source(R"cpp(
+$ParentDef^struct Parent
+{
+  void method ();
+  void method () const;
+  void method (int x);
+  void method (char x);
+};
+
+$Child1Def^struct Child1 : Parent
+{
+  void method ();
+  void method (char x);
+};
+
+struct Child2 : Child1
+{
+  void met$p1^hod ();
+  void met$p2^hod (int x);
+};
+
+struct Child3 : Child2
+{
+  void method (int x);
+};
+)cpp");
+
+  TestTU TU = TestTU::withCode(Source.code());
+  auto AST = TU.build();
+
+  ASSERT_TRUE(AST.getDiagnostics().empty());
+
+  {
+TypeHierarchy ExpectedResult{{TypeHierarchyResult{
+"Child1",
+Source.point("Child1Def"),
+true,
+{TypeHierarchyResult{"Parent", Source.point("ParentDef"), true, {}};
+
+llvm::Optional Result =
+getTypeHierarchy(AST, Source.point("p1"));
+ASSERT_TRUE(bool(Result));
+EXPECT_THAT(*Result, Eq(ExpectedResult));
+  }
+
+  {
+TypeHierarchy ExpectedResult{{TypeHierarchyResult{
+"Child1",
+Source.point("Child1Def"),
+false,
+{TypeHierarchyResult{"Parent", Source.point("ParentDef"), true, {}};
+
+llvm::Optional Result =
+getTypeHierarchy(AST, Source.point("p2"));
+ASSERT_TRUE(bool(Result));
+EXPECT_THAT(*Result, Eq(ExpectedResult));
+  }
+}
+
 } // namespace
 } // namespace clangd
 } // namespace clang
Index: clangd/XRefs.h
===
--- clangd/XRefs.h
+++ clangd/XRefs.h
@@ -34,6 +34,9 @@
 /// Get the hover information when hovering at \p Pos.
 llvm::Optional getHover(ParsedAST , Position Pos);
 
+/// Get the type hierarchy information at \p Pos.
+llvm::Optional getTypeHierarchy(ParsedAST , Position Pos);
+
 } // namespace clangd
 } // namespace clang
 
Index: clangd/XRefs.cpp
===
--- clangd/XRefs.cpp
+++ clangd/XRefs.cpp
@@ -17,6