Movatterモバイル変換


[0]ホーム

URL:


Google Git
Sign in
chromium /chromium /src /main /. /tools /clang /plugins /StackAllocatedChecker.cpp
blob: 45a3778172a31d0376906b0601058d9abdda9caf [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include"StackAllocatedChecker.h"
#include"clang/AST/Attr.h"
#include"clang/AST/DeclCXX.h"
#include"clang/AST/DeclTemplate.h"
#include"clang/Frontend/CompilerInstance.h"
namespace chrome_checker{
namespace{
constchar kStackAllocatedFieldError[]=
"Non-stack-allocated type '%0' has a field '%1' which is a stack-allocated "
"type, pointer/reference to a stack-allocated type, or template "
"instantiation with a stack-allocated type as template parameter.";
const clang::Type*StripReferences(const clang::Type* type){
while(type){
if(type->isArrayType()){
type= type->getPointeeOrArrayElementType();
}elseif(type->isPointerType()|| type->isReferenceType()){
type= type->getPointeeType().getTypePtrOrNull();
}else{
break;
}
}
return type;
}
}// namespace
boolStackAllocatedPredicate::IsStackAllocated(
const clang::CXXRecordDecl* record)const{
if(!record){
returnfalse;
}
auto iter= cache_.find(record);
if(iter!= cache_.end()){
return iter->second;
}
bool stack_allocated=false;
// Check member fields
for(clang::Decl* decl: record->decls()){
clang::TypeAliasDecl* alias= clang::dyn_cast<clang::TypeAliasDecl>(decl);
if(!alias){
continue;
}
if(alias->getName()=="IsStackAllocatedTypeMarker"){
stack_allocated=true;
break;
}
}
// Check base classes
if(record->hasDefinition()){
for(clang::CXXRecordDecl::base_class_const_iterator it=
record->bases_begin();
!stack_allocated&& it!= record->bases_end();++it){
clang::CXXRecordDecl* parent_record=
it->getType().getTypePtr()->getAsCXXRecordDecl();
stack_allocated=IsStackAllocated(parent_record);
}
}
// If we don't create a cache record now, it's possible to get into infinite
// mutual recursion between the base class check (above) and the template
// parameter check (below).
iter= cache_.insert({record, stack_allocated}).first;
// Check template parameters. This is aggressive and can cause false positives
// -- a templated class doesn't necessarily store instances of its type
// parameters, in which case it need not be stack-allocated. In practice,
// though, this kind of false positive is rare; and conservatively marking
// this type as stack-allocated will catch cases where a type parameter
// doesn't have a full type definition in the translation unit.
if(auto* field_record_template=
clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(record)){
constauto& template_args= field_record_template->getTemplateArgs();
for(unsigned i=0; i< template_args.size(); i++){
if(template_args[i].getKind()== clang::TemplateArgument::Type){
constauto* type=
StripReferences(template_args[i].getAsType().getTypePtrOrNull());
if(type&&IsStackAllocated(type->getAsCXXRecordDecl())){
stack_allocated=true;
}
}
}
}
iter->second= stack_allocated;
return stack_allocated;
}
StackAllocatedChecker::StackAllocatedChecker(clang::CompilerInstance& compiler)
: compiler_(compiler),
stack_allocated_field_error_signature_(
compiler.getDiagnostics().getCustomDiagID(
clang::DiagnosticsEngine::Error,
kStackAllocatedFieldError)){}
voidStackAllocatedChecker::Check(clang::CXXRecordDecl* record){
if(!record->isCompleteDefinition()){
return;
}
// If this type is stack allocated, no need to check fields.
if(predicate_.IsStackAllocated(record)){
return;
}
for(clang::RecordDecl::field_iterator it= record->field_begin();
it!= record->field_end();++it){
clang::FieldDecl* field=*it;
bool ignore=false;
for(auto annotation: field->specific_attrs<clang::AnnotateAttr>()){
if(annotation->getAnnotation()=="stack_allocated_ignore"){
ignore=true;
break;
}
}
if(ignore){
continue;
}
const clang::Type* type=
StripReferences(field->getType().getTypePtrOrNull());
if(!type){
continue;
}
auto* field_record= type->getAsCXXRecordDecl();
if(!field_record){
continue;
}
if(predicate_.IsStackAllocated(field_record)){
compiler_.getDiagnostics().Report(field->getLocation(),
stack_allocated_field_error_signature_)
<< record->getName()<< field->getNameAsString();
}
}
}
}// namespace chrome_checker

[8]ページ先頭

©2009-2025 Movatter.jp