Index: include/clang/AST/CommentCommandTraits.h =================================================================== --- include/clang/AST/CommentCommandTraits.h (revision 174067) +++ include/clang/AST/CommentCommandTraits.h (working copy) @@ -96,6 +96,9 @@ /// \fn void f(int a); /// \endcode unsigned IsDeclarationCommand : 1; + + /// \brief True if this is a \headerfile documentation + unsigned IsHeaderfileCommand : 1; /// \brief True if this command is unknown. This \c CommandInfo object was /// created during parsing. Index: include/clang/AST/CommentCommands.td =================================================================== --- include/clang/AST/CommentCommands.td (revision 174067) +++ include/clang/AST/CommentCommands.td (working copy) @@ -19,6 +19,7 @@ bit IsVerbatimBlockEndCommand = 0; bit IsVerbatimLineCommand = 0; bit IsDeclarationCommand = 0; + bit IsHeaderfileCommand = 0; } class InlineCommand : Command { @@ -72,6 +73,7 @@ // Doxygen def Tparam : BlockCommand<"tparam"> { let IsTParamCommand = 1; } +def Headerfile : BlockCommand<"headerfile"> { let IsHeaderfileCommand = 1; } // HeaderDoc def Templatefield : BlockCommand<"templatefield"> { let IsTParamCommand = 1; } Index: include/clang/AST/CommentSema.h =================================================================== --- include/clang/AST/CommentSema.h (revision 174067) +++ include/clang/AST/CommentSema.h (working copy) @@ -60,6 +60,9 @@ /// AST node for the \\returns command and its aliases. const BlockCommandComment *ReturnsCommand; + + /// AST node for the \\headerfile command. + const BlockCommandComment *HeaderfileCommand; DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) { return Diags.Report(Loc, DiagID); Index: lib/AST/CommentSema.cpp =================================================================== --- lib/AST/CommentSema.cpp (revision 174067) +++ lib/AST/CommentSema.cpp (working copy) @@ -29,7 +29,8 @@ DiagnosticsEngine &Diags, CommandTraits &Traits, const Preprocessor *PP) : Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits), - PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), ReturnsCommand(NULL) { + PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), ReturnsCommand(NULL), + HeaderfileCommand(NULL){ } void Sema::setDecl(const Decl *D) { @@ -485,6 +486,12 @@ return; } PrevCommand = ReturnsCommand; + } else if (Info->IsHeaderfileCommand) { + if (!HeaderfileCommand) { + HeaderfileCommand = Command; + return; + } + PrevCommand = HeaderfileCommand; } else { // We don't want to check this command for duplicates. return; Index: test/Index/headerfile-comment-to-html.m =================================================================== --- test/Index/headerfile-comment-to-html.m (revision 0) +++ test/Index/headerfile-comment-to-html.m (working copy) @@ -0,0 +1,81 @@ +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: c-index-test -test-load-source all -comments-xml-schema=%S/../../bindings/xml/comment-xml-schema.rng %s > %t/out +// RUN: FileCheck %s < %t/out +// rdar://13067629 + +// Ensure that XML we generate is not invalid. +// RUN: FileCheck %s -check-prefix=WRONG < %t/out +// WRONG-NOT: CommentXMLInvalid + +// rdar://12397511 + +/*! + \headerfile Device.h + + A Device represents a remote or local computer or device with which the Developer Tools can interact. Each Device supports blah blah blah from doing blah blah blah. +*/ +@interface Device +@end +// CHECK: headerfile-comment-to-html.m:[[@LINE-2]]:12: ObjCInterfaceDecl=Device:{{.*}} FullCommentAsXML=[Devicec:objc(cs)Device@interface Device\n@end Device.h <Foundation/Device.h> A Device represents a remote or local computer or device with which the Developer Tools can interact. Each Device supports blah blah blah from doing blah blah blah.] CommentXMLValid +// CHECK-NEXT: CommentAST=[ +// CHECK-NEXT: (CXComment_FullComment +// CHECK-NEXT: (CXComment_Paragraph IsWhitespace +// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)) +// CHECK-NEXT: (CXComment_BlockCommand CommandName=[headerfile] +// CHECK-NEXT: (CXComment_Paragraph +// CHECK-NEXT: (CXComment_Text Text=[ Device.h ]) +// CHECK-NEXT: (CXComment_Text Text=[]))) +// CHECK-NEXT: (CXComment_Paragraph +// CHECK-NEXT: (CXComment_Text Text=[ A Device represents a remote or local computer or device with which the Developer Tools can interact. Each Device supports blah blah blah from doing blah blah blah.])))] + +/*! + \headerfile Sensor.h "Sensor.h" + + \brief This is Sensor on the Device. + Its purpose is not to Sense Device's heat. +*/ + +@interface Sensor +@end +// CHECK: headerfile-comment-to-html.m:[[@LINE-2]]:12: ObjCInterfaceDecl=Sensor:{{.*}} FullCommentAsXML=[Sensorc:objc(cs)Sensor@interface Sensor\n@end Sensor.h "Sensor.h" This is Sensor on the Device. Its purpose is not to Sense Device's heat.] CommentXMLValid +// CHECK-NEXT: CommentAST=[ +// CHECK-NEXT: (CXComment_FullComment +// CHECK-NEXT: (CXComment_Paragraph IsWhitespace +// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)) +// CHECK-NEXT: (CXComment_BlockCommand CommandName=[headerfile] +// CHECK-NEXT: (CXComment_Paragraph +// CHECK-NEXT: (CXComment_Text Text=[ Sensor.h "Sensor.h"]))) +// CHECK-NEXT: (CXComment_Paragraph IsWhitespace +// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)) +// CHECK-NEXT: (CXComment_BlockCommand CommandName=[brief] +// CHECK-NEXT: (CXComment_Paragraph +// CHECK-NEXT: (CXComment_Text Text=[ This is Sensor on the Device.] HasTrailingNewline) +// CHECK-NEXT: (CXComment_Text Text=[ Its purpose is not to Sense Device's heat.]))))] + +/*! + \brief Test that headerfile can come after brief. + \headerfile VTDevice.h + + More property decription goes here. +*/ +@interface VTDevice : Device +@end +// CHECK: headerfile-comment-to-html.m:[[@LINE-2]]:12: ObjCInterfaceDecl=VTDevice:{{.*}} FullCommentAsXML=[VTDevicec:objc(cs)VTDevice@interface VTDevice : Device\n@end VTDevice.h <VTFoundation/VTDevice.h> Test that headerfile can come after brief. More property decription goes here.] CommentXMLValid +// CHECK-NEXT: CommentAST=[ +// CHECK-NEXT: (CXComment_FullComment +// CHECK-NEXT: (CXComment_Paragraph IsWhitespace +// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)) +// CHECK-NEXT: (CXComment_BlockCommand CommandName=[brief] +// CHECK-NEXT: (CXComment_Paragraph +// CHECK-NEXT: (CXComment_Text Text=[ Test that headerfile can come after brief.] HasTrailingNewline) +// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))) +// CHECK-NEXT: (CXComment_BlockCommand CommandName=[headerfile] +// CHECK-NEXT: (CXComment_Paragraph +// CHECK-NEXT: (CXComment_Text Text=[ VTDevice.h ]) +// CHECK-NEXT: (CXComment_Text Text=[]))) +// CHECK-NEXT: (CXComment_Paragraph +// CHECK-NEXT: (CXComment_Text Text=[ More property decription goes here.])))] + Index: tools/libclang/CXComment.cpp =================================================================== --- tools/libclang/CXComment.cpp (revision 174067) +++ tools/libclang/CXComment.cpp (working copy) @@ -411,6 +411,7 @@ const CommandTraits &Traits); const BlockContentComment *Brief; + const BlockContentComment *Headerfile; const ParagraphComment *FirstParagraph; const BlockCommandComment *Returns; SmallVector Params; @@ -420,7 +421,7 @@ FullCommentParts::FullCommentParts(const FullComment *C, const CommandTraits &Traits) : - Brief(NULL), FirstParagraph(NULL), Returns(NULL) { + Brief(NULL), Headerfile(NULL), FirstParagraph(NULL), Returns(NULL) { for (Comment::child_iterator I = C->child_begin(), E = C->child_end(); I != E; ++I) { const Comment *Child = *I; @@ -448,6 +449,10 @@ Brief = BCC; break; } + if (!Headerfile && Info->IsHeaderfileCommand) { + Headerfile = BCC; + break; + } if (!Returns && Info->IsReturnsCommand) { Returns = BCC; break; @@ -750,6 +755,8 @@ FullCommentParts Parts(C, Traits); bool FirstParagraphIsBrief = false; + if (Parts.Headerfile) + visit(Parts.Headerfile); if (Parts.Brief) visit(Parts.Brief); else if (Parts.FirstParagraph) { @@ -1217,15 +1224,19 @@ bool FirstParagraphIsBrief = false; if (Parts.Brief) { Result << ""; + if (Parts.Headerfile) + visit(Parts.Headerfile); visit(Parts.Brief); Result << ""; } else if (Parts.FirstParagraph) { Result << ""; + if (Parts.Headerfile) + visit(Parts.Headerfile); visit(Parts.FirstParagraph); Result << ""; FirstParagraphIsBrief = true; } - + if (Parts.TParams.size() != 0) { Result << ""; for (unsigned i = 0, e = Parts.TParams.size(); i != e; ++i) Index: utils/TableGen/ClangCommentCommandInfoEmitter.cpp =================================================================== --- utils/TableGen/ClangCommentCommandInfoEmitter.cpp (revision 174067) +++ utils/TableGen/ClangCommentCommandInfoEmitter.cpp (working copy) @@ -46,6 +46,7 @@ << Tag.getValueAsBit("IsVerbatimBlockEndCommand") << ", " << Tag.getValueAsBit("IsVerbatimLineCommand") << ", " << Tag.getValueAsBit("IsDeclarationCommand") << ", " + << Tag.getValueAsBit("IsHeaderfileCommand") << ", " << /* IsUnknownCommand = */ "0" << " }"; if (i + 1 != e)