]> granicus.if.org Git - clang/commitdiff
[libclang] Fix cursors for functions with trailing return type
authorIvan Donchevskii <ivan.donchevskii@qt.io>
Wed, 3 Jan 2018 10:04:37 +0000 (10:04 +0000)
committerIvan Donchevskii <ivan.donchevskii@qt.io>
Wed, 3 Jan 2018 10:04:37 +0000 (10:04 +0000)
For the function declaration

auto foo5(Foo) -> Foo;
the parameter tokens were mapped to cursors representing the
FunctionDecl:

Keyword: "auto" [1:1 - 1:5] FunctionDecl=test5:1:6
Identifier: "test5" [1:6 - 1:11] FunctionDecl=test5:1:6
Punctuation: "(" [1:11 - 1:12] FunctionDecl=test5:1:6
Identifier: "X" [1:12 - 1:13] FunctionDecl=test5:1:6 // Ops, not a TypeRef
Punctuation: ")" [1:13 - 1:14] FunctionDecl=test5:1:6
Punctuation: "->" [1:15 - 1:17] FunctionDecl=test5:1:6
Identifier: "X" [1:18 - 1:19] TypeRef=struct X:7:8
Punctuation: ";" [1:19 - 1:20]

Fix this by ensuring that the trailing return type is not visited as
first.

Patch by Nikolai Kosjar.

Differential Revision: https://reviews.llvm.org/D40561

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@321698 91177308-0d34-0410-b5e6-96231b3b80d8

test/Index/annotate-tokens.cpp
tools/libclang/CIndex.cpp

index 460ab51dd9598437bdad295ae1392d013ecf9fd1..f477b964371c8ad8345e4d2cc47fec039e495b77 100644 (file)
@@ -34,13 +34,15 @@ void test4() {
 }
 
 class C {
-  ~C();
-};
-
-// RUN: c-index-test -test-annotate-tokens=%s:1:1:38:1 %s -fno-delayed-template-parsing | FileCheck %s
-// CHECK: Keyword: "struct" [1:1 - 1:7] StructDecl=bonk:1:8 (Definition)
-// CHECK: Identifier: "bonk" [1:8 - 1:12] StructDecl=bonk:1:8 (Definition)
-// CHECK: Punctuation: "{" [1:13 - 1:14] StructDecl=bonk:1:8 (Definition)
+  ~C();\r
+};\r
+\r
+auto test5(X) -> X;\r
+\r
+// RUN: c-index-test -test-annotate-tokens=%s:1:1:41:1 %s -std=c++14 -fno-delayed-template-parsing | FileCheck %s\r
+// CHECK: Keyword: "struct" [1:1 - 1:7] StructDecl=bonk:1:8 (Definition)\r
+// CHECK: Identifier: "bonk" [1:8 - 1:12] StructDecl=bonk:1:8 (Definition)\r
+// CHECK: Punctuation: "{" [1:13 - 1:14] StructDecl=bonk:1:8 (Definition)\r
 // CHECK: Punctuation: "}" [1:15 - 1:16] StructDecl=bonk:1:8 (Definition)
 // CHECK: Punctuation: ";" [1:16 - 1:17]
 // CHECK: Keyword: "void" [2:1 - 2:5] FunctionDecl=test:2:6 (Definition)
