Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/Analysis/CocoaConventions.cpp
35233 views
1
//===- CocoaConventions.h - Special handling of Cocoa conventions -*- C++ -*--//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This file implements cocoa naming convention analysis.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
14
#include "clang/AST/Decl.h"
15
#include "clang/AST/DeclObjC.h"
16
#include "clang/AST/Type.h"
17
#include "clang/Basic/CharInfo.h"
18
#include "llvm/ADT/StringExtras.h"
19
#include "llvm/Support/ErrorHandling.h"
20
21
using namespace clang;
22
using namespace ento;
23
24
bool cocoa::isRefType(QualType RetTy, StringRef Prefix,
25
StringRef Name) {
26
// Recursively walk the typedef stack, allowing typedefs of reference types.
27
while (const TypedefType *TD = RetTy->getAs<TypedefType>()) {
28
StringRef TDName = TD->getDecl()->getIdentifier()->getName();
29
if (TDName.starts_with(Prefix) && TDName.ends_with("Ref"))
30
return true;
31
// XPC unfortunately uses CF-style function names, but aren't CF types.
32
if (TDName.starts_with("xpc_"))
33
return false;
34
RetTy = TD->getDecl()->getUnderlyingType();
35
}
36
37
if (Name.empty())
38
return false;
39
40
// Is the type void*?
41
const PointerType* PT = RetTy->castAs<PointerType>();
42
if (!PT || !PT->getPointeeType().getUnqualifiedType()->isVoidType())
43
return false;
44
45
// Does the name start with the prefix?
46
return Name.starts_with(Prefix);
47
}
48
49
/// Returns true when the passed-in type is a CF-style reference-counted
50
/// type from the DiskArbitration framework.
51
static bool isDiskArbitrationAPIRefType(QualType T) {
52
return cocoa::isRefType(T, "DADisk") ||
53
cocoa::isRefType(T, "DADissenter") ||
54
cocoa::isRefType(T, "DASessionRef");
55
}
56
57
bool coreFoundation::isCFObjectRef(QualType T) {
58
return cocoa::isRefType(T, "CF") || // Core Foundation.
59
cocoa::isRefType(T, "CG") || // Core Graphics.
60
cocoa::isRefType(T, "CM") || // Core Media.
61
isDiskArbitrationAPIRefType(T);
62
}
63
64
65
bool cocoa::isCocoaObjectRef(QualType Ty) {
66
if (!Ty->isObjCObjectPointerType())
67
return false;
68
69
const ObjCObjectPointerType *PT = Ty->getAs<ObjCObjectPointerType>();
70
71
// Can be true for objects with the 'NSObject' attribute.
72
if (!PT)
73
return true;
74
75
// We assume that id<..>, id, Class, and Class<..> all represent tracked
76
// objects.
77
if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() ||
78
PT->isObjCClassType() || PT->isObjCQualifiedClassType())
79
return true;
80
81
// Does the interface subclass NSObject?
82
// FIXME: We can memoize here if this gets too expensive.
83
const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
84
85
// Assume that anything declared with a forward declaration and no
86
// @interface subclasses NSObject.
87
if (!ID->hasDefinition())
88
return true;
89
90
for ( ; ID ; ID = ID->getSuperClass())
91
if (ID->getIdentifier()->getName() == "NSObject")
92
return true;
93
94
return false;
95
}
96
97
bool coreFoundation::followsCreateRule(const FunctionDecl *fn) {
98
// For now, *just* base this on the function name, not on anything else.
99
100
const IdentifierInfo *ident = fn->getIdentifier();
101
if (!ident) return false;
102
StringRef functionName = ident->getName();
103
104
StringRef::iterator it = functionName.begin();
105
StringRef::iterator start = it;
106
StringRef::iterator endI = functionName.end();
107
108
while (true) {
109
// Scan for the start of 'create' or 'copy'.
110
for ( ; it != endI ; ++it) {
111
// Search for the first character. It can either be 'C' or 'c'.
112
char ch = *it;
113
if (ch == 'C' || ch == 'c') {
114
// Make sure this isn't something like 'recreate' or 'Scopy'.
115
if (ch == 'c' && it != start && isLetter(*(it - 1)))
116
continue;
117
118
++it;
119
break;
120
}
121
}
122
123
// Did we hit the end of the string? If so, we didn't find a match.
124
if (it == endI)
125
return false;
126
127
// Scan for *lowercase* 'reate' or 'opy', followed by no lowercase
128
// character.
129
StringRef suffix = functionName.substr(it - start);
130
if (suffix.starts_with("reate")) {
131
it += 5;
132
} else if (suffix.starts_with("opy")) {
133
it += 3;
134
} else {
135
// Keep scanning.
136
continue;
137
}
138
139
if (it == endI || !isLowercase(*it))
140
return true;
141
142
// If we matched a lowercase character, it isn't the end of the
143
// word. Keep scanning.
144
}
145
}
146
147