[cfe-commits] r160078 - in /cfe/trunk: include/clang/AST/ include/clang/Basic/ include/clang/Sema/ lib/AST/ lib/Basic/ lib/Sema/ test/Sema/ tools/diagtool/ unittests/AST/
Dmitri Gribenko
gribozavr at gmail.com
Wed Jul 11 14:38:40 PDT 2012
Author: gribozavr
Date: Wed Jul 11 16:38:39 2012
New Revision: 160078
URL: http://llvm.org/viewvc/llvm-project?rev=160078&view=rev
Log:
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).
Added:
cfe/trunk/include/clang/AST/CommentDiagnostic.h
cfe/trunk/include/clang/Basic/DiagnosticCommentKinds.td
cfe/trunk/test/Sema/warn-documentation-almost-trailing.c
- copied, changed from r160070, cfe/trunk/test/Sema/doxygen-comments.c
cfe/trunk/test/Sema/warn-documentation-fixits.c
cfe/trunk/test/Sema/warn-documentation.cpp
cfe/trunk/test/Sema/warn-documentation.m
Removed:
cfe/trunk/test/Sema/doxygen-comments.c
Modified:
cfe/trunk/include/clang/AST/ASTContext.h
cfe/trunk/include/clang/AST/Comment.h
cfe/trunk/include/clang/AST/CommentLexer.h
cfe/trunk/include/clang/AST/CommentParser.h
cfe/trunk/include/clang/AST/CommentSema.h
cfe/trunk/include/clang/AST/RawCommentList.h
cfe/trunk/include/clang/Basic/AllDiagnostics.h
cfe/trunk/include/clang/Basic/CMakeLists.txt
cfe/trunk/include/clang/Basic/Diagnostic.td
cfe/trunk/include/clang/Basic/DiagnosticGroups.td
cfe/trunk/include/clang/Basic/DiagnosticIDs.h
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Basic/Makefile
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/AST/ASTContext.cpp
cfe/trunk/lib/AST/CMakeLists.txt
cfe/trunk/lib/AST/Comment.cpp
cfe/trunk/lib/AST/CommentDumper.cpp
cfe/trunk/lib/AST/CommentLexer.cpp
cfe/trunk/lib/AST/CommentParser.cpp
cfe/trunk/lib/AST/CommentSema.cpp
cfe/trunk/lib/AST/RawCommentList.cpp
cfe/trunk/lib/Basic/DiagnosticIDs.cpp
cfe/trunk/lib/Sema/CMakeLists.txt
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaDeclObjC.cpp
cfe/trunk/tools/diagtool/DiagnosticNames.cpp
cfe/trunk/unittests/AST/CommentLexer.cpp
cfe/trunk/unittests/AST/CommentParser.cpp
cfe/trunk/unittests/AST/Makefile
Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Wed Jul 11 16:38:39 2012
@@ -392,6 +392,11 @@
SourceManager& getSourceManager() { return SourceMgr; }
const SourceManager& getSourceManager() const { return SourceMgr; }
+
+ llvm::BumpPtrAllocator &getAllocator() const {
+ return BumpAlloc;
+ }
+
void *Allocate(unsigned Size, unsigned Align = 8) const {
return BumpAlloc.Allocate(Size, Align);
}
@@ -436,9 +441,13 @@
/// \brief Return the documentation comment attached to a given declaration,
/// without looking into cache.
- const RawComment *getRawCommentForDeclNoCache(const Decl *D) const;
+ RawComment *getRawCommentForDeclNoCache(const Decl *D) const;
public:
+ RawCommentList &getRawCommentList() {
+ return Comments;
+ }
+
void addComment(const RawComment &RC) {
Comments.addComment(RC, BumpAlloc);
}
Modified: cfe/trunk/include/clang/AST/Comment.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Comment.h?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Comment.h (original)
+++ cfe/trunk/include/clang/AST/Comment.h Wed Jul 11 16:38:39 2012
@@ -50,6 +50,16 @@
};
enum { NumInlineContentCommentBitfields = 9 };
+ class HTMLOpenTagCommentBitfields {
+ friend class HTMLOpenTagComment;
+
+ unsigned : NumInlineContentCommentBitfields;
+
+ /// True if this tag is self-closing (e. g., <br />). This is based on tag
+ /// spelling in comment (plain <br> would not set this flag).
+ unsigned IsSelfClosing : 1;
+ };
+
class ParamCommandCommentBitfields {
friend class ParamCommandComment;
@@ -66,6 +76,7 @@
union {
CommentBitfields CommentBits;
InlineContentCommentBitfields InlineContentCommentBits;
+ HTMLOpenTagCommentBitfields HTMLOpenTagCommentBits;
ParamCommandCommentBitfields ParamCommandCommentBits;
};
@@ -107,8 +118,6 @@
static bool classof(const Comment *) { return true; }
- typedef Comment * const *child_iterator;
-
SourceRange getSourceRange() const LLVM_READONLY { return Range; }
SourceLocation getLocStart() const LLVM_READONLY {
@@ -121,9 +130,13 @@
SourceLocation getLocation() const LLVM_READONLY { return Loc; }
+ typedef Comment * const *child_iterator;
+
child_iterator child_begin() const;
child_iterator child_end() const;
+ // TODO: const child iterator
+
unsigned child_count() const {
return child_end() - child_begin();
}
@@ -180,6 +193,8 @@
child_iterator child_end() const { return NULL; }
StringRef getText() const LLVM_READONLY { return Text; }
+
+ bool isWhitespace() const;
};
/// A command with word-like arguments that is considered inline content.
@@ -325,8 +340,9 @@
LocBegin, LocBegin.getLocWithOffset(1 + TagName.size()),
TagName,
LocBegin.getLocWithOffset(1),
- LocBegin.getLocWithOffset(1 + TagName.size()))
- { }
+ LocBegin.getLocWithOffset(1 + TagName.size())) {
+ HTMLOpenTagCommentBits.IsSelfClosing = false;
+ }
static bool classof(const Comment *C) {
return C->getCommentKind() == HTMLOpenTagCommentKind;
@@ -362,6 +378,14 @@
void setGreaterLoc(SourceLocation GreaterLoc) {
Range.setEnd(GreaterLoc);
}
+
+ bool isSelfClosing() const {
+ return HTMLOpenTagCommentBits.IsSelfClosing;
+ }
+
+ void setSelfClosing() {
+ HTMLOpenTagCommentBits.IsSelfClosing = true;
+ }
};
/// A closing HTML tag.
@@ -438,6 +462,8 @@
child_iterator child_end() const {
return reinterpret_cast<child_iterator>(Content.end());
}
+
+ bool isWhitespace() const;
};
/// A command that has zero or more word-like arguments (number of word-like
@@ -520,6 +546,11 @@
void setArgs(llvm::ArrayRef<Argument> A) {
Args = A;
+ if (Args.size() > 0) {
+ SourceLocation NewLocEnd = Args.back().Range.getEnd();
+ if (NewLocEnd.isValid())
+ setSourceRange(SourceRange(getLocStart(), NewLocEnd));
+ }
}
ParagraphComment *getParagraph() const LLVM_READONLY {
@@ -536,18 +567,18 @@
/// Doxygen \\param command.
class ParamCommandComment : public BlockCommandComment {
-public:
- enum PassDirection {
- In,
- Out,
- InOut
- };
+private:
+ /// Parameter index in the function declaration.
+ unsigned ParamIndex;
public:
+ enum { InvalidParamIndex = ~0U };
+
ParamCommandComment(SourceLocation LocBegin,
SourceLocation LocEnd,
StringRef Name) :
- BlockCommandComment(ParamCommandCommentKind, LocBegin, LocEnd, Name) {
+ BlockCommandComment(ParamCommandCommentKind, LocBegin, LocEnd, Name),
+ ParamIndex(InvalidParamIndex) {
ParamCommandCommentBits.Direction = In;
ParamCommandCommentBits.IsDirectionExplicit = false;
}
@@ -558,6 +589,14 @@
static bool classof(const ParamCommandComment *) { return true; }
+ enum PassDirection {
+ In,
+ Out,
+ InOut
+ };
+
+ static const char *getDirectionAsString(PassDirection D);
+
PassDirection getDirection() const LLVM_READONLY {
return static_cast<PassDirection>(ParamCommandCommentBits.Direction);
}
@@ -582,6 +621,19 @@
SourceRange getParamNameRange() const {
return Args[0].Range;
}
+
+ bool isParamIndexValid() const LLVM_READONLY {
+ return ParamIndex != InvalidParamIndex;
+ }
+
+ unsigned getParamIndex() const LLVM_READONLY {
+ return ParamIndex;
+ }
+
+ void setParamIndex(unsigned Index) {
+ ParamIndex = Index;
+ assert(isParamIndexValid());
+ }
};
/// A line of text contained in a verbatim block.
Added: cfe/trunk/include/clang/AST/CommentDiagnostic.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/CommentDiagnostic.h?rev=160078&view=auto
==============================================================================
--- cfe/trunk/include/clang/AST/CommentDiagnostic.h (added)
+++ cfe/trunk/include/clang/AST/CommentDiagnostic.h Wed Jul 11 16:38:39 2012
@@ -0,0 +1,29 @@
+//===--- CommentDiagnostic.h - Diagnostics for the AST library --*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_COMMENTDIAGNOSTIC_H
+#define LLVM_CLANG_COMMENTDIAGNOSTIC_H
+
+#include "clang/Basic/Diagnostic.h"
+
+namespace clang {
+ namespace diag {
+ enum {
+#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\
+ SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM,
+#define COMMENTSTART
+#include "clang/Basic/DiagnosticCommentKinds.inc"
+#undef DIAG
+ NUM_BUILTIN_COMMENT_DIAGNOSTICS
+ };
+ } // end namespace diag
+} // end namespace clang
+
+#endif
+
Modified: cfe/trunk/include/clang/AST/CommentLexer.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/CommentLexer.h?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/CommentLexer.h (original)
+++ cfe/trunk/include/clang/AST/CommentLexer.h Wed Jul 11 16:38:39 2012
@@ -43,6 +43,7 @@
html_equals, // =
html_quoted_string, // "blah\"blah" or 'blah\'blah'
html_greater, // >
+ html_slash_greater, // />
html_tag_close // </tag
};
} // end namespace tok
Modified: cfe/trunk/include/clang/AST/CommentParser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/CommentParser.h?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/CommentParser.h (original)
+++ cfe/trunk/include/clang/AST/CommentParser.h Wed Jul 11 16:38:39 2012
@@ -14,12 +14,15 @@
#ifndef LLVM_CLANG_AST_COMMENT_PARSER_H
#define LLVM_CLANG_AST_COMMENT_PARSER_H
+#include "clang/Basic/Diagnostic.h"
#include "clang/AST/CommentLexer.h"
#include "clang/AST/Comment.h"
#include "clang/AST/CommentSema.h"
#include "llvm/Support/Allocator.h"
namespace clang {
+class SourceManager;
+
namespace comments {
/// Doxygen comment parser.
@@ -28,8 +31,12 @@
Sema &S;
+ /// Allocator for anything that goes into AST nodes.
llvm::BumpPtrAllocator &Allocator;
+ /// Source manager for the comment being parsed.
+ const SourceManager &SourceMgr;
+
template<typename T>
ArrayRef<T> copyArray(ArrayRef<T> Source) {
size_t Size = Source.size();
@@ -41,6 +48,12 @@
return llvm::makeArrayRef(static_cast<T *>(NULL), 0);
}
+ DiagnosticsEngine &Diags;
+
+ DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) {
+ return Diags.Report(Loc, DiagID);
+ }
+
/// Current lookahead token. We can safely assume that all tokens are from
/// a single source file.
Token Tok;
@@ -79,7 +92,8 @@
}
public:
- Parser(Lexer &L, Sema &S, llvm::BumpPtrAllocator &Allocator);
+ Parser(Lexer &L, Sema &S, llvm::BumpPtrAllocator &Allocator,
+ const SourceManager &SourceMgr, DiagnosticsEngine &Diags);
/// Parse arguments for \\param command.
ParamCommandComment *parseParamCommandArgs(
Modified: cfe/trunk/include/clang/AST/CommentSema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/CommentSema.h?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/CommentSema.h (original)
+++ cfe/trunk/include/clang/AST/CommentSema.h Wed Jul 11 16:38:39 2012
@@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_AST_COMMENT_SEMA_H
#define LLVM_CLANG_AST_COMMENT_SEMA_H
+#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/AST/Comment.h"
#include "llvm/ADT/ArrayRef.h"
@@ -21,13 +22,37 @@
#include "llvm/Support/Allocator.h"
namespace clang {
+class Decl;
+class FunctionDecl;
+class ParmVarDecl;
+class SourceMgr;
+
namespace comments {
class Sema {
+ /// Allocator for AST nodes.
llvm::BumpPtrAllocator &Allocator;
+ /// Source manager for the comment being parsed.
+ const SourceManager &SourceMgr;
+
+ DiagnosticsEngine &Diags;
+
+ const Decl *ThisDecl;
+
+ DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) {
+ return Diags.Report(Loc, DiagID);
+ }
+
+ /// A stack of HTML tags that are currently open (not matched with closing
+ /// tags).
+ SmallVector<HTMLOpenTagComment *, 8> HTMLOpenTags;
+
public:
- Sema(llvm::BumpPtrAllocator &Allocator);
+ Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr,
+ DiagnosticsEngine &Diags);
+
+ void setDecl(const Decl *D);
ParagraphComment *actOnParagraphComment(
ArrayRef<InlineContentComment *> Content);
@@ -47,11 +72,17 @@
SourceLocation LocEnd,
StringRef Name);
- ParamCommandComment *actOnParamCommandArg(ParamCommandComment *Command,
+ ParamCommandComment *actOnParamCommandDirectionArg(
+ ParamCommandComment *Command,
+ SourceLocation ArgLocBegin,
+ SourceLocation ArgLocEnd,
+ StringRef Arg);
+
+ ParamCommandComment *actOnParamCommandParamNameArg(
+ ParamCommandComment *Command,
SourceLocation ArgLocBegin,
SourceLocation ArgLocEnd,
- StringRef Arg,
- bool IsDirection);
+ StringRef Arg);
ParamCommandComment *actOnParamCommandFinish(ParamCommandComment *Command,
ParagraphComment *Paragraph);
@@ -98,7 +129,8 @@
HTMLOpenTagComment *actOnHTMLOpenTagFinish(
HTMLOpenTagComment *Tag,
ArrayRef<HTMLOpenTagComment::Attribute> Attrs,
- SourceLocation GreaterLoc);
+ SourceLocation GreaterLoc,
+ bool IsSelfClosing);
HTMLCloseTagComment *actOnHTMLCloseTag(SourceLocation LocBegin,
SourceLocation LocEnd,
@@ -106,6 +138,19 @@
FullComment *actOnFullComment(ArrayRef<BlockContentComment *> Blocks);
+ void checkBlockCommandEmptyParagraph(BlockCommandComment *Command);
+
+ /// Returns index of a function parameter with a given name.
+ unsigned resolveParmVarReference(StringRef Name,
+ const ParmVarDecl * const *ParamVars,
+ unsigned NumParams);
+
+ /// Returns index of a function parameter with the name closest to a given
+ /// typo.
+ unsigned correctTypoInParmVarReference(StringRef Typo,
+ const ParmVarDecl * const *ParamVars,
+ unsigned NumParams);
+
bool isBlockCommand(StringRef Name);
bool isParamCommand(StringRef Name);
unsigned getBlockCommandNumArgs(StringRef Name);
Modified: cfe/trunk/include/clang/AST/RawCommentList.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RawCommentList.h?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/RawCommentList.h (original)
+++ cfe/trunk/include/clang/AST/RawCommentList.h Wed Jul 11 16:38:39 2012
@@ -48,6 +48,14 @@
return Kind == RCK_Merged;
}
+ bool isAttached() const LLVM_READONLY {
+ return IsAttached;
+ }
+
+ void setAttached() {
+ IsAttached = true;
+ }
+
/// Returns true if it is a comment that should be put after a member:
/// \code ///< stuff \endcode
/// \code //!< stuff \endcode
@@ -110,6 +118,9 @@
unsigned Kind : 3;
+ /// True if comment is attached to a declaration in ASTContext.
+ bool IsAttached : 1;
+
bool IsTrailingComment : 1;
bool IsAlmostTrailingComment : 1;
@@ -122,7 +133,7 @@
RawComment(SourceRange SR, CommentKind K, bool IsTrailingComment,
bool IsAlmostTrailingComment) :
Range(SR), RawTextValid(false), BriefTextValid(false), Kind(K),
- IsTrailingComment(IsTrailingComment),
+ IsAttached(false), IsTrailingComment(IsTrailingComment),
IsAlmostTrailingComment(IsAlmostTrailingComment),
BeginLineValid(false), EndLineValid(false)
{ }
Modified: cfe/trunk/include/clang/Basic/AllDiagnostics.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/AllDiagnostics.h?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/AllDiagnostics.h (original)
+++ cfe/trunk/include/clang/Basic/AllDiagnostics.h Wed Jul 11 16:38:39 2012
@@ -16,6 +16,7 @@
#define LLVM_CLANG_ALL_DIAGNOSTICS_H
#include "clang/AST/ASTDiagnostic.h"
+#include "clang/AST/CommentDiagnostic.h"
#include "clang/Analysis/AnalysisDiagnostic.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Frontend/FrontendDiagnostic.h"
Modified: cfe/trunk/include/clang/Basic/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/CMakeLists.txt?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/CMakeLists.txt (original)
+++ cfe/trunk/include/clang/Basic/CMakeLists.txt Wed Jul 11 16:38:39 2012
@@ -7,6 +7,7 @@
clang_diag_gen(Analysis)
clang_diag_gen(AST)
+clang_diag_gen(Comment)
clang_diag_gen(Common)
clang_diag_gen(Driver)
clang_diag_gen(Frontend)
Modified: cfe/trunk/include/clang/Basic/Diagnostic.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Diagnostic.td?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Diagnostic.td (original)
+++ cfe/trunk/include/clang/Basic/Diagnostic.td Wed Jul 11 16:38:39 2012
@@ -88,6 +88,7 @@
// Definitions for Diagnostics.
include "DiagnosticASTKinds.td"
include "DiagnosticAnalysisKinds.td"
+include "DiagnosticCommentKinds.td"
include "DiagnosticCommonKinds.td"
include "DiagnosticDriverKinds.td"
include "DiagnosticFrontendKinds.td"
Added: cfe/trunk/include/clang/Basic/DiagnosticCommentKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticCommentKinds.td?rev=160078&view=auto
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticCommentKinds.td (added)
+++ cfe/trunk/include/clang/Basic/DiagnosticCommentKinds.td Wed Jul 11 16:38:39 2012
@@ -0,0 +1,70 @@
+//==--- DiagnosticCommentKinds.td - diagnostics related to comments -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+let Component = "Comment" in {
+let CategoryName = "Documentation Issue" in {
+
+// HTML parsing errors. These are under -Wdocumentation to make sure the user
+// knows that we didn't parse something as he might expect.
+
+def warn_doc_html_open_tag_expected_quoted_string : Warning<
+ "expected quoted string after equals sign">,
+ InGroup<Documentation>, DefaultIgnore;
+
+def warn_doc_html_open_tag_expected_ident_or_greater : Warning<
+ "HTML opening tag prematurely ended, expected attribute name or '>'">,
+ InGroup<Documentation>, DefaultIgnore;
+
+def note_doc_html_tag_started_here : Note<
+ "HTML tag started here">;
+
+// HTML semantic errors
+
+def warn_doc_html_close_unbalanced : Warning<
+ "HTML closing tag does not match any opening tag">,
+ InGroup<DocumentationHTML>, DefaultIgnore;
+
+def warn_doc_html_open_close_mismatch : Warning<
+ "HTML opening tag '%0' closed by '%1'">,
+ InGroup<DocumentationHTML>, DefaultIgnore;
+
+def note_doc_html_closing_tag : Note<
+ "closing tag">;
+
+// Commands
+
+def warn_doc_block_command_empty_paragraph : Warning<
+ "empty paragraph passed to '\\%0' command">,
+ InGroup<Documentation>, DefaultIgnore;
+
+// \param command
+
+def warn_doc_param_invalid_direction : Warning<
+ "unrecognized parameter passing direction, "
+ "valid directions are '[in]', '[out]' and '[in,out]'">,
+ InGroup<Documentation>, DefaultIgnore;
+
+def warn_doc_param_spaces_in_direction : Warning<
+ "whitespace is not allowed in parameter passing direction">,
+ InGroup<DocumentationPedantic>, DefaultIgnore;
+
+def warn_doc_param_not_attached_to_a_function_decl : Warning<
+ "'\\param' command used in a comment that is not attached to "
+ "a function declaration">,
+ InGroup<Documentation>, DefaultIgnore;
+
+def warn_doc_param_not_found : Warning<
+ "parameter '%0' not found in the function declaration">,
+ InGroup<Documentation>, DefaultIgnore;
+
+def note_doc_param_name_suggestion : Note<
+ "did you mean '%0'?">;
+
+} // end of documentation issue category
+} // end of AST component
Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Wed Jul 11 16:38:39 2012
@@ -57,7 +57,9 @@
def : DiagGroup<"disabled-optimization">;
def : DiagGroup<"discard-qual">;
def : DiagGroup<"div-by-zero">;
-def Doxygen : DiagGroup<"doxygen">;
+def DocumentationHTML : DiagGroup<"documentation-html">;
+def DocumentationPedantic : DiagGroup<"documentation-pedantic">;
+def Documentation : DiagGroup<"documentation", [DocumentationHTML]>;
def EmptyBody : DiagGroup<"empty-body">;
def ExtraTokens : DiagGroup<"extra-tokens">;
Modified: cfe/trunk/include/clang/Basic/DiagnosticIDs.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticIDs.h?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticIDs.h (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticIDs.h Wed Jul 11 16:38:39 2012
@@ -38,7 +38,8 @@
DIAG_START_LEX = DIAG_START_SERIALIZATION + 120,
DIAG_START_PARSE = DIAG_START_LEX + 300,
DIAG_START_AST = DIAG_START_PARSE + 400,
- DIAG_START_SEMA = DIAG_START_AST + 100,
+ DIAG_START_COMMENT = DIAG_START_AST + 100,
+ DIAG_START_SEMA = DIAG_START_COMMENT + 100,
DIAG_START_ANALYSIS = DIAG_START_SEMA + 3000,
DIAG_UPPER_LIMIT = DIAG_START_ANALYSIS + 100
};
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Jul 11 16:38:39 2012
@@ -5704,7 +5704,7 @@
let CategoryName = "Documentation Issue" in {
def warn_not_a_doxygen_trailing_member_comment : Warning<
- "not a Doxygen trailing comment">, InGroup<Doxygen>, DefaultIgnore;
+ "not a Doxygen trailing comment">, InGroup<Documentation>, DefaultIgnore;
} // end of documentation issue category
} // end of sema component.
Modified: cfe/trunk/include/clang/Basic/Makefile
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Makefile?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Makefile (original)
+++ cfe/trunk/include/clang/Basic/Makefile Wed Jul 11 16:38:39 2012
@@ -1,6 +1,7 @@
CLANG_LEVEL := ../../..
BUILT_SOURCES = \
DiagnosticAnalysisKinds.inc DiagnosticASTKinds.inc \
+ DiagnosticCommentKinds.inc \
DiagnosticCommonKinds.inc DiagnosticDriverKinds.inc \
DiagnosticFrontendKinds.inc DiagnosticLexKinds.inc \
DiagnosticParseKinds.inc DiagnosticSemaKinds.inc \
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Jul 11 16:38:39 2012
@@ -1313,6 +1313,12 @@
unsigned NumDecls);
DeclGroupPtrTy BuildDeclaratorGroup(Decl **Group, unsigned NumDecls,
bool TypeMayContainAuto = true);
+
+ /// Should be called on all declarations that might have attached
+ /// documentation comments.
+ void ActOnDocumentableDecl(Decl *D);
+ void ActOnDocumentableDecls(Decl **Group, unsigned NumDecls);
+
void ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
SourceLocation LocAfterDecls);
void CheckForFunctionRedefinition(FunctionDecl *FD);
Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Wed Jul 11 16:38:39 2012
@@ -56,7 +56,7 @@
HalfRank, FloatRank, DoubleRank, LongDoubleRank
};
-const RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
+RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
if (!CommentsLoaded && ExternalSource) {
ExternalSource->ReadComments();
CommentsLoaded = true;
@@ -160,11 +160,13 @@
return C.first;
}
- const RawComment *RC = getRawCommentForDeclNoCache(D);
+ RawComment *RC = getRawCommentForDeclNoCache(D);
// If we found a comment, it should be a documentation comment.
assert(!RC || RC->isDocumentation());
DeclComments[D] =
RawAndParsedComment(RC, static_cast<comments::FullComment *>(NULL));
+ if (RC)
+ RC->setAttached();
return RC;
}
@@ -187,8 +189,10 @@
comments::Lexer L(RC->getSourceRange().getBegin(), comments::CommentOptions(),
RawText.begin(), RawText.end());
- comments::Sema S(this->BumpAlloc);
- comments::Parser P(L, S, this->BumpAlloc);
+ comments::Sema S(getAllocator(), getSourceManager(), getDiagnostics());
+ S.setDecl(D);
+ comments::Parser P(L, S, getAllocator(), getSourceManager(),
+ getDiagnostics());
comments::FullComment *FC = P.parseFullComment();
DeclComments[D].second = FC;
Modified: cfe/trunk/lib/AST/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/CMakeLists.txt?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/lib/AST/CMakeLists.txt (original)
+++ cfe/trunk/lib/AST/CMakeLists.txt Wed Jul 11 16:38:39 2012
@@ -64,6 +64,7 @@
ClangAttrList
ClangAttrImpl
ClangDiagnosticAST
+ ClangDiagnosticComment
ClangCommentNodes
ClangDeclNodes
ClangStmtNodes
Modified: cfe/trunk/lib/AST/Comment.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Comment.cpp?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Comment.cpp (original)
+++ cfe/trunk/lib/AST/Comment.cpp Wed Jul 11 16:38:39 2012
@@ -86,6 +86,38 @@
llvm_unreachable("Unknown comment kind!");
}
+bool TextComment::isWhitespace() const {
+ for (StringRef::const_iterator I = Text.begin(), E = Text.end();
+ I != E; ++I) {
+ const char C = *I;
+ if (C != ' ' && C != '\n' && C != '\r' &&
+ C != '\t' && C != '\f' && C != '\v')
+ return false;
+ }
+ return true;
+}
+
+bool ParagraphComment::isWhitespace() const {
+ for (child_iterator I = child_begin(), E = child_end(); I != E; ++I) {
+ if (const TextComment *TC = dyn_cast<TextComment>(*I)) {
+ if (!TC->isWhitespace())
+ return false;
+ }
+ }
+ return true;
+}
+
+const char *ParamCommandComment::getDirectionAsString(PassDirection D) {
+ switch (D) {
+ case ParamCommandComment::In:
+ return "[in]";
+ case ParamCommandComment::Out:
+ return "[out]";
+ case ParamCommandComment::InOut:
+ return "[in,out]";
+ }
+ llvm_unreachable("unknown PassDirection");
+}
} // end namespace comments
} // end namespace clang
Modified: cfe/trunk/lib/AST/CommentDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/CommentDumper.cpp?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/lib/AST/CommentDumper.cpp (original)
+++ cfe/trunk/lib/AST/CommentDumper.cpp Wed Jul 11 16:38:39 2012
@@ -121,6 +121,8 @@
OS << " \"" << Attr.Name << "=\"" << Attr.Value << "\"";
}
}
+ if (C->isSelfClosing())
+ OS << " SelfClosing";
}
void CommentDumper::visitHTMLCloseTagComment(const HTMLCloseTagComment *C) {
@@ -142,17 +144,7 @@
void CommentDumper::visitParamCommandComment(const ParamCommandComment *C) {
dumpComment(C);
- switch (C->getDirection()) {
- case ParamCommandComment::In:
- OS << " [in]";
- break;
- case ParamCommandComment::Out:
- OS << " [out]";
- break;
- case ParamCommandComment::InOut:
- OS << " [in,out]";
- break;
- }
+ OS << " " << ParamCommandComment::getDirectionAsString(C->getDirection());
if (C->isDirectionExplicit())
OS << " explicitly";
Modified: cfe/trunk/lib/AST/CommentLexer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/CommentLexer.cpp?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/lib/AST/CommentLexer.cpp (original)
+++ cfe/trunk/lib/AST/CommentLexer.cpp Wed Jul 11 16:38:39 2012
@@ -509,7 +509,7 @@
const char C = *BufferPtr;
if (BufferPtr != CommentEnd &&
- (C == '>' || isHTMLIdentifierStartingCharacter(C)))
+ (C == '>' || C == '/' || isHTMLIdentifierStartingCharacter(C)))
State = LS_HTMLOpenTag;
}
@@ -546,6 +546,18 @@
formTokenWithChars(T, TokenPtr, tok::html_greater);
State = LS_Normal;
return;
+ case '/':
+ TokenPtr++;
+ if (TokenPtr != CommentEnd && *TokenPtr == '>') {
+ TokenPtr++;
+ formTokenWithChars(T, TokenPtr, tok::html_slash_greater);
+ } else {
+ StringRef Text(BufferPtr, TokenPtr - BufferPtr);
+ formTokenWithChars(T, TokenPtr, tok::text);
+ T.setText(Text);
+ }
+ State = LS_Normal;
+ return;
}
}
Modified: cfe/trunk/lib/AST/CommentParser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/CommentParser.cpp?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/lib/AST/CommentParser.cpp (original)
+++ cfe/trunk/lib/AST/CommentParser.cpp Wed Jul 11 16:38:39 2012
@@ -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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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");
Modified: cfe/trunk/lib/AST/CommentSema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/CommentSema.cpp?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/lib/AST/CommentSema.cpp (original)
+++ cfe/trunk/lib/AST/CommentSema.cpp Wed Jul 11 16:38:39 2012
@@ -8,13 +8,22 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/CommentSema.h"
+#include "clang/AST/CommentDiagnostic.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/StringSwitch.h"
namespace clang {
namespace comments {
-Sema::Sema(llvm::BumpPtrAllocator &Allocator) :
- Allocator(Allocator) {
+Sema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr,
+ DiagnosticsEngine &Diags) :
+ Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), ThisDecl(NULL) {
+}
+
+void Sema::setDecl(const Decl *D) {
+ ThisDecl = D;
}
ParagraphComment *Sema::actOnParagraphComment(
@@ -39,83 +48,153 @@
BlockCommandComment *Command,
ParagraphComment *Paragraph) {
Command->setParagraph(Paragraph);
+ checkBlockCommandEmptyParagraph(Command);
return Command;
}
ParamCommandComment *Sema::actOnParamCommandStart(SourceLocation LocBegin,
SourceLocation LocEnd,
StringRef Name) {
- return new (Allocator) ParamCommandComment(LocBegin, LocEnd, Name);
+ ParamCommandComment *Command =
+ new (Allocator) ParamCommandComment(LocBegin, LocEnd, Name);
+
+ if (!ThisDecl ||
+ !(isa<FunctionDecl>(ThisDecl) || isa<ObjCMethodDecl>(ThisDecl)))
+ Diag(Command->getLocation(),
+ diag::warn_doc_param_not_attached_to_a_function_decl)
+ << Command->getCommandNameRange();
+
+ return Command;
}
-ParamCommandComment *Sema::actOnParamCommandArg(ParamCommandComment *Command,
+ParamCommandComment *Sema::actOnParamCommandDirectionArg(
+ ParamCommandComment *Command,
SourceLocation ArgLocBegin,
SourceLocation ArgLocEnd,
- StringRef Arg,
- bool IsDirection) {
- if (IsDirection) {
- ParamCommandComment::PassDirection Direction;
- std::string ArgLower = Arg.lower();
- // TODO: optimize: lower Name first (need an API in SmallString for that),
- // after that StringSwitch.
- if (ArgLower == "[in]")
+ StringRef Arg) {
+ ParamCommandComment::PassDirection Direction;
+ std::string ArgLower = Arg.lower();
+ // TODO: optimize: lower Name first (need an API in SmallString for that),
+ // after that StringSwitch.
+ if (ArgLower == "[in]")
+ Direction = ParamCommandComment::In;
+ else if (ArgLower == "[out]")
+ Direction = ParamCommandComment::Out;
+ else if (ArgLower == "[in,out]" || ArgLower == "[out,in]")
+ Direction = ParamCommandComment::InOut;
+ else {
+ // Remove spaces.
+ std::string::iterator O = ArgLower.begin();
+ for (std::string::iterator I = ArgLower.begin(), E = ArgLower.end();
+ I != E; ++I) {
+ const char C = *I;
+ if (C != ' ' && C != '\n' && C != '\r' &&
+ C != '\t' && C != '\v' && C != '\f')
+ *O++ = C;
+ }
+ ArgLower.resize(O - ArgLower.begin());
+
+ bool RemovingWhitespaceHelped = false;
+ if (ArgLower == "[in]") {
Direction = ParamCommandComment::In;
- else if (ArgLower == "[out]")
+ RemovingWhitespaceHelped = true;
+ } else if (ArgLower == "[out]") {
Direction = ParamCommandComment::Out;
- else if (ArgLower == "[in,out]" || ArgLower == "[out,in]")
+ RemovingWhitespaceHelped = true;
+ } else if (ArgLower == "[in,out]" || ArgLower == "[out,in]") {
Direction = ParamCommandComment::InOut;
- else {
- // Remove spaces.
- std::string::iterator O = ArgLower.begin();
- for (std::string::iterator I = ArgLower.begin(), E = ArgLower.end();
- I != E; ++I) {
- const char C = *I;
- if (C != ' ' && C != '\n' && C != '\r' &&
- C != '\t' && C != '\v' && C != '\f')
- *O++ = C;
- }
- ArgLower.resize(O - ArgLower.begin());
-
- bool RemovingWhitespaceHelped = false;
- if (ArgLower == "[in]") {
- Direction = ParamCommandComment::In;
- RemovingWhitespaceHelped = true;
- } else if (ArgLower == "[out]") {
- Direction = ParamCommandComment::Out;
- RemovingWhitespaceHelped = true;
- } else if (ArgLower == "[in,out]" || ArgLower == "[out,in]") {
- Direction = ParamCommandComment::InOut;
- RemovingWhitespaceHelped = true;
- } else {
- Direction = ParamCommandComment::In;
- RemovingWhitespaceHelped = false;
- }
- // Diag() unrecognized parameter passing direction, valid directions are ...
- // if (RemovingWhitespaceHelped) FixIt
- }
- Command->setDirection(Direction, /* Explicit = */ true);
- } else {
- if (Command->getArgCount() == 0) {
- if (!Command->isDirectionExplicit()) {
- // User didn't provide a direction argument.
- Command->setDirection(ParamCommandComment::In, /* Explicit = */ false);
- }
- typedef BlockCommandComment::Argument Argument;
- Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
- ArgLocEnd),
- Arg);
- Command->setArgs(llvm::makeArrayRef(A, 1));
- // if (...) Diag() unrecognized parameter name
+ RemovingWhitespaceHelped = true;
} else {
- // Diag() \\param command requires at most 2 arguments
+ Direction = ParamCommandComment::In;
+ RemovingWhitespaceHelped = false;
}
+
+ SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
+ if (RemovingWhitespaceHelped)
+ Diag(ArgLocBegin, diag::warn_doc_param_spaces_in_direction)
+ << ArgRange
+ << FixItHint::CreateReplacement(
+ ArgRange,
+ ParamCommandComment::getDirectionAsString(Direction));
+ else
+ Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction)
+ << ArgRange;
+ }
+ Command->setDirection(Direction, /* Explicit = */ true);
+ return Command;
+}
+
+ParamCommandComment *Sema::actOnParamCommandParamNameArg(
+ ParamCommandComment *Command,
+ SourceLocation ArgLocBegin,
+ SourceLocation ArgLocEnd,
+ StringRef Arg) {
+ // Parser will not feed us more arguments than needed.
+ assert(Command->getArgCount() == 0);
+
+ if (!Command->isDirectionExplicit()) {
+ // User didn't provide a direction argument.
+ Command->setDirection(ParamCommandComment::In, /* Explicit = */ false);
+ }
+ typedef BlockCommandComment::Argument Argument;
+ Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
+ ArgLocEnd),
+ Arg);
+ Command->setArgs(llvm::makeArrayRef(A, 1));
+
+ if (!ThisDecl)
+ return Command;
+
+ const ParmVarDecl * const *ParamVars;
+ unsigned NumParams;
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ThisDecl)) {
+ ParamVars = FD->param_begin();
+ NumParams = FD->getNumParams();
+ } else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(ThisDecl)) {
+ ParamVars = MD->param_begin();
+ NumParams = MD->param_size();
+ } else {
+ // We already warned that this \\param is not attached to a function decl.
+ return Command;
+ }
+
+ // Check that referenced parameter name is in the function decl.
+ const unsigned ResolvedParamIndex = resolveParmVarReference(Arg, ParamVars,
+ NumParams);
+ if (ResolvedParamIndex != ParamCommandComment::InvalidParamIndex) {
+ Command->setParamIndex(ResolvedParamIndex);
+ return Command;
+ }
+
+ SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
+ Diag(ArgLocBegin, diag::warn_doc_param_not_found)
+ << Arg << ArgRange;
+
+ unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex;
+ if (NumParams == 1) {
+ // If function has only one parameter then only that parameter
+ // can be documented.
+ CorrectedParamIndex = 0;
+ } else {
+ // Do typo correction.
+ CorrectedParamIndex = correctTypoInParmVarReference(Arg, ParamVars,
+ NumParams);
+ }
+ if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) {
+ const ParmVarDecl *CorrectedPVD = ParamVars[CorrectedParamIndex];
+ if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier())
+ Diag(ArgLocBegin, diag::note_doc_param_name_suggestion)
+ << CorrectedII->getName()
+ << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName());
}
+
return Command;
}
ParamCommandComment *Sema::actOnParamCommandFinish(ParamCommandComment *Command,
ParagraphComment *Paragraph) {
Command->setParagraph(Paragraph);
+ checkBlockCommandEmptyParagraph(Command);
return Command;
}
@@ -196,22 +275,78 @@
HTMLOpenTagComment *Sema::actOnHTMLOpenTagStart(SourceLocation LocBegin,
StringRef TagName) {
- return new (Allocator) HTMLOpenTagComment(LocBegin, TagName);
+ HTMLOpenTagComment *HOT =
+ new (Allocator) HTMLOpenTagComment(LocBegin, TagName);
+ return HOT;
}
HTMLOpenTagComment *Sema::actOnHTMLOpenTagFinish(
HTMLOpenTagComment *Tag,
ArrayRef<HTMLOpenTagComment::Attribute> Attrs,
- SourceLocation GreaterLoc) {
+ SourceLocation GreaterLoc,
+ bool IsSelfClosing) {
Tag->setAttrs(Attrs);
Tag->setGreaterLoc(GreaterLoc);
+ if (IsSelfClosing)
+ Tag->setSelfClosing();
+ else
+ HTMLOpenTags.push_back(Tag);
return Tag;
}
HTMLCloseTagComment *Sema::actOnHTMLCloseTag(SourceLocation LocBegin,
SourceLocation LocEnd,
StringRef TagName) {
- return new (Allocator) HTMLCloseTagComment(LocBegin, LocEnd, TagName);
+ HTMLCloseTagComment *HCT =
+ new (Allocator) HTMLCloseTagComment(LocBegin, LocEnd, TagName);
+ bool FoundOpen = false;
+ for (SmallVectorImpl<HTMLOpenTagComment *>::const_reverse_iterator
+ I = HTMLOpenTags.rbegin(), E = HTMLOpenTags.rend();
+ I != E; ++I) {
+ if ((*I)->getTagName() == TagName) {
+ FoundOpen = true;
+ break;
+ }
+ }
+ if (!FoundOpen) {
+ Diag(HCT->getLocation(), diag::warn_doc_html_close_unbalanced)
+ << HCT->getSourceRange();
+ return HCT;
+ }
+
+ while (!HTMLOpenTags.empty()) {
+ const HTMLOpenTagComment *HOT = HTMLOpenTags.back();
+ HTMLOpenTags.pop_back();
+ StringRef LastNotClosedTagName = HOT->getTagName();
+ if (LastNotClosedTagName == TagName)
+ break;
+
+ if (!HTMLOpenTagNeedsClosing(LastNotClosedTagName))
+ continue;
+
+ bool OpenLineInvalid;
+ const unsigned OpenLine = SourceMgr.getPresumedLineNumber(
+ HOT->getLocation(),
+ &OpenLineInvalid);
+ bool CloseLineInvalid;
+ const unsigned CloseLine = SourceMgr.getPresumedLineNumber(
+ HCT->getLocation(),
+ &CloseLineInvalid);
+
+ if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine)
+ Diag(HOT->getLocation(), diag::warn_doc_html_open_close_mismatch)
+ << HOT->getTagName() << HCT->getTagName()
+ << HOT->getSourceRange() << HCT->getSourceRange();
+ else {
+ Diag(HOT->getLocation(), diag::warn_doc_html_open_close_mismatch)
+ << HOT->getTagName() << HCT->getTagName()
+ << HOT->getSourceRange();
+ Diag(HCT->getLocation(), diag::note_doc_html_closing_tag)
+ << HCT->getSourceRange();
+ }
+ }
+
+ return HCT;
}
FullComment *Sema::actOnFullComment(
@@ -219,6 +354,61 @@
return new (Allocator) FullComment(Blocks);
}
+void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) {
+ ParagraphComment *Paragraph = Command->getParagraph();
+ if (Paragraph->isWhitespace()) {
+ SourceLocation DiagLoc;
+ if (Command->getArgCount() > 0)
+ DiagLoc = Command->getArgRange(Command->getArgCount() - 1).getEnd();
+ if (!DiagLoc.isValid())
+ DiagLoc = Command->getCommandNameRange().getEnd();
+ Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
+ << Command->getCommandName()
+ << Command->getSourceRange();
+ }
+}
+
+unsigned Sema::resolveParmVarReference(StringRef Name,
+ const ParmVarDecl * const *ParamVars,
+ unsigned NumParams) {
+ for (unsigned i = 0; i != NumParams; ++i) {
+ const IdentifierInfo *II = ParamVars[i]->getIdentifier();
+ if (II && II->getName() == Name)
+ return i;
+ }
+ return ParamCommandComment::InvalidParamIndex;
+}
+
+unsigned Sema::correctTypoInParmVarReference(
+ StringRef Typo,
+ const ParmVarDecl * const *ParamVars,
+ unsigned NumParams) {
+ const unsigned MaxEditDistance = (Typo.size() + 2) / 3;
+ unsigned BestPVDIndex = NULL;
+ unsigned BestEditDistance = MaxEditDistance + 1;
+ for (unsigned i = 0; i != NumParams; ++i) {
+ const IdentifierInfo *II = ParamVars[i]->getIdentifier();
+ if (II) {
+ StringRef Name = II->getName();
+ unsigned MinPossibleEditDistance = abs(Name.size() - Typo.size());
+ if (MinPossibleEditDistance > 0 &&
+ Typo.size() / MinPossibleEditDistance < 3)
+ continue;
+
+ unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
+ if (EditDistance < BestEditDistance) {
+ BestEditDistance = EditDistance;
+ BestPVDIndex = i;
+ }
+ }
+ }
+
+ if (BestEditDistance <= MaxEditDistance)
+ return BestPVDIndex;
+ else
+ return ParamCommandComment::InvalidParamIndex;;
+}
+
// TODO: tablegen
bool Sema::isBlockCommand(StringRef Name) {
return llvm::StringSwitch<bool>(Name)
@@ -259,7 +449,9 @@
bool Sema::HTMLOpenTagNeedsClosing(StringRef Name) {
return llvm::StringSwitch<bool>(Name)
- .Case("br", true)
+ .Case("br", false)
+ .Case("hr", false)
+ .Case("li", false)
.Default(true);
}
Modified: cfe/trunk/lib/AST/RawCommentList.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/RawCommentList.cpp?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/lib/AST/RawCommentList.cpp (original)
+++ cfe/trunk/lib/AST/RawCommentList.cpp Wed Jul 11 16:38:39 2012
@@ -61,7 +61,7 @@
RawComment::RawComment(const SourceManager &SourceMgr, SourceRange SR,
bool Merged) :
Range(SR), RawTextValid(false), BriefTextValid(false),
- IsAlmostTrailingComment(false),
+ IsAttached(false), IsAlmostTrailingComment(false),
BeginLineValid(false), EndLineValid(false) {
// Extract raw comment text, if possible.
if (SR.getBegin() == SR.getEnd() || getRawText(SourceMgr).empty()) {
Modified: cfe/trunk/lib/Basic/DiagnosticIDs.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/DiagnosticIDs.cpp?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/DiagnosticIDs.cpp (original)
+++ cfe/trunk/lib/Basic/DiagnosticIDs.cpp Wed Jul 11 16:38:39 2012
@@ -79,6 +79,7 @@
#include "clang/Basic/DiagnosticLexKinds.inc"
#include "clang/Basic/DiagnosticParseKinds.inc"
#include "clang/Basic/DiagnosticASTKinds.inc"
+#include "clang/Basic/DiagnosticCommentKinds.inc"
#include "clang/Basic/DiagnosticSemaKinds.inc"
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
#undef DIAG
Modified: cfe/trunk/lib/Sema/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/CMakeLists.txt?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/CMakeLists.txt (original)
+++ cfe/trunk/lib/Sema/CMakeLists.txt Wed Jul 11 16:38:39 2012
@@ -46,6 +46,7 @@
ClangARMNeon
ClangAttrClasses
ClangAttrList
+ ClangDiagnosticComment
ClangDiagnosticSema
ClangCommentNodes
ClangDeclNodes
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Jul 11 16:38:39 2012
@@ -21,6 +21,7 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/CommentDiagnostic.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
@@ -2703,6 +2704,8 @@
}
}
+ ActOnDocumentableDecl(TagD);
+
return TagD;
}
@@ -7104,9 +7107,55 @@
}
}
+ ActOnDocumentableDecls(Group, NumDecls);
+
return DeclGroupPtrTy::make(DeclGroupRef::Create(Context, Group, NumDecls));
}
+void Sema::ActOnDocumentableDecl(Decl *D) {
+ ActOnDocumentableDecls(&D, 1);
+}
+
+void Sema::ActOnDocumentableDecls(Decl **Group, unsigned NumDecls) {
+ // Don't parse the comment if Doxygen diagnostics are ignored.
+ if (NumDecls == 0 || !Group[0])
+ return;
+
+ if (Diags.getDiagnosticLevel(diag::warn_doc_param_not_found,
+ Group[0]->getLocation())
+ == DiagnosticsEngine::Ignored)
+ return;
+
+ if (NumDecls >= 2) {
+ // This is a decl group. Normally it will contain only declarations
+ // procuded from declarator list. But in case we have any definitions or
+ // additional declaration references:
+ // 'typedef struct S {} S;'
+ // 'typedef struct S *S;'
+ // 'struct S *pS;'
+ // FinalizeDeclaratorGroup adds these as separate declarations.
+ Decl *MaybeTagDecl = Group[0];
+ if (MaybeTagDecl && isa<TagDecl>(MaybeTagDecl)) {
+ Group++;
+ NumDecls--;
+ }
+ }
+
+ // See if there are any new comments that are not attached to a decl.
+ ArrayRef<RawComment *> Comments = Context.getRawCommentList().getComments();
+ if (!Comments.empty() &&
+ !Comments.back()->isAttached()) {
+ // There is at least one comment that not attached to a decl.
+ // Maybe it should be attached to one of these decls?
+ //
+ // Note that this way we pick up not only comments that precede the
+ // declaration, but also comments that *follow* the declaration -- thanks to
+ // the lookahead in the lexer: we've consumed the semicolon and looked
+ // ahead through comments.
+ for (unsigned i = 0; i != NumDecls; ++i)
+ Context.getCommentForDecl(Group[i]);
+ }
+}
/// ActOnParamDeclarator - Called from Parser::ParseFunctionDeclarator()
/// to introduce parameters into function prototype scope.
@@ -8868,6 +8917,8 @@
// Enter the tag context.
PushDeclContext(S, Tag);
+
+ ActOnDocumentableDecl(TagD);
}
Decl *Sema::ActOnObjCContainerStartDefinition(Decl *IDecl) {
@@ -8877,6 +8928,7 @@
assert(getContainingDC(OCD) == CurContext &&
"The next DeclContext should be lexically contained in the current one.");
CurContext = OCD;
+ ActOnDocumentableDecl(IDecl);
return IDecl;
}
@@ -10339,6 +10391,8 @@
PushOnScopeChains(New, S);
}
+ ActOnDocumentableDecl(New);
+
return New;
}
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Jul 11 16:38:39 2012
@@ -5422,6 +5422,8 @@
}
}
+ ActOnDocumentableDecl(Namespc);
+
// Although we could have an invalid decl (i.e. the namespace name is a
// redefinition), push it as current DeclContext and try to continue parsing.
// FIXME: We should be able to push Namespc here, so that the each DeclContext
Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Wed Jul 11 16:38:39 2012
@@ -2952,7 +2952,9 @@
if (InferRelatedResultType)
ObjCMethod->SetRelatedResultType();
}
-
+
+ ActOnDocumentableDecl(ObjCMethod);
+
return ObjCMethod;
}
Removed: cfe/trunk/test/Sema/doxygen-comments.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/doxygen-comments.c?rev=160077&view=auto
==============================================================================
--- cfe/trunk/test/Sema/doxygen-comments.c (original)
+++ cfe/trunk/test/Sema/doxygen-comments.c (removed)
@@ -1,14 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -Wdoxygen -verify %s
-// RUN: %clang_cc1 -fsyntax-only -Wdoxygen -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
-// RUN: cp %s %t
-// RUN: %clang_cc1 -fsyntax-only -Wdoxygen -fixit %t
-// RUN: %clang_cc1 -fsyntax-only -Wdoxygen -Werror %t
-
-struct a {
- int x; //< comment // expected-warning {{not a Doxygen trailing comment}}
- int y; /*< comment */ // expected-warning {{not a Doxygen trailing comment}}
-};
-
-// CHECK: fix-it:"{{.*}}":{8:10-8:13}:"///<"
-// CHECK: fix-it:"{{.*}}":{9:10-9:13}:"/**<"
-
Copied: cfe/trunk/test/Sema/warn-documentation-almost-trailing.c (from r160070, cfe/trunk/test/Sema/doxygen-comments.c)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/warn-documentation-almost-trailing.c?p2=cfe/trunk/test/Sema/warn-documentation-almost-trailing.c&p1=cfe/trunk/test/Sema/doxygen-comments.c&r1=160070&r2=160078&rev=160078&view=diff
==============================================================================
--- cfe/trunk/test/Sema/doxygen-comments.c (original)
+++ cfe/trunk/test/Sema/warn-documentation-almost-trailing.c Wed Jul 11 16:38:39 2012
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -fsyntax-only -Wdoxygen -verify %s
-// RUN: %clang_cc1 -fsyntax-only -Wdoxygen -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -fsyntax-only -Wdocumentation -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wdocumentation -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
// RUN: cp %s %t
-// RUN: %clang_cc1 -fsyntax-only -Wdoxygen -fixit %t
-// RUN: %clang_cc1 -fsyntax-only -Wdoxygen -Werror %t
+// RUN: %clang_cc1 -fsyntax-only -Wdocumentation -fixit %t
+// RUN: %clang_cc1 -fsyntax-only -Wdocumentation -Werror %t
struct a {
int x; //< comment // expected-warning {{not a Doxygen trailing comment}}
Added: cfe/trunk/test/Sema/warn-documentation-fixits.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/warn-documentation-fixits.c?rev=160078&view=auto
==============================================================================
--- cfe/trunk/test/Sema/warn-documentation-fixits.c (added)
+++ cfe/trunk/test/Sema/warn-documentation-fixits.c Wed Jul 11 16:38:39 2012
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -Wdocumentation -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wdocumentation -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+
+/// \param ZZZZZZZZZZ Blah blah. expected-warning {{parameter 'ZZZZZZZZZZ' not found in the function declaration}} expected-note {{did you mean 'a'?}}
+int test1(int a);
+
+/// \param aab Blah blah. expected-warning {{parameter 'aab' not found in the function declaration}} expected-note {{did you mean 'aaa'?}}
+int test2(int aaa, int bbb);
+
+// CHECK: fix-it:"{{.*}}":{4:12-4:22}:"a"
+// CHECK: fix-it:"{{.*}}":{7:12-7:15}:"aaa"
+
Added: cfe/trunk/test/Sema/warn-documentation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/warn-documentation.cpp?rev=160078&view=auto
==============================================================================
--- cfe/trunk/test/Sema/warn-documentation.cpp (added)
+++ cfe/trunk/test/Sema/warn-documentation.cpp Wed Jul 11 16:38:39 2012
@@ -0,0 +1,272 @@
+// RUN: %clang_cc1 -fsyntax-only -Wdocumentation -Wdocumentation-pedantic -verify %s
+
+// expected-warning at +1 {{expected quoted string after equals sign}}
+/// <a href=>
+int test_html1(int);
+
+// expected-warning at +1 {{expected quoted string after equals sign}}
+/// <a href==>
+int test_html2(int);
+
+// expected-warning at +2 {{expected quoted string after equals sign}}
+// expected-warning at +1 {{HTML opening tag prematurely ended, expected attribute name or '>'}}
+/// <a href= blah
+int test_html3(int);
+
+// expected-warning at +1 {{HTML opening tag prematurely ended, expected attribute name or '>'}}
+/// <a =>
+int test_html4(int);
+
+// expected-warning at +1 {{HTML opening tag prematurely ended, expected attribute name or '>'}}
+/// <a "aaa">
+int test_html5(int);
+
+// expected-warning at +1 {{HTML opening tag prematurely ended, expected attribute name or '>'}}
+/// <a a="b" =>
+int test_html6(int);
+
+// expected-warning at +1 {{HTML opening tag prematurely ended, expected attribute name or '>'}}
+/// <a a="b" "aaa">
+int test_html7(int);
+
+// expected-warning at +1 {{HTML opening tag prematurely ended, expected attribute name or '>'}}
+/// <a a="b" =
+int test_html8(int);
+
+// expected-warning at +2 {{HTML opening tag prematurely ended, expected attribute name or '>'}} expected-note at +1 {{HTML tag started here}}
+/** Aaa bbb<ccc ddd eee
+ * fff ggg.
+ */
+int test_html9(int);
+
+// expected-warning at +1 {{HTML opening tag prematurely ended, expected attribute name or '>'}}
+/** Aaa bbb<ccc ddd eee 42%
+ * fff ggg.
+ */
+int test_html10(int);
+
+
+/// <blockquote>Meow</blockquote>
+int test_html_nesting1(int);
+
+/// <b><i>Meow</i></b>
+int test_html_nesting2(int);
+
+/// <p>Aaa<br>
+/// Bbb</p>
+int test_html_nesting3(int);
+
+/// <p>Aaa<br />
+/// Bbb</p>
+int test_html_nesting4(int);
+
+// expected-warning at +1 {{HTML closing tag does not match any opening tag}}
+/// <b><i>Meow</a>
+int test_html_nesting5(int);
+
+// expected-warning at +2 {{HTML opening tag 'i' closed by 'b'}}
+// expected-warning at +1 {{HTML closing tag does not match any opening tag}}
+/// <b><i>Meow</b></b>
+int test_html_nesting6(int);
+
+// expected-warning at +2 {{HTML opening tag 'i' closed by 'b'}}
+// expected-warning at +1 {{HTML closing tag does not match any opening tag}}
+/// <b><i>Meow</b></i>
+int test_html_nesting7(int);
+
+
+// expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+/// \brief\brief Aaa
+int test_block_command1(int);
+
+// expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+/// \brief \brief Aaa
+int test_block_command2(int);
+
+// expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+/// \brief
+/// \brief Aaa
+int test_block_command3(int);
+
+// expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+/// \brief
+///
+/// \brief Aaa
+int test_block_command4(int);
+
+// There is trailing whitespace on one of the following lines, don't remove it!
+// expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+/// \brief
+///
+/// \brief Aaa
+int test_block_command5(int);
+
+// expected-warning at +1 {{'\param' command used in a comment that is not attached to a function declaration}}
+/// \param a Blah blah.
+int test_param1;
+
+// expected-warning at +1 {{empty paragraph passed to '\param' command}}
+/// \param
+/// \param a Blah blah.
+int test_param2(int a);
+
+// expected-warning at +1 {{empty paragraph passed to '\param' command}}
+/// \param a
+int test_param3(int a);
+
+/// \param a Blah blah.
+int test_param4(int a);
+
+/// \param [in] a Blah blah.
+int test_param5(int a);
+
+/// \param [out] a Blah blah.
+int test_param6(int a);
+
+/// \param [in,out] a Blah blah.
+int test_param7(int a);
+
+// expected-warning at +1 {{whitespace is not allowed in parameter passing direction}}
+/// \param [ in ] a Blah blah.
+int test_param8(int a);
+
+// expected-warning at +1 {{whitespace is not allowed in parameter passing direction}}
+/// \param [in, out] a Blah blah.
+int test_param9(int a);
+
+// expected-warning at +1 {{unrecognized parameter passing direction, valid directions are '[in]', '[out]' and '[in,out]'}}
+/// \param [ junk] a Blah blah.
+int test_param10(int a);
+
+// expected-warning at +1 {{parameter 'A' not found in the function declaration}} expected-note at +1 {{did you mean 'a'?}}
+/// \param A Blah blah.
+int test_param11(int a);
+
+// expected-warning at +1 {{parameter 'aab' not found in the function declaration}} expected-note at +1 {{did you mean 'aaa'?}}
+/// \param aab Blah blah.
+int test_param12(int aaa, int bbb);
+
+// expected-warning at +1 {{parameter 'aab' not found in the function declaration}}
+/// \param aab Blah blah.
+int test_param13(int bbb, int ccc);
+
+class C {
+ // expected-warning at +1 {{parameter 'aaa' not found in the function declaration}}
+ /// \param aaa Blah blah.
+ C(int bbb, int ccc);
+
+ // expected-warning at +1 {{parameter 'aaa' not found in the function declaration}}
+ /// \param aaa Blah blah.
+ int test_param14(int bbb, int ccc);
+};
+
+
+// expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+int test1; ///< \brief\brief Aaa
+
+// expected-warning at +2 {{empty paragraph passed to '\brief' command}}
+// expected-warning at +2 {{empty paragraph passed to '\brief' command}}
+int test2, ///< \brief\brief Aaa
+ test3; ///< \brief\brief Aaa
+
+// expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+int test4; ///< \brief
+ ///< \brief Aaa
+
+
+// Check that we attach the comment to the declaration during parsing in the
+// following cases. The test is based on the fact that we don't parse
+// documentation comments that are not attached to anything.
+
+// expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+/// \brief\brief Aaa
+int test_attach1;
+
+// expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+/// \brief\brief Aaa
+int test_attach2(int);
+
+// expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+/// \brief\brief Aaa
+struct test_attach3 {
+ // expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+ /// \brief\brief Aaa
+ int test_attach4;
+
+ // expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+ int test_attach5; ///< \brief\brief Aaa
+
+ // expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+ /// \brief\brief Aaa
+ int test_attach6(int);
+};
+
+// expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+/// \brief\brief Aaa
+class test_attach7 {
+ // expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+ /// \brief\brief Aaa
+ int test_attach8;
+
+ // expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+ int test_attach9; ///< \brief\brief Aaa
+
+ // expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+ /// \brief\brief Aaa
+ int test_attach10(int);
+};
+
+// expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+/// \brief\brief Aaa
+enum test_attach9 {
+ // expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+ /// \brief\brief Aaa
+ test_attach10,
+
+ // expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+ test_attach11 ///< \brief\brief Aaa
+};
+
+// expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+/// \brief\brief Aaa
+struct test_noattach12 *test_attach13;
+
+// expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+/// \brief\brief Aaa
+typedef struct test_noattach14 *test_attach15;
+
+// expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+/// \brief\brief Aaa
+typedef struct test_attach16 { int a; } test_attach17;
+
+struct S { int a; };
+
+// expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+/// \brief\brief Aaa
+struct S *test_attach18;
+
+// expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+/// \brief\brief Aaa
+typedef struct S *test_attach19;
+
+// expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+/// \brief\brief Aaa
+struct test_attach20;
+
+// expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+/// \brief\brief Aaa
+typedef struct test_attach21 {
+ // expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+ /// \brief\brief Aaa
+ int test_attach22;
+} test_attach23;
+
+// expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+/// \brief\brief Aaa
+namespace test_attach24 {
+ // expected-warning at +1 {{empty paragraph passed to '\brief' command}}
+ /// \brief\brief Aaa
+ namespace test_attach25 {
+ }
+}
+
Added: cfe/trunk/test/Sema/warn-documentation.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/warn-documentation.m?rev=160078&view=auto
==============================================================================
--- cfe/trunk/test/Sema/warn-documentation.m (added)
+++ cfe/trunk/test/Sema/warn-documentation.m Wed Jul 11 16:38:39 2012
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -fsyntax-only -Wdocumentation -Wdocumentation-pedantic -verify %s
+
+ at class NSString;
+
+// expected-warning at +2 {{empty paragraph passed to '\brief' command}}
+/**
+ * \brief\brief Aaa
+ */
+ at interface A
+// expected-warning at +2 {{empty paragraph passed to '\brief' command}}
+/**
+ * \brief\brief Aaa
+ * \param aaa Aaa
+ * \param bbb Bbb
+ */
++ (NSString *)test1:(NSString *)aaa suffix:(NSString *)bbb;
+
+// expected-warning at +2 {{parameter 'aab' not found in the function declaration}} expected-note at +2 {{did you mean 'aaa'?}}
+/**
+ * \param aab Aaa
+ */
++ (NSString *)test2:(NSString *)aaa;
+ at end
+
Modified: cfe/trunk/tools/diagtool/DiagnosticNames.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/diagtool/DiagnosticNames.cpp?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/tools/diagtool/DiagnosticNames.cpp (original)
+++ cfe/trunk/tools/diagtool/DiagnosticNames.cpp Wed Jul 11 16:38:39 2012
@@ -39,6 +39,7 @@
#include "clang/Basic/DiagnosticLexKinds.inc"
#include "clang/Basic/DiagnosticParseKinds.inc"
#include "clang/Basic/DiagnosticASTKinds.inc"
+#include "clang/Basic/DiagnosticCommentKinds.inc"
#include "clang/Basic/DiagnosticSemaKinds.inc"
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
#undef DIAG
Modified: cfe/trunk/unittests/AST/CommentLexer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/CommentLexer.cpp?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/unittests/AST/CommentLexer.cpp (original)
+++ cfe/trunk/unittests/AST/CommentLexer.cpp Wed Jul 11 16:38:39 2012
@@ -1142,6 +1142,60 @@
}
TEST_F(CommentLexerTest, HTML15) {
+ const char *Sources[] = {
+ "// <tag/>",
+ "// <tag />"
+ };
+
+ for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
+ std::vector<Token> Toks;
+
+ lexString(Sources[i], Toks);
+
+ ASSERT_EQ(4U, Toks.size());
+
+ ASSERT_EQ(tok::text, Toks[0].getKind());
+ ASSERT_EQ(StringRef(" "), Toks[0].getText());
+
+ ASSERT_EQ(tok::html_tag_open, Toks[1].getKind());
+ ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagOpenName());
+
+ ASSERT_EQ(tok::html_slash_greater, Toks[2].getKind());
+
+ ASSERT_EQ(tok::newline, Toks[3].getKind());
+ }
+}
+
+TEST_F(CommentLexerTest, HTML16) {
+ const char *Sources[] = {
+ "// <tag/ Aaa",
+ "// <tag / Aaa"
+ };
+
+ for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
+ std::vector<Token> Toks;
+
+ lexString(Sources[i], Toks);
+
+ ASSERT_EQ(5U, Toks.size());
+
+ ASSERT_EQ(tok::text, Toks[0].getKind());
+ ASSERT_EQ(StringRef(" "), Toks[0].getText());
+
+ ASSERT_EQ(tok::html_tag_open, Toks[1].getKind());
+ ASSERT_EQ(StringRef("tag"), Toks[1].getHTMLTagOpenName());
+
+ ASSERT_EQ(tok::text, Toks[2].getKind());
+ ASSERT_EQ(StringRef("/"), Toks[2].getText());
+
+ ASSERT_EQ(tok::text, Toks[3].getKind());
+ ASSERT_EQ(StringRef(" Aaa"), Toks[3].getText());
+
+ ASSERT_EQ(tok::newline, Toks[4].getKind());
+ }
+}
+
+TEST_F(CommentLexerTest, HTML17) {
const char *Source = "// </";
std::vector<Token> Toks;
@@ -1159,8 +1213,7 @@
ASSERT_EQ(tok::newline, Toks[2].getKind());
}
-
-TEST_F(CommentLexerTest, HTML16) {
+TEST_F(CommentLexerTest, HTML18) {
const char *Source = "// </@";
std::vector<Token> Toks;
@@ -1181,7 +1234,7 @@
ASSERT_EQ(tok::newline, Toks[3].getKind());
}
-TEST_F(CommentLexerTest, HTML17) {
+TEST_F(CommentLexerTest, HTML19) {
const char *Source = "// </tag";
std::vector<Token> Toks;
@@ -1199,7 +1252,7 @@
ASSERT_EQ(tok::newline, Toks[2].getKind());
}
-TEST_F(CommentLexerTest, HTML18) {
+TEST_F(CommentLexerTest, HTML20) {
const char *Sources[] = {
"// </tag>",
"// </ tag>",
Modified: cfe/trunk/unittests/AST/CommentParser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/CommentParser.cpp?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/unittests/AST/CommentParser.cpp (original)
+++ cfe/trunk/unittests/AST/CommentParser.cpp Wed Jul 11 16:38:39 2012
@@ -57,8 +57,8 @@
comments::Lexer L(Begin, CommentOptions(),
Source, Source + strlen(Source));
- comments::Sema S(Allocator);
- comments::Parser P(L, S, Allocator);
+ comments::Sema S(Allocator, SourceMgr, Diags);
+ comments::Parser P(L, S, Allocator, SourceMgr, Diags);
comments::FullComment *FC = P.parseFullComment();
if (DEBUG) {
@@ -292,6 +292,25 @@
return ::testing::AssertionSuccess();
}
+struct SelfClosing {};
+
+::testing::AssertionResult HasHTMLOpenTagAt(const Comment *C,
+ size_t Idx,
+ HTMLOpenTagComment *&HOT,
+ StringRef TagName,
+ SelfClosing) {
+ ::testing::AssertionResult AR = HasHTMLOpenTagAt(C, Idx, HOT, TagName);
+ if (!AR)
+ return AR;
+
+ if (!HOT->isSelfClosing())
+ return ::testing::AssertionFailure()
+ << "HTMLOpenTagComment is not self-closing";
+
+ return ::testing::AssertionSuccess();
+}
+
+
struct NoAttrs {};
::testing::AssertionResult HasHTMLOpenTagAt(const Comment *C,
@@ -303,6 +322,10 @@
if (!AR)
return AR;
+ if (HOT->isSelfClosing())
+ return ::testing::AssertionFailure()
+ << "HTMLOpenTagComment is self-closing";
+
if (HOT->getAttrCount() != 0)
return ::testing::AssertionFailure()
<< "HTMLOpenTagComment has " << HOT->getAttrCount() << " attr(s), "
@@ -321,6 +344,10 @@
if (!AR)
return AR;
+ if (HOT->isSelfClosing())
+ return ::testing::AssertionFailure()
+ << "HTMLOpenTagComment is self-closing";
+
if (HOT->getAttrCount() != 1)
return ::testing::AssertionFailure()
<< "HTMLOpenTagComment has " << HOT->getAttrCount() << " attr(s), "
@@ -837,6 +864,28 @@
TEST_F(CommentParserTest, HTML2) {
const char *Sources[] = {
+ "// <br/>",
+ "// <br />"
+ };
+
+ for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
+ FullComment *FC = parseString(Sources[i]);
+ ASSERT_TRUE(HasChildCount(FC, 1));
+
+ {
+ ParagraphComment *PC;
+ HTMLOpenTagComment *HOT;
+ ASSERT_TRUE(GetChildAt(FC, 0, PC));
+
+ ASSERT_TRUE(HasChildCount(PC, 2));
+ ASSERT_TRUE(HasTextAt(PC, 0, " "));
+ ASSERT_TRUE(HasHTMLOpenTagAt(PC, 1, HOT, "br", SelfClosing()));
+ }
+ }
+}
+
+TEST_F(CommentParserTest, HTML3) {
+ const char *Sources[] = {
"// <a href",
"// <a href ",
"// <a href>",
@@ -859,7 +908,7 @@
}
}
-TEST_F(CommentParserTest, HTML3) {
+TEST_F(CommentParserTest, HTML4) {
const char *Sources[] = {
"// <a href=\"bbb\"",
"// <a href=\"bbb\">",
@@ -881,7 +930,7 @@
}
}
-TEST_F(CommentParserTest, HTML4) {
+TEST_F(CommentParserTest, HTML5) {
const char *Sources[] = {
"// </a",
"// </a>",
@@ -904,7 +953,7 @@
}
}
-TEST_F(CommentParserTest, HTML5) {
+TEST_F(CommentParserTest, HTML6) {
const char *Source =
"// <pre>\n"
"// Aaa\n"
Modified: cfe/trunk/unittests/AST/Makefile
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/Makefile?rev=160078&r1=160077&r2=160078&view=diff
==============================================================================
--- cfe/trunk/unittests/AST/Makefile (original)
+++ cfe/trunk/unittests/AST/Makefile Wed Jul 11 16:38:39 2012
@@ -10,6 +10,6 @@
CLANG_LEVEL = ../..
TESTNAME = AST
LINK_COMPONENTS := support mc
-USEDLIBS = clangAST.a clangBasic.a
+USEDLIBS = clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/unittests/Makefile
More information about the cfe-commits
mailing list