From 5fde33a32955166622f689b974ad6776c4b1559b Mon Sep 17 00:00:00 2001
From: Erik Verbruggen <erik.verbruggen@nokia.com>
Date: Thu, 6 Oct 2011 11:13:16 +0200
Subject: [PATCH] [libclang] Allow for annotate attributes after access
 specifiers. When such attributes are found, propagate them
 to subsequent declarations.

---
 include/clang-c/Index.h                    |    3 +-
 include/clang/Basic/DiagnosticSemaKinds.td |    2 +
 include/clang/Parse/Parser.h               |   18 +++++++++------
 lib/Parse/ParseCXXInlineMethods.cpp        |    7 +++++-
 lib/Parse/ParseDeclCXX.cpp                 |   32 ++++++++++++++++++++------
 lib/Parse/ParseTemplate.cpp                |   17 +++++++++-----
 lib/Sema/SemaDeclAttr.cpp                  |    7 ++++++
 test/Index/annotate-attribute.cpp          |   33 ++++++++++++++++++++++++++++
 tools/libclang/CIndex.cpp                  |    7 ++++++
 tools/libclang/CXCursor.cpp                |    1 +
 10 files changed, 104 insertions(+), 23 deletions(-)
 create mode 100644 test/Index/annotate-attribute.cpp

diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index 9ff04f4..3df1670 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -1830,7 +1830,8 @@ enum CXCursorKind {
   CXCursor_IBOutletCollectionAttr        = 403,
   CXCursor_CXXFinalAttr                  = 404,
   CXCursor_CXXOverrideAttr               = 405,
-  CXCursor_LastAttr                      = CXCursor_CXXOverrideAttr,
+  CXCursor_AnnotateAttr                  = 406,
+  CXCursor_LastAttr                      = CXCursor_AnnotateAttr,
      
   /* Preprocessing */
   CXCursor_PreprocessingDirective        = 500,
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 368bdc3..828fa86 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1359,6 +1359,8 @@ def err_attr_objc_ownership_redundant : Error<
   "the type %0 already has retainment attributes set on it">;
 def err_attribute_not_string : Error<
   "argument to %0 attribute was not a string literal">;
+def err_only_annotate_after_access_spec : Error<
+  "access specifier can only have annotation attributes">;
 def err_attribute_section_invalid_for_target : Error<
   "argument to 'section' attribute is not valid for this target: %0">;
 def err_attribute_section_local_variable : Error<
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index a1f602c..b188b31 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -1047,7 +1047,8 @@ private:
   void DeallocateParsedClasses(ParsingClass *Class);
   void PopParsingClass(Sema::ParsingClassState);
 
-  Decl *ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D,
+  Decl *ParseCXXInlineMethodDef(AccessSpecifier AS, AttributeList *AccessAttrs,
+                                ParsingDeclarator &D,
                                 const ParsedTemplateInfo &TemplateInfo,
                                 const VirtSpecifiers& VS, ExprResult& Init);
   void ParseCXXNonStaticMemberInitializer(Decl *VarD);
@@ -1884,7 +1885,7 @@ private:
                                    Decl *TagDecl);
   ExprResult ParseCXXMemberInitializer(bool IsFunction,
                                        SourceLocation &EqualLoc);
