diff --git a/src/org/rascalmpl/library/Node.rsc b/src/org/rascalmpl/library/Node.rsc index 6f1172c34da..ff146416bec 100644 --- a/src/org/rascalmpl/library/Node.rsc +++ b/src/org/rascalmpl/library/Node.rsc @@ -49,7 +49,7 @@ getKeywordParameters("f"(10, "abc", height=0)); @javaClass{org.rascalmpl.library.Prelude} public java map[str,value] getKeywordParameters(node T); -@Deprecated{ +@deprecated{ Use getKeywordParameters(T) } public map[str, value] getAnnotations(node T) = getKeywordParameters(T); @@ -65,7 +65,7 @@ setKeywordParameters("f"(10, "abc"), ("height":0)); @javaClass{org.rascalmpl.library.Prelude} public java &T <: node setKeywordParameters(&T <: node x, map[str,value] keywordParameters); -@Deprecated{ +@deprecated{ Use setKeywordParameters(x, keywordParameters) } public &T <: node setAnnotations(&T <: node x, map[str,value] keywordParameters) @@ -98,7 +98,7 @@ public java node makeNode(str N, value V..., map[str, value] keywordParameters = @javaClass{org.rascalmpl.library.Prelude} public java &T <: node unset(&T <: node x, str keywordParameter); -@Deprecated{ +@deprecated{ Use unset(x, kw) } public &T <: node delAnnotation(&T <: node x, str keywordParameter) = unset(x, keywordParameter); @@ -118,7 +118,7 @@ public &T <: node unset(&T <: node x, set[str] keywordParameters){ @javaClass{org.rascalmpl.library.Prelude} public java &T <: node unset(&T <: node x); -@Deprecated{ +@deprecated{ Use `unset(x)` } public &T <: node delAnnotations(&T <: node x) = unset(x); @@ -128,7 +128,7 @@ public &T <: node delAnnotations(&T <: node x) = unset(x); @javaClass{org.rascalmpl.library.Prelude} public java &T unsetRec(&T x); -@Deprecated{ +@deprecated{ Use `unsetRec(x)` } public &T delAnnotationsRec(&T x) = unsetRec(x); diff --git a/src/org/rascalmpl/library/lang/java/m3/AST.rsc b/src/org/rascalmpl/library/lang/java/m3/AST.rsc index 89360f8bf1d..48b768f55c4 100644 --- a/src/org/rascalmpl/library/lang/java/m3/AST.rsc +++ b/src/org/rascalmpl/library/lang/java/m3/AST.rsc @@ -10,7 +10,7 @@ import util::Reflective; import IO; import String; import List; - + data Declaration = \compilationUnit(list[Declaration] imports, list[Declaration] types) | \compilationUnit(Declaration package, list[Declaration] imports, list[Declaration] types) @@ -39,7 +39,7 @@ data Declaration ; -data Expression +data Expression = \arrayAccess(Expression array, Expression index) | \newArray(Type \type, list[Expression] dimensions, Expression init) | \newArray(Type \type, list[Expression] dimensions) @@ -76,11 +76,11 @@ data Expression | \simpleName(str name) | \markerAnnotation(str typeName) | \normalAnnotation(str typeName, list[Expression] memberValuePairs) - | \memberValuePair(str name, Expression \value) + | \memberValuePair(str name, Expression \value) | \singleMemberAnnotation(str typeName, Expression \value) - ; - -data Statement + ; + +data Statement = \assert(Expression expression) | \assert(Expression expression, Expression message) | \block(list[Statement] statements) @@ -104,16 +104,16 @@ data Statement | \synchronizedStatement(Expression lock, Statement body) | \throw(Expression expression) | \try(Statement body, list[Statement] catchClauses) - | \try(Statement body, list[Statement] catchClauses, Statement \finally) + | \try(Statement body, list[Statement] catchClauses, Statement \finally) | \catch(Declaration exception, Statement body) | \declarationStatement(Declaration declaration) | \while(Expression condition, Statement body) | \expressionStatement(Expression stmt) | \constructorCall(bool isSuper, Expression expr, list[Expression] arguments) | \constructorCall(bool isSuper, list[Expression] arguments) - ; - -data Type + ; + +data Type = arrayType(Type \type) | parameterizedType(Type \type) | qualifiedType(Type qualifier, Expression simpleName) @@ -133,7 +133,7 @@ data Type | \void() | \boolean() ; - + data Modifier = \private() | \public() @@ -153,7 +153,7 @@ data Modifier ; @memo -set[loc] getPaths(loc dir, str suffix) { +set[loc] getPaths(loc dir, str suffix) { bool containsFile(loc d) = isDirectory(d) ? (x <- d.ls && x.extension == suffix) : false; return find(dir, containsFile); } @@ -172,15 +172,15 @@ set[loc] findRoots(set[loc] folders) { packagedepth = size(split(".", trim(p))); roots += { d[path = intercalate("/", split("/", d.path)[..-packagedepth])] }; } - - if (roots == {}) { // no package declaration means d is a root - roots += { d }; + + if (roots == {}) { // no package declaration means d is a root + roots += { d }; } - - break; - } catch: ; + + break; + } catch: ; } - + if (roots != {}) { result += roots; } @@ -190,14 +190,14 @@ set[loc] findRoots(set[loc] folders) { } } } - + return result; } - -@synopsis{Creates AST from a file} -@description{ +@synopsis{Creates AST from a single file.} +@description{ +Wrapper around ((createAstsFromFiles)) to call it on a single file. } public Declaration createAstFromFile(loc file, bool collectBindings, bool errorRecovery = false, list[loc] sourcePath = [], list[loc] classPath = [], str javaVersion = "1.7") { result = createAstsFromFiles({file}, collectBindings, errorRecovery = errorRecovery, sourcePath = sourcePath, classPath = classPath, javaVersion = javaVersion); @@ -207,29 +207,42 @@ public Declaration createAstFromFile(loc file, bool collectBindings, bool errorR throw "Unexpected number of ASTs returned from "; } -@synopsis{Creates AST from a file using Eclipse JDT compiler} +@synopsis{Creates ASTs for a set of files using Eclipse JDT compiler.} +@pitfalls{ + While the function takes a set of locations, it ignores the positional information of the location. + Meaning, that it analyzes the whole file and not just the part that the positional information describes. +} @javaClass{org.rascalmpl.library.lang.java.m3.internal.EclipseJavaCompiler} public java set[Declaration] createAstsFromFiles(set[loc] file, bool collectBindings, bool errorRecovery = false, list[loc] sourcePath = [], list[loc] classPath = [], str javaVersion = "1.7"); -@synopsis{Creates AST from a string using Eclipse JDT compiler} +@synopsis{Creates AST from a string using Eclipse JDT compiler.} @javaClass{org.rascalmpl.library.lang.java.m3.internal.EclipseJavaCompiler} public java Declaration createAstFromString(loc fileName, str source, bool collectBinding, bool errorRecovery = false, list[loc] sourcePath = [], list[loc] classPath = [], str javaVersion = "1.7"); @synopsis{Creates a set ASTs for all Java source files in a project using Eclipse's JDT compiler} +@description{ + The function recursively looks for the `.java` files in the directory. + The function also looks for the dependencies (`.jar` files) to include them. + Wraps around ((createAstsFromFiles)). +} public set[Declaration] createAstsFromDirectory(loc project, bool collectBindings, bool errorRecovery = false, str javaVersion = "1.7" ) { if (!(isDirectory(project))) { throw " is not a valid directory"; } - + classPaths = [ j | j <- find(project, "jar"), isFile(j) ]; sourcePaths = getPaths(project, "java"); return createAstsFromFiles({ p | sp <- sourcePaths, p <- find(sp, "java"), isFile(p)}, collectBindings, sourcePath = [*findRoots(sourcePaths)], classPath = classPaths, errorRecovery = errorRecovery, javaVersion = javaVersion); } -@synopsis{Creates a set ASTs for all Java source files in a Maven project using Eclipse's JDT compiler} +@synopsis{Creates a set of ASTs for all Java source files in a Maven project using Eclipse's JDT compiler.} @description{ This function uses ((util::Reflective-getProjectPathConfig)), which inspects a `pom.xml` to compute the dependencies and concrete locations of jar files that a Maven project depends on. +The location of `project` points to the root of the project to analyze. As a consequence, the `pom.xml` +is expected to be at `project + "pom.xml"`. + +Wraps around ((createAstsFromFiles)). } public set[Declaration] createAstsFromMavenProject(loc project, bool collectBindings, bool errorRecovery = false, str javaVersion = "1.7" ) { if (!exists(project + "pom.xml")) { @@ -239,9 +252,8 @@ public set[Declaration] createAstsFromMavenProject(loc project, bool collectBind if (!(isDirectory(project))) { throw " is not a valid directory"; } - + classPaths = getProjectPathConfig(project).javaCompilerPath; sourcePaths = getPaths(project, "java"); return createAstsFromFiles({ p | sp <- sourcePaths, p <- find(sp, "java"), isFile(p)}, collectBindings, sourcePath = [*findRoots(sourcePaths)], classPath = classPaths, errorRecovery = errorRecovery, javaVersion = javaVersion); } - diff --git a/src/org/rascalmpl/library/lang/java/m3/Core.rsc b/src/org/rascalmpl/library/lang/java/m3/Core.rsc index 88b7f5920b2..08e21e84d13 100644 --- a/src/org/rascalmpl/library/lang/java/m3/Core.rsc +++ b/src/org/rascalmpl/library/lang/java/m3/Core.rsc @@ -18,6 +18,10 @@ import List; import util::FileSystem; import util::Reflective; +@synopsis{Java extensions to the generic M3 model.} +@description{ + Notice that this model also contains the attributes from ((Library:analysis::m3::Core::M3)). +} data M3( rel[loc from, loc to] extends = {}, // classes extending classes and interfaces extending interfaces rel[loc from, loc to] implements = {}, // classes implementing interfaces @@ -30,6 +34,7 @@ data M3( data Language(str version="") = java(); +@synopsis{Combines a set of Java meta models by merging their relations.} @memo M3 composeJavaM3(loc id, set[M3] models) { // Compose the generic M3 relations first @@ -47,6 +52,13 @@ M3 composeJavaM3(loc id, set[M3] models) { return comp; } +@synopsis{Returns the difference between the first model and the others.} +@description{ + Combines `models[1..]` into a single model and then calculates + the difference between `model[0]` and this new joined model. + + The `id` is the identifier for the returned model. +} @memo M3 diffJavaM3(loc id, list[M3] models) { // Diff the generic M3 relations first @@ -67,6 +79,10 @@ M3 diffJavaM3(loc id, list[M3] models) { return diff; } +@synopsis{Creates a M3 from a single files.} +@description{ + Identical to ((createM3sFromFiles)): `createM3sFromFiles({file})`. +} M3 createM3FromFile(loc file, bool errorRecovery = false, list[loc] sourcePath = [], list[loc] classPath = [], str javaVersion = "1.7") { result = createM3sFromFiles({file}, errorRecovery = errorRecovery, sourcePath = sourcePath, classPath = classPath, javaVersion = javaVersion); if ({oneResult} := result) { @@ -75,9 +91,17 @@ M3 createM3FromFile(loc file, bool errorRecovery = false, list[loc] sourcePath = throw "Unexpected number of M3s returned for "; } +@synopsis{For a set of Java files, generates matching M3s.} +@description{ + Each M3 has the `id` filled with a matching location from `files`. +} @javaClass{org.rascalmpl.library.lang.java.m3.internal.EclipseJavaCompiler} java set[M3] createM3sFromFiles(set[loc] files, bool errorRecovery = false, list[loc] sourcePath = [], list[loc] classPath = [], str javaVersion = "1.7"); +@synopsis{For a set of Java files, creates a composed M3.} +@description{ + While ((createM3sFromFiles)) leaves the M3s separated, this function composes them into a single model. +} M3 createM3FromFiles(loc projectName, set[loc] files, bool errorRecovery = false, list[loc] sourcePath = [], list[loc] classPath = [], str javaVersion = "1.7") = composeJavaM3(projectName, createM3sFromFiles(files, errorRecovery = errorRecovery, sourcePath = sourcePath, classPath = classPath, javaVersion = javaVersion)); @@ -124,7 +148,7 @@ M3 createM3FromDirectory(loc project, bool errorRecovery = false, bool includeJa } @synopsis{Globs for jars, class files and java files in a directory and tries to compile all source files into an M3 model} -M3 createM3FromMavenProject(loc project, bool errorRecovery = false, bool includeJarModels=false, str javaVersion = "1.7", list[loc] classPath = []) { +M3 createM3FromMavenProject(loc project, bool errorRecovery = false, bool includeJarModels=false, str javaVersion = "1.7") { if (!exists(project + "pom.xml")) { throw IO("pom.xml not found"); } @@ -168,8 +192,8 @@ M3 createM3FromJar(loc jarFile, list[loc] classPath = []) { methodContainment = { | <- containment, isMethod(m)}; for( <- candidates) { - model.methodOverrides += { | m <- methodContainment[from]} - o { | m <- methodContainment[to]}; + model.methodOverrides += { | m <- methodContainment[from]} + o { | m <- methodContainment[to]}; } return model; @@ -179,66 +203,199 @@ void unregisterJavaProject(loc project) { unregisterProjectSchemes(project, {"java+compilationUnit", "java+compilationUnit", "java+class", "java+constructor", "java+initializer", "java+parameter","java+variable","java+field" , "java+interface" , "java+enum", "java+class" , "java+interface","java+enum"}); } -str getMethodSignature(loc method) +@deprecated{ + Use `.file` on a location instead, i.e. `someLocation.file`. +} +str getMethodSignature(loc method) = substring(method.path, findLast(method.path,"/") + 1); +@synopsis{Checks if the logical name of the `entity` is a compilation unit.} +@description{ + A compilation unit is equivalent to a `.java` file in Java. +} bool isCompilationUnit(loc entity) = entity.scheme == "java+compilationUnit"; + +@synopsis{Checks if the logical name of the `entity` is a package.} bool isPackage(loc entity) = entity.scheme == "java+package"; + +@synopsis{Checks if the logical name of the `entity` is a class.} bool isClass(loc entity) = entity.scheme == "java+class"; + +@synopsis{Checks if the logical name of the `entity` is a constructor.} bool isConstructor(loc entity) = entity.scheme == "java+constructor"; + +@synopsis{Checks if the logical name of the `entity` is a method.} +@description{ + Constructors and initializers are also considered methods here. +} +@pitfalls{ + If `isConstructor(entity)`, then also `isMethod(entity)`. + Note that the opposite is not true. +} bool isMethod(loc entity) = entity.scheme == "java+method" || entity.scheme == "java+constructor" || entity.scheme == "java+initializer"; + +@synopsis{Checks if the logical name of the `entity` is a parameter.} bool isParameter(loc entity) = entity.scheme == "java+parameter"; + +@synopsis{Checks if the logical name of the `entity` is a variable.} bool isVariable(loc entity) = entity.scheme == "java+variable"; + +@synopsis{Checks if the logical name of the `entity` is a field.} bool isField(loc entity) = entity.scheme == "java+field"; + +@synopsis{Checks if the logical name of the `entity` is an interface.} bool isInterface(loc entity) = entity.scheme == "java+interface"; + +@synopsis{Checks if the logical name of the `entity` is an enum.} bool isEnum(loc entity) = entity.scheme == "java+enum"; + +@synopsis{Checks if the logical name of the `entity` is a type.} +@description{ + A type is considered to be a class, an interface, or an enum. +} +@pitfalls{ + If `isClass(entity)`, then also `isType(entity)`. + If `isInterface(entity)`, then also `isType(entity)`. + If `isEnum(entity)`, then also `isType(entity)`. + + Note that the opposite is not true. +} bool isType(loc entity) = entity.scheme == "java+class" || entity.scheme == "java+interface" || entity.scheme == "java+enum"; -set[loc] files(rel[loc, loc] containment) +@synopsis{Extracts all fields that are contained in `parent`.} +set[loc] files(rel[loc, loc] containment) = {e.lhs | tuple[loc lhs, loc rhs] e <- containment, isCompilationUnit(e.lhs)}; rel[loc, loc] declaredMethods(M3 m, set[Modifier] checkModifiers = {}) { declaredTypes = types(m); modifiersMap = toMap(m.modifiers); - + return {e | tuple[loc lhs, loc rhs] e <- domainR(m.containment, declaredTypes), isMethod(e.rhs), checkModifiers <= (modifiersMap[e.rhs]? ? modifiersMap[e.rhs] : {}) }; } rel[loc, loc] declaredFields(M3 m, set[Modifier] checkModifiers = {}) { declaredTypes = types(m); modifiersMap = toMap(m.modifiers); - + return {e | tuple[loc lhs, loc rhs] e <- domainR(m.containment, declaredTypes), isField(e.rhs), checkModifiers <= (modifiersMap[e.rhs]? ? modifiersMap[e.rhs] : {}) }; } rel[loc, loc] declaredFieldsX(M3 m, set[Modifier] checkModifiers = {}) { declaredTypes = types(m); modifiersMap = toMap(m.modifiers); - + return {e | tuple[loc lhs, loc rhs] e <- domainR(m.containment, declaredTypes), isField(e.rhs), isEmpty(checkModifiers & (modifiersMap[e.rhs]? ? modifiersMap[e.rhs] : {})) }; -} - -rel[loc, loc] declaredTopTypes(M3 m) - = {e | tuple[loc lhs, loc rhs] e <- m.containment, isCompilationUnit(e.lhs), isType(e.rhs)}; +} + +@synopsis{For all compilation units (left side), gets the types (right side).} +rel[loc, loc] declaredTopTypes(M3 m) + = {e | tuple[loc lhs, loc rhs] e <- m.containment, isCompilationUnit(e.lhs), isType(e.rhs)}; -rel[loc, loc] declaredSubTypes(M3 m) +rel[loc, loc] declaredSubTypes(M3 m) = {e | tuple[loc lhs, loc rhs] e <- m.containment, isClass(e.rhs)} - declaredTopTypes(m); -@memo set[loc] classes(M3 m) = {e | <- m.declarations, isClass(e)}; -@memo set[loc] interfaces(M3 m) = {e | <- m.declarations, isInterface(e)}; -@memo set[loc] packages(M3 m) = {e | <- m.declarations, isPackage(e)}; -@memo set[loc] variables(M3 m) = {e | <- m.declarations, isVariable(e)}; -@memo set[loc] parameters(M3 m) = {e | <- m.declarations, isParameter(e)}; -@memo set[loc] fields(M3 m) = {e | <- m.declarations, isField(e)}; -@memo set[loc] methods(M3 m) = {e | <- m.declarations, isMethod(e)}; -@memo set[loc] constructors(M3 m) = {e | <- m.declarations, isConstructor(e)}; -@memo set[loc] enums(M3 m) = {e | <- m.declarations, isEnum(e)}; -@memo set[loc] types(M3 m) = {e | <- m.declarations, isType(e)}; +@synopsis{Extracts all classes (logical names) from an M3.} +@description{ + Caches the results in memory. +} +@memo +set[loc] classes(M3 m) = {e | <- m.declarations, isClass(e)}; + +@synopsis{Extracts all interfaces (logical names) from an M3.} +@description{ + Caches the results in memory. +} +@memo +set[loc] interfaces(M3 m) = {e | <- m.declarations, isInterface(e)}; + +@synopsis{Extracts all packages (logical names) from an M3.} +@description{ + Caches the results in memory. +} +@memo +set[loc] packages(M3 m) = {e | <- m.declarations, isPackage(e)}; + +@synopsis{Extracts all variables (logical names) from an M3.} +@description{ + Caches the results in memory. +} +@memo +set[loc] variables(M3 m) = {e | <- m.declarations, isVariable(e)}; + +@synopsis{Extracts all parameters (logical names) from an M3.} +@description{ + Caches the results in memory. +} +@memo +set[loc] parameters(M3 m) = {e | <- m.declarations, isParameter(e)}; + +@synopsis{Extracts all fields (logical names) from an M3.} +@description{ + Caches the results in memory. +} +@memo +set[loc] fields(M3 m) = {e | <- m.declarations, isField(e)}; + +@synopsis{Extracts all methods (logical names) from an M3.} +@description{ + Caches the results in memory. +} +@memo +set[loc] methods(M3 m) = {e | <- m.declarations, isMethod(e)}; + +@synopsis{Extracts all constructors (logical names) from an M3.} +@description{ + Caches the results in memory. +} +@memo +set[loc] constructors(M3 m) = {e | <- m.declarations, isConstructor(e)}; + +@synopsis{Extracts all enums (logical names) from an M3.} +@description{ + Caches the results in memory. +} +@memo +set[loc] enums(M3 m) = {e | <- m.declarations, isEnum(e)}; + +@synopsis{Extracts all types (logical names) from an M3.} +@description{ + Caches the results in memory. +} +@memo +set[loc] types(M3 m) = {e | <- m.declarations, isType(e)}; +@synopsis{Extracts all elements that are contained in `parent`.} +@description{ + See ((Library:analysis::m3::Core::M3)) `containment` for the definition of contains. +} set[loc] elements(M3 m, loc parent) = m.containment[parent]; -@memo set[loc] fields(M3 m, loc class) = { e | e <- elements(m, class), isField(e) }; -@memo set[loc] methods(M3 m, loc class) = { e | e <- elements(m, class), isMethod(e) }; -@memo set[loc] constructors(M3 m, loc class) = { e | e <- elements(m, class), isConstructor(e) }; -@memo set[loc] nestedClasses(M3 m, loc class) = { e | e <- elements(m, class), isClass(e) }; + +@synopsis{Extracts all fields that are contained in `class`.} +@description{ + Filtered version of ((elements)). +} +@memo +set[loc] fields(M3 m, loc class) = { e | e <- elements(m, class), isField(e) }; + +@synopsis{Extracts all methods that are contained in `class`.} +@description{ + Filtered version of ((elements)). +} +@memo +set[loc] methods(M3 m, loc class) = { e | e <- elements(m, class), isMethod(e) }; + +@synopsis{Extracts all constructors that are contained in `class`.} +@description{ + Filtered version of ((elements)). +} +@memo +set[loc] constructors(M3 m, loc class) = { e | e <- elements(m, class), isConstructor(e) }; + +@synopsis{Extracts all classes that are contained in `class`.} +@description{ + Filtered version of ((elements)). +} +@memo +set[loc] nestedClasses(M3 m, loc class) = { e | e <- elements(m, class), isClass(e) };