From f26054f0fb53f65dbfbfc01954dc3b2028582cde Mon Sep 17 00:00:00 2001 From: Dmitri Gribenko Date: Wed, 11 Jul 2012 21:38:39 +0000 Subject: 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,
). 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 --- clang/lib/Sema/CMakeLists.txt | 1 + clang/lib/Sema/SemaDecl.cpp | 54 +++++++++++++++++++++++++++++++++++++++++ clang/lib/Sema/SemaDeclCXX.cpp | 2 ++ clang/lib/Sema/SemaDeclObjC.cpp | 4 ++- 4 files changed, 60 insertions(+), 1 deletion(-) (limited to 'clang/lib/Sema') diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt index ad684d3f99e..58cab5aefca 100644 --- a/clang/lib/Sema/CMakeLists.txt +++ b/clang/lib/Sema/CMakeLists.txt @@ -46,6 +46,7 @@ add_dependencies(clangSema ClangARMNeon ClangAttrClasses ClangAttrList + ClangDiagnosticComment ClangDiagnosticSema ClangCommentNodes ClangDeclNodes diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 607f57d74fd..dfe2882166b 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -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 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, } } + ActOnDocumentableDecl(TagD); + return TagD; } @@ -7104,9 +7107,55 @@ Sema::BuildDeclaratorGroup(Decl **Group, unsigned NumDecls, } } + 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(MaybeTagDecl)) { + Group++; + NumDecls--; + } + } + + // See if there are any new comments that are not attached to a decl. + ArrayRef 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 @@ void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) { // Enter the tag context. PushDeclContext(S, Tag); + + ActOnDocumentableDecl(TagD); } Decl *Sema::ActOnObjCContainerStartDefinition(Decl *IDecl) { @@ -8877,6 +8928,7 @@ Decl *Sema::ActOnObjCContainerStartDefinition(Decl *IDecl) { 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 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst, PushOnScopeChains(New, S); } + ActOnDocumentableDecl(New); + return New; } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 32708090c9d..fa42fdd827c 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -5422,6 +5422,8 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, } } + 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 diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index d67fb5002a1..8d4694662d5 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -2952,7 +2952,9 @@ Decl *Sema::ActOnMethodDeclaration( if (InferRelatedResultType) ObjCMethod->SetRelatedResultType(); } - + + ActOnDocumentableDecl(ObjCMethod); + return ObjCMethod; } -- cgit v1.2.3