ROSE 0.11.145.281
Public Types | Public Member Functions | Protected Member Functions | Static Protected Member Functions | List of all members
Rose::Snippet Class Reference

Description

Simple mechanism for inserting statements into a specimen.

This class implements a simple API for inserting crafted statements into locations in a (typically) larger specimen. It isn't intended to handle all possible cases, but rather to be an alternative to the more complicated SageBuilder interface. See "Limitations" below.

What is a snippet?

A snippet is a function in a snippet source file (SnippetFile) along with prerequisites in its global scope. The statements of the snippet are injected into a specimen function at a chosen insertion point akin to inlining, and the snippet's global prerequisites are injected ino the specimen's global scope. For C source code, each function definition in the snippet file is a snippet.

A Snippet object is usually created with the instanceFromFile() class method, which takes a snippet name and a file name and returns a reference-counted pointer to the snippet. This method efficiently handles the case when multiple related snippets are defined in a single file (a practice that allows related snippets to share their global prerequisites).

SnippetPtr foo = Snippet::instanceFromFile("foo", "snippetfile.c");
SnippetPtr bar = Snippet::instanceFromFile("bar", "snippetfile.c");
SnippetPtr banana = Snippet::instanceFromFile("banana", "fruit.c");
static SnippetPtr instanceFromFile(const std::string &snippetName, const std::string &fileName)
Construct a new Snippet.
boost::shared_ptr< class Snippet > SnippetPtr
Shared-ownership pointer to a Snippet object.
Definition Snippet.h:19

The injection process

A snippet is injected along with its global prerequisites via its insert() method. The first argument is a SgStatement cursor to indicate where the insertion is to take place (the snippet is inserted before the cursor). The remaining arguments are either variable declarations (SgInitializedName) or expressions (SgExpression) that are bound to the formal arguments of the snippet and thereby expanded into the specimen during the injection. They should be variables or expressions that are valid at the point where the snippet is injected.

SgStatement *cursor = ...; // statement before which snippet is inserted
SgInitializedName *var_a = ..., *var_b = ...; // insertion point variables to be bound to snippet
SgExpression *expr_1 = ...; // insertion point expression to be bound to snippet
foo->insert(cursor); // insert snippet foo() with no arguments
bar->insert(cursor, var_a); // 1st arg of snippet bar() is bound to var_a
bannana->insert(cursor, var_a, expr_1, var_b);// 3 args of bannana() are bound to things
This class represents the notion of an expression. Expressions are derived from SgLocatedNodes,...
This class represents the notion of a declared variable.
This class represents the notion of a statement.

Two modes of insertion are supported: The INJECT_BODY mode copies the snippet's body scope into the insertion point so that all snippet local variables remain in the same (new) scope as the rest of the inserted snippet statements. This is quick and easy, but doesn't allow two snippets that are inserted at the same level in a function to share any local variables (but they can still both refer to variables at the injection site via argument binding in the insert() method). The alternative is INJECT_STMTS, which doesn't create a new scope for the injected statements, but rather copies each statement individually to the injection site. During INJECT_STMTS mode, snippet local declarations are copied to either the beginning of the injection point's function, or to the end of that function's list of declarations (see setLocalDeclarationPosition()).

Parameterized data types

Sometimes a snippet needs to know the type of an actual argument, and this is accomplished with a function-local typedef that has a special name. If the snippet has a formal argument named "a" then a typedef for "typeof_a" will be modified so its base type is the same type as the actual value bound to "a". This only works when the type of the actaul value is consistent with the default value provided in the typedef. For instance, here's the implementation of a snippet that swaps the value of two variables regardless of the type of the variables (this works as long as 'int' can be replaced with the actual type and still be syntactically correct):

// This snippet operates only on integers
void swap_ints(int a, int b) {
int tmp = a;
a = b;
b = tmp;
}
// This snippet operates on any type. The type "int" here is
// only a place holder so the snippet can be parsed.
void swap(int a, int b) {
typedef int typeof_a;
typeof_a tmp = a;
a = b;
b = tmp;
}