@@ -181,12 +183,20 @@ class C {
 // CHECK: Punctuation: "(" [29:18 - 29:19] CXXMethod=foo:29:15 (Definition)
 // CHECK: Punctuation: ")" [29:19 - 29:20] CXXMethod=foo:29:15 (Definition)
 // CHECK: Punctuation: "{" [29:21 - 29:22] CompoundStmt=
-// CHECK: Punctuation: "}" [29:22 - 29:23] CompoundStmt=
-// CHECK: Punctuation: "~" [37:3 - 37:4] CXXDestructor=~C:37:3
-// CHECK: Identifier: "C" [37:4 - 37:5] CXXDestructor=~C:37:3
-
-// RUN: env LIBCLANG_DISABLE_CRASH_RECOVERY=1 c-index-test -test-annotate-tokens=%s:32:1:32:13 %s | FileCheck %s -check-prefix=CHECK2
-// CHECK2: Keyword: "if" [32:3 - 32:5] IfStmt=
+// CHECK: Punctuation: "}" [29:22 - 29:23] CompoundStmt=\r
+// CHECK: Punctuation: "~" [37:3 - 37:4] CXXDestructor=~C:37:3\r
+// CHECK: Identifier: "C" [37:4 - 37:5] CXXDestructor=~C:37:3\r
+// CHECK: Keyword: "auto" [40:1 - 40:5] FunctionDecl=test5:40:6\r
+// CHECK: Identifier: "test5" [40:6 - 40:11] FunctionDecl=test5:40:6\r
+// CHECK: Punctuation: "(" [40:11 - 40:12] FunctionDecl=test5:40:6\r
+// CHECK: Identifier: "X" [40:12 - 40:13] TypeRef=struct X:7:8\r
+// CHECK: Punctuation: ")" [40:13 - 40:14] FunctionDecl=test5:40:6\r
+// CHECK: Punctuation: "->" [40:15 - 40:17] FunctionDecl=test5:40:6\r
+// CHECK: Identifier: "X" [40:18 - 40:19] TypeRef=struct X:7:8\r
+// CHECK: Punctuation: ";" [40:19 - 40:20]\r
+\r
+// RUN: env LIBCLANG_DISABLE_CRASH_RECOVERY=1 c-index-test -test-annotate-tokens=%s:32:1:32:13 %s | FileCheck %s -check-prefix=CHECK2\r
+// CHECK2: Keyword: "if" [32:3 - 32:5] IfStmt=\r
 // CHECK2: Punctuation: "(" [32:6 - 32:7] IfStmt=
 // CHECK2: Keyword: "int" [32:7 - 32:10] VarDecl=p:32:11 (Definition)
 // CHECK2: Identifier: "p" [32:11 - 32:12] VarDecl=p:32:11 (Definition)
index 70bccc7eeaf0bb1c28e5ec340719d336d73af549..f73706dee1a95c5bb14021749cc7fe189ef2548e 100644 (file)
@@ -782,12 +782,22 @@ bool CursorVisitor::VisitDeclaratorDecl(DeclaratorDecl *DD) {
     if (VisitNestedNameSpecifierLoc(QualifierLoc))
       return true;
 
-  return false;
-}
-
-/// \brief Compare two base or member initializers based on their source order.
-static int CompareCXXCtorInitializers(CXXCtorInitializer *const *X,
-                                      CXXCtorInitializer *const *Y) {
+  return false;\r
+}\r
+\r
+static bool HasTrailingReturnType(FunctionDecl *ND) {\r
+  const QualType Ty = ND->getType();\r
+  if (const FunctionType *AFT = Ty->getAs<FunctionType>()) {\r
+    if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(AFT))\r
+      return FT->hasTrailingReturn();\r
+  }\r
+\r
+  return false;\r
+}\r
+\r
+/// \brief Compare two base or member initializers based on their source order.\r
+static int CompareCXXCtorInitializers(CXXCtorInitializer *const *X,\r
+                                      CXXCtorInitializer *const *Y) {\r
   return (*X)->getSourceOrder() - (*Y)->getSourceOrder();
 }
 
@@ -801,20 +811,22 @@ bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) {
 
   if (TypeSourceInfo *TSInfo = ND->getTypeSourceInfo()) {
     // Visit the function declaration's syntactic components in the order
-    // written. This requires a bit of work.
-    TypeLoc TL = TSInfo->getTypeLoc().IgnoreParens();
-    FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>();
-    
-    // If we have a function declared directly (without the use of a typedef),
-    // visit just the return type. Otherwise, just visit the function's type
-    // now.
-    if ((FTL && !isa<CXXConversionDecl>(ND) && Visit(FTL.getReturnLoc())) ||
-        (!FTL && Visit(TL)))
-      return true;
-    
-    // Visit the nested-name-specifier, if present.
-    if (NestedNameSpecifierLoc QualifierLoc = ND->getQualifierLoc())
-      if (VisitNestedNameSpecifierLoc(QualifierLoc))
+    // written. This requires a bit of work.\r
+    TypeLoc TL = TSInfo->getTypeLoc().IgnoreParens();\r
+    FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>();\r
+    const bool HasTrailingRT = HasTrailingReturnType(ND);\r
+    \r
+    // If we have a function declared directly (without the use of a typedef),\r
+    // visit just the return type. Otherwise, just visit the function's type\r
+    // now.\r
+    if ((FTL && !isa<CXXConversionDecl>(ND) && !HasTrailingRT &&\r
+         Visit(FTL.getReturnLoc())) ||\r
+        (!FTL && Visit(TL)))\r
+      return true;\r
+\r
+    // Visit the nested-name-specifier, if present.\r
+    if (NestedNameSpecifierLoc QualifierLoc = ND->getQualifierLoc())\r
+      if (VisitNestedNameSpecifierLoc(QualifierLoc))\r
         return true;
     
     // Visit the declaration name.
@@ -824,13 +836,17 @@ bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) {
     
     // FIXME: Visit explicitly-specified template arguments!
     
-    // Visit the function parameters, if we have a function type.
-    if (FTL && VisitFunctionTypeLoc(FTL, true))
-      return true;
-    
-    // FIXME: Attributes?
-  }
-  
+    // Visit the function parameters, if we have a function type.\r
+    if (FTL && VisitFunctionTypeLoc(FTL, true))\r
+      return true;\r
+\r
+    // Visit the function's trailing return type.\r
+    if (FTL && HasTrailingRT && Visit(FTL.getReturnLoc()))\r
+      return true;\r
+\r
+    // FIXME: Attributes?\r
+  }\r
+  \r
   if (ND->doesThisDeclarationHaveABody() && !ND->isLateTemplateParsed()) {
     if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(ND)) {
       // Find the initializers that were written in the source.