diff options
author | Alexander Kornienko <alexfh@google.com> | 2017-11-24 14:16:29 +0000 |
---|---|---|
committer | Alexander Kornienko <alexfh@google.com> | 2017-11-24 14:16:29 +0000 |
commit | d4ac4afda75c9ef174e85eea7f40a6ae6cc50ab4 (patch) | |
tree | c43c0be034454ea297f0ccdc84302e9636abed63 /clang-tools-extra/clang-tidy/misc | |
parent | 70cdb5b3914803ca89a96a867a47936d049a4b32 (diff) | |
download | bcm5719-llvm-d4ac4afda75c9ef174e85eea7f40a6ae6cc50ab4.tar.gz bcm5719-llvm-d4ac4afda75c9ef174e85eea7f40a6ae6cc50ab4.zip |
[clang-tidy] Move a few more checks from misc to bugprone.
Summary:
clang_tidy/rename_check.py misc-assert-side-effect bugprone-assert-side-effect
clang_tidy/rename_check.py misc-bool-pointer-implicit-conversion bugprone-bool-pointer-implicit-conversion
clang_tidy/rename_check.py misc-fold-init-type bugprone-fold-init-type
clang_tidy/rename_check.py misc-forward-declaration-namespace bugprone-forward-declaration-namespace
clang_tidy/rename_check.py misc-inaccurate-erase bugprone-inaccurate-erase
clang_tidy/rename_check.py misc-move-forwarding-reference bugprone-move-forwarding-reference
clang_tidy/rename_check.py misc-multiple-statement-macro bugprone-multiple-statement-macro
clang_tidy/rename_check.py misc-use-after-move bugprone-use-after-move
clang_tidy/rename_check.py misc-virtual-near-miss bugprone-virtual-near-miss
Manually fixed a reference to UseAfterMoveCheck in the hicpp module.
Manually fixed header guards.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nemanjai, mgorny, javed.absar, xazax.hun, kbarton, cfe-commits
Differential Revision: https://reviews.llvm.org/D40426
llvm-svn: 318950
Diffstat (limited to 'clang-tools-extra/clang-tidy/misc')
20 files changed, 0 insertions, 1997 deletions
diff --git a/clang-tools-extra/clang-tidy/misc/AssertSideEffectCheck.cpp b/clang-tools-extra/clang-tidy/misc/AssertSideEffectCheck.cpp deleted file mode 100644 index 0b63c0d33a4..00000000000 --- a/clang-tools-extra/clang-tidy/misc/AssertSideEffectCheck.cpp +++ /dev/null @@ -1,127 +0,0 @@ -//===--- AssertSideEffectCheck.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 "AssertSideEffectCheck.h" -#include "clang/AST/ASTContext.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Lex/Lexer.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/Casting.h" -#include <algorithm> -#include <string> - -using namespace clang::ast_matchers; - -namespace clang { -namespace tidy { -namespace misc { - -namespace { - -AST_MATCHER_P(Expr, hasSideEffect, bool, CheckFunctionCalls) { - const Expr *E = &Node; - - if (const auto *Op = dyn_cast<UnaryOperator>(E)) { - UnaryOperator::Opcode OC = Op->getOpcode(); - return OC == UO_PostInc || OC == UO_PostDec || OC == UO_PreInc || - OC == UO_PreDec; - } - - if (const auto *Op = dyn_cast<BinaryOperator>(E)) { - return Op->isAssignmentOp(); - } - - if (const auto *OpCallExpr = dyn_cast<CXXOperatorCallExpr>(E)) { - OverloadedOperatorKind OpKind = OpCallExpr->getOperator(); - return OpKind == OO_Equal || OpKind == OO_PlusEqual || - OpKind == OO_MinusEqual || OpKind == OO_StarEqual || - OpKind == OO_SlashEqual || OpKind == OO_AmpEqual || - OpKind == OO_PipeEqual || OpKind == OO_CaretEqual || - OpKind == OO_LessLessEqual || OpKind == OO_GreaterGreaterEqual || - OpKind == OO_PlusPlus || OpKind == OO_MinusMinus || - OpKind == OO_PercentEqual || OpKind == OO_New || - OpKind == OO_Delete || OpKind == OO_Array_New || - OpKind == OO_Array_Delete; - } - - if (const auto *CExpr = dyn_cast<CallExpr>(E)) { - bool Result = CheckFunctionCalls; - if (const auto *FuncDecl = CExpr->getDirectCallee()) { - if (FuncDecl->getDeclName().isIdentifier() && - FuncDecl->getName() == "__builtin_expect") // exceptions come here - Result = false; - else if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(FuncDecl)) - Result &= !MethodDecl->isConst(); - } - return Result; - } - - return isa<CXXNewExpr>(E) || isa<CXXDeleteExpr>(E) || isa<CXXThrowExpr>(E); -} - -} // namespace - -AssertSideEffectCheck::AssertSideEffectCheck(StringRef Name, - ClangTidyContext *Context) - : ClangTidyCheck(Name, Context), - CheckFunctionCalls(Options.get("CheckFunctionCalls", false)), - RawAssertList(Options.get("AssertMacros", "assert")) { - StringRef(RawAssertList).split(AssertMacros, ",", -1, false); -} - -// The options are explained in AssertSideEffectCheck.h. -void AssertSideEffectCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { - Options.store(Opts, "CheckFunctionCalls", CheckFunctionCalls); - Options.store(Opts, "AssertMacros", RawAssertList); -} - -void AssertSideEffectCheck::registerMatchers(MatchFinder *Finder) { - auto DescendantWithSideEffect = - hasDescendant(expr(hasSideEffect(CheckFunctionCalls))); - auto ConditionWithSideEffect = hasCondition(DescendantWithSideEffect); - Finder->addMatcher( - stmt( - anyOf(conditionalOperator(ConditionWithSideEffect), - ifStmt(ConditionWithSideEffect), - unaryOperator(hasOperatorName("!"), - hasUnaryOperand(unaryOperator( - hasOperatorName("!"), - hasUnaryOperand(DescendantWithSideEffect)))))) - .bind("condStmt"), - this); -} - -void AssertSideEffectCheck::check(const MatchFinder::MatchResult &Result) { - const SourceManager &SM = *Result.SourceManager; - const LangOptions LangOpts = getLangOpts(); - SourceLocation Loc = Result.Nodes.getNodeAs<Stmt>("condStmt")->getLocStart(); - - StringRef AssertMacroName; - while (Loc.isValid() && Loc.isMacroID()) { - StringRef MacroName = Lexer::getImmediateMacroName(Loc, SM, LangOpts); - - // Check if this macro is an assert. - if (std::find(AssertMacros.begin(), AssertMacros.end(), MacroName) != - AssertMacros.end()) { - AssertMacroName = MacroName; - break; - } - Loc = SM.getImmediateMacroCallerLoc(Loc); - } - if (AssertMacroName.empty()) - return; - - diag(Loc, "found %0() with side effect") << AssertMacroName; -} - -} // namespace misc -} // namespace tidy -} // namespace clang diff --git a/clang-tools-extra/clang-tidy/misc/AssertSideEffectCheck.h b/clang-tools-extra/clang-tidy/misc/AssertSideEffectCheck.h deleted file mode 100644 index 2bb25e2d4a4..00000000000 --- a/clang-tools-extra/clang-tidy/misc/AssertSideEffectCheck.h +++ /dev/null @@ -1,52 +0,0 @@ -//===--- AssertSideEffectCheck.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_ASSERTSIDEEFFECTCHECK_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_ASSERTSIDEEFFECTCHECK_H - -#include "../ClangTidy.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" -#include <string> - -namespace clang { -namespace tidy { -namespace misc { - -/// Finds `assert()` with side effect. -/// -/// The condition of `assert()` is evaluated only in debug builds so a -/// condition with side effect can cause different behavior in debug / release -/// builds. -/// -/// There are two options: -/// -/// - `AssertMacros`: A comma-separated list of the names of assert macros to -/// be checked. -/// - `CheckFunctionCalls`: Whether to treat non-const member and non-member -/// functions as they produce side effects. Disabled by default because it -/// can increase the number of false positive warnings. -class AssertSideEffectCheck : public ClangTidyCheck { -public: - AssertSideEffectCheck(StringRef Name, ClangTidyContext *Context); - void storeOptions(ClangTidyOptions::OptionMap &Opts) override; - void registerMatchers(ast_matchers::MatchFinder *Finder) override; - void check(const ast_matchers::MatchFinder::MatchResult &Result) override; - -private: - const bool CheckFunctionCalls; - const std::string RawAssertList; - SmallVector<StringRef, 5> AssertMacros; -}; - -} // namespace misc -} // namespace tidy -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_ASSERTSIDEEFFECTCHECK_H diff --git a/clang-tools-extra/clang-tidy/misc/BoolPointerImplicitConversionCheck.cpp b/clang-tools-extra/clang-tidy/misc/BoolPointerImplicitConversionCheck.cpp deleted file mode 100644 index f831125838d..00000000000 --- a/clang-tools-extra/clang-tidy/misc/BoolPointerImplicitConversionCheck.cpp +++ /dev/null @@ -1,73 +0,0 @@ -//===--- BoolPointerImplicitConversionCheck.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 "BoolPointerImplicitConversionCheck.h" - -using namespace clang::ast_matchers; - -namespace clang { -namespace tidy { -namespace misc { - -void BoolPointerImplicitConversionCheck::registerMatchers(MatchFinder *Finder) { - // Look for ifs that have an implicit bool* to bool conversion in the - // condition. Filter negations. - Finder->addMatcher( - ifStmt(hasCondition(findAll(implicitCastExpr( - allOf(unless(hasParent(unaryOperator(hasOperatorName("!")))), - hasSourceExpression(expr( - hasType(pointerType(pointee(booleanType()))), - ignoringParenImpCasts(declRefExpr().bind("expr")))), - hasCastKind(CK_PointerToBoolean))))), - unless(isInTemplateInstantiation())) - .bind("if"), - this); -} - -void BoolPointerImplicitConversionCheck::check( - const MatchFinder::MatchResult &Result) { - auto *If = Result.Nodes.getNodeAs<IfStmt>("if"); - auto *Var = Result.Nodes.getNodeAs<DeclRefExpr>("expr"); - - // Ignore macros. - if (Var->getLocStart().isMacroID()) - return; - - // Only allow variable accesses for now, no function calls or member exprs. - // Check that we don't dereference the variable anywhere within the if. This - // avoids false positives for checks of the pointer for nullptr before it is - // dereferenced. If there is a dereferencing operator on this variable don't - // emit a diagnostic. Also ignore array subscripts. - const Decl *D = Var->getDecl(); - auto DeclRef = ignoringParenImpCasts(declRefExpr(to(equalsNode(D)))); - if (!match(findAll( - unaryOperator(hasOperatorName("*"), hasUnaryOperand(DeclRef))), - *If, *Result.Context) - .empty() || - !match(findAll(arraySubscriptExpr(hasBase(DeclRef))), *If, - *Result.Context) - .empty() || - // FIXME: We should still warn if the paremater is implicitly converted to - // bool. - !match(findAll(callExpr(hasAnyArgument(ignoringParenImpCasts(DeclRef)))), - *If, *Result.Context) - .empty() || - !match(findAll(cxxDeleteExpr(has(ignoringParenImpCasts(expr(DeclRef))))), - *If, *Result.Context) - .empty()) - return; - - diag(Var->getLocStart(), "dubious check of 'bool *' against 'nullptr', did " - "you mean to dereference it?") - << FixItHint::CreateInsertion(Var->getLocStart(), "*"); -} - -} // namespace misc -} // namespace tidy -} // namespace clang diff --git a/clang-tools-extra/clang-tidy/misc/BoolPointerImplicitConversionCheck.h b/clang-tools-extra/clang-tidy/misc/BoolPointerImplicitConversionCheck.h deleted file mode 100644 index d8a90f35729..00000000000 --- a/clang-tools-extra/clang-tidy/misc/BoolPointerImplicitConversionCheck.h +++ /dev/null @@ -1,42 +0,0 @@ -//===--- BoolPointerImplicitConversionCheck.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_BOOLPOINTERIMPLICITCONVERSIONCHECK_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_BOOLPOINTERIMPLICITCONVERSIONCHECK_H - -#include "../ClangTidy.h" - -namespace clang { -namespace tidy { -namespace misc { - -/// Checks for conditions based on implicit conversion from a bool pointer to -/// bool. -/// -/// Example: -/// -/// \code -/// bool *p; -/// if (p) { -/// // Never used in a pointer-specific way. -/// } -/// \endcode -class BoolPointerImplicitConversionCheck : public ClangTidyCheck { -public: - BoolPointerImplicitConversionCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} - void registerMatchers(ast_matchers::MatchFinder *Finder) override; - void check(const ast_matchers::MatchFinder::MatchResult &Result) override; -}; - -} // namespace misc -} // namespace tidy -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_BOOLPOINTERIMPLICITCONVERSIONCHECK_H diff --git a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt index f67c1365949..8a4dcbd5638 100644 --- a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt @@ -1,16 +1,11 @@ set(LLVM_LINK_COMPONENTS support) add_clang_library(clangTidyMiscModule - AssertSideEffectCheck.cpp ForwardingReferenceOverloadCheck.cpp LambdaFunctionNameCheck.cpp MisplacedConstCheck.cpp UnconventionalAssignOperatorCheck.cpp - BoolPointerImplicitConversionCheck.cpp DefinitionsInHeadersCheck.cpp - FoldInitTypeCheck.cpp - ForwardDeclarationNamespaceCheck.cpp - InaccurateEraseCheck.cpp IncorrectRoundings.cpp InefficientAlgorithmCheck.cpp MacroParenthesesCheck.cpp @@ -19,8 +14,6 @@ add_clang_library(clangTidyMiscModule MisplacedWideningCastCheck.cpp MoveConstantArgumentCheck.cpp MoveConstructorInitCheck.cpp - MoveForwardingReferenceCheck.cpp - MultipleStatementMacroCheck.cpp NewDeleteOverloadsCheck.cpp NoexceptMoveConstructorCheck.cpp NonCopyableObjects.cpp @@ -43,8 +36,6 @@ add_clang_library(clangTidyMiscModule UnusedParametersCheck.cpp UnusedRAIICheck.cpp UnusedUsingDeclsCheck.cpp - UseAfterMoveCheck.cpp - VirtualNearMissCheck.cpp LINK_LIBS clangAnalysis diff --git a/clang-tools-extra/clang-tidy/misc/FoldInitTypeCheck.cpp b/clang-tools-extra/clang-tidy/misc/FoldInitTypeCheck.cpp deleted file mode 100644 index c5d27201b8b..00000000000 --- a/clang-tools-extra/clang-tidy/misc/FoldInitTypeCheck.cpp +++ /dev/null @@ -1,140 +0,0 @@ -//===--- FoldInitTypeCheck.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 "FoldInitTypeCheck.h" -#include "clang/AST/ASTContext.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" - -using namespace clang::ast_matchers; - -namespace clang { -namespace tidy { -namespace misc { - -void FoldInitTypeCheck::registerMatchers(MatchFinder *Finder) { - // We match functions of interest and bind the iterator and init value types. - // Note: Right now we check only builtin types. - const auto BuiltinTypeWithId = [](const char *ID) { - return hasCanonicalType(builtinType().bind(ID)); - }; - const auto IteratorWithValueType = [&BuiltinTypeWithId](const char *ID) { - return anyOf( - // Pointer types. - pointsTo(BuiltinTypeWithId(ID)), - // Iterator types. - recordType(hasDeclaration(has(typedefNameDecl( - hasName("value_type"), hasType(BuiltinTypeWithId(ID))))))); - }; - - const auto IteratorParam = parmVarDecl( - hasType(hasCanonicalType(IteratorWithValueType("IterValueType")))); - const auto Iterator2Param = parmVarDecl( - hasType(hasCanonicalType(IteratorWithValueType("Iter2ValueType")))); - const auto InitParam = parmVarDecl(hasType(BuiltinTypeWithId("InitType"))); - - // std::accumulate, std::reduce. - Finder->addMatcher( - callExpr(callee(functionDecl( - hasAnyName("::std::accumulate", "::std::reduce"), - hasParameter(0, IteratorParam), hasParameter(2, InitParam))), - argumentCountIs(3)) - .bind("Call"), - this); - // std::inner_product. - Finder->addMatcher( - callExpr(callee(functionDecl(hasName("::std::inner_product"), - hasParameter(0, IteratorParam), - hasParameter(2, Iterator2Param), - hasParameter(3, InitParam))), - argumentCountIs(4)) - .bind("Call"), - this); - // std::reduce with a policy. - Finder->addMatcher( - callExpr(callee(functionDecl(hasName("::std::reduce"), - hasParameter(1, IteratorParam), - hasParameter(3, InitParam))), - argumentCountIs(4)) - .bind("Call"), - this); - // std::inner_product with a policy. - Finder->addMatcher( - callExpr(callee(functionDecl(hasName("::std::inner_product"), - hasParameter(1, IteratorParam), - hasParameter(3, Iterator2Param), - hasParameter(4, InitParam))), - argumentCountIs(5)) - .bind("Call"), - this); -} - -/// Returns true if ValueType is allowed to fold into InitType, i.e. if: -/// static_cast<InitType>(ValueType{some_value}) -/// does not result in trucation. -static bool isValidBuiltinFold(const BuiltinType &ValueType, - const BuiltinType &InitType, - const ASTContext &Context) { - const auto ValueTypeSize = Context.getTypeSize(&ValueType); - const auto InitTypeSize = Context.getTypeSize(&InitType); - // It's OK to fold a float into a float of bigger or equal size, but not OK to - // fold into an int. - if (ValueType.isFloatingPoint()) - return InitType.isFloatingPoint() && InitTypeSize >= ValueTypeSize; - // It's OK to fold an int into: - // - an int of the same size and signedness. - // - a bigger int, regardless of signedness. - // - FIXME: should it be a warning to fold into floating point? - if (ValueType.isInteger()) { - if (InitType.isInteger()) { - if (InitType.isSignedInteger() == ValueType.isSignedInteger()) - return InitTypeSize >= ValueTypeSize; - return InitTypeSize > ValueTypeSize; - } - if (InitType.isFloatingPoint()) - return InitTypeSize >= ValueTypeSize; - } - return false; -} - -/// Prints a diagnostic if IterValueType doe snot fold into IterValueType (see -// isValidBuiltinFold for details). -void FoldInitTypeCheck::doCheck(const BuiltinType &IterValueType, - const BuiltinType &InitType, - const ASTContext &Context, - const CallExpr &CallNode) { - if (!isValidBuiltinFold(IterValueType, InitType, Context)) { - diag(CallNode.getExprLoc(), "folding type %0 into type %1 might result in " - "loss of precision") - << IterValueType.desugar() << InitType.desugar(); - } -} - -void FoldInitTypeCheck::check(const MatchFinder::MatchResult &Result) { - // Given the iterator and init value type retreived by the matchers, - // we check that the ::value_type of the iterator is compatible with - // the init value type. - const auto *InitType = Result.Nodes.getNodeAs<BuiltinType>("InitType"); - const auto *IterValueType = - Result.Nodes.getNodeAs<BuiltinType>("IterValueType"); - assert(InitType != nullptr); - assert(IterValueType != nullptr); - - const auto *CallNode = Result.Nodes.getNodeAs<CallExpr>("Call"); - assert(CallNode != nullptr); - - doCheck(*IterValueType, *InitType, *Result.Context, *CallNode); - - if (const auto *Iter2ValueType = - Result.Nodes.getNodeAs<BuiltinType>("Iter2ValueType")) - doCheck(*Iter2ValueType, *InitType, *Result.Context, *CallNode); -} - -} // namespace misc -} // namespace tidy -} // namespace clang diff --git a/clang-tools-extra/clang-tidy/misc/FoldInitTypeCheck.h b/clang-tools-extra/clang-tidy/misc/FoldInitTypeCheck.h deleted file mode 100644 index df4ec88fa04..00000000000 --- a/clang-tools-extra/clang-tidy/misc/FoldInitTypeCheck.h +++ /dev/null @@ -1,44 +0,0 @@ -//===--- FoldInitTypeCheck.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_FOLD_INIT_TYPE_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_FOLD_INIT_TYPE_H - -#include "../ClangTidy.h" - -namespace clang { -namespace tidy { -namespace misc { - -/// Find and flag invalid initializer values in folds, e.g. std::accumulate. -/// Example: -/// \code -/// auto v = {65536L * 65536 * 65536}; -/// std::accumulate(begin(v), end(v), 0 /* int type is too small */); -/// \endcode -/// -/// For the user-facing documentation see: -/// http://clang.llvm.org/extra/clang-tidy/checks/misc-fold-init-type.html -class FoldInitTypeCheck : public ClangTidyCheck { -public: - FoldInitTypeCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} - void registerMatchers(ast_matchers::MatchFinder *Finder) override; - void check(const ast_matchers::MatchFinder::MatchResult &Result) override; - -private: - void doCheck(const BuiltinType &IterValueType, const BuiltinType &InitType, - const ASTContext &Context, const CallExpr &CallNode); -}; - -} // namespace misc -} // namespace tidy -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_FOLD_INIT_TYPE_H diff --git a/clang-tools-extra/clang-tidy/misc/ForwardDeclarationNamespaceCheck.cpp b/clang-tools-extra/clang-tidy/misc/ForwardDeclarationNamespaceCheck.cpp deleted file mode 100644 index 1487e8f1861..00000000000 --- a/clang-tools-extra/clang-tidy/misc/ForwardDeclarationNamespaceCheck.cpp +++ /dev/null @@ -1,174 +0,0 @@ -//===--- ForwardDeclarationNamespaceCheck.cpp - clang-tidy ------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "ForwardDeclarationNamespaceCheck.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Decl.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/ASTMatchers/ASTMatchers.h" -#include <stack> -#include <string> - -using namespace clang::ast_matchers; - -namespace clang { -namespace tidy { -namespace misc { - -void ForwardDeclarationNamespaceCheck::registerMatchers(MatchFinder *Finder) { - // Match all class declarations/definitions *EXCEPT* - // 1. implicit classes, e.g. `class A {};` has implicit `class A` inside `A`. - // 2. nested classes declared/defined inside another class. - // 3. template class declaration, template instantiation or - // specialization (NOTE: extern specialization is filtered out by - // `unless(hasAncestor(cxxRecordDecl()))`). - auto IsInSpecialization = hasAncestor( - decl(anyOf(cxxRecordDecl(isExplicitTemplateSpecialization()), - functionDecl(isExplicitTemplateSpecialization())))); - Finder->addMatcher( - cxxRecordDecl( - hasParent(decl(anyOf(namespaceDecl(), translationUnitDecl()))), - unless(isImplicit()), unless(hasAncestor(cxxRecordDecl())), - unless(isInstantiated()), unless(IsInSpecialization), - unless(classTemplateSpecializationDecl())) - .bind("record_decl"), - this); - - // Match all friend declarations. Classes used in friend declarations are not - // marked as referenced in AST. We need to record all record classes used in - // friend declarations. - Finder->addMatcher(friendDecl().bind("friend_decl"), this); -} - -void ForwardDeclarationNamespaceCheck::check( - const MatchFinder::MatchResult &Result) { - if (const auto *RecordDecl = - Result.Nodes.getNodeAs<CXXRecordDecl>("record_decl")) { - StringRef DeclName = RecordDecl->getName(); - if (RecordDecl->isThisDeclarationADefinition()) { - DeclNameToDefinitions[DeclName].push_back(RecordDecl); - } else { - // If a declaration has no definition, the definition could be in another - // namespace (a wrong namespace). - // NOTE: even a declaration does have definition, we still need it to - // compare with other declarations. - DeclNameToDeclarations[DeclName].push_back(RecordDecl); - } - } else { - const auto *Decl = Result.Nodes.getNodeAs<FriendDecl>("friend_decl"); - assert(Decl && "Decl is neither record_decl nor friend decl!"); - - // Classes used in friend delarations are not marked referenced in AST, - // so we need to check classes used in friend declarations manually to - // reduce the rate of false positive. - // For example, in - // \code - // struct A; - // struct B { friend A; }; - // \endcode - // `A` will not be marked as "referenced" in the AST. - if (const TypeSourceInfo *Tsi = Decl->getFriendType()) { - QualType Desugared = Tsi->getType().getDesugaredType(*Result.Context); - FriendTypes.insert(Desugared.getTypePtr()); - } - } -} - -static bool haveSameNamespaceOrTranslationUnit(const CXXRecordDecl *Decl1, - const CXXRecordDecl *Decl2) { - const DeclContext *ParentDecl1 = Decl1->getLexicalParent(); - const DeclContext *ParentDecl2 = Decl2->getLexicalParent(); - - // Since we only matched declarations whose parent is Namespace or - // TranslationUnit declaration, the parent should be either a translation unit - // or namespace. - if (ParentDecl1->getDeclKind() == Decl::TranslationUnit || - ParentDecl2->getDeclKind() == Decl::TranslationUnit) { - return ParentDecl1 == ParentDecl2; - } - assert(ParentDecl1->getDeclKind() == Decl::Namespace && - "ParentDecl1 declaration must be a namespace"); - assert(ParentDecl2->getDeclKind() == Decl::Namespace && - "ParentDecl2 declaration must be a namespace"); - auto *Ns1 = NamespaceDecl::castFromDeclContext(ParentDecl1); - auto *Ns2 = NamespaceDecl::castFromDeclContext(ParentDecl2); - return Ns1->getOriginalNamespace() == Ns2->getOriginalNamespace(); -} - -static std::string getNameOfNamespace(const CXXRecordDecl *Decl) { - const auto *ParentDecl = Decl->getLexicalParent(); - if (ParentDecl->getDeclKind() == Decl::TranslationUnit) { - return "(global)"; - } - const auto *NsDecl = cast<NamespaceDecl>(ParentDecl); - std::string Ns; - llvm::raw_string_ostream OStream(Ns); - NsDecl->printQualifiedName(OStream); - OStream.flush(); - return Ns.empty() ? "(global)" : Ns; -} - -void ForwardDeclarationNamespaceCheck::onEndOfTranslationUnit() { - // Iterate each group of declarations by name. - for (const auto &KeyValuePair : DeclNameToDeclarations) { - const auto &Declarations = KeyValuePair.second; - // If more than 1 declaration exists, we check if all are in the same - // namespace. - for (const auto *CurDecl : Declarations) { - if (CurDecl->hasDefinition() || CurDecl->isReferenced()) { - continue; // Skip forward declarations that are used/referenced. - } - if (FriendTypes.count(CurDecl->getTypeForDecl()) != 0) { - continue; // Skip forward declarations referenced as friend. - } - if (CurDecl->getLocation().isMacroID() || - CurDecl->getLocation().isInvalid()) { - continue; - } - // Compare with all other declarations with the same name. - for (const auto *Decl : Declarations) { - if (Decl == CurDecl) { - continue; // Don't compare with self. - } - if (!CurDecl->hasDefinition() && - !haveSameNamespaceOrTranslationUnit(CurDecl, Decl)) { - diag(CurDecl->getLocation(), - "declaration %0 is never referenced, but a declaration with " - "the same name found in another namespace '%1'") - << CurDecl << getNameOfNamespace(Decl); - diag(Decl->getLocation(), "a declaration of %0 is found here", - DiagnosticIDs::Note) - << Decl; - break; // FIXME: We only generate one warning for each declaration. - } - } - // Check if a definition in another namespace exists. - const auto DeclName = CurDecl->getName(); - if (DeclNameToDefinitions.find(DeclName) == DeclNameToDefinitions.end()) { - continue; // No definition in this translation unit, we can skip it. - } - // Make a warning for each definition with the same name (in other - // namespaces). - const auto &Definitions = DeclNameToDefinitions[DeclName]; - for (const auto *Def : Definitions) { - diag(CurDecl->getLocation(), - "no definition found for %0, but a definition with " - "the same name %1 found in another namespace '%2'") - << CurDecl << Def << getNameOfNamespace(Def); - diag(Def->getLocation(), "a definition of %0 is found here", - DiagnosticIDs::Note) - << Def; - } - } - } -} - -} // namespace misc -} // namespace tidy -} // namespace clang diff --git a/clang-tools-extra/clang-tidy/misc/ForwardDeclarationNamespaceCheck.h b/clang-tools-extra/clang-tidy/misc/ForwardDeclarationNamespaceCheck.h deleted file mode 100644 index dd7042d3691..00000000000 --- a/clang-tools-extra/clang-tidy/misc/ForwardDeclarationNamespaceCheck.h +++ /dev/null @@ -1,59 +0,0 @@ -//===--- ForwardDeclarationNamespaceCheck.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_FORWARDDECLARATIONNAMESPACECHECK_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_FORWARDDECLARATIONNAMESPACECHECK_H - -#include "../ClangTidy.h" -#include "llvm/ADT/SmallPtrSet.h" -#include <set> -#include <vector> - -namespace clang { -namespace tidy { -namespace misc { - -/// Checks if an unused forward declaration is in a wrong namespace. -/// -/// The check inspects all unused forward declarations and checks if there is -/// any declaration/definition with the same name, which could indicate -/// that the forward declaration is potentially in a wrong namespace. -/// -/// \code -/// namespace na { struct A; } -/// namespace nb { struct A {} }; -/// nb::A a; -/// // warning : no definition found for 'A', but a definition with the same -/// name 'A' found in another namespace 'nb::' -/// \endcode -/// -/// This check can only generate warnings, but it can't suggest fixes at this -/// point. -/// -/// For the user-facing documentation see: -/// http://clang.llvm.org/extra/clang-tidy/checks/misc-forward-declaration-namespace.html -class ForwardDeclarationNamespaceCheck : public ClangTidyCheck { -public: - ForwardDeclarationNamespaceCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} - void registerMatchers(ast_matchers::MatchFinder *Finder) override; - void check(const ast_matchers::MatchFinder::MatchResult &Result) override; - void onEndOfTranslationUnit() override; - -private: - llvm::StringMap<std::vector<const CXXRecordDecl *>> DeclNameToDefinitions; - llvm::StringMap<std::vector<const CXXRecordDecl *>> DeclNameToDeclarations; - llvm::SmallPtrSet<const Type *, 16> FriendTypes; -}; - -} // namespace misc -} // namespace tidy -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_FORWARDDECLARATIONNAMESPACECHECK_H diff --git a/clang-tools-extra/clang-tidy/misc/InaccurateEraseCheck.cpp b/clang-tools-extra/clang-tidy/misc/InaccurateEraseCheck.cpp deleted file mode 100644 index fd86d1723e3..00000000000 --- a/clang-tools-extra/clang-tidy/misc/InaccurateEraseCheck.cpp +++ /dev/null @@ -1,81 +0,0 @@ -//===--- InaccurateEraseCheck.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 "InaccurateEraseCheck.h" -#include "clang/AST/ASTContext.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/Lex/Lexer.h" - -using namespace clang::ast_matchers; - -namespace clang { -namespace tidy { -namespace misc { - -namespace { -AST_MATCHER(Decl, isInStdNamespace) { return Node.isInStdNamespace(); } -} - -void InaccurateEraseCheck::registerMatchers(MatchFinder *Finder) { - // Only register the matchers for C++; the functionality currently does not - // provide any benefit to other languages, despite being benign. - if (!getLangOpts().CPlusPlus) - return; - - const auto EndCall = - callExpr( - callee(functionDecl(hasAnyName("remove", "remove_if", "unique"))), - hasArgument( - 1, - anyOf(cxxConstructExpr(has(ignoringImplicit( - cxxMemberCallExpr(callee(cxxMethodDecl(hasName("end")))) - .bind("end")))), - anything()))) - .bind("alg"); - - const auto DeclInStd = type(hasUnqualifiedDesugaredType( - tagType(hasDeclaration(decl(isInStdNamespace()))))); - Finder->addMatcher( - cxxMemberCallExpr( - on(anyOf(hasType(DeclInStd), hasType(pointsTo(DeclInStd)))), - callee(cxxMethodDecl(hasName("erase"))), argumentCountIs(1), - hasArgument(0, has(ignoringImplicit( - anyOf(EndCall, has(ignoringImplicit(EndCall)))))), - unless(isInTemplateInstantiation())) - .bind("erase"), - this); -} - -void InaccurateEraseCheck::check(const MatchFinder::MatchResult &Result) { - const auto *MemberCall = - Result.Nodes.getNodeAs<CXXMemberCallExpr>("erase"); - const auto *EndExpr = - Result.Nodes.getNodeAs<CXXMemberCallExpr>("end"); - const SourceLocation Loc = MemberCall->getLocStart(); - - FixItHint Hint; - - if (!Loc.isMacroID() && EndExpr) { - const auto *AlgCall = Result.Nodes.getNodeAs<CallExpr>("alg"); - std::string ReplacementText = Lexer::getSourceText( - CharSourceRange::getTokenRange(EndExpr->getSourceRange()), - *Result.SourceManager, getLangOpts()); - const SourceLocation EndLoc = Lexer::getLocForEndOfToken( - AlgCall->getLocEnd(), 0, *Result.SourceManager, getLangOpts()); - Hint = FixItHint::CreateInsertion(EndLoc, ", " + ReplacementText); - } - - diag(Loc, "this call will remove at most one item even when multiple items " - "should be removed") - << Hint; -} - -} // namespace misc -} // namespace tidy -} // namespace clang diff --git a/clang-tools-extra/clang-tidy/misc/InaccurateEraseCheck.h b/clang-tools-extra/clang-tidy/misc/InaccurateEraseCheck.h deleted file mode 100644 index 623e1c236eb..00000000000 --- a/clang-tools-extra/clang-tidy/misc/InaccurateEraseCheck.h +++ /dev/null @@ -1,38 +0,0 @@ -//===--- InaccurateEraseCheck.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_INACCURATEERASECHECK_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_INACCURATEERASECHECK_H - -#include "../ClangTidy.h" - -namespace clang { -namespace tidy { -namespace misc { - -/// Checks for inaccurate use of the `erase()` method. -/// -/// Algorithms like `remove()` do not actually remove any element from the -/// container but return an iterator to the first redundant element at the end -/// of the container. These redundant elements must be removed using the -/// `erase()` method. This check warns when not all of the elements will be -/// removed due to using an inappropriate overload. -class InaccurateEraseCheck : public ClangTidyCheck { -public: - InaccurateEraseCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} - void registerMatchers(ast_matchers::MatchFinder *Finder) override; - void check(const ast_matchers::MatchFinder::MatchResult &Result) override; -}; - -} // namespace misc -} // namespace tidy -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_INACCURATEERASECHECK_H diff --git a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp index fbc999f2a0a..1dddd4e2832 100644 --- a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp @@ -10,13 +10,8 @@ #include "../ClangTidy.h" #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" -#include "AssertSideEffectCheck.h" -#include "BoolPointerImplicitConversionCheck.h" #include "DefinitionsInHeadersCheck.h" -#include "FoldInitTypeCheck.h" -#include "ForwardDeclarationNamespaceCheck.h" #include "ForwardingReferenceOverloadCheck.h" -#include "InaccurateEraseCheck.h" #include "IncorrectRoundings.h" #include "InefficientAlgorithmCheck.h" #include "LambdaFunctionNameCheck.h" @@ -26,8 +21,6 @@ #include "MisplacedWideningCastCheck.h" #include "MoveConstantArgumentCheck.h" #include "MoveConstructorInitCheck.h" -#include "MoveForwardingReferenceCheck.h" -#include "MultipleStatementMacroCheck.h" #include "NewDeleteOverloadsCheck.h" #include "NoexceptMoveConstructorCheck.h" #include "NonCopyableObjects.h" @@ -51,8 +44,6 @@ #include "UnusedParametersCheck.h" #include "UnusedRAIICheck.h" #include "UnusedUsingDeclsCheck.h" -#include "UseAfterMoveCheck.h" -#include "VirtualNearMissCheck.h" namespace clang { namespace tidy { @@ -61,8 +52,6 @@ namespace misc { class MiscModule : public ClangTidyModule { public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { - CheckFactories.registerCheck<AssertSideEffectCheck>( - "misc-assert-side-effect"); CheckFactories.registerCheck<ForwardingReferenceOverloadCheck>( "misc-forwarding-reference-overload"); CheckFactories.registerCheck<LambdaFunctionNameCheck>( @@ -70,14 +59,8 @@ public: CheckFactories.registerCheck<MisplacedConstCheck>("misc-misplaced-const"); CheckFactories.registerCheck<UnconventionalAssignOperatorCheck>( "misc-unconventional-assign-operator"); - CheckFactories.registerCheck<BoolPointerImplicitConversionCheck>( - "misc-bool-pointer-implicit-conversion"); CheckFactories.registerCheck<DefinitionsInHeadersCheck>( "misc-definitions-in-headers"); - CheckFactories.registerCheck<FoldInitTypeCheck>("misc-fold-init-type"); - CheckFactories.registerCheck<ForwardDeclarationNamespaceCheck>( - "misc-forward-declaration-namespace"); - CheckFactories.registerCheck<InaccurateEraseCheck>("misc-inaccurate-erase"); CheckFactories.registerCheck<IncorrectRoundings>( "misc-incorrect-roundings"); CheckFactories.registerCheck<InefficientAlgorithmCheck>( @@ -92,10 +75,6 @@ public: "misc-move-const-arg"); CheckFactories.registerCheck<MoveConstructorInitCheck>( "misc-move-constructor-init"); - CheckFactories.registerCheck<MoveForwardingReferenceCheck>( - "misc-move-forwarding-reference"); - CheckFactories.registerCheck<MultipleStatementMacroCheck>( - "misc-multiple-statement-macro"); CheckFactories.registerCheck<NewDeleteOverloadsCheck>( "misc-new-delete-overloads"); CheckFactories.registerCheck<NoexceptMoveConstructorCheck>( @@ -136,9 +115,6 @@ public: CheckFactories.registerCheck<UnusedRAIICheck>("misc-unused-raii"); CheckFactories.registerCheck<UnusedUsingDeclsCheck>( "misc-unused-using-decls"); - CheckFactories.registerCheck<UseAfterMoveCheck>("misc-use-after-move"); - CheckFactories.registerCheck<VirtualNearMissCheck>( - "misc-virtual-near-miss"); } }; diff --git a/clang-tools-extra/clang-tidy/misc/MoveForwardingReferenceCheck.cpp b/clang-tools-extra/clang-tidy/misc/MoveForwardingReferenceCheck.cpp deleted file mode 100644 index 12c19dd9c20..00000000000 --- a/clang-tools-extra/clang-tidy/misc/MoveForwardingReferenceCheck.cpp +++ /dev/null @@ -1,133 +0,0 @@ -//===--- MoveForwardingReferenceCheck.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 "MoveForwardingReferenceCheck.h" -#include "clang/Lex/Lexer.h" -#include "llvm/Support/raw_ostream.h" - -#include <algorithm> - -using namespace clang::ast_matchers; - -namespace clang { -namespace tidy { -namespace misc { - -static void replaceMoveWithForward(const UnresolvedLookupExpr *Callee, - const ParmVarDecl *ParmVar, - const TemplateTypeParmDecl *TypeParmDecl, - DiagnosticBuilder &Diag, - const ASTContext &Context) { - const SourceManager &SM = Context.getSourceManager(); - const LangOptions &LangOpts = Context.getLangOpts(); - - CharSourceRange CallRange = - Lexer::makeFileCharRange(CharSourceRange::getTokenRange( - Callee->getLocStart(), Callee->getLocEnd()), - SM, LangOpts); - - if (CallRange.isValid()) { - const std::string TypeName = - TypeParmDecl->getIdentifier() - ? TypeParmDecl->getName().str() - : (llvm::Twine("decltype(") + ParmVar->getName() + ")").str(); - - const std::string ForwardName = - (llvm::Twine("forward<") + TypeName + ">").str(); - - // Create a replacement only if we see a "standard" way of calling - // std::move(). This will hopefully prevent erroneous replacements if the - // code does unusual things (e.g. create an alias for std::move() in - // another namespace). - NestedNameSpecifier *NNS = Callee->getQualifier(); - if (!NNS) { - // Called as "move" (i.e. presumably the code had a "using std::move;"). - // We still conservatively put a "std::" in front of the forward because - // we don't know whether the code also had a "using std::forward;". - Diag << FixItHint::CreateReplacement(CallRange, "std::" + ForwardName); - } else if (const NamespaceDecl *Namespace = NNS->getAsNamespace()) { - if (Namespace->getName() == "std") { - if (!NNS->getPrefix()) { - // Called as "std::move". - Diag << FixItHint::CreateReplacement(CallRange, - "std::" + ForwardName); - } else if (NNS->getPrefix()->getKind() == NestedNameSpecifier::Global) { - // Called as "::std::move". - Diag << FixItHint::CreateReplacement(CallRange, - "::std::" + ForwardName); - } - } - } - } -} - -void MoveForwardingReferenceCheck::registerMatchers(MatchFinder *Finder) { - if (!getLangOpts().CPlusPlus11) - return; - - // Matches a ParmVarDecl for a forwarding reference, i.e. a non-const rvalue - // reference of a function template parameter type. - auto ForwardingReferenceParmMatcher = - parmVarDecl( - hasType(qualType(rValueReferenceType(), - references(templateTypeParmType(hasDeclaration( - templateTypeParmDecl().bind("type-parm-decl")))), - unless(references(qualType(isConstQualified())))))) - .bind("parm-var"); - - Finder->addMatcher( - callExpr(callee(unresolvedLookupExpr( - hasAnyDeclaration(namedDecl( - hasUnderlyingDecl(hasName("::std::move"))))) - .bind("lookup")), - argumentCountIs(1), - hasArgument(0, ignoringParenImpCasts(declRefExpr( - to(ForwardingReferenceParmMatcher))))) - .bind("call-move"), - this); -} - -void MoveForwardingReferenceCheck::check( - const MatchFinder::MatchResult &Result) { - const auto *CallMove = Result.Nodes.getNodeAs<CallExpr>("call-move"); - const auto *UnresolvedLookup = - Result.Nodes.getNodeAs<UnresolvedLookupExpr>("lookup"); - const auto *ParmVar = Result.Nodes.getNodeAs<ParmVarDecl>("parm-var"); - const auto *TypeParmDecl = - Result.Nodes.getNodeAs<TemplateTypeParmDecl>("type-parm-decl"); - - // Get the FunctionDecl and FunctionTemplateDecl containing the function - // parameter. - const auto *FuncForParam = dyn_cast<FunctionDecl>(ParmVar->getDeclContext()); - if (!FuncForParam) - return; - const FunctionTemplateDecl *FuncTemplate = - FuncForParam->getDescribedFunctionTemplate(); - if (!FuncTemplate) - return; - - // Check that the template type parameter belongs to the same function - // template as the function parameter of that type. (This implies that type - // deduction will happen on the type.) - const TemplateParameterList *Params = FuncTemplate->getTemplateParameters(); - if (!std::count(Params->begin(), Params->end(), TypeParmDecl)) - return; - - auto Diag = diag(CallMove->getExprLoc(), - "forwarding reference passed to std::move(), which may " - "unexpectedly cause lvalues to be moved; use " - "std::forward() instead"); - - replaceMoveWithForward(UnresolvedLookup, ParmVar, TypeParmDecl, Diag, - *Result.Context); -} - -} // namespace misc -} // namespace tidy -} // namespace clang diff --git a/clang-tools-extra/clang-tidy/misc/MoveForwardingReferenceCheck.h b/clang-tools-extra/clang-tidy/misc/MoveForwardingReferenceCheck.h deleted file mode 100644 index 2e6ec363488..00000000000 --- a/clang-tools-extra/clang-tidy/misc/MoveForwardingReferenceCheck.h +++ /dev/null @@ -1,49 +0,0 @@ -//===--- MoveForwardingReferenceCheck.h - clang-tidy ----------------------===// -// -// 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_MOVEFORWARDINGREFERENCECHECK_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVEFORWARDINGREFERENCECHECK_H - -#include "../ClangTidy.h" - -namespace clang { -namespace tidy { -namespace misc { - -/// The check warns if std::move is applied to a forwarding reference (i.e. an -/// rvalue reference of a function template argument type). -/// -/// If a developer is unaware of the special rules for template argument -/// deduction on forwarding references, it will seem reasonable to apply -/// std::move to the forwarding reference, in the same way that this would be -/// done for a "normal" rvalue reference. -/// -/// This has a consequence that is usually unwanted and possibly surprising: if -/// the function that takes the forwarding reference as its parameter is called -/// with an lvalue, that lvalue will be moved from (and hence placed into an -/// indeterminate state) even though no std::move was applied to the lvalue at -/// the call site. -// -/// The check suggests replacing the std::move with a std::forward. -/// -/// For the user-facing documentation see: -/// http://clang.llvm.org/extra/clang-tidy/checks/misc-move-forwarding-reference.html -class MoveForwardingReferenceCheck : public ClangTidyCheck { -public: - MoveForwardingReferenceCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} - void registerMatchers(ast_matchers::MatchFinder *Finder) override; - void check(const ast_matchers::MatchFinder::MatchResult &Result) override; -}; - -} // namespace misc -} // namespace tidy -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVEFORWARDINGREFERENCECHECK_H diff --git a/clang-tools-extra/clang-tidy/misc/MultipleStatementMacroCheck.cpp b/clang-tools-extra/clang-tidy/misc/MultipleStatementMacroCheck.cpp deleted file mode 100644 index 9d485fd211b..00000000000 --- a/clang-tools-extra/clang-tidy/misc/MultipleStatementMacroCheck.cpp +++ /dev/null @@ -1,106 +0,0 @@ -//===--- MultipleStatementMacroCheck.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 "MultipleStatementMacroCheck.h" -#include "clang/AST/ASTContext.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" - -using namespace clang::ast_matchers; - -namespace clang { -namespace tidy { -namespace misc { - -namespace { - -AST_MATCHER(Expr, isInMacro) { return Node.getLocStart().isMacroID(); } - -/// \brief Find the next statement after `S`. -const Stmt *nextStmt(const MatchFinder::MatchResult &Result, const Stmt *S) { - auto Parents = Result.Context->getParents(*S); - if (Parents.empty()) - return nullptr; - const auto *Parent = Parents[0].get<Stmt>(); - if (!Parent) - return nullptr; - const Stmt *Prev = nullptr; - for (const Stmt *Child : Parent->children()) { - if (Prev == S) - return Child; - Prev = Child; - } - return nextStmt(Result, Parent); -} - -using ExpansionRanges = std::vector<std::pair<SourceLocation, SourceLocation>>; - -/// \bried Get all the macro expansion ranges related to `Loc`. -/// -/// The result is ordered from most inner to most outer. -ExpansionRanges getExpansionRanges(SourceLocation Loc, - const MatchFinder::MatchResult &Result) { - ExpansionRanges Locs; - while (Loc.isMacroID()) { - Locs.push_back(Result.SourceManager->getImmediateExpansionRange(Loc)); - Loc = Locs.back().first; - } - return Locs; -} - -} // namespace - -void MultipleStatementMacroCheck::registerMatchers(MatchFinder *Finder) { - const auto Inner = expr(isInMacro(), unless(compoundStmt())).bind("inner"); - Finder->addMatcher( - stmt(anyOf(ifStmt(hasThen(Inner)), ifStmt(hasElse(Inner)).bind("else"), - whileStmt(hasBody(Inner)), forStmt(hasBody(Inner)))) - .bind("outer"), - this); -} - -void MultipleStatementMacroCheck::check( - const MatchFinder::MatchResult &Result) { - const auto *Inner = Result.Nodes.getNodeAs<Expr>("inner"); - const auto *Outer = Result.Nodes.getNodeAs<Stmt>("outer"); - const auto *Next = nextStmt(Result, Outer); - if (!Next) - return; - - SourceLocation OuterLoc = Outer->getLocStart(); - if (Result.Nodes.getNodeAs<Stmt>("else")) - OuterLoc = cast<IfStmt>(Outer)->getElseLoc(); - - auto InnerRanges = getExpansionRanges(Inner->getLocStart(), Result); - auto OuterRanges = getExpansionRanges(OuterLoc, Result); - auto NextRanges = getExpansionRanges(Next->getLocStart(), Result); - - // Remove all the common ranges, starting from the top (the last ones in the - // list). - while (!InnerRanges.empty() && !OuterRanges.empty() && !NextRanges.empty() && - InnerRanges.back() == OuterRanges.back() && - InnerRanges.back() == NextRanges.back()) { - InnerRanges.pop_back(); - OuterRanges.pop_back(); - NextRanges.pop_back(); - } - - // Inner and Next must have at least one more macro that Outer doesn't have, - // and that range must be common to both. - if (InnerRanges.empty() || NextRanges.empty() || - InnerRanges.back() != NextRanges.back()) - return; - - diag(InnerRanges.back().first, "multiple statement macro used without " - "braces; some statements will be " - "unconditionally executed"); -} - -} // namespace misc -} // namespace tidy -} // namespace clang diff --git a/clang-tools-extra/clang-tidy/misc/MultipleStatementMacroCheck.h b/clang-tools-extra/clang-tidy/misc/MultipleStatementMacroCheck.h deleted file mode 100644 index 77a6b27dcde..00000000000 --- a/clang-tools-extra/clang-tidy/misc/MultipleStatementMacroCheck.h +++ /dev/null @@ -1,37 +0,0 @@ -//===--- MultipleStatementMacroCheck.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_MULTIPLE_STATEMENT_MACRO_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MULTIPLE_STATEMENT_MACRO_H - -#include "../ClangTidy.h" - -namespace clang { -namespace tidy { -namespace misc { - -/// Detect multiple statement macros that are used in unbraced conditionals. -/// Only the first statement of the macro will be inside the conditional and the -/// other ones will be executed unconditionally. -/// -/// For the user-facing documentation see: -/// http://clang.llvm.org/extra/clang-tidy/checks/misc-multiple-statement-macro.html -class MultipleStatementMacroCheck : public ClangTidyCheck { -public: - MultipleStatementMacroCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} - void registerMatchers(ast_matchers::MatchFinder *Finder) override; - void check(const ast_matchers::MatchFinder::MatchResult &Result) override; -}; - -} // namespace misc -} // namespace tidy -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MULTIPLE_STATEMENT_MACRO_H diff --git a/clang-tools-extra/clang-tidy/misc/UseAfterMoveCheck.cpp b/clang-tools-extra/clang-tidy/misc/UseAfterMoveCheck.cpp deleted file mode 100644 index 99673766a53..00000000000 --- a/clang-tools-extra/clang-tidy/misc/UseAfterMoveCheck.cpp +++ /dev/null @@ -1,434 +0,0 @@ -//===--- UseAfterMoveCheck.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 "UseAfterMoveCheck.h" - -#include "clang/Analysis/CFG.h" -#include "clang/Lex/Lexer.h" - -#include "../utils/ExprSequence.h" - -using namespace clang::ast_matchers; -using namespace clang::tidy::utils; - - -namespace clang { -namespace tidy { -namespace misc { - -namespace { - -/// Contains information about a use-after-move. -struct UseAfterMove { - // The DeclRefExpr that constituted the use of the object. - const DeclRefExpr *DeclRef; - - // Is the order in which the move and the use are evaluated undefined? - bool EvaluationOrderUndefined; -}; - -/// Finds uses of a variable after a move (and maintains state required by the -/// various internal helper functions). -class UseAfterMoveFinder { -public: - UseAfterMoveFinder(ASTContext *TheContext); - - // Within the given function body, finds the first use of 'MovedVariable' that - // occurs after 'MovingCall' (the expression that performs the move). If a - // use-after-move is found, writes information about it to 'TheUseAfterMove'. - // Returns whether a use-after-move was found. - bool find(Stmt *FunctionBody, const Expr *MovingCall, - const ValueDecl *MovedVariable, UseAfterMove *TheUseAfterMove); - -private: - bool findInternal(const CFGBlock *Block, const Expr *MovingCall, - const ValueDecl *MovedVariable, - UseAfterMove *TheUseAfterMove); - void getUsesAndReinits(const CFGBlock *Block, const ValueDecl *MovedVariable, - llvm::SmallVectorImpl<const DeclRefExpr *> *Uses, - llvm::SmallPtrSetImpl<const Stmt *> *Reinits); - void getDeclRefs(const CFGBlock *Block, const Decl *MovedVariable, - llvm::SmallPtrSetImpl<const DeclRefExpr *> *DeclRefs); - void getReinits(const CFGBlock *Block, const ValueDecl *MovedVariable, - llvm::SmallPtrSetImpl<const Stmt *> *Stmts, - llvm::SmallPtrSetImpl<const DeclRefExpr *> *DeclRefs); - - ASTContext *Context; - std::unique_ptr<ExprSequence> Sequence; - std::unique_ptr<StmtToBlockMap> BlockMap; - llvm::SmallPtrSet<const CFGBlock *, 8> Visited; -}; - -} // namespace - - -// Matches nodes that are -// - Part of a decltype argument or class template argument (we check this by -// seeing if they are children of a TypeLoc), or -// - Part of a function template argument (we check this by seeing if they are -// children of a DeclRefExpr that references a function template). -// DeclRefExprs that fulfill these conditions should not be counted as a use or -// move. -static StatementMatcher inDecltypeOrTemplateArg() { - return anyOf(hasAncestor(typeLoc()), - hasAncestor(declRefExpr( - to(functionDecl(ast_matchers::isTemplateInstantiation()))))); -} - -UseAfterMoveFinder::UseAfterMoveFinder(ASTContext *TheContext) - : Context(TheContext) {} - -bool UseAfterMoveFinder::find(Stmt *FunctionBody, const Expr *MovingCall, - const ValueDecl *MovedVariable, - UseAfterMove *TheUseAfterMove) { - // Generate the CFG manually instead of through an AnalysisDeclContext because - // it seems the latter can't be used to generate a CFG for the body of a - // labmda. - // - // We include implicit and temporary destructors in the CFG so that - // destructors marked [[noreturn]] are handled correctly in the control flow - // analysis. (These are used in some styles of assertion macros.) - CFG::BuildOptions Options; - Options.AddImplicitDtors = true; - Options.AddTemporaryDtors = true; - std::unique_ptr<CFG> TheCFG = - CFG::buildCFG(nullptr, FunctionBody, Context, Options); - if (!TheCFG) - return false; - - Sequence.reset(new ExprSequence(TheCFG.get(), Context)); - BlockMap.reset(new StmtToBlockMap(TheCFG.get(), Context)); - Visited.clear(); - - const CFGBlock *Block = BlockMap->blockContainingStmt(MovingCall); - if (!Block) - return false; - - return findInternal(Block, MovingCall, MovedVariable, TheUseAfterMove); -} - -bool UseAfterMoveFinder::findInternal(const CFGBlock *Block, - const Expr *MovingCall, - const ValueDecl *MovedVariable, - UseAfterMove *TheUseAfterMove) { - if (Visited.count(Block)) - return false; - - // Mark the block as visited (except if this is the block containing the - // std::move() and it's being visited the first time). - if (!MovingCall) - Visited.insert(Block); - - // Get all uses and reinits in the block. - llvm::SmallVector<const DeclRefExpr *, 1> Uses; - llvm::SmallPtrSet<const Stmt *, 1> Reinits; - getUsesAndReinits(Block, MovedVariable, &Uses, &Reinits); - - // Ignore all reinitializations where the move potentially comes after the - // reinit. - llvm::SmallVector<const Stmt *, 1> ReinitsToDelete; - for (const Stmt *Reinit : Reinits) { - if (MovingCall && Sequence->potentiallyAfter(MovingCall, Reinit)) - ReinitsToDelete.push_back(Reinit); - } - for (const Stmt *Reinit : ReinitsToDelete) { - Reinits.erase(Reinit); - } - - // Find all uses that potentially come after the move. - for (const DeclRefExpr *Use : Uses) { - if (!MovingCall || Sequence->potentiallyAfter(Use, MovingCall)) { - // Does the use have a saving reinit? A reinit is saving if it definitely - // comes before the use, i.e. if there's no potential that the reinit is - // after the use. - bool HaveSavingReinit = false; - for (const Stmt *Reinit : Reinits) { - if (!Sequence->potentiallyAfter(Reinit, Use)) - HaveSavingReinit = true; - } - - if (!HaveSavingReinit) { - TheUseAfterMove->DeclRef = Use; - - // Is this a use-after-move that depends on order of evaluation? - // This is the case if the move potentially comes after the use (and we - // already know that use potentially comes after the move, which taken - // together tells us that the ordering is unclear). - TheUseAfterMove->EvaluationOrderUndefined = - MovingCall != nullptr && - Sequence->potentiallyAfter(MovingCall, Use); - - return true; - } - } - } - - // If the object wasn't reinitialized, call ourselves recursively on all - // successors. - if (Reinits.empty()) { - for (const auto &Succ : Block->succs()) { - if (Succ && findInternal(Succ, nullptr, MovedVariable, TheUseAfterMove)) - return true; - } - } - - return false; -} - -void UseAfterMoveFinder::getUsesAndReinits( - const CFGBlock *Block, const ValueDecl *MovedVariable, - llvm::SmallVectorImpl<const DeclRefExpr *> *Uses, - llvm::SmallPtrSetImpl<const Stmt *> *Reinits) { - llvm::SmallPtrSet<const DeclRefExpr *, 1> DeclRefs; - llvm::SmallPtrSet<const DeclRefExpr *, 1> ReinitDeclRefs; - - getDeclRefs(Block, MovedVariable, &DeclRefs); - getReinits(Block, MovedVariable, Reinits, &ReinitDeclRefs); - - // All references to the variable that aren't reinitializations are uses. - Uses->clear(); - for (const DeclRefExpr *DeclRef : DeclRefs) { - if (!ReinitDeclRefs.count(DeclRef)) - Uses->push_back(DeclRef); - } - - // Sort the uses by their occurrence in the source code. - std::sort(Uses->begin(), Uses->end(), - [](const DeclRefExpr *D1, const DeclRefExpr *D2) { - return D1->getExprLoc() < D2->getExprLoc(); - }); -} - -bool isStandardSmartPointer(const ValueDecl *VD) { - const Type *TheType = VD->getType().getTypePtrOrNull(); - if (!TheType) - return false; - - const CXXRecordDecl *RecordDecl = TheType->getAsCXXRecordDecl(); - if (!RecordDecl) - return false; - - const IdentifierInfo *ID = RecordDecl->getIdentifier(); - if (!ID) - return false; - - StringRef Name = ID->getName(); - if (Name != "unique_ptr" && Name != "shared_ptr" && Name != "weak_ptr") - return false; - - return RecordDecl->getDeclContext()->isStdNamespace(); -} - -void UseAfterMoveFinder::getDeclRefs( - const CFGBlock *Block, const Decl *MovedVariable, - llvm::SmallPtrSetImpl<const DeclRefExpr *> *DeclRefs) { - DeclRefs->clear(); - for (const auto &Elem : *Block) { - Optional<CFGStmt> S = Elem.getAs<CFGStmt>(); - if (!S) - continue; - - auto addDeclRefs = [this, Block, - DeclRefs](const ArrayRef<BoundNodes> Matches) { - for (const auto &Match : Matches) { - const auto *DeclRef = Match.getNodeAs<DeclRefExpr>("declref"); - const auto *Operator = Match.getNodeAs<CXXOperatorCallExpr>("operator"); - if (DeclRef && BlockMap->blockContainingStmt(DeclRef) == Block) { - // Ignore uses of a standard smart pointer that don't dereference the - // pointer. - if (Operator || !isStandardSmartPointer(DeclRef->getDecl())) { - DeclRefs->insert(DeclRef); - } - } - } - }; - - auto DeclRefMatcher = declRefExpr(hasDeclaration(equalsNode(MovedVariable)), - unless(inDecltypeOrTemplateArg())) - .bind("declref"); - - addDeclRefs(match(findAll(DeclRefMatcher), *S->getStmt(), *Context)); - addDeclRefs(match( - findAll(cxxOperatorCallExpr(anyOf(hasOverloadedOperatorName("*"), - hasOverloadedOperatorName("->"), - hasOverloadedOperatorName("[]")), - hasArgument(0, DeclRefMatcher)) - .bind("operator")), - *S->getStmt(), *Context)); - } -} - -void UseAfterMoveFinder::getReinits( - const CFGBlock *Block, const ValueDecl *MovedVariable, - llvm::SmallPtrSetImpl<const Stmt *> *Stmts, - llvm::SmallPtrSetImpl<const DeclRefExpr *> *DeclRefs) { - auto DeclRefMatcher = - declRefExpr(hasDeclaration(equalsNode(MovedVariable))).bind("declref"); - - auto StandardContainerTypeMatcher = hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(cxxRecordDecl(hasAnyName( - "::std::basic_string", "::std::vector", "::std::deque", - "::std::forward_list", "::std::list", "::std::set", "::std::map", - "::std::multiset", "::std::multimap", "::std::unordered_set", - "::std::unordered_map", "::std::unordered_multiset", - "::std::unordered_multimap")))))); - - auto StandardSmartPointerTypeMatcher = hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(cxxRecordDecl(hasAnyName( - "::std::unique_ptr", "::std::shared_ptr", "::std::weak_ptr")))))); - - // Matches different types of reinitialization. - auto ReinitMatcher = - stmt(anyOf( - // Assignment. In addition to the overloaded assignment operator, - // test for built-in assignment as well, since template functions - // may be instantiated to use std::move() on built-in types. - binaryOperator(hasOperatorName("="), hasLHS(DeclRefMatcher)), - cxxOperatorCallExpr(hasOverloadedOperatorName("="), - hasArgument(0, DeclRefMatcher)), - // Declaration. We treat this as a type of reinitialization too, - // so we don't need to treat it separately. - declStmt(hasDescendant(equalsNode(MovedVariable))), - // clear() and assign() on standard containers. - cxxMemberCallExpr( - on(allOf(DeclRefMatcher, StandardContainerTypeMatcher)), - // To keep the matcher simple, we check for assign() calls - // on all standard containers, even though only vector, - // deque, forward_list and list have assign(). If assign() - // is called on any of the other containers, this will be - // flagged by a compile error anyway. - callee(cxxMethodDecl(hasAnyName("clear", "assign")))), - // reset() on standard smart pointers. - cxxMemberCallExpr( - on(allOf(DeclRefMatcher, StandardSmartPointerTypeMatcher)), - callee(cxxMethodDecl(hasName("reset")))), - // Passing variable to a function as a non-const pointer. - callExpr(forEachArgumentWithParam( - unaryOperator(hasOperatorName("&"), - hasUnaryOperand(DeclRefMatcher)), - unless(parmVarDecl(hasType(pointsTo(isConstQualified())))))), - // Passing variable to a function as a non-const lvalue reference - // (unless that function is std::move()). - callExpr(forEachArgumentWithParam( - DeclRefMatcher, - unless(parmVarDecl(hasType( - references(qualType(isConstQualified())))))), - unless(callee(functionDecl(hasName("::std::move"))))))) - .bind("reinit"); - - Stmts->clear(); - DeclRefs->clear(); - for (const auto &Elem : *Block) { - Optional<CFGStmt> S = Elem.getAs<CFGStmt>(); - if (!S) - continue; - - SmallVector<BoundNodes, 1> Matches = - match(findAll(ReinitMatcher), *S->getStmt(), *Context); - - for (const auto &Match : Matches) { - const auto *TheStmt = Match.getNodeAs<Stmt>("reinit"); - const auto *TheDeclRef = Match.getNodeAs<DeclRefExpr>("declref"); - if (TheStmt && BlockMap->blockContainingStmt(TheStmt) == Block) { - Stmts->insert(TheStmt); - - // We count DeclStmts as reinitializations, but they don't have a - // DeclRefExpr associated with them -- so we need to check 'TheDeclRef' - // before adding it to the set. - if (TheDeclRef) - DeclRefs->insert(TheDeclRef); - } - } - } -} - -static void emitDiagnostic(const Expr *MovingCall, const DeclRefExpr *MoveArg, - const UseAfterMove &Use, ClangTidyCheck *Check, - ASTContext *Context) { - SourceLocation UseLoc = Use.DeclRef->getExprLoc(); - SourceLocation MoveLoc = MovingCall->getExprLoc(); - - Check->diag(UseLoc, "'%0' used after it was moved") - << MoveArg->getDecl()->getName(); - Check->diag(MoveLoc, "move occurred here", DiagnosticIDs::Note); - if (Use.EvaluationOrderUndefined) { - Check->diag(UseLoc, - "the use and move are unsequenced, i.e. there is no guarantee " - "about the order in which they are evaluated", - DiagnosticIDs::Note); - } else if (UseLoc < MoveLoc || Use.DeclRef == MoveArg) { - Check->diag(UseLoc, - "the use happens in a later loop iteration than the move", - DiagnosticIDs::Note); - } -} - -void UseAfterMoveCheck::registerMatchers(MatchFinder *Finder) { - if (!getLangOpts().CPlusPlus11) - return; - - auto CallMoveMatcher = - callExpr(callee(functionDecl(hasName("::std::move"))), argumentCountIs(1), - hasArgument(0, declRefExpr().bind("arg")), - anyOf(hasAncestor(lambdaExpr().bind("containing-lambda")), - hasAncestor(functionDecl().bind("containing-func"))), - unless(inDecltypeOrTemplateArg())) - .bind("call-move"); - - Finder->addMatcher( - // To find the Stmt that we assume performs the actual move, we look for - // the direct ancestor of the std::move() that isn't one of the node - // types ignored by ignoringParenImpCasts(). - stmt(forEach(expr(ignoringParenImpCasts(CallMoveMatcher))), - // Don't allow an InitListExpr to be the moving call. An InitListExpr - // has both a syntactic and a semantic form, and the parent-child - // relationships are different between the two. This could cause an - // InitListExpr to be analyzed as the moving call in addition to the - // Expr that we actually want, resulting in two diagnostics with - // different code locations for the same move. - unless(initListExpr()), - unless(expr(ignoringParenImpCasts(equalsBoundNode("call-move"))))) - .bind("moving-call"), - this); -} - -void UseAfterMoveCheck::check(const MatchFinder::MatchResult &Result) { - const auto *ContainingLambda = - Result.Nodes.getNodeAs<LambdaExpr>("containing-lambda"); - const auto *ContainingFunc = - Result.Nodes.getNodeAs<FunctionDecl>("containing-func"); - const auto *CallMove = Result.Nodes.getNodeAs<CallExpr>("call-move"); - const auto *MovingCall = Result.Nodes.getNodeAs<Expr>("moving-call"); - const auto *Arg = Result.Nodes.getNodeAs<DeclRefExpr>("arg"); - - if (!MovingCall || !MovingCall->getExprLoc().isValid()) - MovingCall = CallMove; - - Stmt *FunctionBody = nullptr; - if (ContainingLambda) - FunctionBody = ContainingLambda->getBody(); - else if (ContainingFunc) - FunctionBody = ContainingFunc->getBody(); - else - return; - - // Ignore the std::move if the variable that was passed to it isn't a local - // variable. - if (!Arg->getDecl()->getDeclContext()->isFunctionOrMethod()) - return; - - UseAfterMoveFinder finder(Result.Context); - UseAfterMove Use; - if (finder.find(FunctionBody, MovingCall, Arg->getDecl(), &Use)) - emitDiagnostic(MovingCall, Arg, Use, this, Result.Context); -} - -} // namespace misc -} // namespace tidy -} // namespace clang diff --git a/clang-tools-extra/clang-tidy/misc/UseAfterMoveCheck.h b/clang-tools-extra/clang-tidy/misc/UseAfterMoveCheck.h deleted file mode 100644 index 2f6be5be300..00000000000 --- a/clang-tools-extra/clang-tidy/misc/UseAfterMoveCheck.h +++ /dev/null @@ -1,36 +0,0 @@ -//===--- UseAfterMoveCheck.h - clang-tidy ---------------------------------===// -// -// 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_USEAFTERMOVECHECK_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_USEAFTERMOVECHECK_H - -#include "../ClangTidy.h" - -namespace clang { -namespace tidy { -namespace misc { - -/// The check warns if an object is used after it has been moved, without an -/// intervening reinitialization. -/// -/// For details, see the user-facing documentation: -/// http://clang.llvm.org/extra/clang-tidy/checks/misc-use-after-move.html -class UseAfterMoveCheck : public ClangTidyCheck { -public: - UseAfterMoveCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} - void registerMatchers(ast_matchers::MatchFinder *Finder) override; - void check(const ast_matchers::MatchFinder::MatchResult &Result) override; -}; - -} // namespace misc -} // namespace tidy -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_USEAFTERMOVECHECK_H diff --git a/clang-tools-extra/clang-tidy/misc/VirtualNearMissCheck.cpp b/clang-tools-extra/clang-tidy/misc/VirtualNearMissCheck.cpp deleted file mode 100644 index fd74bb6692e..00000000000 --- a/clang-tools-extra/clang-tidy/misc/VirtualNearMissCheck.cpp +++ /dev/null @@ -1,274 +0,0 @@ -//===--- VirtualNearMissCheck.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 "VirtualNearMissCheck.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/CXXInheritance.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/Lex/Lexer.h" - -using namespace clang::ast_matchers; - -namespace clang { -namespace tidy { -namespace misc { - -AST_MATCHER(CXXMethodDecl, isStatic) { return Node.isStatic(); } - -AST_MATCHER(CXXMethodDecl, isOverloadedOperator) { - return Node.isOverloadedOperator(); -} - -/// Finds out if the given method overrides some method. -static bool isOverrideMethod(const CXXMethodDecl *MD) { - return MD->size_overridden_methods() > 0 || MD->hasAttr<OverrideAttr>(); -} - -/// Checks whether the return types are covariant, according to -/// C++[class.virtual]p7. -/// -/// Similar with clang::Sema::CheckOverridingFunctionReturnType. -/// \returns true if the return types of BaseMD and DerivedMD are covariant. -static bool checkOverridingFunctionReturnType(const ASTContext *Context, - const CXXMethodDecl *BaseMD, - const CXXMethodDecl *DerivedMD) { - QualType BaseReturnTy = BaseMD->getType() - ->getAs<FunctionType>() - ->getReturnType() - .getCanonicalType(); - QualType DerivedReturnTy = DerivedMD->getType() - ->getAs<FunctionType>() - ->getReturnType() - .getCanonicalType(); - - if (DerivedReturnTy->isDependentType() || BaseReturnTy->isDependentType()) - return false; - - // Check if return types are identical. - if (Context->hasSameType(DerivedReturnTy, BaseReturnTy)) - return true; - - /// Check if the return types are covariant. - - // Both types must be pointers or references to classes. - if (!(BaseReturnTy->isPointerType() && DerivedReturnTy->isPointerType()) && - !(BaseReturnTy->isReferenceType() && DerivedReturnTy->isReferenceType())) - return false; - - /// BTy is the class type in return type of BaseMD. For example, - /// B* Base::md() - /// While BRD is the declaration of B. - QualType DTy = DerivedReturnTy->getPointeeType().getCanonicalType(); - QualType BTy = BaseReturnTy->getPointeeType().getCanonicalType(); - - const CXXRecordDecl *DRD = DTy->getAsCXXRecordDecl(); - const CXXRecordDecl *BRD = BTy->getAsCXXRecordDecl(); - if (DRD == nullptr || BRD == nullptr) - return false; - - if (!DRD->hasDefinition() || !BRD->hasDefinition()) - return false; - - if (DRD == BRD) - return true; - - if (!Context->hasSameUnqualifiedType(DTy, BTy)) { - // Begin checking whether the conversion from D to B is valid. - CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, - /*DetectVirtual=*/false); - - // Check whether D is derived from B, and fill in a CXXBasePaths object. - if (!DRD->isDerivedFrom(BRD, Paths)) - return false; - - // Check ambiguity. - if (Paths.isAmbiguous(Context->getCanonicalType(BTy).getUnqualifiedType())) - return false; - - // Check accessibility. - // FIXME: We currently only support checking if B is accessible base class - // of D, or D is the same class which DerivedMD is in. - bool IsItself = - DRD->getCanonicalDecl() == DerivedMD->getParent()->getCanonicalDecl(); - bool HasPublicAccess = false; - for (const auto &Path : Paths) { - if (Path.Access == AS_public) - HasPublicAccess = true; - } - if (!HasPublicAccess && !IsItself) - return false; - // End checking conversion from D to B. - } - - // Both pointers or references should have the same cv-qualification. - if (DerivedReturnTy.getLocalCVRQualifiers() != - BaseReturnTy.getLocalCVRQualifiers()) - return false; - - // The class type D should have the same cv-qualification as or less - // cv-qualification than the class type B. - if (DTy.isMoreQualifiedThan(BTy)) - return false; - - return true; -} - -/// \returns decayed type for arrays and functions. -static QualType getDecayedType(QualType Type) { - if (const auto *Decayed = Type->getAs<DecayedType>()) - return Decayed->getDecayedType(); - return Type; -} - -/// \returns true if the param types are the same. -static bool checkParamTypes(const CXXMethodDecl *BaseMD, - const CXXMethodDecl *DerivedMD) { - unsigned NumParamA = BaseMD->getNumParams(); - unsigned NumParamB = DerivedMD->getNumParams(); - if (NumParamA != NumParamB) - return false; - - for (unsigned I = 0; I < NumParamA; I++) { - if (getDecayedType(BaseMD->getParamDecl(I)->getType().getCanonicalType()) != - getDecayedType( - DerivedMD->getParamDecl(I)->getType().getCanonicalType())) - return false; - } - return true; -} - -/// \returns true if derived method can override base method except for the -/// name. -static bool checkOverrideWithoutName(const ASTContext *Context, - const CXXMethodDecl *BaseMD, - const CXXMethodDecl *DerivedMD) { - if (BaseMD->isStatic() != DerivedMD->isStatic()) - return false; - - if (BaseMD->getType() == DerivedMD->getType()) - return true; - - // Now the function types are not identical. Then check if the return types - // are covariant and if the param types are the same. - if (!checkOverridingFunctionReturnType(Context, BaseMD, DerivedMD)) - return false; - return checkParamTypes(BaseMD, DerivedMD); -} - -/// Check whether BaseMD overrides DerivedMD. -/// -/// Prerequisite: the class which BaseMD is in should be a base class of that -/// DerivedMD is in. -static bool checkOverrideByDerivedMethod(const CXXMethodDecl *BaseMD, - const CXXMethodDecl *DerivedMD) { - for (CXXMethodDecl::method_iterator I = DerivedMD->begin_overridden_methods(), - E = DerivedMD->end_overridden_methods(); - I != E; ++I) { - const CXXMethodDecl *OverriddenMD = *I; - if (BaseMD->getCanonicalDecl() == OverriddenMD->getCanonicalDecl()) - return true; - } - - return false; -} - -bool VirtualNearMissCheck::isPossibleToBeOverridden( - const CXXMethodDecl *BaseMD) { - auto Iter = PossibleMap.find(BaseMD); - if (Iter != PossibleMap.end()) - return Iter->second; - - bool IsPossible = !BaseMD->isImplicit() && !isa<CXXConstructorDecl>(BaseMD) && - !isa<CXXDestructorDecl>(BaseMD) && BaseMD->isVirtual() && - !BaseMD->isOverloadedOperator() && - !isa<CXXConversionDecl>(BaseMD); - PossibleMap[BaseMD] = IsPossible; - return IsPossible; -} - -bool VirtualNearMissCheck::isOverriddenByDerivedClass( - const CXXMethodDecl *BaseMD, const CXXRecordDecl *DerivedRD) { - auto Key = std::make_pair(BaseMD, DerivedRD); - auto Iter = OverriddenMap.find(Key); - if (Iter != OverriddenMap.end()) - return Iter->second; - - bool IsOverridden = false; - for (const CXXMethodDecl *DerivedMD : DerivedRD->methods()) { - if (!isOverrideMethod(DerivedMD)) - continue; - - if (checkOverrideByDerivedMethod(BaseMD, DerivedMD)) { - IsOverridden = true; - break; - } - } - OverriddenMap[Key] = IsOverridden; - return IsOverridden; -} - -void VirtualNearMissCheck::registerMatchers(MatchFinder *Finder) { - if (!getLangOpts().CPlusPlus) - return; - - Finder->addMatcher( - cxxMethodDecl( - unless(anyOf(isOverride(), isImplicit(), cxxConstructorDecl(), - cxxDestructorDecl(), cxxConversionDecl(), isStatic(), - isOverloadedOperator()))) - .bind("method"), - this); -} - -void VirtualNearMissCheck::check(const MatchFinder::MatchResult &Result) { - const auto *DerivedMD = Result.Nodes.getNodeAs<CXXMethodDecl>("method"); - assert(DerivedMD); - - const ASTContext *Context = Result.Context; - - const auto *DerivedRD = DerivedMD->getParent()->getDefinition(); - assert(DerivedRD); - - for (const auto &BaseSpec : DerivedRD->bases()) { - if (const auto *BaseRD = BaseSpec.getType()->getAsCXXRecordDecl()) { - for (const auto *BaseMD : BaseRD->methods()) { - if (!isPossibleToBeOverridden(BaseMD)) - continue; - - if (isOverriddenByDerivedClass(BaseMD, DerivedRD)) - continue; - - unsigned EditDistance = BaseMD->getName().edit_distance( - DerivedMD->getName(), EditDistanceThreshold); - if (EditDistance > 0 && EditDistance <= EditDistanceThreshold) { - if (checkOverrideWithoutName(Context, BaseMD, DerivedMD)) { - // A "virtual near miss" is found. - auto Range = CharSourceRange::getTokenRange( - SourceRange(DerivedMD->getLocation())); - - bool ApplyFix = !BaseMD->isTemplateInstantiation() && - !DerivedMD->isTemplateInstantiation(); - auto Diag = - diag(DerivedMD->getLocStart(), - "method '%0' has a similar name and the same signature as " - "virtual method '%1'; did you mean to override it?") - << DerivedMD->getQualifiedNameAsString() - << BaseMD->getQualifiedNameAsString(); - if (ApplyFix) - Diag << FixItHint::CreateReplacement(Range, BaseMD->getName()); - } - } - } - } - } -} - -} // namespace misc -} // namespace tidy -} // namespace clang diff --git a/clang-tools-extra/clang-tidy/misc/VirtualNearMissCheck.h b/clang-tools-extra/clang-tidy/misc/VirtualNearMissCheck.h deleted file mode 100644 index 3d3b9eba762..00000000000 --- a/clang-tools-extra/clang-tidy/misc/VirtualNearMissCheck.h +++ /dev/null @@ -1,65 +0,0 @@ -//===--- VirtualNearMissCheck.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_VIRTUAL_NEAR_MISS_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_VIRTUAL_NEAR_MISS_H - -#include "../ClangTidy.h" -#include "llvm/ADT/DenseMap.h" - -namespace clang { -namespace tidy { -namespace misc { - -/// \brief Checks for near miss of virtual methods. -/// -/// For a method in a derived class, this check looks for virtual method with a -/// very similar name and an identical signature defined in a base class. -/// -/// For the user-facing documentation see: -/// http://clang.llvm.org/extra/clang-tidy/checks/misc-virtual-near-miss.html -class VirtualNearMissCheck : public ClangTidyCheck { -public: - VirtualNearMissCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} - void registerMatchers(ast_matchers::MatchFinder *Finder) override; - void check(const ast_matchers::MatchFinder::MatchResult &Result) override; - -private: - /// Check if the given method is possible to be overridden by some other - /// method. Operators and destructors are excluded. - /// - /// Results are memoized in PossibleMap. - bool isPossibleToBeOverridden(const CXXMethodDecl *BaseMD); - - /// Check if the given base method is overridden by some methods in the given - /// derived class. - /// - /// Results are memoized in OverriddenMap. - bool isOverriddenByDerivedClass(const CXXMethodDecl *BaseMD, - const CXXRecordDecl *DerivedRD); - - /// Key: the unique ID of a method. - /// Value: whether the method is possible to be overridden. - llvm::DenseMap<const CXXMethodDecl *, bool> PossibleMap; - - /// Key: <unique ID of base method, name of derived class> - /// Value: whether the base method is overridden by some method in the derived - /// class. - llvm::DenseMap<std::pair<const CXXMethodDecl *, const CXXRecordDecl *>, bool> - OverriddenMap; - - const unsigned EditDistanceThreshold = 1; -}; - -} // namespace misc -} // namespace tidy -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_VIRTUAL_NEAR_MISS_H |