2013-02-27 19:28:38 +04:00
//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author: Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
2014-01-07 14:08:37 +04:00
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
2013-02-27 19:28:38 +04:00
//------------------------------------------------------------------------------
# include "AutoSynthesizer.h"
# include "clang/AST/ASTContext.h"
# include "clang/AST/RecursiveASTVisitor.h"
# include "clang/Sema/Sema.h"
using namespace clang ;
namespace cling {
class AutoFixer : public RecursiveASTVisitor < AutoFixer > {
private :
Sema * m_Sema ;
2013-10-11 18:23:01 +04:00
DeclRefExpr * m_FoundDRE ;
llvm : : DenseSet < NamedDecl * > m_HandledDecls ;
2013-02-27 19:28:38 +04:00
private :
public :
2013-10-11 18:23:01 +04:00
AutoFixer ( Sema * S ) : m_Sema ( S ) , m_FoundDRE ( 0 ) { }
2013-02-27 19:28:38 +04:00
void Fix ( CompoundStmt * CS ) {
2013-10-11 18:23:01 +04:00
if ( ! CS - > size ( ) )
return ;
typedef llvm : : SmallVector < Stmt * , 32 > Statements ;
Statements Stmts ;
Stmts . append ( CS - > body_begin ( ) , CS - > body_end ( ) ) ;
2013-10-14 11:58:39 +04:00
for ( Statements : : iterator I = Stmts . begin ( ) ; I ! = Stmts . end ( ) ; + + I ) {
2013-10-11 18:23:01 +04:00
if ( ! TraverseStmt ( * I ) & & ! m_HandledDecls . count ( m_FoundDRE - > getDecl ( ) ) ) {
2014-08-04 06:05:42 +04:00
Sema : : DeclGroupPtrTy VDPtrTy
2013-10-11 18:23:01 +04:00
= m_Sema - > ConvertDeclToDeclGroup ( m_FoundDRE - > getDecl ( ) ) ;
2014-08-04 06:05:42 +04:00
StmtResult DS = m_Sema - > ActOnDeclStmt ( VDPtrTy ,
m_FoundDRE - > getLocStart ( ) ,
2013-10-11 18:23:01 +04:00
m_FoundDRE - > getLocEnd ( ) ) ;
2013-02-27 19:28:38 +04:00
assert ( ! DS . isInvalid ( ) & & " Invalid DeclStmt. " ) ;
2014-06-06 12:18:32 +04:00
I = Stmts . insert ( I , DS . get ( ) ) ;
2013-10-11 18:23:01 +04:00
m_HandledDecls . insert ( m_FoundDRE - > getDecl ( ) ) ;
2013-02-27 19:28:38 +04:00
}
}
2016-04-22 16:09:48 +03:00
CS - > setStmts ( m_Sema - > getASTContext ( ) , Stmts ) ;
2013-10-11 18:23:01 +04:00
}
2016-03-03 21:07:28 +03:00
void Fix ( CXXTryStmt * TS ) {
Fix ( TS - > getTryBlock ( ) ) ;
for ( unsigned int h = 0 ; h < TS - > getNumHandlers ( ) ; + + h ) {
Stmt * s = TS - > getHandler ( h ) - > getHandlerBlock ( ) ;
if ( CompoundStmt * CS = dyn_cast_or_null < CompoundStmt > ( s ) )
Fix ( CS ) ;
2016-09-12 22:53:51 +03:00
else if ( CXXTryStmt * HandlerTS = dyn_cast_or_null < CXXTryStmt > ( s ) )
Fix ( HandlerTS ) ;
2016-03-03 21:07:28 +03:00
}
}
2013-10-11 18:23:01 +04:00
bool VisitDeclRefExpr ( DeclRefExpr * DRE ) {
const Decl * D = DRE - > getDecl ( ) ;
if ( const AnnotateAttr * A = D - > getAttr < AnnotateAttr > ( ) )
if ( A - > getAnnotation ( ) . equals ( " __Auto " ) ) {
m_FoundDRE = DRE ;
return false ; // we abort on the first found candidate.
}
2013-02-27 19:28:38 +04:00
return true ; // returning false will abort the in-depth traversal.
}
} ;
} // end namespace cling
2014-08-04 06:05:42 +04:00
namespace cling {
2013-02-27 19:28:38 +04:00
AutoSynthesizer : : AutoSynthesizer ( clang : : Sema * S )
2015-03-16 16:49:28 +03:00
: ASTTransformer ( S ) {
2013-10-11 18:23:01 +04:00
// TODO: We would like to keep that local without keeping track of all
// decls that were handled in the AutoFixer. This can be done by removing
// the __Auto attribute, but for now I am still hesitant to do it. Having
// the __Auto attribute is very useful for debugging because it localize the
// the problem if exists.
m_AutoFixer . reset ( new AutoFixer ( S ) ) ;
2013-02-27 19:28:38 +04:00
}
// pin the vtable here.
2014-08-04 06:05:42 +04:00
AutoSynthesizer : : ~ AutoSynthesizer ( )
2013-02-27 19:28:38 +04:00
{ }
2015-03-16 16:49:28 +03:00
ASTTransformer : : Result AutoSynthesizer : : Transform ( Decl * D ) {
if ( FunctionDecl * FD = dyn_cast < FunctionDecl > ( D ) ) {
// getBody() might return nullptr even though hasBody() is true for
// late template parsed functions. We simply don't do auto auto on
// those.
2016-03-03 21:07:28 +03:00
Stmt * Body = FD - > getBody ( ) ;
if ( CompoundStmt * CS = dyn_cast_or_null < CompoundStmt > ( Body ) )
2015-03-16 16:49:28 +03:00
m_AutoFixer - > Fix ( CS ) ;
2016-03-03 21:07:28 +03:00
else if ( CXXTryStmt * TS = dyn_cast_or_null < CXXTryStmt > ( Body ) )
m_AutoFixer - > Fix ( TS ) ;
2013-03-11 17:11:15 +04:00
}
2015-03-16 16:49:28 +03:00
return Result ( D , true ) ;
2013-02-27 19:28:38 +04:00
}
} // end namespace cling