diff options
Diffstat (limited to 'clang-tools-extra/clang-tidy/misc')
4 files changed, 169 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt index d54af6e1110..21493377e81 100644 --- a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt @@ -25,6 +25,7 @@ add_clang_library(clangTidyMiscModule SizeofContainerCheck.cpp SizeofExpressionCheck.cpp StaticAssertCheck.cpp + StringConstructorCheck.cpp StringIntegerAssignmentCheck.cpp StringLiteralWithEmbeddedNulCheck.cpp SuspiciousMissingCommaCheck.cpp diff --git a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp index aaeddeded21..da6706b94e3 100644 --- a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp @@ -33,6 +33,7 @@ #include "SizeofContainerCheck.h" #include "SizeofExpressionCheck.h" #include "StaticAssertCheck.h" +#include "StringConstructorCheck.h" #include "StringIntegerAssignmentCheck.h" #include "StringLiteralWithEmbeddedNulCheck.h" #include "SuspiciousMissingCommaCheck.h" @@ -99,6 +100,8 @@ public: "misc-sizeof-expression"); CheckFactories.registerCheck<StaticAssertCheck>( "misc-static-assert"); + CheckFactories.registerCheck<StringConstructorCheck>( + "misc-string-constructor"); CheckFactories.registerCheck<StringIntegerAssignmentCheck>( "misc-string-integer-assignment"); CheckFactories.registerCheck<StringLiteralWithEmbeddedNulCheck>( diff --git a/clang-tools-extra/clang-tidy/misc/StringConstructorCheck.cpp b/clang-tools-extra/clang-tidy/misc/StringConstructorCheck.cpp new file mode 100644 index 00000000000..0723ec1ed40 --- /dev/null +++ b/clang-tools-extra/clang-tidy/misc/StringConstructorCheck.cpp @@ -0,0 +1,126 @@ +//===--- StringConstructorCheck.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 "StringConstructorCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace misc { + +AST_MATCHER_P(IntegerLiteral, isBiggerThan, unsigned, N) { + return Node.getValue().getZExtValue() > N; +} + +StringConstructorCheck::StringConstructorCheck(StringRef Name, + ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + WarnOnLargeLength(Options.get("WarnOnLargeLength", 1) != 0), + LargeLengthThreshold(Options.get("LargeLengthThreshold", 0x800000)) {} + +void StringConstructorCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "WarnOnLargeLength", WarnOnLargeLength); + Options.store(Opts, "LargeLengthThreshold", LargeLengthThreshold); +} + +void StringConstructorCheck::registerMatchers(MatchFinder *Finder) { + if (!getLangOpts().CPlusPlus) + return; + + const auto ZeroExpr = expr(ignoringParenImpCasts(integerLiteral(equals(0)))); + const auto CharExpr = expr(ignoringParenImpCasts(characterLiteral())); + const auto NegativeExpr = expr(ignoringParenImpCasts( + unaryOperator(hasOperatorName("-"), + hasUnaryOperand(integerLiteral(unless(equals(0))))))); + const auto LargeLengthExpr = expr(ignoringParenImpCasts( + integerLiteral(isBiggerThan(LargeLengthThreshold)))); + const auto CharPtrType = type(anyOf(pointerType(), arrayType())); + + // Match a string-literal; even through a declaration with initializer. + const auto BoundStringLiteral = stringLiteral().bind("str"); + const auto ConstStrLiteralDecl = varDecl( + isDefinition(), hasType(constantArrayType()), hasType(isConstQualified()), + hasInitializer(ignoringParenImpCasts(BoundStringLiteral))); + const auto ConstPtrStrLiteralDecl = varDecl( + isDefinition(), + hasType(pointerType(pointee(isAnyCharacter(), isConstQualified()))), + hasInitializer(ignoringParenImpCasts(BoundStringLiteral))); + auto ConstStrLiteral = expr(ignoringParenImpCasts(anyOf( + BoundStringLiteral, declRefExpr(hasDeclaration(anyOf( + ConstPtrStrLiteralDecl, ConstStrLiteralDecl)))))); + + // Check the fill constructor. Fills the string with n consecutive copies of + // character c. [i.e string(size_t n, char c);]. + Finder->addMatcher( + cxxConstructExpr( + hasDeclaration(cxxMethodDecl(hasName("basic_string"))), + hasArgument(0, hasType(qualType(isInteger()))), + hasArgument(1, hasType(qualType(isInteger()))), + anyOf( + // Detect the expression: string('x', 40); + hasArgument(0, CharExpr.bind("swapped-parameter")), + // Detect the expression: string(0, ...); + hasArgument(0, ZeroExpr.bind("empty-string")), + // Detect the expression: string(-4, ...); + hasArgument(0, NegativeExpr.bind("negative-length")), + // Detect the expression: string(0x1234567, ...); + hasArgument(0, LargeLengthExpr.bind("large-length")))) + .bind("constructor"), + this); + + // Check the literal string constructor with char pointer and length + // parameters. [i.e. string (const char* s, size_t n);] + Finder->addMatcher( + cxxConstructExpr( + hasDeclaration(cxxMethodDecl(hasName("basic_string"))), + hasArgument(0, hasType(CharPtrType)), + hasArgument(1, hasType(isInteger())), + anyOf( + // Detect the expression: string("...", 0); + hasArgument(1, ZeroExpr.bind("empty-string")), + // Detect the expression: string("...", -4); + hasArgument(1, NegativeExpr.bind("negative-length")), + // Detect the expression: string("lit", 0x1234567); + hasArgument(1, LargeLengthExpr.bind("large-length")), + // Detect the expression: string("lit", 5) + allOf(hasArgument(0, ConstStrLiteral.bind("literal-with-length")), + hasArgument(1, ignoringParenImpCasts( + integerLiteral().bind("int")))))) + .bind("constructor"), + this); +} + +void StringConstructorCheck::check(const MatchFinder::MatchResult &Result) { + const auto *E = Result.Nodes.getNodeAs<Expr>("constructor"); + SourceLocation Loc = E->getLocStart(); + + if (Result.Nodes.getNodeAs<Expr>("swapped-parameter")) { + diag(Loc, "constructor parameters are probably swapped"); + } else if (Result.Nodes.getNodeAs<Expr>("empty-string")) { + diag(Loc, "constructor creating an empty string"); + } else if (Result.Nodes.getNodeAs<Expr>("negative-length")) { + diag(Loc, "negative value used as length parameter"); + } else if (Result.Nodes.getNodeAs<Expr>("large-length")) { + if (WarnOnLargeLength) + diag(Loc, "suspicious large length parameter"); + } else if (Result.Nodes.getNodeAs<Expr>("literal-with-length")) { + const auto *Str = Result.Nodes.getNodeAs<StringLiteral>("str"); + const auto *Lit = Result.Nodes.getNodeAs<IntegerLiteral>("int"); + if (Lit->getValue().ugt(Str->getLength())) { + diag(Loc, "length is bigger then string literal size"); + } + } +} + +} // namespace misc +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/clang-tidy/misc/StringConstructorCheck.h b/clang-tools-extra/clang-tidy/misc/StringConstructorCheck.h new file mode 100644 index 00000000000..dfa58385e7e --- /dev/null +++ b/clang-tools-extra/clang-tidy/misc/StringConstructorCheck.h @@ -0,0 +1,39 @@ +//===--- StringConstructorCheck.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_STRING_CONSTRUCTOR_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_STRING_CONSTRUCTOR_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace misc { + +/// Finds suspicious string constructor and check their parameters. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/misc-string-constructor.html +class StringConstructorCheck : public ClangTidyCheck { +public: + StringConstructorCheck(StringRef Name, ClangTidyContext *Context); + void storeOptions(ClangTidyOptions::OptionMap &Opts); + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + +private: + const bool WarnOnLargeLength; + const unsigned int LargeLengthThreshold; +}; + +} // namespace misc +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_STRING_CONSTRUCTOR_H |