CustomTypeAnnotation.cpp (6352B)
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 VisitFlags ToVisit = VISIT_FIELDS | VISIT_BASES; 79 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; 86 } 87 88 if (hasCustomAttribute(D, Attribute)) { 89 AnnotationReason Reason = {T, RK_Direct, nullptr, ""}; 90 return Reason; 91 } 92 93 std::string ImplAnnotReason = getImplicitReason(D, ToVisit); 94 if (!ImplAnnotReason.empty()) { 95 AnnotationReason Reason = {T, RK_Implicit, nullptr, ImplAnnotReason}; 96 return Reason; 97 } 98 } 99 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; 105 } 106 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; 114 } 115 } 116 117 // Recurse into Base classes 118 if (const CXXRecordDecl *Declaration = T->getAsCXXRecordDecl()) { 119 if (Declaration->hasDefinition()) { 120 Declaration = Declaration->getDefinition(); 121 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; 128 } 129 } 130 } 131 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; 138 } 139 } 140 } 141 142 if (ToVisit & VISIT_TMPL_ARGS) { 143 const ClassTemplateSpecializationDecl *Spec = 144 dyn_cast<ClassTemplateSpecializationDecl>(Declaration); 145 if (Spec) { 146 const TemplateArgumentList &Args = Spec->getTemplateArgs(); 147 148 AnnotationReason Reason = tmplArgAnnotationReason(Args.asArray()); 149 if (Reason.Kind != RK_None) { 150 Cache[Key] = Reason; 151 return Reason; 152 } 153 } 154 } 155 } 156 } 157 158 AnnotationReason Reason{QualType(), RK_None, nullptr, ""}; 159 Cache[Key] = Reason; 160 return Reason; 161 } 162 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; 171 } 172 } else if (Arg.getKind() == TemplateArgument::Pack) { 173 AnnotationReason Reason = tmplArgAnnotationReason(Arg.getPackAsArray()); 174 if (Reason.Kind != RK_None) { 175 return Reason; 176 } 177 } 178 } 179 180 AnnotationReason Reason = {QualType(), RK_None, nullptr, ""}; 181 return Reason; 182 }