Address review comments.
Hi alexfh,
http://llvm-reviews.chandlerc.com/D2914
CHANGE SINCE LAST DIFF
http://llvm-reviews.chandlerc.com/D2914?vs=7453&id=7584#toc
Files:
clang-tidy/misc/MiscTidyModule.cpp
clang-tidy/misc/MiscTidyModule.h
test/clang-tidy/arg-comments.cpp
Index: clang-tidy/misc/MiscTidyModule.cpp
===================================================================
--- clang-tidy/misc/MiscTidyModule.cpp
+++ clang-tidy/misc/MiscTidyModule.cpp
@@ -7,16 +7,168 @@
//
//===----------------------------------------------------------------------===//
+#include "MiscTidyModule.h"
#include "../ClangTidy.h"
#include "../ClangTidyModule.h"
#include "../ClangTidyModuleRegistry.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Token.h"
+
+using namespace clang::ast_matchers;
namespace clang {
namespace tidy {
+void ArgumentCommentCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(callExpr(unless(operatorCallExpr())).bind("expr"), this);
+ Finder->addMatcher(constructExpr().bind("expr"), this);
+}
+
+std::vector<std::pair<SourceLocation, StringRef>>
+ArgumentCommentCheck::getCommentsInRange(ASTContext *Ctx, SourceRange Range) {
+ std::vector<std::pair<SourceLocation, StringRef>> Comments;
+ auto &SM = Ctx->getSourceManager();
+ std::pair<FileID, unsigned> BeginLoc = SM.getDecomposedLoc(Range.getBegin()),
+ EndLoc = SM.getDecomposedLoc(Range.getEnd());
+
+ if (BeginLoc.first != EndLoc.first)
+ return Comments;
+
+ bool Invalid = false;
+ StringRef Buffer = SM.getBufferData(BeginLoc.first, &Invalid);
+ if (Invalid)
+ return Comments;
+
+ const char *StrData = Buffer.data() + BeginLoc.second;
+
+ Lexer TheLexer(SM.getLocForStartOfFile(BeginLoc.first), Ctx->getLangOpts(),
+ Buffer.begin(), StrData, Buffer.end());
+ TheLexer.SetCommentRetentionState(true);
+
+ while (true) {
+ Token Tok;
+ if (TheLexer.LexFromRawLexer(Tok))
+ break;
+ if (Tok.getLocation() == Range.getEnd() || Tok.getKind() == tok::eof)
+ break;
+
+ if (Tok.getKind() == tok::comment) {
+ std::pair<FileID, unsigned> CommentLoc =
+ SM.getDecomposedLoc(Tok.getLocation());
+ assert(CommentLoc.first == BeginLoc.first);
+ Comments.emplace_back(
+ Tok.getLocation(),
+ StringRef(Buffer.begin() + CommentLoc.second, Tok.getLength()));
+ }
+ }
+
+ return Comments;
+}
+
+bool
+ArgumentCommentCheck::isLikelyTypo(llvm::ArrayRef<ParmVarDecl *> Params,
+ StringRef ArgName, unsigned ArgIndex) {
+ std::string ArgNameLower = ArgName.lower();
+ unsigned UpperBound = (ArgName.size() + 2) / 3 + 1;
+ unsigned ThisED = StringRef(ArgNameLower).edit_distance(
+ Params[ArgIndex]->getIdentifier()->getName().lower(),
+ /*AllowReplacements=*/true, UpperBound);
+ if (ThisED >= UpperBound)
+ return false;
+
+ for (const auto &Param : Params) {
+ if (&Param - Params.begin() == ArgIndex)
+ continue;
+ IdentifierInfo *II = Param->getIdentifier();
+ if (!II)
+ continue;
+
+ // Other parameters must be an edit distance at least 2 more away from this
+ // parameter. This gives us greater confidence that this is a typo of this
+ // parameter and not one with a similar name.
+ unsigned OtherED = StringRef(ArgNameLower).edit_distance(
+ II->getName().lower(),
+ /*AllowReplacements=*/true, ThisED + 2);
+ if (OtherED < ThisED + 2)
+ return false;
+ }
+
+ return true;
+}
+
+void ArgumentCommentCheck::checkCallArgs(ASTContext *Ctx,
+ const FunctionDecl *Callee,
+ SourceLocation ArgBeginLoc,
+ llvm::ArrayRef<const Expr *> Args) {
+ Callee = Callee->getFirstDecl();
+ for (unsigned i = 0,
+ e = std::min<unsigned>(Args.size(), Callee->getNumParams());
+ i != e; ++i) {
+ const ParmVarDecl *PVD = Callee->getParamDecl(i);
+ IdentifierInfo *II = PVD->getIdentifier();
+ if (!II)
+ continue;
+
+ SourceLocation BeginSLoc, EndSLoc = Args[i]->getLocStart();
+ if (i == 0)
+ BeginSLoc = ArgBeginLoc;
+ else
+ BeginSLoc = Args[i - 1]->getLocEnd();
+ if (BeginSLoc.isMacroID() || EndSLoc.isMacroID())
+ continue;
+
+ auto Comments =
+ getCommentsInRange(Ctx, SourceRange(BeginSLoc, EndSLoc));
+ for (auto Comment : Comments) {
+ llvm::SmallVector<StringRef, 2> Matches;
+ if (IdentRE.match(Comment.second, &Matches)) {
+ if (Matches[2] != II->getName()) {
+ {
+ DiagnosticBuilder Diag =
+ diag(Comment.first, "argument name '%0' in comment does not "
+ "match parameter name %1")
+ << Matches[2] << II;
+ if (isLikelyTypo(Callee->parameters(), Matches[2], i)) {
+ Diag << FixItHint::CreateReplacement(
+ Comment.first,
+ (Matches[1] + II->getName() + Matches[3]).str());
+ }
+ }
+ diag(PVD->getLocation(), "%0 declared here", DiagnosticIDs::Note)
+ << II;
+ }
+ }
+ }
+ }
+}
+
+void ArgumentCommentCheck::check(const MatchFinder::MatchResult &Result) {
+ const Expr *E = Result.Nodes.getNodeAs<Expr>("expr");
+ if (auto Call = dyn_cast<CallExpr>(E)) {
+ const FunctionDecl *Callee = Call->getDirectCallee();
+ if (!Callee)
+ return;
+
+ checkCallArgs(
+ Result.Context, Callee, Call->getCallee()->getLocEnd(),
+ llvm::ArrayRef<const Expr *>(Call->getArgs(), Call->getNumArgs()));
+ } else {
+ auto Construct = cast<CXXConstructExpr>(E);
+ checkCallArgs(Result.Context, Construct->getConstructor(),
+ Construct->getParenOrBraceRange().getBegin(),
+ llvm::ArrayRef<const Expr *>(Construct->getArgs(),
+ Construct->getNumArgs()));
+ }
+}
+
class MiscModule : public ClangTidyModule {
public:
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+ CheckFactories.addCheckFactory(
+ "misc-argument-comment",
+ new ClangTidyCheckFactory<ArgumentCommentCheck>());
}
};
Index: clang-tidy/misc/MiscTidyModule.h
===================================================================
--- /dev/null
+++ clang-tidy/misc/MiscTidyModule.h
@@ -0,0 +1,40 @@
+//===--- MiscTidyModule.h - clang-tidy --------------------------*- 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_TOOLS_EXTRA_CLANG_TIDY_MISC_MISC_TIDY_MODULE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MISC_TIDY_MODULE_H
+
+#include "../ClangTidy.h"
+#include "llvm/Support/Regex.h"
+
+namespace clang {
+namespace tidy {
+
+/// \brief Checks that argument comments match parameter names.
+class ArgumentCommentCheck : public ClangTidyCheck {
+public:
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ llvm::Regex IdentRE{ "^(/\\* *)([_A-Za-z][_A-Za-z0-9]*)( *= *\\*/)$" };
+
+ bool isLikelyTypo(llvm::ArrayRef<ParmVarDecl *> Params, StringRef ArgName,
+ unsigned ArgIndex);
+ std::vector<std::pair<SourceLocation, StringRef>>
+ getCommentsInRange(ASTContext *Ctx, SourceRange Range);
+ void checkCallArgs(ASTContext *Ctx, const FunctionDecl *Callee,
+ SourceLocation ArgBeginLoc,
+ llvm::ArrayRef<const Expr *> Args);
+};
+
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MISC_TIDY_MODULE_H
Index: test/clang-tidy/arg-comments.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/arg-comments.cpp
@@ -0,0 +1,27 @@
+// RUN: clang-tidy --checks=misc-argument-comment %s -- | FileCheck %s
+
+// FIXME: clang-tidy should provide a -verify mode to make writing these checks
+// easier and more accurate.
+
+// CHECK-NOT: warning
+
+void f(int x, int y);
+
+void ffff(int xxxx, int yyyy);
+
+void g() {
+ // CHECK: [[@LINE+5]]:5: warning: argument name 'y' in comment does not match parameter name 'x'
+ // CHECK: :8:12: note: 'x' declared here
+ // CHECK: [[@LINE+3]]:14: warning: argument name 'z' in comment does not match parameter name 'y'
+ // CHECK: :8:19: note: 'y' declared here
+ // CHECK-NOT: warning
+ f(/*y=*/0, /*z=*/0);
+
+ // CHECK: [[@LINE+4]]:8: warning: argument name 'xxxy' in comment does not match parameter name 'xxxx'
+ // CHECK-NEXT: ffff
+ // CHECK-NEXT: ^
+ // CHECK-NEXT: /*xxxx=*/
+ ffff(/*xxxy=*/0, 0);
+}
+
+// CHECK-NOT: warning
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits