blob: 86a36544a455bf5314596f24c2d8231c0a05ddbe [file] [log] [blame]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#pragma once
#include <unordered_set>
#include <queue>
#include "clang/Frontend/FrontendPluginRegistry.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Sema/Sema.h"
#include "Helpers.h"
using namespace std;
using namespace clang;
// To record seen allocators with a Type
//
enum AllocationTypes
{
Unknown = 0x0, // e.g. template dependent
NonRecycler = 0x1, // Heap, Arena, JitArena, ...
Recycler = 0x2, // Recycler
WriteBarrier = 0x4, // Recycler write barrier
RecyclerWriteBarrier = Recycler | WriteBarrier,
};
class MainVisitor:
public RecursiveASTVisitor<MainVisitor>
{
private:
CompilerInstance& _compilerInstance;
ASTContext& _context;
Rewriter _rewriter;
bool _fix; // whether user requested to fix missing annotations
bool _fixed; // whether this plugin committed any annotation fixes
// For emitting checker errors
DiagnosticsEngine& _diagEngine;
unsigned _diagUnbarrieredField;
unsigned _diagIllegalBarrierCast;
bool _barrierTypeDefined;
map<string, set<string>> _allocatorTypeMap;
set<string> _pointerClasses;
set<string> _barrieredClasses;
map<const Type*, int> _allocationTypes; // {type -> AllocationTypes}
public:
MainVisitor(CompilerInstance& compilerInstance, ASTContext& context, bool fix);
const ASTContext& getContext() const { return _context; }
const CompilerInstance& getCompilerInstance() const { return _compilerInstance; }
bool VisitCXXRecordDecl(CXXRecordDecl* recordDecl);
bool VisitFunctionDecl(FunctionDecl* functionDecl);
void RecordAllocation(QualType qtype, AllocationTypes allocationType);
void RecordRecyclerAllocation(
const string& allocationFunction, const string& type);
void Inspect();
bool ApplyFix();
void ReportUnbarriedField(SourceLocation location);
void ReportIllegalBarrierCast(SourceLocation location);
private:
template <class Set, class DumpItemFunc>
void dump(const char* name, const Set& set, const DumpItemFunc& func);
template <class Item>
void dump(const char* name, const set<Item>& set);
void dump(const char* name, const unordered_set<const Type*> set);
template <class PushFieldType>
void ProcessUnbarrieredFields(CXXRecordDecl* recordDecl, const PushFieldType& pushFieldType);
bool MatchType(const string& type, const char* source, const char** pSourceEnd);
const char* GetFieldTypeAnnotation(QualType qtype);
void DiagReport(SourceLocation location, unsigned diagId);
};
class CheckAllocationsInFunctionVisitor:
public RecursiveASTVisitor<CheckAllocationsInFunctionVisitor>
{
public:
CheckAllocationsInFunctionVisitor(
MainVisitor* mainVisitor, FunctionDecl* functionDecl)
: _mainVisitor(mainVisitor), _functionDecl(functionDecl)
{}
bool VisitCXXNewExpr(CXXNewExpr* newExpression);
bool VisitCallExpr(CallExpr* callExpr);
#define IMPLEMENT_VISIT_CAST(Expr) \
bool Visit##Expr(Expr *cast) { return CommonVisitCastExpr(cast); }
IMPLEMENT_VISIT_CAST(CStyleCastExpr)
IMPLEMENT_VISIT_CAST(CXXFunctionalCastExpr)
IMPLEMENT_VISIT_CAST(CXXConstCastExpr)
IMPLEMENT_VISIT_CAST(CXXDynamicCastExpr)
IMPLEMENT_VISIT_CAST(CXXReinterpretCastExpr)
IMPLEMENT_VISIT_CAST(CXXStaticCastExpr)
#undef IMPLEMENT_VISIT_CAST
private:
MainVisitor* _mainVisitor;
FunctionDecl* _functionDecl;
template <class A0, class A1, class T>
void VisitAllocate(const A0& getArg0, const A1& getArg1, const T& getAllocType);
bool IsFieldPointer(const QualType& qtype, const char* alt = nullptr);
bool CommonVisitCastExpr(CastExpr *cast);
};
class RecyclerCheckerConsumer: public ASTConsumer
{
private:
CompilerInstance& _compilerInstance;
bool _fix; // whether user requested to fix missing annotations
public:
RecyclerCheckerConsumer(CompilerInstance& compilerInstance, bool fix)
: _compilerInstance(compilerInstance), _fix(fix)
{}
void HandleTranslationUnit(ASTContext& context);
};
class RecyclerCheckerAction: public PluginASTAction
{
private:
bool _fix; // whether user requested to fix missing annotations
public:
RecyclerCheckerAction() : _fix(false) {}
protected:
std::unique_ptr<ASTConsumer> CreateASTConsumer(
CompilerInstance& compilerInstance, llvm::StringRef) override;
bool ParseArgs(
const CompilerInstance& compilerInstance,
const std::vector<std::string>& args) override;
};