Global declarations

Snippets often require additional support in the form of global variables, data types, and function declarations. Whenever a snippet is inserted into a target, other declarations and definitions at the same level as the snippet (global scope for C, or class scope for Java) are also copied into the target AST. This also includes all "import" statements for Java. However, function definitions (and their enclosing declaration) are not copied unless the copyAllSnippetDefinitions property of the associated SnippetFile is set. Copying these things occurs at most once per (snippet-file, target-file) pair so that multiple definitions are not inserted when more than one snippet is inserted into a single target.

A declaration in the snippet file can be black-listed for copying by calling SnippetFile::doNotInsert.

Recursive insertion

Snippet insertion is optionally recursive (see setInsertRecursively()). If one snippet's expansion results in calls to other snippets defined in the same snippet file, then the other snippets are injected at the point of their call. Only direct calls (not function pointers) at the statement level (not in subexpressions) are recognized. Here's an example:

// Snippet file
void assert(int);
void *malloc(unsigned);
void *memcpy(void*, const void*, unsigned);
unsigned strlen(const char *);
void notNull(const void *x) {
assert(x != (const void*)0);
}
void copyTo(void *dst, const void *src, unsigned nbytes) {
notNull(dst); // may be expanded recursively
notNull(src); // may be expanded recursively
memcpy(dst, src, nbytes);
}
void storeStringInHeap(const char *s) {
unsigned s_size = strlen(s) + 1;
char *storage = malloc(s_size);
checkAllocation(storage); // may be expanded recursively
copyTo(storage, s, s_size); // may be expanded recursively
}

Recursive insertion

In order to avoid conflicts between the names of local variables in the snippet code and variables that are visible at the point of insertion, any snippet local variable whose name begins with "tmp" will be renamed to "T_xxxxxx" where "xxxxxx" is a randomly generated string of letters. For example, when inserting allocate_string which also inserts copy_string10 from the snippet below, the two tmp_size variables are given two different names, but the heap_storage variable is not renamed–presumably because the user is interested in that specific variable.

void copy_string10(char *dst, const char *src) {
unsigned tmp_size = strlen(src);
tmp_size = tmp_size > 10 ? 10 : tmp_size;
memcpy(dst, src, tmp_size);
dst[tmp_size] = '\0';
}
void allocate_string(const char *s) {
unsigned tmp_size = strlen(s) + 1;
char *heap_storage = malloc(tmp_size);
copy_string10(heap_storage, s);
}

Limitations

Any header-file declarations referenced by any code copied from a snippet file's AST to the target AST (snippets themselves or those copied things described in the "Global declarations" section above) must also already be present in the target AST. Practically speaking, this means any #include directives in snippet files must also exist in the target file.

Definition at line 311 of file Snippet.h.

#include <midend/astSnippet/Snippet.h>

Public Types

enum  InsertMechanism {
  INSERT_BODY ,
  INSERT_STMTS
}
 Determines how a snippet is injected at the insertion point. More...
 
enum  LocalDeclarationPosition {
  LOCDECLS_AT_BEGINNING ,
  LOCDECLS_AT_END ,
  LOCDECLS_AT_CURSOR
}
 Determines where local declarations are injected when using INSERT_STMTS. More...
 

Public Member Functions

const std::string & getName () const
 Return the snippet name.
 
SnippetFilePtr getFile () const
 Return the file where this snippet is defined.
 
SgFunctionDefinitiongetDefinition () const
 Return the function definition for this snippet.
 
size_t numberOfArguments () const
 Returns the number of formal arguments for the snippet.
 
InsertMechanism getInsertMechanism () const
 Accessor for the snippet insertion mechanism.
 
void setInsertMechanism (InsertMechanism im)
 Accessor for the snippet insertion mechanism.
 
LocalDeclarationPosition getLocalDeclarationPosition () const
 Accessor for local declaration insertion position.
 
void setLocalDeclarationPosition (LocalDeclarationPosition pos)
 Accessor for local declaration insertion position.
 
