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/. */
5 #include "CustomTypeAnnotation.h"
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");
22 void CustomTypeAnnotation::dumpAnnotationReason(BaseCheck
&Check
, QualType T
,
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";
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";
32 AnnotationReason Reason
= directAnnotationReason(T
);
34 switch (Reason
.Kind
) {
36 Check
.diag(Loc
, Array
, DiagnosticIDs::Note
) << Pretty
<< T
<< Reason
.Type
;
39 const CXXRecordDecl
*Declaration
= T
->getAsCXXRecordDecl();
40 assert(Declaration
&& "This type should be a C++ class");
42 Check
.diag(Declaration
->getLocation(), Inherits
, DiagnosticIDs::Note
)
43 << Pretty
<< T
<< Reason
.Type
;
47 Check
.diag(Reason
.Field
->getLocation(), Member
, DiagnosticIDs::Note
)
48 << Pretty
<< T
<< Reason
.Field
<< Reason
.Type
;
50 case RK_TemplateInherited
: {
51 const CXXRecordDecl
*Declaration
= T
->getAsCXXRecordDecl();
52 assert(Declaration
&& "This type should be a C++ class");
54 Check
.diag(Declaration
->getLocation(), Templ
, DiagnosticIDs::Note
)
55 << Pretty
<< T
<< Reason
.Type
;
59 const TagDecl
*Declaration
= T
->getAsTagDecl();
60 assert(Declaration
&& "This type should be a TagDecl");
62 Check
.diag(Declaration
->getLocation(), Implicit
, DiagnosticIDs::Note
)
63 << Pretty
<< T
<< Reason
.ImplicitReason
;
67 // FIXME (bug 1203263): note the original annotation.
72 Reason
= directAnnotationReason(T
);
76 CustomTypeAnnotation::AnnotationReason
77 CustomTypeAnnotation::directAnnotationReason(QualType T
) {
78 VisitFlags ToVisit
= VISIT_FIELDS
| VISIT_BASES
;
80 if (const TagDecl
*D
= T
->getAsTagDecl()) {
81 // Recurse into template arguments if the annotation
82 // MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS is present
83 if (hasCustomAttribute
<moz_inherit_type_annotations_from_template_args
>(
85 ToVisit
|= VISIT_TMPL_ARGS
;
88 if (hasCustomAttribute(D
, Attribute
)) {
89 AnnotationReason Reason
= {T
, RK_Direct
, nullptr, ""};
93 std::string ImplAnnotReason
= getImplicitReason(D
, ToVisit
);
94 if (!ImplAnnotReason
.empty()) {
95 AnnotationReason Reason
= {T
, RK_Implicit
, nullptr, ImplAnnotReason
};
100 // Check if we have a cached answer
101 void *Key
= T
.getAsOpaquePtr();
102 ReasonCache::iterator Cached
= Cache
.find(T
.getAsOpaquePtr());
103 if (Cached
!= Cache
.end()) {
104 return Cached
->second
;
107 // Check if we have a type which we can recurse into
108 if (const clang::ArrayType
*Array
= T
->getAsArrayTypeUnsafe()) {
109 if (hasEffectiveAnnotation(Array
->getElementType())) {
110 AnnotationReason Reason
{Array
->getElementType(), RK_ArrayElement
, nullptr,
117 // Recurse into Base classes
118 if (const CXXRecordDecl
*Declaration
= T
->getAsCXXRecordDecl()) {
119 if (Declaration
->hasDefinition()) {
120 Declaration
= Declaration
->getDefinition();
122 if (ToVisit
& VISIT_BASES
) {
123 for (const CXXBaseSpecifier
&Base
: Declaration
->bases()) {
124 if (hasEffectiveAnnotation(Base
.getType())) {
125 AnnotationReason Reason
{Base
.getType(), RK_BaseClass
, nullptr, ""};
132 if (ToVisit
& VISIT_FIELDS
) {
133 for (const FieldDecl
*Field
: Declaration
->fields()) {
134 if (hasEffectiveAnnotation(Field
->getType())) {
135 AnnotationReason Reason
{Field
->getType(), RK_Field
, Field
, ""};
142 if (ToVisit
& VISIT_TMPL_ARGS
) {
143 const ClassTemplateSpecializationDecl
*Spec
=
144 dyn_cast
<ClassTemplateSpecializationDecl
>(Declaration
);
146 const TemplateArgumentList
&Args
= Spec
->getTemplateArgs();
148 AnnotationReason Reason
= tmplArgAnnotationReason(Args
.asArray());
149 if (Reason
.Kind
!= RK_None
) {
158 AnnotationReason Reason
{QualType(), RK_None
, nullptr, ""};
163 CustomTypeAnnotation::AnnotationReason
164 CustomTypeAnnotation::tmplArgAnnotationReason(ArrayRef
<TemplateArgument
> Args
) {
165 for (const TemplateArgument
&Arg
: Args
) {
166 if (Arg
.getKind() == TemplateArgument::Type
) {
167 QualType Type
= Arg
.getAsType();
168 if (hasEffectiveAnnotation(Type
)) {
169 AnnotationReason Reason
= {Type
, RK_TemplateInherited
, nullptr, ""};
172 } else if (Arg
.getKind() == TemplateArgument::Pack
) {
173 AnnotationReason Reason
= tmplArgAnnotationReason(Arg
.getPackAsArray());
174 if (Reason
.Kind
!= RK_None
) {
180 AnnotationReason Reason
= {QualType(), RK_None
, nullptr, ""};