Index: include/clang/AST/RawCommentList.h =================================================================== --- include/clang/AST/RawCommentList.h +++ include/clang/AST/RawCommentList.h @@ -11,6 +11,7 @@ #define LLVM_CLANG_AST_RAW_COMMENT_LIST_H #include "clang/Basic/SourceManager.h" +#include "clang/Basic/CommentOptions.h" #include "llvm/ADT/ArrayRef.h" namespace clang { @@ -40,7 +41,8 @@ RawComment() : Kind(RCK_Invalid), IsAlmostTrailingComment(false) { } RawComment(const SourceManager &SourceMgr, SourceRange SR, - bool Merged = false); + bool Merged = false, + bool TreatOrdinaryCommentAsDocComment = false); CommentKind getKind() const LLVM_READONLY { return (CommentKind) Kind; @@ -87,7 +89,7 @@ /// Returns true if this comment any kind of a documentation comment. bool isDocumentation() const LLVM_READONLY { - return !isInvalid() && !isOrdinary(); + return !isInvalid() && (!isOrdinary() || TreatOrdinaryCommentAsDocComment); } /// Returns raw comment text with comment markers. @@ -139,14 +141,19 @@ mutable bool EndLineValid : 1; ///< True if EndLine is valid mutable unsigned BeginLine; ///< Cached line number mutable unsigned EndLine; ///< Cached line number + /// When true, ordinary comments starting with "//" will be considered as + // doc-comments. + bool TreatOrdinaryCommentAsDocComment; /// \brief Constructor for AST deserialization. RawComment(SourceRange SR, CommentKind K, bool IsTrailingComment, - bool IsAlmostTrailingComment) : + bool IsAlmostTrailingComment, + bool TreatOrdinaryCommentAsDoccomment) : Range(SR), RawTextValid(false), BriefTextValid(false), Kind(K), IsAttached(false), IsTrailingComment(IsTrailingComment), IsAlmostTrailingComment(IsAlmostTrailingComment), - BeginLineValid(false), EndLineValid(false) + BeginLineValid(false), EndLineValid(false), + TreatOrdinaryCommentAsDocComment(TreatOrdinaryCommentAsDocComment) { } StringRef getRawTextSlow(const SourceManager &SourceMgr) const; @@ -207,4 +214,3 @@ } // end namespace clang #endif - Index: include/clang/Basic/CommentOptions.h =================================================================== --- include/clang/Basic/CommentOptions.h +++ include/clang/Basic/CommentOptions.h @@ -27,6 +27,11 @@ /// \brief Command names to treat as block commands in comments. /// Should not include the leading backslash. BlockCommandNamesTy BlockCommandNames; + + /// \brief Treat ordinary comments as doc-comments. + bool TreatOrdinaryCommentAsDocComment; + + CommentOptions() : TreatOrdinaryCommentAsDocComment(false) { } }; } // end namespace clang Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -330,6 +330,7 @@ def fcomment_block_commands : CommaJoined<["-"], "fcomment-block-commands=">, Group, Flags<[CC1Option]>, HelpText<"Treat each comma separated argument in as a documentation comment block command">, MetaVarName<"">; +def ftreat_ordinary_comment_as_doccomment : Flag<["-"], "ftreat-ordinary-comment-as-doccomment">, Group; def fcommon : Flag<["-"], "fcommon">, Group; def fcompile_resource_EQ : Joined<["-"], "fcompile-resource=">, Group; def fconstant_cfstrings : Flag<["-"], "fconstant-cfstrings">, Group; Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -141,7 +141,9 @@ // When searching for comments during parsing, the comment we are looking // for is usually among the last two comments we parsed -- check them // first. - RawComment CommentAtDeclLoc(SourceMgr, SourceRange(DeclLoc)); + RawComment CommentAtDeclLoc( + SourceMgr, SourceRange(DeclLoc), false, + LangOpts.CommentOpts.TreatOrdinaryCommentAsDocComment); BeforeThanCompare Compare(SourceMgr); ArrayRef::iterator MaybeBeforeDecl = RawComments.end() - 1; bool Found = Compare(*MaybeBeforeDecl, &CommentAtDeclLoc); Index: lib/AST/RawCommentList.cpp =================================================================== --- lib/AST/RawCommentList.cpp +++ lib/AST/RawCommentList.cpp @@ -63,10 +63,11 @@ } // unnamed namespace RawComment::RawComment(const SourceManager &SourceMgr, SourceRange SR, - bool Merged) : + bool Merged, bool TreatOrdinaryCommentAsDocComment) : Range(SR), RawTextValid(false), BriefTextValid(false), IsAttached(false), IsAlmostTrailingComment(false), - BeginLineValid(false), EndLineValid(false) { + BeginLineValid(false), EndLineValid(false), + TreatOrdinaryCommentAsDocComment(TreatOrdinaryCommentAsDocComment) { // Extract raw comment text, if possible. if (SR.getBegin() == SR.getEnd() || getRawText(SourceMgr).empty()) { Kind = RCK_Invalid; @@ -227,8 +228,9 @@ PrevCommentEndLoc = RC.getSourceRange().getEnd(); - // Ordinary comments are not interesting for us. - if (RC.isOrdinary()) + // Ordinary comments are not interesting for us only when they are not + // treated as documentation. + if (!RC.isDocumentation()) return; // If this is the first Doxygen comment, save it (because there isn't @@ -253,7 +255,7 @@ if (C1EndLine + 1 == C2BeginLine || C1EndLine == C2BeginLine) { SourceRange MergedRange(C1.getSourceRange().getBegin(), C2.getSourceRange().getEnd()); - *Comments.back() = RawComment(SourceMgr, MergedRange, true); + *Comments.back() = RawComment(SourceMgr, MergedRange, true, true); Merged = true; } } @@ -262,4 +264,3 @@ OnlyWhitespaceSeen = true; } - Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -281,6 +281,8 @@ static void ParseCommentArgs(CommentOptions &Opts, ArgList &Args) { Opts.BlockCommandNames = Args.getAllArgValues(OPT_fcomment_block_commands); + Opts.TreatOrdinaryCommentAsDocComment = + Args.hasArg(OPT_ftreat_ordinary_comment_as_doccomment); } static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Index: lib/Sema/Sema.cpp =================================================================== --- lib/Sema/Sema.cpp +++ lib/Sema/Sema.cpp @@ -1073,7 +1073,8 @@ if (!LangOpts.RetainCommentsFromSystemHeaders && SourceMgr.isInSystemHeader(Comment.getBegin())) return; - RawComment RC(SourceMgr, Comment); + RawComment RC(SourceMgr, Comment, false, + LangOpts.CommentOpts.TreatOrdinaryCommentAsDocComment); if (RC.isAlmostTrailingComment()) { SourceRange MagicMarkerRange(Comment.getBegin(), Comment.getBegin().getLocWithOffset(3)); Index: lib/Serialization/ASTReader.cpp =================================================================== --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -7158,9 +7158,10 @@ (RawComment::CommentKind) Record[Idx++]; bool IsTrailingComment = Record[Idx++]; bool IsAlmostTrailingComment = Record[Idx++]; - Comments.push_back(new (Context) RawComment(SR, Kind, - IsTrailingComment, - IsAlmostTrailingComment)); + Comments.push_back(new (Context) RawComment( + SR, Kind, IsTrailingComment, IsAlmostTrailingComment, + Context + .getLangOpts().CommentOpts.TreatOrdinaryCommentAsDocComment)); break; } } Index: unittests/Frontend/FrontendActionTest.cpp =================================================================== --- unittests/Frontend/FrontendActionTest.cpp +++ unittests/Frontend/FrontendActionTest.cpp @@ -70,4 +70,63 @@ EXPECT_EQ("x", test_action.decl_names[2]); } +class TestOrdinaryCommentAction : public ASTFrontendAction { + public: + std::vector comments; + + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) { + return new Visitor(&comments); + } + + private: + class Visitor : public ASTConsumer, public RecursiveASTVisitor { + public: + explicit Visitor(std::vector *comments) + : comments_(comments), context_(NULL) { + } + + virtual void HandleTranslationUnit(ASTContext &context) { + this->context_ = &context; + TraverseDecl(context.getTranslationUnitDecl()); + } + + bool VisitFunctionDecl(clang::FunctionDecl* decl) { + RawComment* RC = context_->getRawCommentForDeclNoCache(decl); + if (RC != NULL) { + comments_->push_back(RC->getRawText(context_->getSourceManager()).str()); + } + return true; + } + + private: + std::vector* comments_; + ASTContext* context_; + }; +}; + +TEST(ASTFrontendAction, TreatOrdinaryCommentAsDoccomment) { + CompilerInvocation *invocation = new CompilerInvocation; + invocation->getPreprocessorOpts().addRemappedFile( + "test.cc", MemoryBuffer::getMemBuffer( + "// ordinary comment\n" + "// for main method\n" + "int main() { float x; }" + )); + invocation->getFrontendOpts().Inputs.push_back(FrontendInputFile("test.cc", + IK_CXX)); + invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly; + invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu"; + invocation->getLangOpts() + ->CommentOpts.TreatOrdinaryCommentAsDocComment = true; + CompilerInstance compiler; + compiler.setInvocation(invocation); + compiler.createDiagnostics(); + + TestOrdinaryCommentAction test_action; + ASSERT_TRUE(compiler.ExecuteAction(test_action)); + ASSERT_EQ(1, test_action.comments.size()); + EXPECT_EQ("// ordinary comment\n// for main method", test_action.comments[0]); +} + } // anonymous namespace