wiki:SemanticQuery/Examples

Version 2 (modified by manualwiki, 13 years ago) (diff)

join basic and advanced queries, swap example queries and their explanation

Query Examples

With our query language we can build either simple or more complex, compound quries. In the followings there are some useful and often used queries with different complexity.

Returns a list of expressions which call the pointed function:

@fun.refs

Returns all function calls from current module group by the module's own functions:

@file.funs.calls

Returns all functions which have 3 arguments:

@file.funs[arity==3]

Returns all functions which have a variable named "Expl". It useful when we want to know which functions use variables with same name:

@file.funs.vars[name=="Expl"]

Returns all io:format calls (this query is very useful when you have finished your software, and you want to find all debug messages):

mods[name=="io"].funs[name==format].refs

For example we stand in a variable, and run this query, we get information about the variable gets its value from where. This functionality uses data-flow analysis?.

@expr.origin

Returns information about the function gets its return value from where and how its calculated:

@fun.refs.origin

Checking coding convensions

In RefactorErl, metrics can be applied to modules or to functions. Modules are equivalent to file entities in the semantic query language, and functions are equivalent to function entities. We can say that a metric is a kind of property belongs to a file or function entity, so we can simply add the proper metrics to the properties of entities.

Usually we have some coding conventions applied to our modules or functions. With our extended semantic query language we can check these conventions, and filter improper modules or functions. Hereinafter we present some design rules and some metrics to check these rules.

Rule1. A module should not contain more then 400 lines.

When we would like to filter modules containing more than 400 effective lines of code, we have to load our modules to RefactorErl system, and enter the following query:

mods[line_of_code > 400]

In the result we will find our too long modules.

Rule2. A function should not contain more then 15 to 20 lines.

When we would like to check, which functions do not fulfil this convention in our modules loaded into the RefactorErl database, we use the following query:

mods.funs[line_of_code > 20]

Rule3. Use at most two level of nesting, do not write deeply nested code. It is achieved by dividing the code into shorter functions.

With one of our metrics we can count the nesting level of case expressions, so we can filter functions with more than two maximum depth of cases. In this example, we would like to get the result just from our actual module.

@file.funs[max_depth_of_cases > 2]

If we just would like to know, whether all of the functions fulfil this convention or not, we can simply query the maximum nesting level of cases in the whole module. If this value is more than two, there is at least one function containing deeply nested cases.

@file.max_depth_of_cases

At least, let's filter modules containing functions with too deeply nested cases.

mods[max_depth_of_cases > 2]

Rule4. Use no more than 80 characters on a line.

We can filter all of the functions, which contains lines with more than 80 characters with the following query:

mods.funs[max_length_of_line > 80]

Rule5. Use space after commas.

We have a metric which returns with the number of cases when we do not fulfil this convention. When a modul or a function breaks this rule, the result of the metric will be more, then 0.

Filter functions containing at least one case when whitespace misses after a comma:

mods.funs[no_space_after_comma > 0]

Rule6. Every recursive function should tail recursive.

Tail recursion means that we have no recursive call (either direct or indirect) in our function, just in the last expression. Filter functions that recursive, but not tail recursive:

mods.funs[is_tail_recursive == non_tail_rec]