diff options
author | Alexander Kornienko <alexfh@google.com> | 2014-05-19 16:39:08 +0000 |
---|---|---|
committer | Alexander Kornienko <alexfh@google.com> | 2014-05-19 16:39:08 +0000 |
commit | bef51cdf055d19dfb276c0e155d82acf62feed09 (patch) | |
tree | 65692f83672d62722c421559d7d1e28b70821794 /clang-tools-extra/clang-tidy/llvm/NamespaceCommentCheck.cpp | |
parent | 06c59e259867ee866b23ae3108a10e62af72c852 (diff) | |
download | bcm5719-llvm-bef51cdf055d19dfb276c0e155d82acf62feed09.tar.gz bcm5719-llvm-bef51cdf055d19dfb276c0e155d82acf62feed09.zip |
Improved llvm-namespace-comment check.
Summary:
Handle various forms of existing namespace closing comments, fix
existing comments with wrong namespace name, ignore short namespaces.
The state of this check now seems to be enough to enable it by default to gather
user feedback ;)
Reviewers: klimek
Reviewed By: klimek
Subscribers: cfe-commits
Differential Revision: http://reviews.llvm.org/D3825
llvm-svn: 209141
Diffstat (limited to 'clang-tools-extra/clang-tidy/llvm/NamespaceCommentCheck.cpp')
-rw-r--r-- | clang-tools-extra/clang-tidy/llvm/NamespaceCommentCheck.cpp | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/llvm/NamespaceCommentCheck.cpp b/clang-tools-extra/clang-tidy/llvm/NamespaceCommentCheck.cpp new file mode 100644 index 00000000000..b5dca4ba13f --- /dev/null +++ b/clang-tools-extra/clang-tidy/llvm/NamespaceCommentCheck.cpp @@ -0,0 +1,115 @@ +//===--- NamespaceCommentCheck.cpp - clang-tidy ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "NamespaceCommentCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Lex/Lexer.h" + + +#include "llvm/Support/raw_ostream.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { + +NamespaceCommentCheck::NamespaceCommentCheck() + : NamespaceCommentPattern("^/[/*] *(end (of )?)? *(anonymous|unnamed)? *" + "namespace( +([a-zA-Z0-9_]+))? *(\\*/)?$", + llvm::Regex::IgnoreCase), + ShortNamespaceLines(1) {} + +void NamespaceCommentCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher(namespaceDecl().bind("namespace"), this); +} + +bool locationsInSameFile(const SourceManager &Sources, SourceLocation Loc1, + SourceLocation Loc2) { + return Loc1.isFileID() && Loc2.isFileID() && + Sources.getFileID(Loc1) == Sources.getFileID(Loc2); +} + +std::string getNamespaceComment(const NamespaceDecl *ND, bool InsertLineBreak) { + std::string Fix = "// namespace"; + if (!ND->isAnonymousNamespace()) + Fix.append(" ").append(ND->getNameAsString()); + if (InsertLineBreak) + Fix.append("\n"); + return Fix; +} + +void NamespaceCommentCheck::check(const MatchFinder::MatchResult &Result) { + const NamespaceDecl *ND = Result.Nodes.getNodeAs<NamespaceDecl>("namespace"); + const SourceManager &Sources = *Result.SourceManager; + + if (!locationsInSameFile(Sources, ND->getLocStart(), ND->getRBraceLoc())) + return; + + // Don't require closing comments for namespaces spanning less than certain + // number of lines. + unsigned StartLine = Sources.getSpellingLineNumber(ND->getLocStart()); + unsigned EndLine = Sources.getSpellingLineNumber(ND->getRBraceLoc()); + if (EndLine - StartLine + 1 <= ShortNamespaceLines) + return; + + // Find next token after the namespace closing brace. + SourceLocation AfterRBrace = ND->getRBraceLoc().getLocWithOffset(1); + SourceLocation Loc = AfterRBrace; + Token Tok; + // Skip whitespace until we find the next token. + while (Lexer::getRawToken(Loc, Tok, Sources, Result.Context->getLangOpts())) { + Loc = Loc.getLocWithOffset(1); + } + if (!locationsInSameFile(Sources, ND->getRBraceLoc(), Loc)) + return; + + bool NextTokenIsOnSameLine = Sources.getSpellingLineNumber(Loc) == EndLine; + bool NeedLineBreak = NextTokenIsOnSameLine && Tok.isNot(tok::eof); + + // Try to find existing namespace closing comment on the same line. + if (Tok.is(tok::comment) && NextTokenIsOnSameLine) { + StringRef Comment(Sources.getCharacterData(Loc), Tok.getLength()); + SmallVector<StringRef, 6> Groups; + if (NamespaceCommentPattern.match(Comment, &Groups)) { + StringRef NamespaceNameInComment = Groups.size() >= 6 ? Groups[5] : ""; + + // Check if the namespace in the comment is the same. + if ((ND->isAnonymousNamespace() && NamespaceNameInComment.empty()) || + ND->getNameAsString() == NamespaceNameInComment) { + // FIXME: Maybe we need a strict mode, where we always fix namespace + // comments with different format. + return; + } + + // Otherwise we need to fix the comment. + NeedLineBreak = Comment.startswith("/*"); + CharSourceRange OldCommentRange = CharSourceRange::getCharRange( + SourceRange(Loc, Loc.getLocWithOffset(Tok.getLength()))); + diag(Loc, "namespace closing comment refers to a wrong namespace '%0'") + << NamespaceNameInComment + << FixItHint::CreateReplacement( + OldCommentRange, getNamespaceComment(ND, NeedLineBreak)); + return; + } + + // This is not a recognized form of a namespace closing comment. + // Leave line comment on the same line. Move block comment to the next line, + // as it can be multi-line or there may be other tokens behind it. + if (Comment.startswith("//")) + NeedLineBreak = false; + } + + diag(ND->getLocation(), "namespace not terminated with a closing comment") + << FixItHint::CreateInsertion( + AfterRBrace, " " + getNamespaceComment(ND, NeedLineBreak)); +} + +} // namespace tidy +} // namespace clang |