-  void ParseCXXClassMemberDeclaration(AccessSpecifier AS,
+  void ParseCXXClassMemberDeclaration(AccessSpecifier AS, AttributeList *Attr,
                 const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
                                  ParsingDeclRAIIObject *DiagsFromTParams = 0);
   void ParseConstructorInitializer(Decl *ConstructorDecl);
@@ -1920,17 +1921,20 @@ private:
 
   // C++ 14.1: Template Parameters [temp.param]
   Decl *ParseDeclarationStartingWithTemplate(unsigned Context,
-                                                 SourceLocation &DeclEnd,
-                                                 AccessSpecifier AS = AS_none);
+                                             SourceLocation &DeclEnd,
+                                             AccessSpecifier AS = AS_none,
+                                             AttributeList *AccessAttrs = 0);
   Decl *ParseTemplateDeclarationOrSpecialization(unsigned Context,
-                                                     SourceLocation &DeclEnd,
-                                                     AccessSpecifier AS);
+                                                 SourceLocation &DeclEnd,
+                                                 AccessSpecifier AS,
+                                                 AttributeList *AccessAttrs);
   Decl *ParseSingleDeclarationAfterTemplate(
                                        unsigned Context,
                                        const ParsedTemplateInfo &TemplateInfo,
                                        ParsingDeclRAIIObject &DiagsFromParams,
                                        SourceLocation &DeclEnd,
-                                       AccessSpecifier AS=AS_none);
+                                       AccessSpecifier AS=AS_none,
+                                       AttributeList *AccessAttrs = 0);
   bool ParseTemplateParameters(unsigned Depth,
                                SmallVectorImpl<Decl*> &TemplateParams,
                                SourceLocation &LAngleLoc,
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index 40e36f0..e2ff206 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -21,7 +21,9 @@ using namespace clang;
 /// ParseCXXInlineMethodDef - We parsed and verified that the specified
 /// Declarator is a well formed C++ inline method definition. Now lex its body
 /// and store its tokens for parsing after the C++ class is complete.
-Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D,
+Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
+                                      AttributeList *AccessAttrs,
+                                      ParsingDeclarator &D,
                                 const ParsedTemplateInfo &TemplateInfo,
                                 const VirtSpecifiers& VS, ExprResult& Init) {
   assert(D.isFunctionDeclarator() && "This isn't a function declarator!");
@@ -44,6 +46,9 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D,
                                            VS, Init.release(),
                                            /*HasInit=*/false,
                                            /*IsDefinition*/true);
+    if (AccessAttrs)
+      Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs,
+                                       false, true);
   }
 
   HandleMemberFunctionDefaultArgs(D, FnD);
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 1ec6fcb..b486146 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -1589,6 +1589,7 @@ bool Parser::isCXX0XFinalKeyword() const {
 ///         '=' constant-expression
 ///
 void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
+                                            AttributeList *AccessAttrs,
                                        const ParsedTemplateInfo &TemplateInfo,
                                        ParsingDeclRAIIObject *TemplateDiags) {
   if (Tok.is(tok::at)) {
@@ -1655,7 +1656,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
            "Nested template improperly parsed?");
     SourceLocation DeclEnd;
     ParseDeclarationStartingWithTemplate(Declarator::MemberContext, DeclEnd,
-                                         AS);
+                                         AS, AccessAttrs);
     return;
   }
 
@@ -1664,7 +1665,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
     // __extension__ silences extension warnings in the subexpression.
     ExtensionRAIIObject O(Diags);  // Use RAII to do this.
     ConsumeToken();
-    return ParseCXXClassMemberDeclaration(AS, TemplateInfo, TemplateDiags);
+    return ParseCXXClassMemberDeclaration(AS, AccessAttrs,
+                                          TemplateInfo, TemplateDiags);
   }
 
   // Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it
@@ -1795,7 +1797,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
       }
 
       Decl *FunDecl =
-        ParseCXXInlineMethodDef(AS, DeclaratorInfo, TemplateInfo, VS, Init);
+        ParseCXXInlineMethodDef(AS, AccessAttrs, DeclaratorInfo, TemplateInfo,
+                                VS, Init);
 
       for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i) {
         LateParsedAttrs[i]->setDecl(FunDecl);
@@ -1888,6 +1891,9 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
                                                   VS, Init.release(),
                                                   HasDeferredInitializer,
                                                   /*IsDefinition*/ false);
+      if (AccessAttrs)
+        Actions.ProcessDeclAttributeList(getCurScope(), ThisDecl, AccessAttrs,
+                                         false, true);
     }
     if (ThisDecl)
       DeclsInGroup.push_back(ThisDecl);
@@ -2111,6 +2117,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
     CurAS = AS_private;
   else
     CurAS = AS_public;
