//===--- NonCopyableObjects.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 "NonCopyableObjects.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include using namespace clang::ast_matchers; namespace clang { namespace tidy { namespace 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("decl"); const auto *BD = Result.Nodes.getNodeAs("type_decl"); const auto *E = Result.Nodes.getNodeAs("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 misc } // namespace tidy } // namespace clang