clang-tools  3.9.0
NonCopyableObjects.cpp
Go to the documentation of this file.
1 //===--- NonCopyableObjects.cpp - clang-tidy-------------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "NonCopyableObjects.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include <algorithm>
14 
15 using namespace clang::ast_matchers;
16 
17 namespace clang {
18 namespace tidy {
19 namespace misc {
20 
21 namespace {
22 // FIXME: it would be good to make a list that is also user-configurable so that
23 // users can add their own elements to the list. However, it may require some
24 // extra thought since POSIX types and FILE types are usable in different ways.
25 bool isPOSIXTypeName(StringRef ClassName) {
26  static const char *const TypeNames[] = {
27  "::pthread_cond_t",
28  "::pthread_mutex_t",
29  "pthread_cond_t",
30  "pthread_mutex_t"
31  };
32  return std::binary_search(std::begin(TypeNames), std::end(TypeNames),
33  ClassName);
34 }
35 
36 bool isFILETypeName(StringRef ClassName) {
37  static const char *const TypeNames[] = {
38  "::FILE",
39  "FILE",
40  "std::FILE"
41  };
42  return std::binary_search(std::begin(TypeNames), std::end(TypeNames),
43  ClassName);
44 }
45 
46 AST_MATCHER(NamedDecl, isFILEType) {
47  return isFILETypeName(Node.getQualifiedNameAsString());
48 }
49 
50 AST_MATCHER(NamedDecl, isPOSIXType) {
51  return isPOSIXTypeName(Node.getQualifiedNameAsString());
52 }
53 } // namespace
54 
55 void NonCopyableObjectsCheck::registerMatchers(MatchFinder *Finder) {
56  // There are two ways to get into trouble with objects like FILE *:
57  // dereferencing the pointer type to be a non-pointer type, and declaring
58  // the type as a non-pointer type in the first place. While the declaration
59  // itself could technically be well-formed in the case where the type is not
60  // an opaque type, it's highly suspicious behavior.
61  //
62  // POSIX types are a bit different in that it's reasonable to declare a
63  // non-pointer variable or data member of the type, but it is not reasonable
64  // to dereference a pointer to the type, or declare a parameter of non-pointer
65  // type.
66  auto BadFILEType = hasType(namedDecl(isFILEType()).bind("type_decl"));
67  auto BadPOSIXType = hasType(namedDecl(isPOSIXType()).bind("type_decl"));
68  auto BadEitherType = anyOf(BadFILEType, BadPOSIXType);
69 
70  Finder->addMatcher(
71  namedDecl(anyOf(varDecl(BadFILEType), fieldDecl(BadFILEType)))
72  .bind("decl"),
73  this);
74  Finder->addMatcher(parmVarDecl(BadPOSIXType).bind("decl"), this);
75  Finder->addMatcher(
76  expr(unaryOperator(hasOperatorName("*"), BadEitherType)).bind("expr"),
77  this);
78 }
79 
80 void NonCopyableObjectsCheck::check(const MatchFinder::MatchResult &Result) {
81  const auto *D = Result.Nodes.getNodeAs<NamedDecl>("decl");
82  const auto *BD = Result.Nodes.getNodeAs<NamedDecl>("type_decl");
83  const auto *E = Result.Nodes.getNodeAs<Expr>("expr");
84 
85  if (D && BD)
86  diag(D->getLocation(), "%0 declared as type '%1', which is unsafe to copy"
87  "; did you mean '%1 *'?")
88  << D << BD->getName();
89  else if (E)
90  diag(E->getExprLoc(),
91  "expression has opaque data structure type %0; type should only be "
92  "used as a pointer and not dereferenced")
93  << BD;
94 }
95 
96 } // namespace misc
97 } // namespace tidy
98 } // namespace clang
99 
AST_MATCHER(Type, isStrictlyInteger)
std::unique_ptr< ast_matchers::MatchFinder > Finder
Definition: ClangTidy.cpp:210
const NamedDecl * Result
Definition: USRFinder.cpp:137