Backed out 2 changesets (bug 1908320) for causing wr failures on align-items-baseline...
[gecko.git] / build / clang-plugin / CustomTypeAnnotation.cpp
blob6e0f44ce05fca6b34a4720bc272ed079ecaa4813
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"
6 #include "Utils.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,
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";
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");
42 Check.diag(Declaration->getLocation(), Inherits, DiagnosticIDs::Note)
43 << Pretty << T << Reason.Type;
44 break;
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");
54 Check.diag(Declaration->getLocation(), Templ, DiagnosticIDs::Note)
55 << Pretty << T << Reason.Type;
56 break;
58 case RK_Implicit: {
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;
64 return;
66 default:
67 // FIXME (bug 1203263): note the original annotation.
68 return;
71 T = Reason.Type;
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>(
84 D)) {
85 ToVisit |= VISIT_TMPL_ARGS;
88 if (hasCustomAttribute(D, Attribute)) {
89 AnnotationReason Reason = {T, RK_Direct, nullptr, ""};
90 return Reason;
93 std::string ImplAnnotReason = getImplicitReason(D, ToVisit);
94 if (!ImplAnnotReason.empty()) {
95 AnnotationReason Reason = {T, RK_Implicit, nullptr, ImplAnnotReason};
96 return Reason;
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,
111 ""};
112 Cache[Key] = Reason;
113 return Reason;
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, ""};
126 Cache[Key] = Reason;
127 return Reason;
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, ""};
136 Cache[Key] = Reason;
137 return Reason;
142 if (ToVisit & VISIT_TMPL_ARGS) {
143 const ClassTemplateSpecializationDecl *Spec =
144 dyn_cast<ClassTemplateSpecializationDecl>(Declaration);
145 if (Spec) {
146 const TemplateArgumentList &Args = Spec->getTemplateArgs();
148 AnnotationReason Reason = tmplArgAnnotationReason(Args.asArray());
149 if (Reason.Kind != RK_None) {
150 Cache[Key] = Reason;
151 return Reason;
158 AnnotationReason Reason{QualType(), RK_None, nullptr, ""};
159 Cache[Key] = Reason;
160 return Reason;
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, ""};
170 return Reason;
172 } else if (Arg.getKind() == TemplateArgument::Pack) {
173 AnnotationReason Reason = tmplArgAnnotationReason(Arg.getPackAsArray());
174 if (Reason.Kind != RK_None) {
175 return Reason;
180 AnnotationReason Reason = {QualType(), RK_None, nullptr, ""};
181 return Reason;