bool getInsertRecursively () const
 Accessor for the property that indicates whether an insert() should be recursive.
 
void setInsertRecursively (bool b=true)
 Accessor for the property that indicates whether an insert() should be recursive.
 
void clearInsertRecursively ()
 Accessor for the property that indicates whether an insert() should be recursive.
 
void insert (SgStatement *insertionPoint)
 Insert a snippet into the project.
 
void insert (SgStatement *insertionPoint, SgNode *arg1)
 Insert a snippet into the project.
 
void insert (SgStatement *insertionPoint, SgNode *arg1, SgNode *arg2)
 Insert a snippet into the project.
 
void insert (SgStatement *insertionPoint, SgNode *arg1, SgNode *arg2, SgNode *arg3)
 Insert a snippet into the project.
 
void insert (SgStatement *insertionPoint, SgNode *arg1, SgNode *arg2, SgNode *arg3, SgNode *arg4)
 Insert a snippet into the project.
 
void insert (SgStatement *insertionPoint, const std::vector< SgNode * > &args)
 Insert a snippet into the project.
 
bool getFixupAst () const
 Determines whether the target AST should be fixed up after insertion.
 
void setFixupAst (bool b=true)
 Determines whether the target AST should be fixed up after insertion.
 
void clearFixupAst ()
 Determines whether the target AST should be fixed up after insertion.
 

Static Public Member Functions

static SnippetPtr instance (const std::string &snippetName, const SnippetFilePtr &snippetFile)
 Construct a new Snippet.
 
static SnippetPtr instanceFromFile (const std::string &snippetName, const std::string &fileName)
 Construct a new Snippet.
 

Protected Member Functions

 Snippet (const std::string &name, const SnippetFilePtr &file, SgFunctionDefinition *ast)
 
void causeUnparsing (SgNode *ast, Sg_File_Info *targetLocation)
 Mark nodes so they're unparsed when the insertion point is unparsed.
 
void insertRelatedThings (SgStatement *snippetInsertionPoint)
 Insert other things from the snippet file into the target file.
 
void insertRelatedThingsForJava (SgStatement *snippetInsertionPoint)
 Java-specific things that need to be copied from the snippet file to the target file.
 
void insertRelatedThingsForC (SgStatement *snippetInsertionPoint)
 C-specific things that need to be copied from the snippet file to the target file.
 
void renameTemporaries (SgNode *ast)
 Rename snippet local variables so they don't interfere with names visible at the insertion point.
 

Static Protected Member Functions

static void replaceArguments (SgNode *ast, const ArgumentBindings &)
 Replace formal argument occurrances with actual values.
 
static void replaceVariable (SgVarRefExp *, SgExpression *)
 Replace a variable reference with some other expression.
 
static void removeIncludeDirectives (SgNode *)
 Remove C preprocessor #include directives from the specified node.
 

Member Enumeration Documentation

◆ InsertMechanism

Determines how a snippet is injected at the insertion point.

Either the entire body scope of the snippet can be inserted in its entirety as a new scope, or each statement of the body can be inserted individually without using a new scope. The latter allows sharing of snippet local variables since they're essentially hoisted into the function scope of the injection point.

Enumerator
INSERT_BODY 

Insert entire snippet body as a single scope.

INSERT_STMTS 

Insert snippet statements one at a time.

Definition at line 319 of file Snippet.h.

◆ LocalDeclarationPosition

Determines where local declarations are injected when using INSERT_STMTS.

New declarations can be injected starting at the beginning of the injection site's function scope, after the last leading declaration statement in that scope, or in the same place that the non-declaration statements are being inserted. The last case is only useful in languages like C++ and Java that don't require declarations to be at the beginning of a scope. In any case, the snippet's declarations will appear in the injected code in the same order as in the snippet.

Enumerator
LOCDECLS_AT_BEGINNING 

Local declarations inserted at beginning of function.

LOCDECLS_AT_END 

Local declarations inserted at end of leading declarations.

