tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }