|  | //===--- NonCopyableObjects.cpp - clang-tidy-------------------------------===// | 
|  | // | 
|  | // 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 "NonCopyableObjects.h" | 
|  | #include "clang/AST/ASTContext.h" | 
|  | #include "clang/ASTMatchers/ASTMatchFinder.h" | 
|  | #include <algorithm> | 
|  |  | 
|  | 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<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 misc | 
|  | } // namespace tidy | 
|  | } // namespace clang | 
|  |  |