LOCDECLS_AT_CURSOR 

Local declarations are not moved to a declarations area.

Definition at line 329 of file Snippet.h.

Constructor & Destructor Documentation

◆ Snippet()

Rose::Snippet::Snippet ( const std::string &  name,
const SnippetFilePtr file,
SgFunctionDefinition ast 
)
inlineprotected

Definition at line 347 of file Snippet.h.

Member Function Documentation

◆ instance()

static SnippetPtr Rose::Snippet::instance ( const std::string &  snippetName,
const SnippetFilePtr snippetFile 
)
static

Construct a new Snippet.

The name of a snippet corresponds to a name of a global function in a snippet source file. The snippet source file can be specified as either a file name or a SnippetFile object.

◆ instanceFromFile()

static SnippetPtr Rose::Snippet::instanceFromFile ( const std::string &  snippetName,
const std::string &  fileName 
)
static

Construct a new Snippet.

The name of a snippet corresponds to a name of a global function in a snippet source file. The snippet source file can be specified as either a file name or a SnippetFile object.

◆ getName()

const std::string & Rose::Snippet::getName ( ) const
inline

Return the snippet name.

Snippet names are set when the snippet is constructed, and are read-only.

Definition at line 364 of file Snippet.h.

◆ getFile()

SnippetFilePtr Rose::Snippet::getFile ( ) const
inline

Return the file where this snippet is defined.

Definition at line 367 of file Snippet.h.

◆ getDefinition()

SgFunctionDefinition * Rose::Snippet::getDefinition ( ) const
inline

Return the function definition for this snippet.

Definition at line 370 of file Snippet.h.

◆ getInsertMechanism()

InsertMechanism Rose::Snippet::getInsertMechanism ( ) const
inline

Accessor for the snippet insertion mechanism.

See enum for documentation.

Definition at line 377 of file Snippet.h.

◆ setInsertMechanism()

void Rose::Snippet::setInsertMechanism ( InsertMechanism  im)
inline

Accessor for the snippet insertion mechanism.

See enum for documentation.

Definition at line 378 of file Snippet.h.

◆ getLocalDeclarationPosition()

LocalDeclarationPosition Rose::Snippet::getLocalDeclarationPosition ( ) const
inline

Accessor for local declaration insertion position.

See enum for documentation.

Definition at line 383 of file Snippet.h.

◆ setLocalDeclarationPosition()

void Rose::Snippet::setLocalDeclarationPosition ( LocalDeclarationPosition  pos)
inline

Accessor for local declaration insertion position.

See enum for documentation.

Definition at line 384 of file Snippet.h.

◆ getInsertRecursively()

bool Rose::Snippet::getInsertRecursively ( ) const
inline

Accessor for the property that indicates whether an insert() should be recursive.

If insertion is recursive, then any calls in the inserted code to another snippet in the same snippet file as the inserted snippet will be inserted recursively.

Definition at line 391 of file Snippet.h.

◆ setInsertRecursively()

void Rose::Snippet::setInsertRecursively ( bool  b = true)
inline

Accessor for the property that indicates whether an insert() should be recursive.

If insertion is recursive, then any calls in the inserted code to another snippet in the same snippet file as the inserted snippet will be inserted recursively.

Definition at line 392 of file Snippet.h.

◆ clearInsertRecursively()

void Rose::Snippet::clearInsertRecursively ( )
inline

Accessor for the property that indicates whether an insert() should be recursive.

If insertion is recursive, then any calls in the inserted code to another snippet in the same snippet file as the inserted snippet will be inserted recursively.

Definition at line 393 of file Snippet.h.

◆ insert() [1/6]

void Rose::Snippet::insert ( SgStatement insertionPoint)

Insert a snippet into the project.

Inserts the snippet before the insertionPoint statement. The remaining arguments of this method are bound to formal arguments in the snippet code; they can be either variable declarations (SgInitializedName) or expressions (SgExpression).

◆ insert() [2/6]