+  ParsedAttributes AccessAttrs(AttrFactory);
 
   SourceLocation RBraceLoc;
   if (TagDecl) {
@@ -2139,10 +2146,19 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
         CurAS = AS;
         SourceLocation ASLoc = Tok.getLocation();
         ConsumeToken();
-        if (Tok.is(tok::colon))
-          Actions.ActOnAccessSpecifier(AS, ASLoc, Tok.getLocation());
-        else
+
+        AccessAttrs.clear();
+        MaybeParseGNUAttributes(AccessAttrs);
+
+        if (Tok.is(tok::colon)) {
+          Decl *AccessDecl = Actions.ActOnAccessSpecifier(AS, ASLoc,
+                                                          Tok.getLocation());
+          if (AttributeList *Attrs = AccessAttrs.getList())
+            Actions.ProcessDeclAttributeList(Actions.CurScope, AccessDecl,
+                                             Attrs, false, true);
+        } else {
           Diag(Tok, diag::err_expected_colon);
+        }
         ConsumeToken();
         continue;
       }
@@ -2150,7 +2166,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
       // FIXME: Make sure we don't have a template here.
 
       // Parse all the comma separated declarators.
-      ParseCXXClassMemberDeclaration(CurAS);
+      ParseCXXClassMemberDeclaration(CurAS, AccessAttrs.getList());
     }
 
     RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
@@ -2767,7 +2783,7 @@ void Parser::ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType,
     }
 
     // Parse all the comma separated declarators.
-    ParseCXXClassMemberDeclaration(CurAS);
+    ParseCXXClassMemberDeclaration(CurAS, 0);
   }
 
   if (Tok.isNot(tok::r_brace)) {
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 4509662..92fe4a5 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -26,14 +26,16 @@ using namespace clang;
 Decl *
 Parser::ParseDeclarationStartingWithTemplate(unsigned Context,
                                              SourceLocation &DeclEnd,
-                                             AccessSpecifier AS) {
+                                             AccessSpecifier AS,
+                                             AttributeList *AccessAttrs) {
   ObjCDeclContextSwitch ObjCDC(*this);
   
   if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less)) {
     return ParseExplicitInstantiation(SourceLocation(), ConsumeToken(),
                                            DeclEnd);
   }
-  return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AS);
+  return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AS,
+                                                  AccessAttrs);
 }
 
 /// \brief RAII class that manages the template parameter depth.
@@ -77,7 +79,8 @@ namespace {
 Decl *
 Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context,
                                                  SourceLocation &DeclEnd,
-                                                 AccessSpecifier AS) {
+                                                 AccessSpecifier AS,
+                                                 AttributeList *AccessAttrs) {
   assert((Tok.is(tok::kw_export) || Tok.is(tok::kw_template)) &&
          "Token does not start a template declaration.");
 
@@ -161,7 +164,7 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context,
                                                              isSpecialization,
                                                          LastParamListWasEmpty),
                                              ParsingTemplateParams,
-                                             DeclEnd, AS);
+                                             DeclEnd, AS, AccessAttrs);
 }
 
 /// \brief Parse a single declaration that declares a template,
