ROSE 0.11.145.281
|
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.
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).
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.
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()).
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):
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.
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:
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.
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.
#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. | |
SgFunctionDefinition * | getDefinition () 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. | |
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. |
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.
|
inlineprotected |
|
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.
|
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.
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
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).
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).
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).
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).
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).
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).
|
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.
|
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.
|
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.
|
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.
|
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.