summaryrefslogtreecommitdiffstats
path: root/clang/lib/AST/CommentParser.cpp
diff options
context:
space:
mode:
authorDmitri Gribenko <gribozavr@gmail.com>2012-07-11 21:38:39 +0000
committerDmitri Gribenko <gribozavr@gmail.com>2012-07-11 21:38:39 +0000
commitf26054f0fb53f65dbfbfc01954dc3b2028582cde (patch)
tree51e846b631a7c929833c43b321a0532d3b64bf45 /clang/lib/AST/CommentParser.cpp
parenta46ec4534d458f9cdb76f213ca3a42690296f21b (diff)
downloadbcm5719-llvm-f26054f0fb53f65dbfbfc01954dc3b2028582cde.tar.gz
bcm5719-llvm-f26054f0fb53f65dbfbfc01954dc3b2028582cde.zip
Enable comment parsing and semantic analysis to emit diagnostics. A few
diagnostics implemented -- see testcases. I created a new TableGen file for comment diagnostics, DiagnosticCommentKinds.td, because comment diagnostics don't logically fit into AST diagnostics file. But I don't feel strongly about it. This also implements support for self-closing HTML tags in comment lexer and parser (for example, <br />). In order to issue precise diagnostics CommentSema needs to know the declaration the comment is attached to. There is no easy way to find a decl by comment, so we match comments and decls in lockstep: after parsing one declgroup we check if we have any new, not yet attached comments. If we do -- then we do the usual comment-finding process. It is interesting that this automatically handles trailing comments. We pick up not only comments that precede the declaration, but also comments that *follow* the declaration -- thanks to the lookahead in the lexer: after parsing the declgroup we've consumed the semicolon and looked ahead through comments. Added -Wdocumentation-html flag for semantic HTML errors to allow the user to disable only HTML warnings (but not HTML parse errors, which we emit as warnings in -Wdocumentation). llvm-svn: 160078
Diffstat (limited to 'clang/lib/AST/CommentParser.cpp')
-rw-r--r--clang/lib/AST/CommentParser.cpp98
1 files changed, 74 insertions, 24 deletions
diff --git a/clang/lib/AST/CommentParser.cpp b/clang/lib/AST/CommentParser.cpp
index 2df3759bb96..eabe61c9795 100644
--- a/clang/lib/AST/CommentParser.cpp
+++ b/clang/lib/AST/CommentParser.cpp
@@ -9,13 +9,16 @@
#include "clang/AST/CommentParser.h"
#include "clang/AST/CommentSema.h"
+#include "clang/AST/CommentDiagnostic.h"
+#include "clang/Basic/SourceManager.h"
#include "llvm/Support/ErrorHandling.h"
namespace clang {
namespace comments {
-Parser::Parser(Lexer &L, Sema &S, llvm::BumpPtrAllocator &Allocator):
- L(L), S(S), Allocator(Allocator) {
+Parser::Parser(Lexer &L, Sema &S, llvm::BumpPtrAllocator &Allocator,
+ const SourceManager &SourceMgr, DiagnosticsEngine &Diags):
+ L(L), S(S), Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags) {
consumeToken();
}
@@ -26,18 +29,16 @@ ParamCommandComment *Parser::parseParamCommandArgs(
// Check if argument looks like direction specification: [dir]
// e.g., [in], [out], [in,out]
if (Retokenizer.lexDelimitedSeq(Arg, '[', ']'))
- PC = S.actOnParamCommandArg(PC,
- Arg.getLocation(),
- Arg.getEndLocation(),
- Arg.getText(),
- /* IsDirection = */ true);
+ PC = S.actOnParamCommandDirectionArg(PC,
+ Arg.getLocation(),
+ Arg.getEndLocation(),
+ Arg.getText());
if (Retokenizer.lexWord(Arg))
- PC = S.actOnParamCommandArg(PC,
- Arg.getLocation(),
- Arg.getEndLocation(),
- Arg.getText(),
- /* IsDirection = */ false);
+ PC = S.actOnParamCommandParamNameArg(PC,
+ Arg.getLocation(),
+ Arg.getEndLocation(),
+ Arg.getText());
return PC;
}
@@ -84,7 +85,6 @@ BlockCommandComment *Parser::parseBlockCommand() {
if (Tok.is(tok::command) && S.isBlockCommand(Tok.getCommandName())) {
// Block command ahead. We can't nest block commands, so pretend that this
// command has an empty argument.
- // TODO: Diag() Warn empty arg to block command
ParagraphComment *PC = S.actOnParagraphComment(
ArrayRef<InlineContentComment *>());
return S.actOnBlockCommandFinish(BC, PC);
@@ -164,7 +164,8 @@ HTMLOpenTagComment *Parser::parseHTMLOpenTag() {
SmallVector<HTMLOpenTagComment::Attribute, 2> Attrs;
while (true) {
- if (Tok.is(tok::html_ident)) {
+ switch (Tok.getKind()) {
+ case tok::html_ident: {
Token Ident = Tok;
consumeToken();
if (Tok.isNot(tok::html_equals)) {
@@ -175,9 +176,14 @@ HTMLOpenTagComment *Parser::parseHTMLOpenTag() {
Token Equals = Tok;
consumeToken();
if (Tok.isNot(tok::html_quoted_string)) {
- // TODO: Diag() expected quoted string
+ Diag(Tok.getLocation(),
+ diag::warn_doc_html_open_tag_expected_quoted_string)
+ << SourceRange(Equals.getLocation());
Attrs.push_back(HTMLOpenTagComment::Attribute(Ident.getLocation(),
Ident.getHTMLIdent()));
+ while (Tok.is(tok::html_equals) ||
+ Tok.is(tok::html_quoted_string))
+ consumeToken();
continue;
}
Attrs.push_back(HTMLOpenTagComment::Attribute(
@@ -189,24 +195,66 @@ HTMLOpenTagComment *Parser::parseHTMLOpenTag() {
Tok.getHTMLQuotedString()));
consumeToken();
continue;
- } else if (Tok.is(tok::html_greater)) {
+ }
+
+ case tok::html_greater:
+ HOT = S.actOnHTMLOpenTagFinish(HOT,
+ copyArray(llvm::makeArrayRef(Attrs)),
+ Tok.getLocation(),
+ /* IsSelfClosing = */ false);
+ consumeToken();
+ return HOT;
+
+ case tok::html_slash_greater:
HOT = S.actOnHTMLOpenTagFinish(HOT,
copyArray(llvm::makeArrayRef(Attrs)),
- Tok.getLocation());
+ Tok.getLocation(),
+ /* IsSelfClosing = */ true);
consumeToken();
return HOT;
- } else if (Tok.is(tok::html_equals) ||
- Tok.is(tok::html_quoted_string)) {
- // TODO: Diag() Err expected ident
+
+ case tok::html_equals:
+ case tok::html_quoted_string:
+ Diag(Tok.getLocation(),
+ diag::warn_doc_html_open_tag_expected_ident_or_greater);
while (Tok.is(tok::html_equals) ||
Tok.is(tok::html_quoted_string))
consumeToken();
- } else {
- // Not a token from HTML open tag. Thus HTML tag prematurely ended.
- // TODO: Diag() Err HTML tag prematurely ended
+ if (Tok.is(tok::html_ident) ||
+ Tok.is(tok::html_greater) ||
+ Tok.is(tok::html_slash_greater))
+ continue;
+
return S.actOnHTMLOpenTagFinish(HOT,
copyArray(llvm::makeArrayRef(Attrs)),
- SourceLocation());
+ SourceLocation(),
+ /* IsSelfClosing = */ false);
+
+ default:
+ // Not a token from an HTML open tag. Thus HTML tag prematurely ended.
+ HOT = S.actOnHTMLOpenTagFinish(HOT,
+ copyArray(llvm::makeArrayRef(Attrs)),
+ SourceLocation(),
+ /* IsSelfClosing = */ false);
+ bool StartLineInvalid;
+ const unsigned StartLine = SourceMgr.getPresumedLineNumber(
+ HOT->getLocation(),
+ &StartLineInvalid);
+ bool EndLineInvalid;
+ const unsigned EndLine = SourceMgr.getPresumedLineNumber(
+ Tok.getLocation(),
+ &EndLineInvalid);
+ if (StartLineInvalid || EndLineInvalid || StartLine == EndLine)
+ Diag(Tok.getLocation(),
+ diag::warn_doc_html_open_tag_expected_ident_or_greater)
+ << HOT->getSourceRange();
+ else {
+ Diag(Tok.getLocation(),
+ diag::warn_doc_html_open_tag_expected_ident_or_greater);
+ Diag(HOT->getLocation(), diag::note_doc_html_tag_started_here)
+ << HOT->getSourceRange();
+ }
+ return HOT;
}
}
}
@@ -289,6 +337,7 @@ BlockContentComment *Parser::parseParagraphOrBlockCommand() {
case tok::html_equals:
case tok::html_quoted_string:
case tok::html_greater:
+ case tok::html_slash_greater:
llvm_unreachable("should not see this token");
}
break;
@@ -388,6 +437,7 @@ BlockContentComment *Parser::parseBlockContent() {
case tok::html_equals:
case tok::html_quoted_string:
case tok::html_greater:
+ case tok::html_slash_greater:
llvm_unreachable("should not see this token");
}
llvm_unreachable("bogus token kind");
OpenPOWER on IntegriCloud