@@ -190,13 +193,15 @@ Parser::ParseSingleDeclarationAfterTemplate(
                                        const ParsedTemplateInfo &TemplateInfo,
                                        ParsingDeclRAIIObject &DiagsFromTParams,
                                        SourceLocation &DeclEnd,
-                                       AccessSpecifier AS) {
+                                       AccessSpecifier AS,
+                                       AttributeList *AccessAttrs) {
   assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
          "Template information required");
 
   if (Context == Declarator::MemberContext) {
     // We are parsing a member template.
-    ParseCXXClassMemberDeclaration(AS, TemplateInfo, &DiagsFromTParams);
+    ParseCXXClassMemberDeclaration(AS, AccessAttrs, TemplateInfo,
+                                   &DiagsFromTParams);
     return 0;
   }
 
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 38c0c4a..a6ba62e 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -3482,6 +3482,13 @@ static void ProcessNonInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
 
 static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
                                        const AttributeList &Attr) {
+  if (isa<AccessSpecDecl>(D) && Attr.getKind() == AttributeList::AT_annotate) {
+    // Annotation attributes are the only attributes allowed after an access
+    // specifier.
+    S.Diag(Attr.getLoc(), diag::err_only_annotate_after_access_spec);
+    return;
+  }
+
   switch (Attr.getKind()) {
   case AttributeList::AT_IBAction:            handleIBAction(S, D, Attr); break;
     case AttributeList::AT_IBOutlet:          handleIBOutlet(S, D, Attr); break;
diff --git a/test/Index/annotate-attribute.cpp b/test/Index/annotate-attribute.cpp
new file mode 100644
index 0000000..6721371
--- /dev/null
+++ b/test/Index/annotate-attribute.cpp
@@ -0,0 +1,33 @@
+// RUN: c-index-test -test-load-source all %s | FileCheck %s
+
+class Test {
+public:
+  __attribute__((annotate("spiffy_method"))) void aMethod();
+
+public __attribute__((annotate("works"))):
+  void anotherMethod(); // annotation attribute should be propagated.
+
+private __attribute__((annotate("investigations"))):
+  //propagated annotation should have changed from "works" to "investigations"
+  void inlineMethod() {}
+
+protected:
+  // attribute propagation should have stopped here
+  void methodWithoutAttribute();
+};
+
+// CHECK: ClassDecl=Test:3:7 (Definition) Extent=[3:1 - 17:2]
+// CHECK: CXXAccessSpecifier=:4:1 (Definition) Extent=[4:1 - 4:8]
+// CHECK: CXXMethod=aMethod:5:51 Extent=[5:3 - 5:60]
+// CHECK: attribute(annotate)=spiffy_method Extent=[5:18 - 5:43]
+// CHECK: CXXAccessSpecifier=:7:1 (Definition) Extent=[7:1 - 7:43]
+// CHECK: attribute(annotate)=works Extent=[7:23 - 7:40]
+// CHECK: CXXMethod=anotherMethod:8:8 Extent=[8:3 - 8:23]
+// CHECK: attribute(annotate)=works Extent=[7:23 - 7:40]
+// CHECK: CXXAccessSpecifier=:10:1 (Definition) Extent=[10:1 - 10:53]
+// CHECK: attribute(annotate)=investigations Extent=[10:24 - 10:50]
+// CHECK: CXXMethod=inlineMethod:12:8 (Definition) Extent=[12:3 - 12:25]
+// CHECK: attribute(annotate)=investigations Extent=[10:24 - 10:50]
+// CHECK: CompoundStmt= Extent=[12:23 - 12:25]
+// CHECK: CXXAccessSpecifier=:14:1 (Definition) Extent=[14:1 - 14:11]
+// CHECK: CXXMethod=methodWithoutAttribute:16:8 Extent=[16:3 - 16:32]
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 4610ae3..7badeab 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -3198,6 +3198,11 @@ CXString clang_getCursorSpelling(CXCursor C) {
   if (clang_isDeclaration(C.kind))
     return getDeclSpelling(getCursorDecl(C));
 
+  if (C.kind == CXCursor_AnnotateAttr) {
+    AnnotateAttr *AA = cast<AnnotateAttr>(cxcursor::getCursorAttr(C));
+    return createCXString(AA->getAnnotation());
+  }
+
   return createCXString("");
 }
 
@@ -3519,6 +3524,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
       return createCXString("attribute(final)");
   case CXCursor_CXXOverrideAttr:
       return createCXString("attribute(override)");
+  case CXCursor_AnnotateAttr:
+    return createCXString("attribute(annotate)");
   case CXCursor_PreprocessingDirective:
     return createCXString("preprocessing directive");
   case CXCursor_MacroDefinition:
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index 16aea6f..ce26e3a 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -45,6 +45,7 @@ static CXCursorKind GetCursorKind(const Attr *A) {
     case attr::IBOutletCollection: return CXCursor_IBOutletCollectionAttr;
     case attr::Final: return CXCursor_CXXFinalAttr;
     case attr::Override: return CXCursor_CXXOverrideAttr;
+    case attr::Annotate: return CXCursor_AnnotateAttr;
   }
 
   return CXCursor_UnexposedAttr;
-- 
1.7.4.4

