在LLVM中,有原生的AST Clone,卻沒有一個比較好的Stmt copy功能,基於Scout在LLVM上進行的修改,我們實現了自己的Stmt Clone功能。
要進行Stmt Clone,肯定需要新建新的AST節點,首先用一個立即介紹如何進行AST節點的構建,以新建一個全局的variable為例。
首先分析下需求,新建variable,自然的有幾個問題:
1.變量如何新建
2.新建的變量應該處於程序的哪個部分
以如下的代碼為例子:
int main() { return 0; }
我們有兩個地方可以插入新建的variable,一個是將其作為全局變量進行插入,一個是作為main函數的局部變量進行插入,這里選擇作為全局變量進行插入。那么插入后,示例代碼會變成:
int main() { return 0; }
int a;
(想要有個比較系統的了解的,建議看下tools/clang/lib/StaticAnalyzer,StaticAnalyzer是一個良好的例子)
std::string keyName = "a"; int value = 0; IdentifierTable& idTable = Context->Idents; IdentifierInfo& idInfo =idTable.get(keyName); const SourceLocation nopos; VarDecl *tmpVar = VarDecl::Create(*Context, Context->getTranslationUnitDecl(), nopos, nopos, &idInfo, Context->IntTy, Context->CreateTypeSourceInfo(Context->IntTy), SC_None); Context->getTranslationUnitDecl()->addDeclInternal (tmpVar); IntegerLiteral *init = IntegerLiteral::Create(*Context,llvm::APInt(Context->getIntWidth(Context->IntTy),value,true), Context->IntTy,nopos); if (init != 0) { tmpVar->setInit(init); }
如果想新建一個int *a;這種的,稍微比較麻煩,因為需要自己新建類型。在context中只提供了基礎類型的:
// Builtin Types. CanQualType VoidTy; CanQualType BoolTy; CanQualType CharTy; CanQualType WCharTy; // [C++ 3.9.1p5]. CanQualType WideCharTy; // Same as WCharTy in C++, integer type in C99. CanQualType WIntTy; // [C99 7.24.1], integer type unchanged by default promotions. CanQualType Char16Ty; // [C++0x 3.9.1p5], integer type in C99. CanQualType Char32Ty; // [C++0x 3.9.1p5], integer type in C99. CanQualType SignedCharTy, ShortTy, IntTy, LongTy, LongLongTy, Int128Ty; CanQualType UnsignedCharTy, UnsignedShortTy, UnsignedIntTy, UnsignedLongTy; CanQualType UnsignedLongLongTy, UnsignedInt128Ty; CanQualType FloatTy, DoubleTy, LongDoubleTy, Float128Ty; CanQualType HalfTy; // [OpenCL 6.1.1.1], ARM NEON CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy; CanQualType Float128ComplexTy; CanQualType VoidPtrTy, NullPtrTy; CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy; CanQualType BuiltinFnTy; CanQualType PseudoObjectTy, ARCUnbridgedCastTy; CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy; CanQualType ObjCBuiltinBoolTy; #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ CanQualType SingletonId; #include "clang/Basic/OpenCLImageTypes.def" CanQualType OCLSamplerTy, OCLEventTy, OCLClkEventTy; CanQualType OCLQueueTy, OCLNDRangeTy, OCLReserveIDTy; CanQualType OMPArraySectionTy; // Types for deductions in C++0x [stmt.ranged]'s desugaring. Built on demand. mutable QualType AutoDeductTy; // Deduction against 'auto'. mutable QualType AutoRRefDeductTy; // Deduction against 'auto &&'. // Decl used to help define __builtin_va_list for some targets. // The decl is built when constructing 'BuiltinVaListDecl'. mutable Decl *VaListTagDecl;
新建int *a;第一步自然是在源碼中手動插入這樣的代碼,使用clang -fsyntax-only -Xclang -ast-dump test.cpp來查看這個新建的AST節點是如何表達的,再尋找對應的新建方式。
VarDecl 0xccec418 <test.cpp:2:1, col:6> col:6 a 'int *'
經過查找,我們發現,假如我們在遍歷AST樹根節點的子節點的時候,添加如下的處理代碼:
else if(isa<VarDecl>(*D)) { VarDecl *var = dyn_cast<VarDecl>(*D); var->dump(); QualType varTp = var->getType(); while (true) { varTp.dump(); const PointerType *pointTp = varTp->getAs<PointerType>(); if(pointTp==NULL) { const Type* ET = varTp->getArrayElementTypeNoTypeQual(); ET->dump(); break; } varTp = pointTp ->getPointeeType(); } std::cout <<"********"<<std::endl; }
輸出的代碼如下:
VarDecl 0xde9dcf0 <test.cpp:2:1, col:6> col:6 a 'int *' PointerType 0xd732d00 'int *' `-BuiltinType 0xd6a8140 'int' BuiltinType 0xd6a8140 'int' <<<NULL>>> ********
這里就比較明顯了,這個VarDecl的QUALType是 PointerType,而PointerType對應的Pointee是int。
這樣模仿上邊的代碼,如果新建一個int **aaaa;的節點,可以使用:
std::string keyName = "aaaa"; IdentifierTable& idTable = Context->Idents; IdentifierInfo& idInfo =idTable.get(keyName); const SourceLocation nopos; QualType PointerTy_1 = Context->getPointerType(Context->getIntTypeForBitwidth(32, 1)); QualType PointerTy_2 = Context->getPointerType(PointerTy_1); VarDecl *tmpVar = VarDecl::Create(*Context, Context->getTranslationUnitDecl(), nopos, nopos, &idInfo, PointerTy_2, Context->CreateTypeSourceInfo(PointerTy_2), SC_None); Context->getTranslationUnitDecl()->addDecl (tmpVar);
本來想寫Stmt Clone的,太多了,不好講,先鴿。