void Rose::Snippet::insert ( SgStatement insertionPoint,
SgNode arg1 
)

Insert a snippet into the project.

Inserts the snippet before the insertionPoint statement. The remaining arguments of this method are bound to formal arguments in the snippet code; they can be either variable declarations (SgInitializedName) or expressions (SgExpression).

◆ insert() [3/6]

void Rose::Snippet::insert ( SgStatement insertionPoint,
SgNode arg1,
SgNode arg2 
)

Insert a snippet into the project.

Inserts the snippet before the insertionPoint statement. The remaining arguments of this method are bound to formal arguments in the snippet code; they can be either variable declarations (SgInitializedName) or expressions (SgExpression).

◆ insert() [4/6]

void Rose::Snippet::insert ( SgStatement insertionPoint,
SgNode arg1,
SgNode arg2,
SgNode arg3 
)

Insert a snippet into the project.

Inserts the snippet before the insertionPoint statement. The remaining arguments of this method are bound to formal arguments in the snippet code; they can be either variable declarations (SgInitializedName) or expressions (SgExpression).

◆ insert() [5/6]

void Rose::Snippet::insert ( SgStatement insertionPoint,
SgNode arg1,
SgNode arg2,
SgNode arg3,
SgNode arg4 
)

Insert a snippet into the project.

Inserts the snippet before the insertionPoint statement. The remaining arguments of this method are bound to formal arguments in the snippet code; they can be either variable declarations (SgInitializedName) or expressions (SgExpression).

◆ insert() [6/6]

void Rose::Snippet::insert ( SgStatement insertionPoint,
const std::vector< SgNode * > &  args 
)

Insert a snippet into the project.

Inserts the snippet before the insertionPoint statement. The remaining arguments of this method are bound to formal arguments in the snippet code; they can be either variable declarations (SgInitializedName) or expressions (SgExpression).

◆ getFixupAst()

bool Rose::Snippet::getFixupAst ( ) const
inline

Determines whether the target AST should be fixed up after insertion.

Fixing up the target AST makes it so that the things inserted from the snippet file point only to things in the target part of the AST–the snippet file part of the AST can be deleted without consequence, and analysis will work propertly on the target AST after the insertion and fixup. Fixing up the AST is the default, and turning this feature off is probably only useful for debugging the insertion mechanism itself while bypassing the AST fixups.

Definition at line 414 of file Snippet.h.

◆ setFixupAst()

void Rose::Snippet::setFixupAst ( bool  b = true)
inline

Determines whether the target AST should be fixed up after insertion.

Fixing up the target AST makes it so that the things inserted from the snippet file point only to things in the target part of the AST–the snippet file part of the AST can be deleted without consequence, and analysis will work propertly on the target AST after the insertion and fixup. Fixing up the AST is the default, and turning this feature off is probably only useful for debugging the insertion mechanism itself while bypassing the AST fixups.

Definition at line 415 of file Snippet.h.

◆ clearFixupAst()

void Rose::Snippet::clearFixupAst ( )
inline

Determines whether the target AST should be fixed up after insertion.

Fixing up the target AST makes it so that the things inserted from the snippet file point only to things in the target part of the AST–the snippet file part of the AST can be deleted without consequence, and analysis will work propertly on the target AST after the insertion and fixup. Fixing up the AST is the default, and turning this feature off is probably only useful for debugging the insertion mechanism itself while bypassing the AST fixups.

Definition at line 416 of file Snippet.h.

◆ insertRelatedThings()

void Rose::Snippet::insertRelatedThings ( SgStatement snippetInsertionPoint)
protected

Insert other things from the snippet file into the target file.

These are things like variables and functions that are above the snippet function in the snippet files's AST and must be inserted above the snippet insertion point in the target file.

◆ renameTemporaries()

void Rose::Snippet::renameTemporaries ( SgNode ast)
protected

Rename snippet local variables so they don't interfere with names visible at the insertion point.

Only local variables whose names begin with "tmp" are renamed.


The documentation for this class was generated from the following file: