module analysis::m3::Core
M3 common source code model represent facts extracted from source code for use in downstream metrics or other analyses.
Usage
import analysis::m3::Core;
Dependencies
import Message;
import Set;
import IO;
import util::FileSystem;
import analysis::graphs::Graph;
import Node;
import Map;
import List;
import Relation;
extend analysis::m3::TypeSymbol;
Description
The M3 Core defines basic concepts such as:
- qualified names: we use locations to model qualified names for each programming language
- containment: which artifacts are contained in which other artifacts
- declarations: where artifacts are defined
- uses: where declared artifacts are used
- types: which artifacts has which types
From this Core is supposed to be extended with features specific for a programming language. See for example Java M3.
Benefits
- Qualified names in the shape of a location are a uniform and generic way of identifying source code artifacts, that can be extended across languages, projects, and versions.
- M3 helps standardizing the shape of facts we extract from source code for all different languages, limiting the element of surprise.
- When we use M3 for many languages, common IDE features are made reusable (such as clicking from an extracted fact to the code that generated it).
- Some downstream analyses may be reusable between different languages if they all map to M3.
Pitfalls
- Even though different languages may map to the same M3 model, this does not mean that the semantics is the same. Downstream metrics or other analysis tools should still take semantic differences between programming languages into account.
data M3
m3 model constructor
data M3 (
rel[loc name, loc src] declarations = {}, // maps declarations to where they are declared. contains any kind of data or type or code declaration (classes, fields, methods, variables, etc. etc.)
set[loc] implicitDeclarations = {}, // some languages provide builtin implicit declarations, e.g. |java+class:///java/lang/Object| may not have a source location but still exist.
rel[loc name, TypeSymbol typ] types = {}, // assigns types to declared source code artifacts
rel[loc src, loc name] uses = {}, // maps source locations of usages to the respective declarations
rel[loc from, loc to] containment = {}, // what inner declaration (to) is logically contained in what outer declaration (`from`) (not necessarily physically, but usually also)
list[Message] messages = [], // error messages and warnings produced while constructing a single m3 model
rel[str simpleName, loc qualifiedName] names = {}, // convenience mapping from logical names to end-user readable (GUI) names, and vice versa
rel[loc definition, loc comments] documentation = {}, // comments and javadoc attached to declared things
rel[loc definition, Modifier modifier] modifiers = {} // modifiers associated with declared things
)
= m3(
loc id)
;
This constructor holds all information to an m3 model. It is identified by the id field, which should be a unique name for the project or file that the m3 model was constructor for.
Attached to this m3 model will be annotations with the specific information.
data Language
data Language (str version = "")
= generic()
;
function emptyM3
Create an empty m3 term with empty annotations
M3 emptyM3(loc id)
function composeM3
Generic function to compose the annotations of a set of M3s.
M3 composeM3(loc id, set[M3] models)
function diffM3
Generic function to apply a difference over the annotations of a list of M3s.
M3 diffM3(loc id, list[M3] models)
function modifyM3
M3 modifyM3(loc id, list[M3] models, value (&T,&T) fun)
function isEmpty
bool isEmpty(M3 model)
function relToFileSystem
constructs a recursive FileSystem from a binary [Location] relation.
set[FileSystem] relToFileSystem(rel[loc parent, loc child] r)
function files
set[loc] files(M3 model)
function containmentToFileSystem
transform the containment relation to a recursive tree model
set[FileSystem] containmentToFileSystem(M3 model)
Benefits
- Transforming the containment relation to a tree model allows further analysis using operators
such as
visit
and descendant matching (/
)which is sometimes more convenient.
Pitfalls
- Do not forget that the relational operators such as [TransitiveClosure], [Comprehension] and [Composition] may be just as effective and perhaps more efficient, as applied directly on the containment relation.
function checkM3
list[Message] checkM3(M3 model)
function testM3ModelConsistency
bool testM3ModelConsistency(M3 m)