diff options
Diffstat (limited to 'clang-tools-extra/clang-tidy/misc/NonCopyableObjectsCheck.cpp')
| -rw-r--r-- | clang-tools-extra/clang-tidy/misc/NonCopyableObjectsCheck.cpp | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/misc/NonCopyableObjectsCheck.cpp b/clang-tools-extra/clang-tidy/misc/NonCopyableObjectsCheck.cpp new file mode 100644 index 0000000..bfeb5fa --- /dev/null +++ b/clang-tools-extra/clang-tidy/misc/NonCopyableObjectsCheck.cpp @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "NonCopyableObjectsCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::misc { + +void NonCopyableObjectsCheck::registerMatchers(MatchFinder *Finder) { + // There are two ways to get into trouble with objects like FILE *: + // dereferencing the pointer type to be a non-pointer type, and declaring + // the type as a non-pointer type in the first place. While the declaration + // itself could technically be well-formed in the case where the type is not + // an opaque type, it's highly suspicious behavior. + // + // POSIX types are a bit different in that it's reasonable to declare a + // non-pointer variable or data member of the type, but it is not reasonable + // to dereference a pointer to the type, or declare a parameter of non-pointer + // type. + // FIXME: it would be good to make a list that is also user-configurable so + // that users can add their own elements to the list. However, it may require + // some extra thought since POSIX types and FILE types are usable in different + // ways. + + auto BadFILEType = hasType( + namedDecl(hasAnyName("::FILE", "FILE", "std::FILE")).bind("type_decl")); + auto BadPOSIXType = + hasType(namedDecl(hasAnyName("::pthread_cond_t", "::pthread_mutex_t", + "pthread_cond_t", "pthread_mutex_t")) + .bind("type_decl")); + auto BadEitherType = anyOf(BadFILEType, BadPOSIXType); + + Finder->addMatcher( + namedDecl(anyOf(varDecl(BadFILEType), fieldDecl(BadFILEType))) + .bind("decl"), + this); + Finder->addMatcher(parmVarDecl(BadPOSIXType).bind("decl"), this); + Finder->addMatcher( + expr(unaryOperator(hasOperatorName("*"), BadEitherType)).bind("expr"), + this); +} + +void NonCopyableObjectsCheck::check(const MatchFinder::MatchResult &Result) { + const auto *D = Result.Nodes.getNodeAs<NamedDecl>("decl"); + const auto *BD = Result.Nodes.getNodeAs<NamedDecl>("type_decl"); + const auto *E = Result.Nodes.getNodeAs<Expr>("expr"); + + if (D && BD) + diag(D->getLocation(), "%0 declared as type '%1', which is unsafe to copy" + "; did you mean '%1 *'?") + << D << BD->getName(); + else if (E) + diag(E->getExprLoc(), + "expression has opaque data structure type %0; type should only be " + "used as a pointer and not dereferenced") + << BD; +} + +} // namespace clang::tidy::misc |
