Source code

Revision control

Other Tools

1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
* License, v. 2.0. If a copy of the MPL was not distributed with this
3
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
#include "CustomTypeAnnotation.h"
6
#include "Utils.h"
7
8
CustomTypeAnnotation StackClass =
9
CustomTypeAnnotation(moz_stack_class, "stack");
10
CustomTypeAnnotation GlobalClass =
11
CustomTypeAnnotation(moz_global_class, "global");
12
CustomTypeAnnotation NonHeapClass =
13
CustomTypeAnnotation(moz_nonheap_class, "non-heap");
14
CustomTypeAnnotation HeapClass = CustomTypeAnnotation(moz_heap_class, "heap");
15
CustomTypeAnnotation NonTemporaryClass =
16
CustomTypeAnnotation(moz_non_temporary_class, "non-temporary");
17
CustomTypeAnnotation TemporaryClass =
18
CustomTypeAnnotation(moz_temporary_class, "temporary");
19
CustomTypeAnnotation StaticLocalClass =
20
CustomTypeAnnotation(moz_static_local_class, "static-local");
21
22
void CustomTypeAnnotation::dumpAnnotationReason(BaseCheck &Check, QualType T,
23
SourceLocation Loc) {
24
const char *Inherits =
25
"%1 is a %0 type because it inherits from a %0 type %2";
26
const char *Member = "%1 is a %0 type because member %2 is a %0 type %3";
27
const char *Array = "%1 is a %0 type because it is an array of %0 type %2";
28
const char *Templ =
29
"%1 is a %0 type because it has a template argument %0 type %2";
30
const char *Implicit = "%1 is a %0 type because %2";
31
32
AnnotationReason Reason = directAnnotationReason(T);
33
for (;;) {
34
switch (Reason.Kind) {
35
case RK_ArrayElement:
36
Check.diag(Loc, Array, DiagnosticIDs::Note) << Pretty << T << Reason.Type;
37
break;
38
case RK_BaseClass: {
39
const CXXRecordDecl *Declaration = T->getAsCXXRecordDecl();
40
assert(Declaration && "This type should be a C++ class");
41
42
Check.diag(Declaration->getLocation(), Inherits, DiagnosticIDs::Note)
43
<< Pretty << T << Reason.Type;
44
break;
45
}
46
case RK_Field:
47
Check.diag(Reason.Field->getLocation(), Member, DiagnosticIDs::Note)
48
<< Pretty << T << Reason.Field << Reason.Type;
49
break;
50
case RK_TemplateInherited: {
51
const CXXRecordDecl *Declaration = T->getAsCXXRecordDecl();
52
assert(Declaration && "This type should be a C++ class");
53
54
Check.diag(Declaration->getLocation(), Templ, DiagnosticIDs::Note)
55
<< Pretty << T << Reason.Type;
56
break;
57
}
58
case RK_Implicit: {
59
const TagDecl *Declaration = T->getAsTagDecl();
60
assert(Declaration && "This type should be a TagDecl");
61
62
Check.diag(Declaration->getLocation(), Implicit, DiagnosticIDs::Note)
63
<< Pretty << T << Reason.ImplicitReason;
64
return;
65
}
66
default:
67
// FIXME (bug 1203263): note the original annotation.
68
return;
69
}
70
71
T = Reason.Type;
72
Reason = directAnnotationReason(T);
73
}
74
}
75
76
CustomTypeAnnotation::AnnotationReason
77
CustomTypeAnnotation::directAnnotationReason(QualType T) {
78
if (const TagDecl *D = T->getAsTagDecl()) {
79
if (hasCustomAttribute(D, Attribute)) {
80
AnnotationReason Reason = {T, RK_Direct, nullptr, ""};
81
return Reason;
82
}
83
84
std::string ImplAnnotReason = getImplicitReason(D);
85
if (!ImplAnnotReason.empty()) {
86
AnnotationReason Reason = {T, RK_Implicit, nullptr, ImplAnnotReason};
87
return Reason;
88
}
89
}
90
91
// Check if we have a cached answer
92
void *Key = T.getAsOpaquePtr();
93
ReasonCache::iterator Cached = Cache.find(T.getAsOpaquePtr());
94
if (Cached != Cache.end()) {
95
return Cached->second;
96
}
97
98
// Check if we have a type which we can recurse into
99
if (const clang::ArrayType *Array = T->getAsArrayTypeUnsafe()) {
100
if (hasEffectiveAnnotation(Array->getElementType())) {
101
AnnotationReason Reason = {Array->getElementType(), RK_ArrayElement,
102
nullptr, ""};
103
Cache[Key] = Reason;
104
return Reason;
105
}
106
}
107
108
// Recurse into Base classes
109
if (const CXXRecordDecl *Declaration = T->getAsCXXRecordDecl()) {
110
if (Declaration->hasDefinition()) {
111
Declaration = Declaration->getDefinition();
112
113
for (const CXXBaseSpecifier &Base : Declaration->bases()) {
114
if (hasEffectiveAnnotation(Base.getType())) {
115
AnnotationReason Reason = {Base.getType(), RK_BaseClass, nullptr, ""};
116
Cache[Key] = Reason;
117
return Reason;
118
}
119
}
120
121
// Recurse into members
122
for (const FieldDecl *Field : Declaration->fields()) {
123
if (hasEffectiveAnnotation(Field->getType())) {
124
AnnotationReason Reason = {Field->getType(), RK_Field, Field, ""};
125
Cache[Key] = Reason;
126
return Reason;
127
}
128
}
129
130
// Recurse into template arguments if the annotation
131
// MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS is present
132
if (hasCustomAttribute<moz_inherit_type_annotations_from_template_args>(
133
Declaration)) {
134
const ClassTemplateSpecializationDecl *Spec =
135
dyn_cast<ClassTemplateSpecializationDecl>(Declaration);
136
if (Spec) {
137
const TemplateArgumentList &Args = Spec->getTemplateArgs();
138
139
AnnotationReason Reason = tmplArgAnnotationReason(Args.asArray());
140
if (Reason.Kind != RK_None) {
141
Cache[Key] = Reason;
142
return Reason;
143
}
144
}
145
}
146
}
147
}
148
149
AnnotationReason Reason = {QualType(), RK_None, nullptr, ""};
150
Cache[Key] = Reason;
151
return Reason;
152
}
153
154
CustomTypeAnnotation::AnnotationReason
155
CustomTypeAnnotation::tmplArgAnnotationReason(ArrayRef<TemplateArgument> Args) {
156
for (const TemplateArgument &Arg : Args) {
157
if (Arg.getKind() == TemplateArgument::Type) {
158
QualType Type = Arg.getAsType();
159
if (hasEffectiveAnnotation(Type)) {
160
AnnotationReason Reason = {Type, RK_TemplateInherited, nullptr, ""};
161
return Reason;
162
}
163
} else if (Arg.getKind() == TemplateArgument::Pack) {
164
AnnotationReason Reason = tmplArgAnnotationReason(Arg.getPackAsArray());
165
if (Reason.Kind != RK_None) {
166
return Reason;
167
}
168
}
169
}
170
171
AnnotationReason Reason = {QualType(), RK_None, nullptr, ""};
172
return Reason;
173
}