summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFariborz Jahanian <fjahanian@apple.com>2013-01-31 23:12:39 +0000
committerFariborz Jahanian <fjahanian@apple.com>2013-01-31 23:12:39 +0000
commitf843a580c4a54ca147f22422ee8ccfd2347784fc (patch)
tree03d1aa2095d446d3b4a7142b5314788c145efbab
parent0217b1d045ea99fe792e83ed1a785816289dd53c (diff)
downloadclang-f843a580c4a54ca147f22422ee8ccfd2347784fc.tar.gz
clang-f843a580c4a54ca147f22422ee8ccfd2347784fc.tar.bz2
clang-f843a580c4a54ca147f22422ee8ccfd2347784fc.tar.xz
[Comment parsing] Add support for recognizing
\headerfile command and representing it in an xml document. Patch reviewed by Dmitri Gribenko. // rdar://12397511 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@174109 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--bindings/xml/comment-xml-schema.rng29
-rw-r--r--include/clang/AST/CommentCommandTraits.h3
-rw-r--r--include/clang/AST/CommentCommands.td3
-rw-r--r--include/clang/AST/CommentSema.h3
-rw-r--r--lib/AST/CommentSema.cpp9
-rw-r--r--test/Index/headerfile-comment-to-html.m111
-rw-r--r--test/Sema/warn-documentation.cpp8
-rw-r--r--tools/libclang/CXComment.cpp17
-rw-r--r--utils/TableGen/ClangCommentCommandInfoEmitter.cpp1
9 files changed, 180 insertions, 4 deletions
diff --git a/bindings/xml/comment-xml-schema.rng b/bindings/xml/comment-xml-schema.rng
index d98f405cf9..ed221c60f8 100644
--- a/bindings/xml/comment-xml-schema.rng
+++ b/bindings/xml/comment-xml-schema.rng
@@ -25,6 +25,9 @@
<ref name="USR" />
</optional>
<optional>
+ <ref name="Headerfile" />
+ </optional>
+ <optional>
<ref name="Declaration" />
</optional>
<optional>
@@ -74,6 +77,9 @@
</optional>
<!-- TODO: Add exception specification. -->
<optional>
+ <ref name="Headerfile" />
+ </optional>
+ <optional>
<ref name="Declaration" />
</optional>
<optional>
@@ -121,6 +127,9 @@
<ref name="USR" />
</optional>
<optional>
+ <ref name="Headerfile" />
+ </optional>
+ <optional>
<ref name="Declaration" />
</optional>
<optional>
@@ -153,6 +162,9 @@
<ref name="USR" />
</optional>
<optional>
+ <ref name="Headerfile" />
+ </optional>
+ <optional>
<ref name="Declaration" />
</optional>
<optional>
@@ -186,6 +198,9 @@
<ref name="USR" />
</optional>
<optional>
+ <ref name="Headerfile" />
+ </optional>
+ <optional>
<ref name="Declaration" />
</optional>
<optional>
@@ -219,6 +234,9 @@
<ref name="USR" />
</optional>
<optional>
+ <ref name="Headerfile" />
+ </optional>
+ <optional>
<ref name="Declaration" />
</optional>
<optional>
@@ -252,6 +270,9 @@
<ref name="USR" />
</optional>
<optional>
+ <ref name="Headerfile" />
+ </optional>
+ <optional>
<ref name="Declaration" />
</optional>
<optional>
@@ -329,6 +350,14 @@
</element>
</define>
+ <define name="Headerfile">
+ <element name="Headerfile">
+ <oneOrMore>
+ <ref name="TextBlockContent" />
+ </oneOrMore>
+ </element>
+ </define>
+
<define name="Discussion">
<element name="Discussion">
<zeroOrMore>
diff --git a/include/clang/AST/CommentCommandTraits.h b/include/clang/AST/CommentCommandTraits.h
index 3e04726b43..44876a534d 100644
--- a/include/clang/AST/CommentCommandTraits.h
+++ b/include/clang/AST/CommentCommandTraits.h
@@ -68,6 +68,9 @@ struct CommandInfo {
/// True if this command is \\deprecated or an alias.
unsigned IsDeprecatedCommand : 1;
+
+ /// \brief True if this is a \headerfile-like documentation
+ unsigned IsHeaderfileCommand : 1;
/// True if we don't want to warn about this command being passed an empty
/// paragraph. Meaningful only for block commands.
diff --git a/include/clang/AST/CommentCommands.td b/include/clang/AST/CommentCommands.td
index 3d8bad89c2..ce051a069d 100644
--- a/include/clang/AST/CommentCommands.td
+++ b/include/clang/AST/CommentCommands.td
@@ -12,6 +12,7 @@ class Command<string name> {
bit IsParamCommand = 0;
bit IsTParamCommand = 0;
bit IsDeprecatedCommand = 0;
+ bit IsHeaderfileCommand = 0;
bit IsEmptyParagraphAllowed = 0;
@@ -80,7 +81,7 @@ def Deprecated : BlockCommand<"deprecated"> {
let IsEmptyParagraphAllowed = 1;
let IsDeprecatedCommand = 1;
}
-
+def Headerfile : BlockCommand<"headerfile"> { let IsHeaderfileCommand = 1; }
def Author : BlockCommand<"author">;
def Authors : BlockCommand<"authors">;
def Bug : BlockCommand<"bug">;
diff --git a/include/clang/AST/CommentSema.h b/include/clang/AST/CommentSema.h
index 58cb5d7cfb..97099bfe63 100644
--- a/include/clang/AST/CommentSema.h
+++ b/include/clang/AST/CommentSema.h
@@ -60,6 +60,9 @@ class Sema {
/// 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);
diff --git a/lib/AST/CommentSema.cpp b/lib/AST/CommentSema.cpp
index 590429809b..fd2b5b1810 100644
--- a/lib/AST/CommentSema.cpp
+++ b/lib/AST/CommentSema.cpp
@@ -29,7 +29,8 @@ Sema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr,
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 @@ void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) {
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;
diff --git a/test/Index/headerfile-comment-to-html.m b/test/Index/headerfile-comment-to-html.m
new file mode 100644
index 0000000000..f2e55f07f8
--- /dev/null
+++ b/test/Index/headerfile-comment-to-html.m
@@ -0,0 +1,111 @@
+// 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 <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.
+*/
+@interface Device
+@end
+// CHECK: headerfile-comment-to-html.m:[[@LINE-2]]:12: ObjCInterfaceDecl=Device:{{.*}} FullCommentAsXML=[<Other file="{{[^"]+}}headerfile-comment-to-html.m" line="[[@LINE-2]]" column="12"><Name>Device</Name><USR>c:objc(cs)Device</USR><Headerfile><Para> Device.h &lt;Foundation/Device.h&gt;</Para></Headerfile><Declaration>@interface Device\n@end</Declaration><Abstract><Para> 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.</Para></Abstract></Other>] 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=[<Foundation])
+// CHECK-NEXT: (CXComment_Text Text=[/Device.h>])))
+// 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=[<Other file="{{[^"]+}}headerfile-comment-to-html.m" line="[[@LINE-2]]" column="12"><Name>Sensor</Name><USR>c:objc(cs)Sensor</USR><Headerfile><Para> Sensor.h &quot;Sensor.h&quot;</Para></Headerfile><Declaration>@interface Sensor\n@end</Declaration><Abstract><Para> This is Sensor on the Device. Its purpose is not to Sense Device&apos;s heat.</Para></Abstract></Other>] 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 <VTFoundation/VTDevice.h>
+
+ More property decription goes here.
+*/
+@interface VTDevice : Device
+@end
+// CHECK: headerfile-comment-to-html.m:[[@LINE-2]]:12: ObjCInterfaceDecl=VTDevice:{{.*}} FullCommentAsXML=[<Other file="{{[^"]+}}headerfile-comment-to-html.m" line="[[@LINE-2]]" column="12"><Name>VTDevice</Name><USR>c:objc(cs)VTDevice</USR><Headerfile><Para> VTDevice.h &lt;VTFoundation/VTDevice.h&gt;</Para></Headerfile><Declaration>@interface VTDevice : Device\n@end</Declaration><Abstract><Para> Test that headerfile can come after brief. </Para></Abstract><Discussion><Para> More property decription goes here.</Para></Discussion></Other>] 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=[<VTFoundation])
+// CHECK-NEXT: (CXComment_Text Text=[/VTDevice.h>])))
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ More property decription goes here.])))]
+
+/*!
+ \headerfile <stdio.h>
+*/
+extern void uses_stdio_h();
+// CHECK: headerfile-comment-to-html.m:[[@LINE-1]]:13: FunctionDecl=uses_stdio_h:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}headerfile-comment-to-html.m" line="[[@LINE-1]]" column="13"><Name>uses_stdio_h</Name><USR>c:@F@uses_stdio_h</USR><Headerfile><Para> &lt;stdio.h&gt;</Para></Headerfile><Declaration>extern void uses_stdio_h()</Declaration></Function>] 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=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_Text Text=[<stdio])
+// CHECK-NEXT: (CXComment_Text Text=[.h>]))))]
+
+
+/*!
+ \headerfile <algorithm>
+*/
+extern void uses_argorithm();
+// CHECK: headerfile-comment-to-html.m:[[@LINE-1]]:13: FunctionDecl=uses_argorithm:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}headerfile-comment-to-html.m" line="[[@LINE-1]]" column="13"><Name>uses_argorithm</Name><USR>c:@F@uses_argorithm</USR><Headerfile><Para> &lt;algorithm&gt;</Para></Headerfile><Declaration>extern void uses_argorithm()</Declaration></Function>] 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=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_Text Text=[<algorithm])
+// CHECK-NEXT: (CXComment_Text Text=[>]))))]
diff --git a/test/Sema/warn-documentation.cpp b/test/Sema/warn-documentation.cpp
index 9845f58780..e2e49e59bf 100644
--- a/test/Sema/warn-documentation.cpp
+++ b/test/Sema/warn-documentation.cpp
@@ -887,3 +887,11 @@ int test_nocrash12();
///@param x@param y
int test_nocrash13(int x, int y);
+// rdar://12397511
+
+// expected-note@+2 {{previous command '\headerfile' here}}
+// expected-warning@+2 {{duplicated command '\headerfile'}}
+/// \headerfile ""
+/// \headerfile foo.h
+int test_duplicate_headerfile1(int);
+
diff --git a/tools/libclang/CXComment.cpp b/tools/libclang/CXComment.cpp
index 0fcd7c2166..57bab18546 100644
--- a/tools/libclang/CXComment.cpp
+++ b/tools/libclang/CXComment.cpp
@@ -411,6 +411,7 @@ struct FullCommentParts {
const CommandTraits &Traits);
const BlockContentComment *Brief;
+ const BlockContentComment *Headerfile;
const ParagraphComment *FirstParagraph;
const BlockCommandComment *Returns;
SmallVector<const ParamCommandComment *, 8> Params;
@@ -420,7 +421,7 @@ struct FullCommentParts {
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 @@ FullCommentParts::FullCommentParts(const FullComment *C,
Brief = BCC;
break;
}
+ if (!Headerfile && Info->IsHeaderfileCommand) {
+ Headerfile = BCC;
+ break;
+ }
if (!Returns && Info->IsReturnsCommand) {
Returns = BCC;
break;
@@ -750,6 +755,8 @@ void CommentASTToHTMLConverter::visitFullComment(const FullComment *C) {
FullCommentParts Parts(C, Traits);
bool FirstParagraphIsBrief = false;
+ if (Parts.Headerfile)
+ visit(Parts.Headerfile);
if (Parts.Brief)
visit(Parts.Brief);
else if (Parts.FirstParagraph) {
@@ -1202,6 +1209,12 @@ void CommentASTToXMLConverter::visitFullComment(const FullComment *C) {
RootEndTag = "</Other>";
Result << "<Other><Name>unknown</Name>";
}
+
+ if (Parts.Headerfile) {
+ Result << "<Headerfile>";
+ visit(Parts.Headerfile);
+ Result << "</Headerfile>";
+ }
{
// Pretty-print the declaration.
@@ -1225,7 +1238,7 @@ void CommentASTToXMLConverter::visitFullComment(const FullComment *C) {
Result << "</Abstract>";
FirstParagraphIsBrief = true;
}
-
+
if (Parts.TParams.size() != 0) {
Result << "<TemplateParameters>";
for (unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
diff --git a/utils/TableGen/ClangCommentCommandInfoEmitter.cpp b/utils/TableGen/ClangCommentCommandInfoEmitter.cpp
index 70821ff322..e6253942e0 100644
--- a/utils/TableGen/ClangCommentCommandInfoEmitter.cpp
+++ b/utils/TableGen/ClangCommentCommandInfoEmitter.cpp
@@ -41,6 +41,7 @@ void EmitClangCommentCommandInfo(RecordKeeper &Records, raw_ostream &OS) {
<< Tag.getValueAsBit("IsParamCommand") << ", "
<< Tag.getValueAsBit("IsTParamCommand") << ", "
<< Tag.getValueAsBit("IsDeprecatedCommand") << ", "
+ << Tag.getValueAsBit("IsHeaderfileCommand") << ", "
<< Tag.getValueAsBit("IsEmptyParagraphAllowed") << ", "
<< Tag.getValueAsBit("IsVerbatimBlockCommand") << ", "
<< Tag.getValueAsBit("IsVerbatimBlockEndCommand") << ", "