can parse ruby import relations

This commit is contained in:
Gang ZHANG 2019-01-14 13:38:48 +08:00
parent b6482121d6
commit 1effdf2531
191 changed files with 7150 additions and 4810 deletions

1
.gitignore vendored
View File

@ -4,6 +4,7 @@
*.log
.idea/
out/
data/
*.DS_Store
/target/
.classpath

View File

@ -0,0 +1,76 @@
package depends;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import picocli.CommandLine.Parameters;
@Command(name = "depends")
public class DependsCommand {
@Parameters(index = "0", description = "The lanauge of project files: [java, cpp]")
private String lang;
@Parameters(index = "1", description = "The directory to be analyzed")
private String src;
@Parameters(index = "2", description = "The output file name")
private String output;
@Option(names = {"-f", "--format"},split=",", description = "the output format: [json(default),xml,excel,detail(text format),dot]")
private String[] format=new String[]{"json"};
@Option(names = {"-d", "--dir"}, description = "The output directory")
private String dir;
@Option(names = {"-m", "--map"}, description = "Output DV8 dependency map file.")
private boolean dv8map = true;
@Option(names = {"-s", "--strip-leading-path"}, description = "Strip the leading path.")
private boolean stripLeadingPath = false;
@Option(names = {"-g", "--granularity"}, description = "Granularity of dependency.[file(default),method]")
private String granularity="file";
@Option(names = {"-p", "--namepattern"}, description = "The name path pattern.[default(/),dot(.)")
private String namePathPattern="default";
@Option(names = {"-i","--includes"},split=",", description = "The files of searching path")
private String[] includes = new String[] {};
@Option(names = {"-h","--help"}, usageHelp = true, description = "display this help and exit")
boolean help;
public String getLang() {
return lang;
}
public void setLang(String lang) {
this.lang = lang;
}
public String getSrc() {
return src;
}
public void setSrc(String src) {
this.src = src;
}
public String getOutputName() {
return output;
}
public void setOutput(String output) {
this.output = output;
}
public String[] getFormat() {
return format;
}
public String getOutputDir() {
if (dir==null) {
dir = System.getProperty("user.dir");
}
return dir;
}
public boolean isDv8map() {
return dv8map;
}
public String[] getIncludes() {
return includes;
}
public boolean isHelp() {
return help;
}
public String getGranularity() {
return granularity;
}
public String getNamePathPattern() {
return namePathPattern;
}
public boolean isStripLeadingPath() {
return stripLeadingPath;
}
}

View File

@ -0,0 +1,84 @@
package depends;
import java.io.File;
import java.nio.file.Files;
import depends.addons.DV8MappingFileBuilder;
import depends.extractor.AbstractLangWorker;
import depends.extractor.LangWorkers;
import depends.extractor.cpp.CppWorker;
import depends.extractor.java.JavaWorker;
import depends.extractor.ruby.RubyWorker;
import depends.format.DependencyDumper;
import depends.format.path.DotPathFilenameWritter;
import depends.format.path.EmptyFilenameWritter;
import depends.matrix.DependencyGenerator;
import depends.matrix.FileDependencyGenerator;
import depends.matrix.FilenameWritter;
import depends.matrix.FunctionDependencyGenerator;
import depends.util.FileUtil;
import picocli.CommandLine;
public class Main {
public static void main(String[] args) {
try {
DependsCommand app = CommandLine.populateCommand(new DependsCommand(), args);
if (app.help) {
CommandLine.usage(new DependsCommand(), System.out);
System.exit(0);
}
executeCommand(app);
} catch (Exception e) {
System.err.println("Exception encountered");
CommandLine.usage(new DependsCommand(), System.out);
System.exit(0);
}
}
private static void executeCommand(DependsCommand app) {
String lang = app.getLang();
String inputDir = app.getSrc();
String[] includeDir = app.getIncludes();
String outputName = app.getOutputName();
String outputDir = app.getOutputDir();
String[] outputFormat = app.getFormat();
if ( app.isDv8map()) {
DV8MappingFileBuilder dv8MapfileBuilder = new DV8MappingFileBuilder();
dv8MapfileBuilder.create(outputDir+File.separator+"depends-dv8map.json");
}
inputDir = FileUtil.uniqFilePath(inputDir);
LangWorkers.getRegistry().register(new JavaWorker(inputDir, includeDir));
LangWorkers.getRegistry().register(new CppWorker(inputDir, includeDir));
LangWorkers.getRegistry().register(new RubyWorker(inputDir, includeDir));
AbstractLangWorker worker = LangWorkers.getRegistry().getWorkerOf(lang);
if (worker == null) {
System.out.println("Not support this language: " + lang);
return;
}
long startTime = System.currentTimeMillis();
DependencyGenerator dependencyGenerator = app.getGranularity().equals("file")?
(new FileDependencyGenerator()):(new FunctionDependencyGenerator());
worker.setDependencyGenerator(dependencyGenerator);
worker.work();
if (app.isStripLeadingPath()) {
worker.getDependencies().stripFilenames(inputDir);
}
FilenameWritter filenameWritter = new EmptyFilenameWritter();
if (app.getNamePathPattern().equals("dot")) {
filenameWritter = new DotPathFilenameWritter();
}
worker.getDependencies().reWriteFilenamePattern(filenameWritter );
DependencyDumper output = new DependencyDumper(worker.getDependencies(),worker.getErrors());
output.outputResult(outputName,outputDir,outputFormat);
long endTime = System.currentTimeMillis();
System.out.println("Consumed time: " + (float) ((endTime - startTime) / 1000.00) + " s, or "
+ (float) ((endTime - startTime) / 60000.00) + " min.");
}
}

View File

@ -0,0 +1,79 @@
package depends.addons;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;
import depends.deptypes.DependencyType;
class MappingValue{
int family = 0;
int vendor = 2;
int type = 0;
MappingValue(String orginalName, int typeId){
this.type = typeId;
}
public int getFamily() {
return family;
}
public void setFamily(int family) {
this.family = family;
}
public int getVendor() {
return vendor;
}
public void setVendor(int vendor) {
this.vendor = vendor;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
}
class MappingItem {
String name;
MappingValue id;
public MappingItem(String dv8Name, int typeId) {
this.name = dv8Name;
String orginalName = dv8Name;
this.id = new MappingValue(orginalName, typeId);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public MappingValue getId() {
return id;
}
public void setId(MappingValue id) {
this.id = id;
}
}
public class DV8MappingFileBuilder {
public void create(String fileName) {
Map<String,MappingItem> values = new HashMap<>();
ArrayList<String> dependencies = DependencyType.allDependencies();
for (int i=0;i<dependencies.size();i++) {
String dep = dependencies.get(i);
values.put(dep,new MappingItem(dep,i));
}
ObjectMapper mapper = new ObjectMapper();
try {
mapper.writerWithDefaultPrettyPrinter().writeValue(new File(fileName), values);
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,39 @@
package depends.deptypes;
import java.util.ArrayList;
public class DependencyType {
public static final String IMPORT = "Import";
public static final String CONTAIN = "Contain";
public static final String IMPLEMENT = "Implement";
public static final String INHERIT = "Extend";
public static final String CALL = "Call";
public static final String PARAMETER = "Parameter";
public static final String RETURN = "Return";
public static final String SET = "Set";
public static final String USE = "Use";
public static final String RECEIVE = "Receive";
public static final String CREATE = "Create";
public static final String CAST = "Cast";
public static final String THROW = "Throw";
public static final String ANNOTATION = "Annotation";
public static ArrayList<String> allDependencies() {
ArrayList<String> depedencyTypes = new ArrayList<String>();
depedencyTypes.add(IMPORT);
depedencyTypes.add(CONTAIN);
depedencyTypes.add(IMPLEMENT);
depedencyTypes.add(INHERIT);
depedencyTypes.add(CALL);
depedencyTypes.add(PARAMETER);
depedencyTypes.add(RETURN);
depedencyTypes.add(SET);
depedencyTypes.add(CREATE);
depedencyTypes.add(USE);
depedencyTypes.add(RECEIVE);
depedencyTypes.add(CAST);
depedencyTypes.add(THROW);
depedencyTypes.add(ANNOTATION);
return depedencyTypes;
}
}

View File

@ -0,0 +1,9 @@
package depends.entity;
import java.util.UUID;
public class AnonymousBlock extends ContainerEntity{
public AnonymousBlock(Entity parent, Integer id) {
super(UUID.randomUUID().toString(), parent, id);
}
}

View File

@ -0,0 +1,235 @@
package depends.entity;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import depends.extractor.java.JavaParser.ExpressionContext;
import depends.relations.Inferer;
/**
* ContainerEntity for example file, class, method, etc.
* they could contain vars, functions, ecpressions, type parameters, etc.
*/
public abstract class ContainerEntity extends Entity {
private static final Logger logger = LoggerFactory.getLogger(ContainerEntity.class);
private ArrayList<VarEntity> vars;
private ArrayList<FunctionEntity> functions;
private HashMap<Object, Expression> expressions;
private Collection<String> typeParameters; // Generic type parameters like <T>, <String>, <? extends Object>
private Collection<String> annotations = new ArrayList<>();
private Collection<TypeEntity> resolvedTypeParameters = new ArrayList<>();
private Collection<TypeEntity> resolvedAnnotations = new ArrayList<>();
public ContainerEntity(String rawName, Entity parent, Integer id) {
super(rawName, parent, id);
vars = new ArrayList<>();
functions = new ArrayList<>();
expressions = new HashMap<>();
typeParameters = new ArrayList<>();
}
public void addAnnotation(String name) {
this.annotations.add(name);
}
public void addTypeParameter(String typeName) {
this.typeParameters.add(typeName);
}
public void addTypeParameter(List<String> parameters) {
this.typeParameters.addAll(parameters);
}
public void addVar(VarEntity var) {
if (logger.isDebugEnabled()) {
logger.debug("var found: "+var.getRawName() + ":" + var.getRawType());
}
this.vars.add(var);
}
public ArrayList<VarEntity> getVars() {
return this.vars;
}
public void addFunction(FunctionEntity functionEntity) {
this.functions.add(functionEntity);
}
public ArrayList<FunctionEntity> getFunctions() {
return this.functions;
}
public HashMap<Object, Expression> expressions() {
return expressions;
}
public void addExpression(Object key, Expression expression) {
expressions.put(key, expression);
}
/**
* A common utility function used to transfer the identifiers
* to types.
* @param inferer - the inferer object
* @param identifiers - the identifiers will be translated
* @return The translated Types
*/
protected Collection<TypeEntity> identiferToTypes(Inferer inferer, Collection<String> identifiers) {
ArrayList<TypeEntity> r = new ArrayList<>();
for (String typeParameter : identifiers) {
TypeEntity typeEntity = inferer.inferTypeFromName(this, typeParameter);
if (typeEntity==null) {
if (((ContainerEntity)getParent()).isGenericTypeParameter(typeParameter)) {
typeEntity = Inferer.genericParameterType;
}
}
if (typeEntity != null)
r.add(typeEntity);
}
return r;
}
/**
* For all data in the class, infer their types.
* Should be override in sub-classes
*/
public void inferLocalLevelEntities(Inferer inferer) {
resolvedTypeParameters = identiferToTypes(inferer, typeParameters);
resolvedAnnotations = identiferToTypes(inferer, annotations);
for (VarEntity var : this.vars) {
var.inferLocalLevelEntities(inferer);
}
for (FunctionEntity func:this.functions) {
func.inferLocalLevelEntities(inferer);
}
}
/**
* Resolve all expression's type
* @param inferer
*/
public void resolveExpressions(Inferer inferer) {
for (Expression expression : expressions.values()) {
//1. if expression's type existed, break;
if (expression.getType() != null)
continue;
//2. if expression's rawType existed, directly infer type by rawType
// if expression's rawType does not existed, infer type based on identifiers
if (expression.rawType != null) {
expression.setType(inferer.inferTypeFromName(this, expression.rawType),null,inferer);
}else if (expression.isDot){ //wait for previous
continue;
} else if (expression.rawType!=null) {
expression.setType(inferer.inferTypeFromName(this, expression.rawType),null,inferer);
if (expression.getType() !=null) {
continue;
}
}
if (expression.identifier!=null) {
Entity entity = inferer.resolveName(this, expression.identifier, true);
if (entity!=null) {
expression.setType(entity.getType(),entity,inferer);
continue;
}
if (expression.isCall) {
FunctionEntity func = this.lookupFunctionInVisibleScope(expression.identifier);
if (func!=null) {
expression.setType(func.getType(),func,inferer);
}
}else {
VarEntity varEntity = this.lookupVarsInVisibleScope(expression.identifier);
if (varEntity!=null) {
expression.setType( varEntity.getType(),varEntity,inferer);
}
}
}
}
}
public Collection<TypeEntity> getResolvedTypeParameters() {
return resolvedTypeParameters;
}
public Collection<TypeEntity> getResolvedAnnotations() {
return resolvedAnnotations;
}
public String dumpExpressions() {
StringBuilder sb = new StringBuilder();
for (Expression exp:expressions.values()) {
sb.append(exp.toString()).append("\n");
}
return sb.toString();
}
public boolean isGenericTypeParameter(String rawType) {
if (this.typeParameters.contains(rawType)) return true;
if (this.getParent()==null || !(this.getParent() instanceof ContainerEntity))
return false;
return ((ContainerEntity)getParent()).isGenericTypeParameter(rawType);
}
protected FunctionEntity lookupFunctionLocally(String functionName) {
for (FunctionEntity func : getFunctions()) {
if (func.getRawName().equals(functionName))
return func;
}
return null;
}
public FunctionEntity lookupFunctionInVisibleScope(String functionName) {
ContainerEntity fromEntity = this;
while (fromEntity != null) {
if (fromEntity instanceof ContainerEntity) {
FunctionEntity func = ((ContainerEntity) fromEntity).lookupFunctionLocally(functionName);
if (func != null)
return func;
}
fromEntity = (ContainerEntity) this.getAncestorOfType(ContainerEntity.class);
}
return null;
}
/**
* To found the var. Must be invoked after all entities var binding solved
* @param fromEntity
* @param varName
* @return
*/
public VarEntity lookupVarsInVisibleScope(String varName) {
ContainerEntity fromEntity = this;
while (fromEntity != null) {
if (fromEntity instanceof ContainerEntity) {
VarEntity var = ((ContainerEntity) fromEntity).lookupVarLocally(varName);
if (var != null)
return var;
}
fromEntity = (ContainerEntity) this.getAncestorOfType(ContainerEntity.class);
}
return null;
}
private VarEntity lookupVarLocally(String varName) {
for (VarEntity var:getVars()) {
if (var.getRawName().equals(varName))
return var;
}
return null;
}
}

View File

@ -0,0 +1,9 @@
package depends.entity;
public class EmptyTypeEntity extends TypeEntity {
public EmptyTypeEntity() {
super("", null, -1);
}
}

View File

@ -0,0 +1,152 @@
package depends.entity;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import depends.relations.Inferer;
import depends.relations.Relation;
/**
* Entity is the root of all entities, including file, package, module,
* class, method/function etc.
* Each entity has unique id, name,qualifiedName, parent, children
* We also use entity to record relations
*/
public abstract class Entity {
int id=-1;
String qualifiedName = null;
String rawName = "";
Entity parent;
Set<Entity> children = new HashSet<>();
ArrayList<Relation> relations = new ArrayList<>();
public Entity(String rawName, Entity parent, Integer id) {
this.qualifiedName = null;
this.rawName = rawName;
this.parent = parent;
this.id = id;
if (parent!=null)
parent.children.add(this);
deduceQualifiedName();
}
/**
* Rule 1: if it contains '.' , then the name is equal to raw name
* Rule 2: if parent not exists, the name is equal to raw name
* Rule 3: if parent exists but no qualified name exists or empty, the name is equal to raw name
* Rule 4: otherwise, qualified name = parent_qualfied_name + "."+rawName
* Rule 5: make sure the qualified name do not start with '.'
* TODO: the Rule 1 should be further check. Maybe issue exists - (C++中的ClassName::MethodName()会不会有问题
*/
private void deduceQualifiedName() {
rawName = rawName.replace("::","." );
if (this.rawName.contains(".")) {
this.qualifiedName = this.rawName;
return; //already qualified
}
if (parent==null) {
this.qualifiedName = this.rawName;
return;
}
if (parent.getQualifiedName()==null) {
this.qualifiedName = this.rawName;
return;
}
if (parent.getQualifiedName().isEmpty()) {
this.qualifiedName = rawName;
return;
}
this.qualifiedName= parent.getQualifiedName()+"." + rawName;
if (rawName.startsWith(".")) {
rawName = rawName.substring(2);
}
}
public String getRawName() {
return rawName;
}
public int getId() {
return id;
}
public void addRelation(Relation relation) {
relations.add(relation);
}
public ArrayList<Relation> getRelations() {
return relations;
}
public void addChild(Entity child) {
children.add(child);
}
public Entity getParent() {
return parent;
}
public void setParent(Entity parent) {
this.parent = parent;
}
public Collection<Entity> getChildren() {
return children;
}
public void setQualifiedName(String qualifiedName) {
this.qualifiedName = qualifiedName;
}
public void setRawName(String rawName) {
this.rawName = rawName;
}
public String getQualifiedName() {
return qualifiedName;
}
@Override
public String toString() {
return "Entity [id=" + id + ", qualifiedName=" + qualifiedName + ", rawName=" + rawName + "]";
}
/**
* Get ancestor of type.
* @param classType
* @return null (if not exist) or the type
*/
public Entity getAncestorOfType(@SuppressWarnings("rawtypes") Class classType) {
Entity fromEntity = this;
while(fromEntity!=null) {
if (fromEntity.getClass().equals(classType))
return fromEntity;
if (fromEntity.getParent()==null) return null;
fromEntity = fromEntity.getParent();
}
return null;
}
/**
* Invoke inferer to resolve the entity type etc.
* */
public void inferEntities(Inferer inferer) {
inferLocalLevelEntities(inferer);
for (Entity child:children) {
child.inferEntities(inferer);
}
}
public abstract void inferLocalLevelEntities(Inferer inferer);
public TypeEntity getType() {
return null;
}
public String getDisplayName() {
return getRawName();
}
}

View File

@ -0,0 +1,107 @@
package depends.entity;
import depends.relations.Inferer;
public class Expression {
public Integer id;
public Integer parentId;
public Integer deduceTypeBasedId; //by default, parent expression type determined by most left child
public Expression parent;
public String text; // for debug purpose
public String rawType; //the raw type name
public String identifier; // the varName, or method name, etc.
public boolean isSet = false; // is a set relation from right to leftHand
public boolean isDot = false; // is a dot expression, will decuce variable tfype left to right
public boolean isCall = false;
public boolean isLogic = false;
public boolean isCreate = false;
public boolean isCast = false;
public boolean deriveTypeFromChild = true;
private TypeEntity type; // the type we care - for relation calculation.
//for leaf, it equals to referredEntity.getType. otherwise, depends on child's type strategy
private Entity referredEntity;
public TypeEntity getType() {
return type;
}
public void setType(TypeEntity type, Entity referredEntity, Inferer inferer) {
if (this.type!=null) return;
this.type = type;
this.referredEntity = referredEntity;
if (this.referredEntity==null)
this.referredEntity = type;
deduceParentType(inferer);
}
public Expression(Integer id, Integer parentId) {
this.id = id;
this.parentId = parentId;
}
@Override
public String toString() {
StringBuilder s = new StringBuilder();
s.append("[").append(text).append("]").append("|")
.append("rawType:").append(rawType).append("|")
.append("identifier:").append(identifier).append("|")
.append("prop:").append(isDot?"[dot]":"")
.append(isSet?"[set]":"")
.append(isLogic?"[bool]":"")
.append(isCall?"[call]":"").append("|")
.append("parent:").append(parent==null?"none":parent.text)
.append("type:").append(type).append("|");
return s.toString();
}
/**
* deduce type of parent based on child's type
* @param expressionList
* @param inferer
*/
public void deduceParentType(Inferer inferer) {
if (this.type==null) return;
if (this.parent==null) return;
Expression parent = this.parent;
if (parent.type != null)return;
if (!parent.deriveTypeFromChild) return;
//parent's type depends on first child's type
if (parent.deduceTypeBasedId!=this.id) return;
//if child is a built-in/external type, then parent must also a built-in/external type
if (this.type.equals(Inferer.buildInType)) {
parent.setType(Inferer.buildInType,Inferer.buildInType,inferer);
return;
}else if (this.type.equals(Inferer.externalType)){
parent.setType(Inferer.externalType,Inferer.externalType,inferer);
return;
}
/* if it is a logic expression, the return type/type is boolean. */
if (parent.isLogic) {
parent.setType(Inferer.buildInType,null,inferer);
}
/* if it is a.b, and we already get a's type, b's type could be identified easily */
else if (parent.isDot) {
if (parent.isCall) {
FunctionEntity func = this.getType().lookupFunctionInVisibleScope(parent.identifier);
if (func!=null)
parent.setType(func.getType(), func,inferer);
}else {
parent.setType(inferer.inferTypeFromName(this.getType(), parent.identifier),null,inferer);
if (parent.type!=null) return;
VarEntity var = this.getType().lookupVarsInVisibleScope(parent.identifier);
if (var!=null)
parent.setType(var.getType(),var, inferer);
}
}
/* if other situation, simple make the parent and child type same */
else {
parent.setType(type, null, inferer);
}
}
public Entity getReferredEntity() {
return referredEntity;
}
}

View File

@ -0,0 +1,89 @@
package depends.entity;
import java.util.ArrayList;
import java.util.List;
import depends.importtypes.Import;
import depends.relations.Inferer;
public class FileEntity extends ContainerEntity {
private List<Import> importedNames = new ArrayList<>();
private boolean isInProjectScope = false;
private List<Entity> importedRelationEntities = new ArrayList<>();
private List<Entity> importedFiles = new ArrayList<>();
private List<Entity> importedTypes = new ArrayList<>();
public FileEntity(String fullName, int fileId, boolean isInProjectScope) {
super(fullName, null, fileId);
setQualifiedName(fullName);
}
public FileEntity(String fullName, int fileId) {
this(fullName, fileId, true);
}
public void addImport(Import imported) {
importedNames.add(imported);
}
/**
* To match the imported name by suffix
* for example:
* import a.b.ClassX;
* the b.ClassX, ClassX , a.b.classX should be matched
* @param lastName
* @return
*/
public String importedSuffixMatch(String lastName) {
if (!lastName.startsWith("."))
lastName = "." + lastName;
for (Entity imported : this.importedTypes) {
String name = imported.getQualifiedName();
if (!name.startsWith("."))
name = "." + name;
if (imported.getQualifiedName().endsWith(lastName))
return imported.getQualifiedName();
}
return null;
}
@Override
public String getQualifiedName() {
if (this.getParent() == null) {
return "";
}
if (this.getParent() instanceof PackageEntity)
return this.getParent().getQualifiedName();
else
return super.getQualifiedName();
}
@Override
public void inferLocalLevelEntities(Inferer inferer) {
this.importedRelationEntities = inferer.getImportedRelationEntities(importedNames);
this.importedTypes = inferer.getImportedTypes(importedNames);
this.importedFiles = inferer.getImportedFiles(importedNames);
super.inferLocalLevelEntities(inferer);
}
public boolean isInProjectScope() {
return isInProjectScope;
}
public void setInProjectScope(boolean isInProjectScope) {
this.isInProjectScope = isInProjectScope;
}
public List<Entity> getImportedRelationEntities() {
return importedRelationEntities;
}
public List<Entity> getImportedFiles() {
return importedFiles;
}
public List<Entity> getImportedTypes() {
return importedTypes;
}
}

View File

@ -0,0 +1,78 @@
package depends.entity;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import depends.relations.Inferer;
public class FunctionEntity extends ContainerEntity{
private List<String> returnTypeIdentifiers = new ArrayList<>();
Collection<VarEntity> parameters;
Collection<String> throwTypesIdentifiers = new ArrayList<>();
private Collection<TypeEntity> returnTypes = new ArrayList<>();
private TypeEntity returnType;
private Collection<TypeEntity> throwTypes = new ArrayList<>();
public FunctionEntity(String simpleName, Entity parent, Integer id, String returnType) {
super(simpleName, parent,id);
this.returnTypes = new ArrayList<>();
returnTypeIdentifiers = new ArrayList<>();
this.parameters = new ArrayList<>();
throwTypesIdentifiers = new ArrayList<>();
addReturnType(returnType);
}
public Collection<TypeEntity> getReturnTypes() {
return returnTypes;
}
@Override
public TypeEntity getType() {
return returnType;
}
public void addReturnType(String returnType) {
this.returnTypeIdentifiers.add(returnType);
}
public void addThrowTypes(List<String> throwedType) {
throwTypesIdentifiers.addAll(throwedType);
}
@Override
public void inferLocalLevelEntities(Inferer inferer) {
for (VarEntity param:parameters) {
param.inferLocalLevelEntities(inferer);
}
returnTypes= identiferToTypes(inferer,this.returnTypeIdentifiers);
if (returnTypes.size()>0)
returnType = returnTypes.iterator().next();
throwTypes= identiferToTypes(inferer,this.throwTypesIdentifiers);
super.inferLocalLevelEntities(inferer);
}
public Collection<VarEntity> getParameters() {
return parameters;
}
public Collection<TypeEntity> getThrowTypes() {
return throwTypes;
}
@Override
public VarEntity lookupVarsInVisibleScope(String varName) {
for (VarEntity param:parameters) {
if (varName.equals(param.getRawName())) {
return param;
}
}
return super.lookupVarsInVisibleScope(varName);
}
public void addParameter(VarEntity var) {
this.parameters.add(var);
}
public void setReturnType(TypeEntity returnType) {
this.returnType = returnType;
}
@Override
public String getDisplayName() {
FileEntity f = (FileEntity) this.getAncestorOfType(FileEntity.class);
return f.getRawName()+"("+getRawName()+")";
}
}

View File

@ -0,0 +1,55 @@
package depends.entity;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import depends.relations.Inferer;
/**
* MultiDeclareEntity is a special container, which is used as a wrapper
* of multi-declaration. for example,
* in C++, a function could be declared in different place with the same signature.
*/
public class MultiDeclareEntities extends ContainerEntity {
List<ContainerEntity> entities = new ArrayList<>();
public MultiDeclareEntities(Entity entity, int id ) {
super(entity.getRawName(), entity.getParent(), id);
if (entity instanceof ContainerEntity)
entities.add((ContainerEntity)entity);
}
@Override
public void inferLocalLevelEntities(Inferer inferer) {
for (Entity entity:entities) {
entity.inferLocalLevelEntities(inferer);
}
}
public void add(Entity entity) {
if (entity instanceof ContainerEntity)
entities.add((ContainerEntity)entity);
}
public List<ContainerEntity> getEntities() {
return entities;
}
@Override
public Collection<Entity> getChildren() {
List<Entity> children = new ArrayList<>();
for (Entity entity:entities) {
children.addAll(entity.getChildren());
}
return children;
}
@Override
public TypeEntity getType() {
for (Entity entity:entities) {
if(entity.getType()!=null);
return entity.getType();
}
return null;
}
}

View File

@ -0,0 +1,12 @@
package depends.entity;
public class PackageEntity extends TypeEntity {
public PackageEntity(String rawName, Integer id) {
super(rawName, null,id);
setQualifiedName(rawName); //in Java, package raw name = full name
}
public PackageEntity(String rawName, FileEntity currentFile, Integer id) {
super(rawName, currentFile,id);
}
}

View File

@ -0,0 +1,43 @@
package depends.entity;
import java.util.Collection;
import depends.relations.Inferer;
public class TypeAliasEntity extends TypeEntity{
TypeEntity originType = new EmptyTypeEntity();
String originTypeName;
public TypeAliasEntity(String simpleName, Entity parent, Integer id, String originTypeName) {
super(simpleName, parent, id);
this.originTypeName = originTypeName;
}
@Override
public void inferLocalLevelEntities(Inferer inferer) {
Entity entity = inferer.resolveName(this, originTypeName, true);
TypeEntity type = null;
if (entity!=null)
type = entity.getType();
if (type!=null)
originType = type;
if (type == this) {
System.err.println("cannot typedef as self");
}
originType.inferLocalLevelEntities(inferer);
}
@Override
public Collection<TypeEntity> getInheritedTypes() {
return originType.getInheritedTypes();
}
@Override
public Collection<TypeEntity> getImplementedTypes() {
return originType.getImplementedTypes();
}
@Override
public TypeEntity getInheritedType() {
return originType.getInheritedType();
}
public TypeEntity getOriginType() {
return originType;
}
}

View File

@ -0,0 +1,72 @@
package depends.entity;
import java.util.ArrayList;
import java.util.Collection;
import depends.relations.Inferer;
public class TypeEntity extends ContainerEntity{
Collection<TypeEntity> inheritedTypes = new ArrayList<>();
Collection<TypeEntity> implementedTypes = new ArrayList<>();
Collection<String> inhertedTypeIdentifiers;
Collection<String> implementedIdentifiers;
TypeEntity inheritedType;
public TypeEntity(String simpleName, Entity parent, Integer id) {
super(simpleName,parent,id);
inhertedTypeIdentifiers = new ArrayList<>();
implementedIdentifiers = new ArrayList<>();
}
@Override
public void inferLocalLevelEntities(Inferer inferer) {
inheritedTypes= identiferToTypes(inferer,this.inhertedTypeIdentifiers);
implementedTypes= identiferToTypes(inferer,this.implementedIdentifiers);
if (inheritedTypes.size()>0)
inheritedType = inheritedTypes.iterator().next();
super.inferLocalLevelEntities(inferer);
}
public void addImplements(String typeName) {
if (typeName.equals(this.getRawName())) return;
if (implementedIdentifiers.contains(typeName)) return;
this.implementedIdentifiers.add(typeName);
}
public void addExtends(String typeName) {
if (typeName.equals(this.getRawName())) return;
if (inhertedTypeIdentifiers.contains(typeName)) return;
this.inhertedTypeIdentifiers.add(typeName);
}
public Collection<TypeEntity> getInheritedTypes() {
return inheritedTypes;
}
public Collection<TypeEntity> getImplementedTypes() {
return implementedTypes;
}
public TypeEntity getInheritedType() {
return inheritedType;
}
@Override
protected FunctionEntity lookupFunctionLocally(String functionName) {
FunctionEntity funcType = super.lookupFunctionLocally(functionName);
if (funcType!=null) return funcType;
for (TypeEntity inhertedType : getInheritedTypes()) {
funcType = inhertedType.lookupFunctionLocally(functionName);
if (funcType == null)
break;
}
if (funcType != null)
return funcType;
for (TypeEntity implType : getImplementedTypes()) {
funcType = implType.lookupFunctionLocally( functionName);
if (funcType == null)
break;
}
return funcType;
}
@Override
public TypeEntity getType() {
return this;
}
}

View File

@ -0,0 +1,37 @@
package depends.entity;
import depends.relations.Inferer;
public class VarEntity extends Entity {
private String rawType;
private TypeEntity type;
public VarEntity(String simpleName, String rawType, Entity parent, int id) {
super(simpleName, parent,id);
this.rawType = rawType;
}
public String getRawType() {
return rawType;
}
@Override
public TypeEntity getType() {
return type;
}
public void setType(TypeEntity type) {
this.type = type;
}
@Override
public void inferLocalLevelEntities(Inferer inferer) {
Entity entity = inferer.resolveName(this, rawType, true);
if (entity==null) return;
type = entity.getType();
if (type==null) {
if (((ContainerEntity)getParent()).isGenericTypeParameter(rawType)) {
type = Inferer.genericParameterType;
}
}
}
}

View File

@ -0,0 +1,38 @@
package depends.entity.repo;
import java.util.HashSet;
import java.util.Set;
import depends.relations.Inferer;
public abstract class BuiltInType {
public void createBuiltInTypes() {
for(String prefix:getBuiltInPrefixStr()) {
builtInPrefix.add(prefix);
}
for (String type:getBuiltInTypeStr()) {
builtInType.add(type);
}
}
public abstract String[] getBuiltInTypeStr();
public abstract String[] getBuiltInPrefixStr() ;
private Set<String> builtInType = new HashSet<>();
private Set<String> builtInPrefix = new HashSet<>();
public boolean isBuiltInType(String type) {
if (Inferer.buildInType.getRawName().equals(type)) return true;
return builtInType.contains(type);
}
public boolean isBuiltInTypePrefix(String type) {
for (String prefix:builtInPrefix) {
if (type.startsWith(prefix)) return true;
}
return false;
}
}

View File

@ -0,0 +1,11 @@
package depends.entity.repo;
public class EntityNotExistsException extends Exception {
private static final long serialVersionUID = 8897694627699543193L;
public EntityNotExistsException(int entityId) {
super("given id "+ entityId + " not exists.");
}
}

View File

@ -0,0 +1,54 @@
package depends.entity.repo;
import java.util.Collection;
import java.util.HashMap;
import depends.entity.Entity;
import depends.entity.MultiDeclareEntities;
public class EntityRepo extends IdGenerator{
public HashMap<String, Entity> allEntieisByName = new HashMap<>();
public HashMap<Integer, Entity> allEntitiesById = new HashMap<>();
public EntityRepo() {
}
public Entity getEntity(String entityName) {
return allEntieisByName.get(entityName);
}
public Entity getEntity(Integer entityId) {
return allEntitiesById.get(entityId);
}
public void add(Entity entity) {
allEntitiesById.put(entity.getId(), entity);
String name = entity.getRawName();
if (entity.getQualifiedName()!=null && !(entity.getQualifiedName().isEmpty()) ) {
name = entity.getQualifiedName();
}
if (allEntieisByName.containsKey(name)) {
Entity existedEntity = allEntieisByName.get(name);
if (existedEntity instanceof MultiDeclareEntities) {
((MultiDeclareEntities)existedEntity).add(entity);
}else {
MultiDeclareEntities eMultiDeclare = new MultiDeclareEntities(existedEntity,this.generateId());
eMultiDeclare.add(entity);
allEntieisByName.put(name, eMultiDeclare);
}
}else {
allEntieisByName.put(name, entity);
}
if (entity.getParent()!=null)
this.setParent(entity, entity.getParent());
}
public Collection<Entity> getEntities() {
return allEntitiesById.values();
}
public void setParent(Entity child, Entity parent) {
child.setParent(parent);
parent.addChild(child);
}
}

View File

@ -0,0 +1,15 @@
package depends.entity.repo;
public class IdGenerator {
private int nextAvaliableIndex;
public IdGenerator() {
nextAvaliableIndex = 0;
}
/**
* Generate a global unique ID for entity
* @return the unique id
*/
public Integer generateId() {
return nextAvaliableIndex++;
}
}

View File

@ -0,0 +1,12 @@
package depends.entity.repo;
public class NoRequestedTypeOfAncestorExistsException extends Exception {
private static final long serialVersionUID = -5951549776366770294L;
public NoRequestedTypeOfAncestorExistsException(int entityId, @SuppressWarnings("rawtypes") Class classType) {
super("the given type of " + classType.getCanonicalName() + " for "
+ entityId + " does not exists.");
}
}

View File

@ -0,0 +1,15 @@
package depends.entity.repo;
public class NullBuiltInType extends BuiltInType {
@Override
public String[] getBuiltInTypeStr() {
return new String[] {};
}
@Override
public String[] getBuiltInPrefixStr() {
return new String[] {};
}
}

View File

@ -0,0 +1,114 @@
package depends.extractor;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.codehaus.plexus.util.FileUtils;
import depends.entity.repo.EntityRepo;
import depends.matrix.DependencyGenerator;
import depends.matrix.DependencyMatrix;
import depends.relations.Inferer;
import depends.util.FileTraversal;
abstract public class AbstractLangWorker {
public abstract String supportedLanguage();
public abstract String[] fileSuffixes();
protected Inferer inferer;
protected EntityRepo entityRepo;
DependencyMatrix dependencyMatrix;
private String inputSrcPath;
private String[] includeDirs;
private DependencyGenerator dependencyGenerator;
public AbstractLangWorker(String inputDir, String[] includeDir) {
entityRepo = new EntityRepo();
this.inputSrcPath = inputDir;
this.includeDirs = includeDir;
}
public void work() {
parseAllFiles();
resolveBindings();
identifyDependencies();
}
/**
* Errors during all execution steps. could be extend as several methods in future
* @return
*/
public abstract List<String> getErrors();
/**
*
* @return unsolved bindings
*/
protected void resolveBindings() {
System.out.println("Resolve types and bindings of variables, methods and expressions....");
Set<String> unsolved = inferer.resolveAllBindings();
if (unsolved.size()>0)
System.err.println("The following items are unsolved." + unsolved);
System.out.println("types and bindings resolved successfully...");
}
private void identifyDependencies(){
System.out.println("dependencie data generating...");
dependencyMatrix = dependencyGenerator.build(entityRepo);
dependencyMatrix.remapIds(entityRepo);
System.out.println("dependencie data generating done successfully...");
}
private final void parseAllFiles() {
System.out.println("start parsing files...");
FileTraversal fileTransversal = new FileTraversal(new FileTraversal.IFileVisitor(){
@Override
public void visit(File file) {
FileParser fileParser = getFileParser(file.getAbsolutePath());
try {
System.out.println("parsing " + file.getAbsolutePath()
+ "...");
fileParser.parse();
} catch (IOException e) {
e.printStackTrace();
}
}
});
fileTransversal.extensionFilter(this.fileSuffixes());
fileTransversal.travers(this.inputSrcPath);
System.out.println("all files procceed successfully...");
}
protected abstract FileParser getFileParser(String fileFullPath);
public List<String> includePaths() {
ArrayList<String> r = new ArrayList<String>();
for (String path:includeDirs) {
if (FileUtils.fileExists(path)) {
if (!r.contains(path))
r.add(path);
}
path = this.inputSrcPath +File.separator+path;
if (FileUtils.fileExists(path)) {
if (!r.contains(path))
r.add(path);
}
}
return r;
}
public DependencyMatrix getDependencies() {
return dependencyMatrix;
}
public EntityRepo getEntityRepo() {
return this.entityRepo;
}
public void setDependencyGenerator(DependencyGenerator dependencyGenerator) {
this.dependencyGenerator = dependencyGenerator;
}
}

View File

@ -0,0 +1,8 @@
package depends.extractor;
import java.io.IOException;
public interface FileParser {
void parse() throws IOException;
}

View File

@ -0,0 +1,178 @@
package depends.extractor;
import java.util.List;
import java.util.Stack;
import depends.entity.ContainerEntity;
import depends.entity.Entity;
import depends.entity.FileEntity;
import depends.entity.FunctionEntity;
import depends.entity.TypeAliasEntity;
import depends.entity.TypeEntity;
import depends.entity.VarEntity;
import depends.entity.repo.EntityRepo;
import depends.entity.repo.IdGenerator;
import depends.importtypes.Import;
public abstract class HandlerContext {
protected EntityRepo entityRepo;
protected IdGenerator idGenerator;
protected FileEntity currentFileEntity;
public HandlerContext(EntityRepo entityRepo) {
this.entityRepo = entityRepo;
this.idGenerator = entityRepo;
entityStack = new Stack<Entity>();
}
public FileEntity startFile(String fileName) {
currentFileEntity = new FileEntity(fileName, idGenerator.generateId(),true);
pushToStack(currentFileEntity);
entityRepo.add(currentFileEntity);
return currentFileEntity;
}
public Entity foundNewType(String classOrInterfaceName) {
TypeEntity currentTypeEntity = new TypeEntity(classOrInterfaceName, this.latestValidContainer(),
idGenerator.generateId());
pushToStack(currentTypeEntity);
entityRepo.add(currentTypeEntity);
return currentTypeEntity;
}
public void foundNewTypeAlias(String aliasName, String originalName) {
if (aliasName.equals(originalName)) return; //it is a tricky, we treat same name no different.
//indeed it is not perfect -> the right match should depends on no-bare format like "struct a" instead of "a"
TypeAliasEntity currentTypeEntity = new TypeAliasEntity(aliasName, this.latestValidContainer(),
idGenerator.generateId(),originalName );
entityRepo.add(currentTypeEntity);
return ;
}
public FunctionEntity foundMethodDeclarator(String methodName, String returnType, List<String> throwedType) {
FunctionEntity functionEntity = new FunctionEntity(methodName, this.latestValidContainer(),
idGenerator.generateId(),returnType);
entityRepo.add(functionEntity);
this.typeOrFileContainer().addFunction(functionEntity);
pushToStack(functionEntity);
functionEntity.addThrowTypes(throwedType);
return functionEntity;
}
public void foundNewImport(Import imported) {
currentFileEntity.addImport(imported);
}
public TypeEntity currentType() {
for (int i = entityStack.size() - 1; i >= 0; i--) {
Entity t = entityStack.get(i);
if (t instanceof TypeEntity)
return (TypeEntity) t;
}
return null;
}
public ContainerEntity typeOrFileContainer() {
for (int i = entityStack.size() - 1; i >= 0; i--) {
Entity t = entityStack.get(i);
if (t instanceof TypeEntity)
return (ContainerEntity) t;
if (t instanceof FileEntity) {
return (ContainerEntity)t;
}
}
return null;
}
public FunctionEntity currentFunction() {
for (int i = entityStack.size() - 1; i >= 0; i--) {
Entity t = entityStack.get(i);
if (t instanceof FunctionEntity)
return (FunctionEntity) t;
}
return null;
}
public FileEntity currentFile() {
return currentFileEntity;
}
public Entity latestValidContainer() {
for (int i = entityStack.size() - 1; i >= 0; i--) {
Entity t = entityStack.get(i);
if (t instanceof FunctionEntity)
return t;
if (t instanceof TypeEntity)
return t;
if (t instanceof FileEntity)
return t;
}
return null;
}
public ContainerEntity lastContainer() {
for (int i = entityStack.size() - 1; i >= 0; i--) {
Entity t = entityStack.get(i);
if (t instanceof ContainerEntity)
return (ContainerEntity) t;
}
return null;
}
public void foundAnnotation(String name) {
lastContainer().addAnnotation(name);
}
public void foundImplements(String typeName) {
currentType().addImplements(typeName);
}
public void foundExtends(String typeName) {
if (currentType()==null) {
System.out.println("error: type do not exist");
}
currentType().addExtends(typeName);
}
public void foundTypeParametes(String typeName) {
lastContainer().addTypeParameter(typeName);
}
public void foundVarDefinition(List<String> varNames, String type) {
for (String varName : varNames) {
foundVarDefintion(varName,type);
}
}
public void foundVarDefintion(String varName, String type) {
VarEntity var = new VarEntity(varName, type, lastContainer(), idGenerator.generateId());
lastContainer().addVar(var);
}
public void foundEnumConstDefinition(String varName) {
String type = lastContainer().getRawName();
foundVarDefintion(varName,type);
}
protected Stack<Entity> entityStack = new Stack<Entity>();
private void pushToStack(Entity entity) {
entityStack.push(entity);
}
public void exitLastedEntity() {
entityStack.pop();
}
}

View File

@ -0,0 +1,18 @@
package depends.extractor;
import java.util.HashMap;
public class LangWorkers {
private static LangWorkers inst = new LangWorkers();
public HashMap<String, AbstractLangWorker> workers = new HashMap<>();
public static LangWorkers getRegistry() {
return inst;
}
public AbstractLangWorker getWorkerOf(String lang) {
return workers.get(lang);
}
public void register(AbstractLangWorker worker) {
if (getWorkerOf(worker.supportedLanguage())!=null) return;
workers.put(worker.supportedLanguage(), worker);
}
}

View File

@ -0,0 +1,47 @@
package depends.extractor.cpp;
import depends.entity.repo.BuiltInType;
public class CppBuiltInType extends BuiltInType {
public CppBuiltInType() {
super.createBuiltInTypes();
}
@Override
public String[] getBuiltInTypeStr() {
return new String[] { "alignas", "alignof", "asm", "auto", "bool", "break", "case", "catch", "char",
"char16_t", "char32_t", "class", "const", "constexpr", "const_cast", "continue", "decltype",
"default", "delete", "do", "double", "dynamic_cast", "else", "enum", "explicit", "export", "extern",
"false", "final", "float", "for", "friend", "goto", "if", "inline", "int", "long", "mutable",
"namespace", "new", "noexcept", "nullptr", "operator", "override", "private", "protected", "public",
"register", "reinterpret_cast", "return", "short", "signed", "sizeof", "static", "static_assert",
"static_cast", "struct", "switch", "template", "this", "thread_local", "throw", "true", "try",
"typedef", "typeid", "typename", "union", "unsigned", "using", "virtual", "void", "volatile",
"wchar_t", "while", "<Built-in>",
"__cplusplus","_cpp_aggregate_bases","__cpp_aggregate_nsdmi","__cpp_alias_templates","__cpp_aligned_new",
"__cpp_attributes","__cpp_binary_literals","__cpp_capture_star_this","__cpp_constexpr","__cpp_decltype",
"__cpp_decltype_auto","__cpp_deduction_guides","__cpp_delegating_constructors",
"__cpp_enumerator_attributes","__cpp_explicit_bool","__cpp_fold_expressions","__cpp_generic_lambdas",
"__cpp_guaranteed_copy_elision","__cpp_hex_float","__cpp_if_constexpr","__cpp_inheriting_constructors",
"__cpp_init_captures","__cpp_initializer_lists","__cpp_inline_variables","__cpp_lambdas",
"__cpp_namespace_attributes","__cpp_noexcept_function_type","__cpp_nontype_template_args",
"__cpp_nontype_template_parameter_auto","__cpp_nontype_template_parameter_class","__cpp_nsdmi"
+ "","__cpp_range_based_for","__cpp_raw_strings","__cpp_ref_qualifiers","__cpp_return_type_deduction"
,"__cpp_rvalue_references","__cpp_sized_deallocation","__cpp_static_assert","__cpp_structured_bindings",
"__cpp_template_template_args","__cpp_threadsafe_static_init","__cpp_unicode_characters","__cpp_unicode_literals",
"__cpp_user_defined_literals","__cpp_variable_templates","__cpp_variadic_templates","__cpp_variadic_using",
"__DATE__","__FILE__","__LINE__","__STDC__","__STDC_ANALYZABLE__","__STDC_HOSTED__","__STDC_IEC_559__",
"__STDC_IEC_559_COMPLEX__","__STDC_ISO_10646__","__STDC_LIB_EXT1__","__STDC_MB_MIGHT_NEQ_WC__",
"__STDC_NO_ATOMICS__","__STDC_NO_COMPLEX__","__STDC_NO_THREADS__","__STDC_NO_VLA__",
"__STDCPP_DEFAULT_NEW_ALIGNMENT__","__STDCPP_STRICT_POINTER_SAFETY__","__STDCPP_THREADS__",
"__STDC_UTF_16__","__STDC_UTF_32__","__STDC_VERSION__","__TIME__"
};
}
@Override
public String[] getBuiltInPrefixStr() {
return new String[] {"__"};
}
}

View File

@ -0,0 +1,14 @@
package depends.extractor.cpp;
import depends.entity.repo.EntityRepo;
import depends.relations.Inferer;
public abstract class CppFileParser implements depends.extractor.FileParser {
protected String fileFullPath;
protected EntityRepo entityRepo;
public CppFileParser(String fileFullPath, EntityRepo entityRepo, Inferer inferer) {
this.fileFullPath = fileFullPath;
this.entityRepo = entityRepo;
}
}

View File

@ -0,0 +1,87 @@
package depends.extractor.cpp;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import depends.entity.Entity;
import depends.entity.FileEntity;
import depends.entity.repo.EntityRepo;
import depends.importtypes.FileImport;
import depends.importtypes.Import;
import depends.relations.ImportLookupStrategy;
import depends.relations.Inferer;
public class CppImportLookupStrategy implements ImportLookupStrategy {
@Override
public Entity lookupImportedType(String name, FileEntity fileEntity, EntityRepo repo, Inferer inferer) {
String importedString = fileEntity.importedSuffixMatch(name);
if (importedString!=null) {
Entity r = repo.getEntity(importedString);
if (r!=null) return r;
}
HashSet<String> fileSet = new HashSet<>();
foundIncludedFiles(fileSet, fileEntity.getImportedFiles(),repo);
for (String file:fileSet) {
Entity importedItem = repo.getEntity(file);
if (importedItem instanceof FileEntity) {
FileEntity importedFile = (FileEntity) repo.getEntity(file);
if (importedFile==null) continue;
Entity entity = inferer.resolveName(importedFile,name, false);
if (entity!=null) return entity;
List<Entity> namespaces = fileEntity.getImportedTypes();
for (Entity ns:namespaces) {
String nameWithPrefix = ns.getQualifiedName() + "." + name;
entity = inferer.resolveName(importedFile,nameWithPrefix, false);
if (entity!=null) return entity;
}
}
}
return null;
}
private void foundIncludedFiles(HashSet<String> fileSet, List<Entity> importedFiles, EntityRepo repo) {
for (Entity file:importedFiles) {
if (file==null ) continue;
if (!(file instanceof FileEntity)) continue;
if (fileSet.contains(file.getRawName())) continue;
fileSet.add(file.getRawName());
foundIncludedFiles(fileSet,((FileEntity)file).getImportedFiles(),repo);
}
}
@Override
public List<Entity> getImportedRelationEntities(List<Import> importedList, EntityRepo repo) {
ArrayList<Entity> result = new ArrayList<>();
for (Import importedItem:importedList) {
if (importedItem instanceof FileImport) {
Entity imported = repo.getEntity(importedItem.getContent());
if (imported==null) continue;
result.add(imported);
}
}
return result;
}
@Override
public List<Entity> getImportedTypes(List<Import> importedList, EntityRepo repo) {
ArrayList<Entity> result = new ArrayList<>();
for (Import importedItem:importedList) {
if (!(importedItem instanceof FileImport)) {
Entity imported = repo.getEntity(importedItem.getContent());
if (imported==null) continue;
result.add(imported);
}
}
return result;
}
@Override
public List<Entity> getImportedFiles(List<Import> importedList, EntityRepo repo) {
return getImportedRelationEntities(importedList,repo);
}
}

View File

@ -0,0 +1,43 @@
package depends.extractor.cpp;
import java.util.ArrayList;
import java.util.List;
import depends.extractor.AbstractLangWorker;
import depends.extractor.FileParser;
import depends.extractor.cpp.cdt.CdtCppFileParser;
import depends.extractor.cpp.cdt.PreprocessorHandler;
import depends.relations.Inferer;
public class CppWorker extends AbstractLangWorker {
private static final String LANG = "cpp";
private static final String[] SUFFIX = new String[] {".cpp",".cc",".c",".h",".hpp",".hh"};
PreprocessorHandler preprocessorHandler;
public CppWorker(String inputDir, String[] includeDir) {
super(inputDir,includeDir);
preprocessorHandler = new PreprocessorHandler(super.includePaths());
inferer = new Inferer(entityRepo,new CppImportLookupStrategy(),new CppBuiltInType());
}
@Override
public String supportedLanguage() {
return LANG;
}
@Override
public String[] fileSuffixes() {
return SUFFIX;
}
@Override
protected FileParser getFileParser(String fileFullPath) {
return new CdtCppFileParser(fileFullPath,entityRepo,preprocessorHandler,inferer);
//return new Antlr4CppFileParser(fileFullPath,entityRepo,super.includePaths());
}
public List<String> getErrors(){
return new ArrayList<String>(preprocessorHandler.getNotExistedIncludedFiles());
}
}

View File

@ -0,0 +1,22 @@
package depends.extractor.cpp.cdt;
import org.eclipse.cdt.core.dom.parser.c.ANSICParserExtensionConfiguration;
class ANSICParserExtensionConfigurationExtension extends ANSICParserExtensionConfiguration {
@Override
public boolean supportDeclspecSpecifiers() {
return false;
}
@Override
public boolean supportKnRC() {
return false;
}
@Override
public boolean supportStatementsInExpressions() {
return false;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,71 @@
package depends.extractor.cpp.cdt;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.parser.IScannerExtensionConfiguration;
import org.eclipse.cdt.core.dom.parser.cpp.GPPScannerExtensionConfiguration;
import org.eclipse.cdt.core.parser.CodeReader;
import org.eclipse.cdt.core.parser.FileContent;
import org.eclipse.cdt.core.parser.IScanner;
import org.eclipse.cdt.core.parser.NullLogService;
import org.eclipse.cdt.core.parser.ParserLanguage;
import org.eclipse.cdt.core.parser.ParserMode;
import org.eclipse.cdt.core.parser.ScannerInfo;
import org.eclipse.cdt.internal.core.dom.parser.AbstractGNUSourceCodeParser;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTTranslationUnit;
import org.eclipse.cdt.internal.core.dom.parser.cpp.GNUCPPSourceParser;
import org.eclipse.cdt.internal.core.parser.scanner.CPreprocessor;
@SuppressWarnings("deprecation")
public class CDTParser {
List<String> sysIncludePath = new ArrayList<>();
public CDTParser() {
}
public CDTParser(List<String> includesPath) {
for (String f:includesPath) {
File file = new File(f);
if (file.exists()) {
try {
sysIncludePath.add(file.getCanonicalPath());
} catch (IOException e) {
}
}else {
//System.err.println("include path " + f + " does not exist!");
}
}
}
NullLogService NULL_LOG = new NullLogService();
Map<String, String> macroMap = new HashMap<>();
public IASTTranslationUnit parse(String file ) {
CodeReader cr;
try {
cr = new CodeReader(file);
return getTranslationUnitofCPP(file,new String(cr.buffer));
} catch (IOException e) {
}
return new CASTTranslationUnit();
}
private IASTTranslationUnit getTranslationUnitofCPP(String file, String content) {
IScannerExtensionConfiguration configuration = GPPScannerExtensionConfiguration
.getInstance();
IScanner scanner = new CPreprocessor(FileContent.create(file,
content.toCharArray()), new ScannerInfo(new HashMap<>(),sysIncludePath.toArray(new String[] {})), ParserLanguage.CPP,
new NullLogService(), configuration, null);
AbstractGNUSourceCodeParser sourceCodeParser = new GNUCPPSourceParser(
scanner, ParserMode.COMPLETE_PARSE, new NullLogService(),
new GPPParserExtensionConfigurationExtension(), null);
IASTTranslationUnit astTranslationUnit = sourceCodeParser.parse();
return astTranslationUnit;
}
}

View File

@ -0,0 +1,276 @@
package depends.extractor.cpp.cdt;
import java.util.ArrayList;
import org.codehaus.plexus.util.StringUtils;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTProblem;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDirective;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTLinkageSpecification;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTProblemDeclaration;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTVisibilityLabel;
import depends.entity.Expression;
import depends.entity.FunctionEntity;
import depends.entity.VarEntity;
import depends.entity.repo.EntityRepo;
import depends.entity.repo.IdGenerator;
import depends.importtypes.ExactMatchImport;
import depends.importtypes.FileImport;
import depends.importtypes.PackageWildCardImport;
import depends.relations.Inferer;
public class CdtCppEntitiesListener extends ASTVisitor {
private CppHandlerContext context;
private IdGenerator idGenerator;
private PreprocessorHandler preprocessorHandler;
private EntityRepo entityRepo;
Inferer inferer;
private ExpressionUsage expressionUsage;
public CdtCppEntitiesListener(String fileFullPath, EntityRepo entityRepo, PreprocessorHandler preprocessorHandler,Inferer inferer) {
super(true);
this.context = new CppHandlerContext(entityRepo);
idGenerator = entityRepo;
this.entityRepo = entityRepo;
this.inferer = inferer;
context.startFile(fileFullPath);
this.preprocessorHandler = preprocessorHandler;
expressionUsage = new ExpressionUsage(context,entityRepo);
}
@Override
public int visit(IASTTranslationUnit tu) {
for (String incl:preprocessorHandler.getDirectIncludedFiles(tu.getAllPreprocessorStatements())) {
context.foundNewImport(new FileImport(incl));
CdtCppFileParser importedParser = new CdtCppFileParser(incl, entityRepo, preprocessorHandler,inferer);
importedParser.parse(false);
}
MacroExtractor macroExtractor = new MacroExtractor(tu.getAllPreprocessorStatements());
for (String var:macroExtractor.getMacroVars()) {
context.foundVarDefintion(var,Inferer.buildInType.getRawName());
}
for (String var:macroExtractor.getMacroFuncs()) {
context.foundMethodDeclarator(var, Inferer.buildInType.getRawName(), new ArrayList<>());
context.exitLastedEntity();
}
return super.visit(tu);
}
@Override
public int visit(IASTProblem problem) {
System.out.println("warning: parse error" + problem.getOriginalNode() + problem.getMessageWithLocation());
return super.visit(problem);
}
// PACKAGES
@Override
public int visit(ICPPASTNamespaceDefinition namespaceDefinition) {
String ns = namespaceDefinition.getName().toString().replace("::", ".");
context.foundNamespace(ns);
context.foundNewImport(new PackageWildCardImport(ns));
return super.visit(namespaceDefinition);
}
@Override
public int leave(ICPPASTNamespaceDefinition namespaceDefinition) {
context.exitLastedEntity();
return super.leave(namespaceDefinition);
}
// Types
@Override
public int visit(IASTDeclSpecifier declSpec) {
if (declSpec instanceof IASTCompositeTypeSpecifier) {
IASTCompositeTypeSpecifier type = (IASTCompositeTypeSpecifier)declSpec;
context.foundNewType(type.getName().toString());
if (declSpec instanceof ICPPASTCompositeTypeSpecifier) {
ICPPASTBaseSpecifier[] baseSpecififers = ((ICPPASTCompositeTypeSpecifier)declSpec).getBaseSpecifiers();
for (ICPPASTBaseSpecifier baseSpecififer:baseSpecififers) {
String extendName = new String(baseSpecififer.getNameSpecifier().toCharArray());
context.foundExtends(extendName);
}
}
}
else if (declSpec instanceof IASTEnumerationSpecifier) {
IASTEnumerationSpecifier type = (IASTEnumerationSpecifier)declSpec;
context.foundNewType(type.getName().toString());
}else {
//we do not care other types
}
return super.visit(declSpec);
}
@Override
public int leave(IASTDeclSpecifier declSpec) {
if (declSpec instanceof IASTCompositeTypeSpecifier) {
context.exitLastedEntity();
}
else if (declSpec instanceof IASTEnumerationSpecifier) {
context.exitLastedEntity();
}else {
//we do not care other types
}
return super.leave(declSpec);
}
//Function or Methods
@Override
public int visit(IASTDeclarator declarator) {
if (declarator instanceof IASTFunctionDeclarator){
String returnType = null;
if ( declarator.getParent() instanceof IASTSimpleDeclaration) {
IASTSimpleDeclaration decl = (IASTSimpleDeclaration)(declarator.getParent());
returnType = ASTStringUtil.getName(decl.getDeclSpecifier());
String rawName = declarator.getName().toString();
FunctionEntity namedEntity = context.currentFile().lookupFunctionInVisibleScope(rawName);
if (namedEntity!=null) {
rawName = namedEntity.getQualifiedName();
}
returnType = reMapIfConstructDeconstruct(rawName,returnType);
context.foundMethodDeclarator(rawName, returnType, new ArrayList<>());
}
else if ( declarator.getParent() instanceof IASTFunctionDefinition) {
IASTFunctionDefinition decl = (IASTFunctionDefinition)declarator.getParent();
returnType= ASTStringUtil.getReturnTypeString(decl.getDeclSpecifier(), decl.getDeclarator());
String rawName = declarator.getName().toString();
FunctionEntity namedEntity = context.currentFile().lookupFunctionInVisibleScope(rawName);
if (namedEntity!=null) {
rawName = namedEntity.getQualifiedName();
}
returnType = reMapIfConstructDeconstruct(rawName,returnType);
context.foundMethodDeclarator(rawName, returnType, new ArrayList<>());
}
}
return super.visit(declarator);
}
/**
* In case of return type is empty, it maybe a construct/deconstruct function
* @param functionname
* @param returnType
* @return
*/
private String reMapIfConstructDeconstruct(String functionname, String returnType) {
if (returnType.length()>0) return returnType;
if (functionname.contains("::")) {
return functionname.substring(0, functionname.indexOf("::"));
}else {
return functionname;
}
}
@Override
public int leave(IASTDeclarator declarator) {
if (declarator instanceof IASTFunctionDeclarator){
if ( declarator.getParent() instanceof IASTSimpleDeclaration) {
String rawName = declarator.getName().toString();
if (rawName.equals(context.lastContainer().getRawName())) {
context.exitLastedEntity();
}else {
System.err.println("unexpected symbol");
}
}
}
return super.leave(declarator);
}
@Override
public int leave(IASTDeclaration declaration) {
if ( declaration instanceof IASTFunctionDefinition) {
context.exitLastedEntity();
}
return super.leave(declaration);
}
// Variables
@Override
public int visit(IASTDeclaration declaration) {
if (declaration instanceof ICPPASTUsingDeclaration) {
String ns = ((ICPPASTUsingDeclaration)declaration).getName().toString().replace("::", ".");
context.foundNewImport(new PackageWildCardImport(ns));
}
else if (declaration instanceof ICPPASTUsingDirective) {
String ns = ((ICPPASTUsingDirective)declaration).getQualifiedName().toString().replace("::", ".");
context.foundNewImport(new ExactMatchImport(ns));
}
else if (declaration instanceof IASTSimpleDeclaration ) {
for (IASTDeclarator declarator:((IASTSimpleDeclaration) declaration).getDeclarators()) {
IASTDeclSpecifier declSpecifier = ((IASTSimpleDeclaration) declaration).getDeclSpecifier();
//Found new typedef definition
if (declSpecifier.getStorageClass()==IASTDeclSpecifier.sc_typedef) {
context.foundNewTypeAlias(declarator.getName().toString(),ASTStringUtil.getName(declSpecifier));
}else if (!(declarator instanceof IASTFunctionDeclarator)) {
String varType = ASTStringUtil.getName(declSpecifier);
String varName = declarator.getName().toString();
if (!StringUtils.isEmpty(varType)) {
context.foundVarDefintion(varName, varType);
}else {
expressionUsage.foundCallExpressionOfFunctionStyle(varName,declarator);
}
}
}
}else if (declaration instanceof IASTFunctionDefinition){
//handled in declarator
}else if (declaration instanceof CPPASTVisibilityLabel){
//we ignore the visibility in dependency check
}else if (declaration instanceof CPPASTLinkageSpecification){
}else if (declaration instanceof CPPASTProblemDeclaration){
System.err.println("parsing error \n" + declaration.getRawSignature());
}else {
System.out.println(declaration.getClass().getName());
System.out.println(declaration.getRawSignature());
}
return super.visit(declaration);
}
@Override
public int visit(IASTEnumerator enumerator) {
context.foundVarDefintion(enumerator.getName().toString(), context.currentType().getRawName());
return super.visit(enumerator);
}
@Override
public int visit(IASTExpression expression) {
expressionUsage.foundExpression(expression);
return super.visit(expression);
}
@Override
public int visit(IASTParameterDeclaration parameterDeclaration) {
String parameterName = parameterDeclaration.getDeclarator().getName().toString();
String parameterType = ASTStringUtil.getName(parameterDeclaration.getDeclSpecifier());
if (context.currentFunction()!=null) {
VarEntity var = new VarEntity(parameterName,parameterType,context.currentFunction(),idGenerator.generateId());
context.currentFunction().addParameter(var );
}else {
//System.out.println("** parameterDeclaration = " + parameter);
}
return super.visit(parameterDeclaration);
}
}

View File

@ -0,0 +1,50 @@
package depends.extractor.cpp.cdt;
import java.io.IOException;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import depends.entity.Entity;
import depends.entity.FileEntity;
import depends.entity.repo.EntityRepo;
import depends.extractor.cpp.CppFileParser;
import depends.relations.Inferer;
import depends.util.FileUtil;
public class CdtCppFileParser extends CppFileParser {
private PreprocessorHandler preprocessorHandler ;
private Inferer inferer;
public CdtCppFileParser(String fileFullPath, EntityRepo entityRepo,PreprocessorHandler preprocessorHandler, Inferer inferer) {
super(fileFullPath, entityRepo,inferer);
this.preprocessorHandler = preprocessorHandler;
this.fileFullPath = FileUtil.uniqFilePath(fileFullPath);
this.inferer = inferer;
}
@Override
public void parse() throws IOException {
parse(true);
}
/**
*
* @param isInScope whether the parse is invoked by project file or an 'indirect' included file
*/
public void parse(boolean isInScope) {
/** If file already exist, skip it */
Entity fileEntity = entityRepo.getEntity(fileFullPath);
if (fileEntity!=null && fileEntity instanceof FileEntity) {
FileEntity t = ((FileEntity)fileEntity);
if (!t.isInProjectScope() && isInScope)
t.setInProjectScope(true);
return;
}
CdtCppEntitiesListener bridge = new CdtCppEntitiesListener(fileFullPath, entityRepo, preprocessorHandler,inferer);
IASTTranslationUnit translationUnit = (new CDTParser(preprocessorHandler.getIncludePaths())).parse(fileFullPath);
translationUnit.accept(bridge);
}
}

View File

@ -0,0 +1,61 @@
package depends.extractor.cpp.cdt;
import org.eclipse.cdt.core.dom.ast.IASTComment;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.internal.core.dom.parser.ASTTranslationUnit;
public class CommentManager {
private IASTTranslationUnit translationUnit;
IASTComment[] comments;
boolean[] joinWithNext;
public CommentManager(IASTTranslationUnit translationUnit) {
this.translationUnit = translationUnit;
comments = ((ASTTranslationUnit) translationUnit).getComments();
joinWithNext = new boolean[comments.length];
for (int i=1;i<comments.length;i++) {
IASTComment previous = comments[i-1];
int previousEnd = (previous.getFileLocation().getNodeOffset()+
previous.getFileLocation().getNodeLength());
IASTComment current = comments[i];
if (current.getFileLocation().getNodeOffset()-previousEnd<5)
joinWithNext[i-1] = true;
else
joinWithNext[i-1] = false;
}
joinWithNext[comments.length-1] = false;
}
public String getLeadingCommentText(int startOffset) {
int adjacent = findCommentIndex(startOffset);
if (adjacent==-1) return "";
String comment = new String( comments[adjacent].getComment());
int i=adjacent-1;
while(i>=0) {
if (joinWithNext[i]) {
comment = new String(comments[i].getComment())+comment;
i--;
}else {
break;
}
}
return comment;
}
private int findCommentIndex(int startOffset) {
IASTComment[] comments = ((ASTTranslationUnit) translationUnit).getComments();
int i=0;
for (;i<comments.length;i++) {
IASTComment c = comments[i];
int gap = startOffset-(c.getFileLocation().getNodeOffset()+
c.getFileLocation().getNodeLength());
if (gap>0 && gap<10) {
break;
}
if (gap<0) return -1;
}
return i>=comments.length?-1:i;
}
}

View File

@ -0,0 +1,20 @@
package depends.extractor.cpp.cdt;
import depends.entity.Entity;
import depends.entity.PackageEntity;
import depends.entity.repo.EntityRepo;
import depends.extractor.HandlerContext;
public class CppHandlerContext extends HandlerContext {
public CppHandlerContext(EntityRepo entityRepo) {
super(entityRepo);
}
public Entity foundNamespace(String nampespaceName) {
PackageEntity pkgEntity = new PackageEntity(nampespaceName, currentFile(),idGenerator.generateId());
entityRepo.add(pkgEntity);
entityStack.push(pkgEntity);
return pkgEntity;
}
}

View File

@ -0,0 +1,190 @@
package depends.extractor.cpp.cdt;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNewExpression;
import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression;
import org.eclipse.cdt.core.dom.ast.IASTCastExpression;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression;
import depends.entity.Expression;
import depends.entity.repo.IdGenerator;
import depends.extractor.HandlerContext;
public class ExpressionUsage {
HandlerContext context;
IdGenerator idGenerator;
public ExpressionUsage(HandlerContext context,IdGenerator idGenerator) {
this.context = context;
this.idGenerator = idGenerator;
}
public void foundCallExpressionOfFunctionStyle(String functionName, IASTDeclarator declarator) {
/* create expression and link it with parent*/
Expression expression = new Expression(idGenerator.generateId(),null);
context.lastContainer().addExpression(declarator,expression);
expression.isCall = true;
expression.identifier = functionName;
}
public void foundExpression(IASTExpression ctx) {
Expression parent = findParentInStack(ctx);
/* create expression and link it with parent*/
Expression expression = new Expression(idGenerator.generateId(),parent==null?null:parent.id);
expression.text = ctx.getRawSignature(); //for debug purpose. no actual effect
context.lastContainer().addExpression(ctx,expression);
if (parent!=null) {
if (parent.deduceTypeBasedId==null) parent.deduceTypeBasedId = expression.id;
expression.parent = parent;
}
if (isTerminalExpression(ctx)) {
tryFillExpressionTypeAndIdentifier(ctx,expression);
return;
}
expression.isSet = isSet(ctx);
expression.isCall = (ctx instanceof IASTFunctionCallExpression)?true:false;
expression.isLogic = isLogic(ctx);
if (ctx instanceof ICPPASTNewExpression){
expression.isCreate = true;
}
expression.isDot = isDot(ctx);
/**
* | expression bop='.'
( IDENTIFIER
| methodCall
)
*/
//method call
if (ctx instanceof IASTFunctionCallExpression) {
expression.identifier = getMethodCallIdentifier((IASTFunctionCallExpression)ctx);
expression.isCall = true;
}
if (ctx instanceof ICPPASTNewExpression) {
expression.rawType = ASTStringUtil.getTypeIdString(((ICPPASTNewExpression)ctx).getTypeId());
expression.isCall = true;
expression.deriveTypeFromChild = false;
}
if (ctx instanceof IASTCastExpression) {
expression.isCast=true;
expression.rawType = ASTStringUtil.getTypeIdString(((IASTCastExpression)ctx).getTypeId());
expression.deriveTypeFromChild = false;
}
if (expression.isDot) {
IASTExpression op2 = ((IASTBinaryExpression)ctx).getOperand2();
if (op2 instanceof IASTIdExpression)
expression.identifier = ((IASTIdExpression)op2).getName().toString();
else if (op2 instanceof IASTLiteralExpression)
expression.identifier = ((IASTLiteralExpression)op2).getRawSignature();
else if (op2 instanceof IASTFunctionCallExpression)
expression.identifier = getMethodCallIdentifier((IASTFunctionCallExpression)op2);
return;
}
}
private boolean isTerminalExpression(IASTExpression ctx) {
if(ctx instanceof IASTIdExpression) return true;
if(ctx instanceof IASTLiteralExpression) return true;
if(ctx instanceof IASTTypeIdExpression) return true;
//TODO: add others
return false;
}
private void tryFillExpressionTypeAndIdentifier(IASTExpression ctx, Expression expression) {
//1. we only handle leaf node. if there is still expression,
// the type will be determined by child node in the expression
if (ctx instanceof IASTIdExpression){
expression.identifier = ((IASTIdExpression) ctx).getName().toString();
}else if (ctx instanceof IASTLiteralExpression) {
//2. if it is a var name, dertermine the type based on context.
expression.identifier = "<Literal>";
expression.rawType = "<Built-in>";
}else if (ctx instanceof IASTTypeIdExpression) {
//3. if given type directly
expression.rawType = ASTStringUtil.getTypeIdString(((IASTTypeIdExpression)ctx).getTypeId());
//TODO: check
}
}
private String getMethodCallIdentifier(IASTFunctionCallExpression methodCall) {
IASTExpression f = methodCall.getFunctionNameExpression();
if (f instanceof IASTIdExpression) {
return ((IASTIdExpression)f).getName().toString();
}
return null;
}
private boolean isDot(IASTExpression ctx) {
if (ctx instanceof IASTBinaryExpression) {
int op = ((IASTBinaryExpression)ctx).getOperator();
if (op==IASTBinaryExpression.op_pmdot ||
op==IASTBinaryExpression.op_pmarrow ) return true;
}
return false;
}
private boolean isLogic(IASTExpression ctx) {
if (ctx instanceof IASTBinaryExpression) {
int op = ((IASTBinaryExpression)ctx).getOperator();
if (op == IASTBinaryExpression.op_equals ||
op == IASTBinaryExpression.op_notequals ||
op == IASTBinaryExpression.op_lessThan ||
op == IASTBinaryExpression.op_lessEqual ||
op == IASTBinaryExpression.op_greaterThan ||
op == IASTBinaryExpression.op_greaterEqual ||
op == IASTBinaryExpression.op_logicalAnd ||
op == IASTBinaryExpression.op_logicalOr
) {
return true;
}
}
return false;
}
public boolean isSet(IASTExpression ctx) {
if (ctx instanceof IASTBinaryExpression) {
int op = ((IASTBinaryExpression)ctx).getOperator();
if (op>=IASTBinaryExpression.op_assign &&
op<=IASTBinaryExpression.op_binaryOrAssign) {
return true;
}
}
if (ctx instanceof IASTUnaryExpression) {
int op = ((IASTUnaryExpression)ctx).getOperator();
if (op == IASTUnaryExpression.op_prefixIncr ||
op == IASTUnaryExpression.op_prefixDecr ||
op == IASTUnaryExpression.op_postFixIncr ||
op == IASTUnaryExpression.op_postFixIncr
)
return true;
}
return false;
}
private Expression findParentInStack(IASTNode ctx) {
if (ctx==null) return null;
if (ctx.getParent()==null) return null;
if (context.lastContainer()==null) {
return null;
}
if (context.lastContainer().expressions().containsKey(ctx.getParent())) return context.lastContainer().expressions().get(ctx.getParent());
return findParentInStack(ctx.getParent());
}
}

View File

@ -0,0 +1,22 @@
package depends.extractor.cpp.cdt;
import org.eclipse.cdt.core.dom.parser.cpp.GPPParserExtensionConfiguration;
class GPPParserExtensionConfigurationExtension extends GPPParserExtensionConfiguration {
@Override
public boolean supportKnRC() {
return false;
}
@Override
public boolean supportParameterInfoBlock() {
return false;
}
@Override
public boolean supportStatementsInExpressions() {
return false;
}
}

View File

@ -0,0 +1,31 @@
package depends.extractor.cpp.cdt;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorFunctionStyleMacroDefinition;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorObjectStyleMacroDefinition;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement;
public class MacroExtractor {
ArrayList<String> macroVars = new ArrayList<>();
ArrayList<String> macroFuncs = new ArrayList<>();
public MacroExtractor(IASTPreprocessorStatement[] statements) {
for (int statementIndex=0;statementIndex<statements.length;statementIndex++) {
if (statements[statementIndex] instanceof IASTPreprocessorFunctionStyleMacroDefinition) {
IASTPreprocessorFunctionStyleMacroDefinition funcMacro = (IASTPreprocessorFunctionStyleMacroDefinition)statements[statementIndex];
macroFuncs.add(funcMacro.getName().getRawSignature());
}else if (statements[statementIndex] instanceof IASTPreprocessorObjectStyleMacroDefinition) {
IASTPreprocessorObjectStyleMacroDefinition varMacro = (IASTPreprocessorObjectStyleMacroDefinition)statements[statementIndex];
macroVars.add(varMacro.getName().getRawSignature());
}
}
}
public List<String> getMacroVars() {
return macroVars;
}
public List<String> getMacroFuncs() {
return macroFuncs;
}
}

View File

@ -0,0 +1,49 @@
package depends.extractor.cpp.cdt;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement;
import depends.util.FileUtil;
public class PreprocessorHandler {
private HashMap<String, String> notExistedIncludedFiles = new HashMap<>();
public Collection<String> getNotExistedIncludedFiles() {
return notExistedIncludedFiles.values();
}
private List<String> includePaths;
public PreprocessorHandler(List<String> includePaths){
notExistedIncludedFiles = new HashMap<>();
this.setIncludePaths(includePaths);
}
public List<String> getDirectIncludedFiles(IASTPreprocessorStatement[] statements) {
ArrayList<String> includedFullPathNames = new ArrayList<>();
for (int statementIndex=0;statementIndex<statements.length;statementIndex++) {
if (statements[statementIndex] instanceof IASTPreprocessorIncludeStatement)
{
IASTPreprocessorIncludeStatement incl = (IASTPreprocessorIncludeStatement)(statements[statementIndex]);
String path = FileUtil.uniqFilePath(incl.getPath());
includedFullPathNames.add(path);
if (!FileUtil.existFile(path)) {
if (!notExistedIncludedFiles.containsKey(path)) {
notExistedIncludedFiles.put(path,"Error: " + path + " does not exist in include path!");
}
continue;
}
}
}
return includedFullPathNames;
}
public List<String> getIncludePaths() {
return includePaths;
}
public void setIncludePaths(List<String> includePaths) {
this.includePaths = includePaths;
}
}

View File

@ -0,0 +1,64 @@
package depends.extractor.java;
import depends.entity.repo.BuiltInType;
public class JavaBuiltInType extends BuiltInType{
public JavaBuiltInType() {
super.createBuiltInTypes();
}
@Override
public String[] getBuiltInTypeStr() {
return new String[]{
"void","int","double","char","byte","boolean","long","short","float",
"BigDecimal","Integer","Double","Char","Byte","Boolean","Long","Short","Float",
"String","Object","Class","Exception","StringBuilder",
"Appendable","AutoCloseable","Cloneable","Comparable","Iterable","Readable",
"Runnable","Thread.UncaughtExceptionHandler","Boolean","Byte","Character","Character.Subset",
"Character.UnicodeBlock","ClassLoader","ClassValue","Compiler","Double","Enum",
"InheritableThreadLocal","Math","Number","Package","Process",
"ProcessBuilder","ProcessBuilder.Redirect","Runtime","RuntimePermission",
"SecurityManager","StackTraceElement","StrictMath","StringBuffer",
"System","Thread","ThreadGroup","ThreadLocal","Throwable","Void","ProcessBuilder.Redirect.Type",
"Thread.State","ArithmeticException","ArrayIndexOutOfBoundsException",
"ArrayStoreException","ClassCastException","ClassNotFoundException","CloneNotSupportedException",
"EnumConstantNotPresentException","Exception","IllegalAccessException","IllegalArgumentException",
"IllegalMonitorStateException","IllegalStateException","IllegalThreadStateException",
"IndexOutOfBoundsException","InstantiationException","InterruptedException",
"NegativeArraySizeException","NoSuchFieldException","NoSuchMethodException","NullPointerException",
"NumberFormatException","ReflectiveOperationException","RuntimeException","SecurityException",
"StringIndexOutOfBoundsException","TypeNotPresentException","UnsupportedOperationException","AbstractMethodError",
"AssertionError","BootstrapMethodError","ClassCircularityError","ClassFormatError","Error","ExceptionInInitializerError",
"IllegalAccessError","IncompatibleClassChangeError","InstantiationError","InternalError","LinkageError","NoClassDefFoundError"
,"NoSuchFieldError","NoSuchMethodError","OutOfMemoryError","StackOverflowError","ThreadDeath","UnknownError",
"UnsatisfiedLinkError","UnsupportedClassVersionError","VerifyError","VirtualMachineError","Deprecated","Override",
"SafeVarargs","SuppressWarnings",
"Collection","Comparator","Deque","Enumeration","EventListener","Formattable","Iterator","List",
"ListIterator","Map","Map.Entry","NavigableMap","NavigableSet","Observer","Queue","RandomAccess",
"Set","SortedMap","SortedSet","AbstractCollection","AbstractList","AbstractMap","AbstractMap.SimpleEntry",
"AbstractMap.SimpleImmutableEntry","AbstractQueue","AbstractSequentialList","AbstractSet","ArrayDeque",
"ArrayList","Arrays","BitSet","Calendar","Collections","Currency","Date","Dictionary","EnumMap","EnumSet",
"EventListenerProxy","EventObject","FormattableFlags","Formatter","GregorianCalendar","HashMap","HashSet",
"Hashtable","IdentityHashMap","LinkedHashMap","LinkedHashSet","LinkedList","ListResourceBundle","Locale",
"Locale.Builder","Objects","Observable","PriorityQueue","Properties","PropertyPermission",
"PropertyResourceBundle","Random","ResourceBundle","ResourceBundle.Control","Scanner",
"ServiceLoader","SimpleTimeZone","Stack","StringTokenizer","Timer","TimerTask","TimeZone",
"TreeMap","TreeSet","UUID","Vector","WeakHashMap","Formatter.BigDecimalLayoutForm",
"Locale.Category","ConcurrentModificationException","DuplicateFormatFlagsException",
"EmptyStackException","FormatFlagsConversionMismatchException","FormatterClosedException",
"IllegalFormatCodePointException","IllegalFormatConversionException","IllegalFormatException",
"IllegalFormatFlagsException","IllegalFormatPrecisionException","IllegalFormatWidthException",
"IllformedLocaleException","InputMismatchException","InvalidPropertiesFormatException","MissingFormatArgumentException",
"MissingFormatWidthException","MissingResourceException","NoSuchElementException","TooManyListenersException",
"UnknownFormatConversionException","UnknownFormatFlagsException","ServiceConfigurationError",
"<Built-in>"
};
}
@Override
public String[] getBuiltInPrefixStr() {
return new String[]{
"java.","javax.","com.sun."
};
}
}

View File

@ -0,0 +1,325 @@
package depends.extractor.java;
import java.util.ArrayList;
import java.util.List;
import depends.entity.FunctionEntity;
import depends.entity.repo.EntityRepo;
import depends.extractor.java.context.AnnotationProcessor;
import depends.extractor.java.context.ClassTypeContextHelper;
import depends.extractor.java.context.ExpressionUsage;
import depends.extractor.java.context.FormalParameterListContextHelper;
import depends.extractor.java.context.IdentifierContextHelper;
import depends.extractor.java.context.QualitiedNameContextHelper;
import depends.extractor.java.context.TypeParameterContextHelper;
import depends.extractor.java.context.VariableDeclaratorsContextHelper;
import depends.importtypes.ExactMatchImport;
import depends.extractor.java.JavaParser.AnnotationConstantRestContext;
import depends.extractor.java.JavaParser.AnnotationMethodRestContext;
import depends.extractor.java.JavaParser.AnnotationTypeDeclarationContext;
import depends.extractor.java.JavaParser.BlockContext;
import depends.extractor.java.JavaParser.ClassDeclarationContext;
import depends.extractor.java.JavaParser.ConstDeclarationContext;
import depends.extractor.java.JavaParser.ConstructorDeclarationContext;
import depends.extractor.java.JavaParser.EnhancedForControlContext;
import depends.extractor.java.JavaParser.EnumConstantContext;
import depends.extractor.java.JavaParser.EnumDeclarationContext;
import depends.extractor.java.JavaParser.ExpressionContext;
import depends.extractor.java.JavaParser.FieldDeclarationContext;
import depends.extractor.java.JavaParser.ImportDeclarationContext;
import depends.extractor.java.JavaParser.InterfaceDeclarationContext;
import depends.extractor.java.JavaParser.InterfaceMethodDeclarationContext;
import depends.extractor.java.JavaParser.LocalVariableDeclarationContext;
import depends.extractor.java.JavaParser.MethodDeclarationContext;
import depends.extractor.java.JavaParser.PackageDeclarationContext;
import depends.extractor.java.JavaParser.ResourceContext;
import depends.extractor.java.JavaParser.TypeParameterContext;
import depends.extractor.java.JavaParser.TypeParametersContext;
import depends.extractor.java.JavaParserBaseListener;
public class JavaEntitiesListener extends JavaParserBaseListener {
private JavaHandlerContext context;
private AnnotationProcessor annotationProcessor;
private ExpressionUsage expressionUsage;
private EntityRepo entityRepo;
public JavaEntitiesListener(String fileFullPath, EntityRepo entityRepo) {
this.context = new JavaHandlerContext(entityRepo);
this.entityRepo = entityRepo;
annotationProcessor = new AnnotationProcessor(context);
expressionUsage = new ExpressionUsage(context,entityRepo);
context.startFile(fileFullPath);
}
////////////////////////
// Package
@Override
public void enterPackageDeclaration(PackageDeclarationContext ctx) {
context.foundNewPackage(QualitiedNameContextHelper.getName(ctx.qualifiedName()));
super.enterPackageDeclaration(ctx);
}
////////////////////////
// Import
@Override
public void enterImportDeclaration(ImportDeclarationContext ctx) {
context.foundNewImport(new ExactMatchImport(ctx.qualifiedName().getText()));
super.enterImportDeclaration(ctx);
}
///////////////////////
// Class or Interface
// classDeclaration | enumDeclaration | interfaceDeclaration |
/////////////////////// annotationTypeDeclaration
@Override
public void enterClassDeclaration(ClassDeclarationContext ctx) {
context.foundNewType(ctx.IDENTIFIER().getText());
// implements
if (ctx.typeList() != null) {
for (int i = 0; i < ctx.typeList().typeType().size(); i++) {
context.foundImplements(ClassTypeContextHelper.getClassName(ctx.typeList().typeType().get(i)));
}
}
// extends relation
if (ctx.typeType() != null) {
context.foundExtends(ClassTypeContextHelper.getClassName(ctx.typeType()));
}
if (ctx.typeParameters() != null) {
foundTypeParametersUse(ctx.typeParameters());
}
annotationProcessor.processAnnotationModifier(ctx, "classOrInterfaceModifier");
super.enterClassDeclaration(ctx);
}
@Override
public void exitClassDeclaration(ClassDeclarationContext ctx) {
exitLastEntity();
super.exitClassDeclaration(ctx);
}
@Override
public void enterEnumDeclaration(EnumDeclarationContext ctx) {
context.foundNewType(ctx.IDENTIFIER().getText());
annotationProcessor.processAnnotationModifier(ctx, "classOrInterfaceModifier");
super.enterEnumDeclaration(ctx);
}
@Override
public void exitEnumDeclaration(EnumDeclarationContext ctx) {
exitLastEntity();
super.exitEnumDeclaration(ctx);
}
/**
* interfaceDeclaration : INTERFACE IDENTIFIER typeParameters? (EXTENDS
* typeList)? interfaceBody ;
*/
@Override
public void enterInterfaceDeclaration(InterfaceDeclarationContext ctx) {
context.foundNewType(ctx.IDENTIFIER().getText());
// type parameters
if (ctx.typeParameters() != null) {
foundTypeParametersUse(ctx.typeParameters());
}
// extends relation
if (ctx.typeList() != null) {
for (int i = 0; i < ctx.typeList().typeType().size(); i++) {
context.foundExtends(ClassTypeContextHelper.getClassName(ctx.typeList().typeType().get(i)));
}
}
annotationProcessor.processAnnotationModifier(ctx, "classOrInterfaceModifier");
super.enterInterfaceDeclaration(ctx);
}
@Override
public void exitInterfaceDeclaration(InterfaceDeclarationContext ctx) {
exitLastEntity();
super.exitInterfaceDeclaration(ctx);
}
@Override
public void enterAnnotationTypeDeclaration(AnnotationTypeDeclarationContext ctx) {
context.foundNewType(ctx.IDENTIFIER().getText());
annotationProcessor.processAnnotationModifier(ctx, "classOrInterfaceModifier");
super.enterAnnotationTypeDeclaration(ctx);
}
@Override
public void exitAnnotationTypeDeclaration(AnnotationTypeDeclarationContext ctx) {
exitLastEntity();
super.exitAnnotationTypeDeclaration(ctx);
}
/////////////////////////
// Method
@Override
public void enterMethodDeclaration(MethodDeclarationContext ctx) {
List<String> throwedType = QualitiedNameContextHelper.getNames(ctx.qualifiedNameList());
String methodName = ctx.IDENTIFIER().getText();
String returnedType = ClassTypeContextHelper.getClassName(ctx.typeTypeOrVoid());
FunctionEntity method = context.foundMethodDeclarator(methodName, returnedType, throwedType);
new FormalParameterListContextHelper(ctx.formalParameters(), method, entityRepo);
if (ctx.typeParameters() != null) {
List<String> parameters = TypeParameterContextHelper.getTypeParameters(ctx.typeParameters());
method.addTypeParameter(parameters);
}
annotationProcessor.processAnnotationModifier(ctx, "classOrInterfaceModifier");
super.enterMethodDeclaration(ctx);
}
@Override
public void exitMethodDeclaration(MethodDeclarationContext ctx) {
exitLastEntity();
super.exitMethodDeclaration(ctx);
}
private void exitLastEntity() {
context.exitLastedEntity();
}
// interfaceMethodDeclaration
// : interfaceMethodModifier* (typeTypeOrVoid | typeParameters annotation* typeTypeOrVoid)
// IDENTIFIER formalParameters ('[' ']')* (THROWS qualifiedNameList)? methodBody
@Override
public void enterInterfaceMethodDeclaration(InterfaceMethodDeclarationContext ctx) {
List<String> throwedType = QualitiedNameContextHelper.getNames(ctx.qualifiedNameList());
FunctionEntity method = context.foundMethodDeclarator(ctx.IDENTIFIER().getText(),
ClassTypeContextHelper.getClassName(ctx.typeTypeOrVoid()), throwedType);
new FormalParameterListContextHelper(ctx.formalParameters(), method, entityRepo);
if (ctx.typeParameters() != null) {
foundTypeParametersUse(ctx.typeParameters());
}
annotationProcessor.processAnnotationModifier(ctx, "interfaceMethodModifier");
super.enterInterfaceMethodDeclaration(ctx);
}
@Override
public void exitInterfaceMethodDeclaration(InterfaceMethodDeclarationContext ctx) {
exitLastEntity();
super.exitInterfaceMethodDeclaration(ctx);
}
@Override
public void enterConstructorDeclaration(ConstructorDeclarationContext ctx) {
List<String> throwedType = QualitiedNameContextHelper.getNames(ctx.qualifiedNameList());
FunctionEntity method = context.foundMethodDeclarator(ctx.IDENTIFIER().getText(), ctx.IDENTIFIER().getText(),
throwedType);
new FormalParameterListContextHelper(ctx.formalParameters(), method, entityRepo);
method.setReturnType(context.currentType());
annotationProcessor.processAnnotationModifier(ctx, "classBodyDeclaration");
super.enterConstructorDeclaration(ctx);
}
@Override
public void exitConstructorDeclaration(ConstructorDeclarationContext ctx) {
exitLastEntity();
super.exitConstructorDeclaration(ctx);
}
/////////////////////////////////////////////////////////
// Field
@Override
public void enterFieldDeclaration(FieldDeclarationContext ctx) {
List<String> varNames = VariableDeclaratorsContextHelper.getVariables(ctx.variableDeclarators());
String type = ClassTypeContextHelper.getClassName(ctx.typeType());
context.foundVarDefinition(varNames, type);
annotationProcessor.processAnnotationModifier(ctx, "classBodyDeclaration");
super.enterFieldDeclaration(ctx);
}
@Override
public void enterConstDeclaration(ConstDeclarationContext ctx) {
context.foundVarDefinition(VariableDeclaratorsContextHelper.getVariables(ctx.constantDeclarator()),
ClassTypeContextHelper.getClassName(ctx.typeType()));
annotationProcessor.processAnnotationModifier(ctx, "interfaceBodyDeclaration");
super.enterConstDeclaration(ctx);
}
@Override
public void enterEnumConstant(EnumConstantContext ctx) {
if (ctx.IDENTIFIER() != null)
context.foundEnumConstDefinition(ctx.IDENTIFIER().getText());
super.enterEnumConstant(ctx);
}
@Override
public void enterAnnotationMethodRest(AnnotationMethodRestContext ctx) {
context.foundMethodDeclarator(ctx.IDENTIFIER().getText(), ClassTypeContextHelper.getClassName(ctx.typeType()),
new ArrayList<>());
super.enterAnnotationMethodRest(ctx);
}
@Override
public void exitAnnotationMethodRest(AnnotationMethodRestContext ctx) {
exitLastEntity();
super.exitAnnotationMethodRest(ctx);
}
@Override
public void enterAnnotationConstantRest(AnnotationConstantRestContext ctx) {
// TODO: no variable type defined in annotation const
context.foundVarDefinition(VariableDeclaratorsContextHelper.getVariables(ctx.variableDeclarators()), "");
super.enterAnnotationConstantRest(ctx);
}
///////////////////////////////////////////
// variables
// TODO: all modifier have not processed yet.
@Override
public void enterLocalVariableDeclaration(LocalVariableDeclarationContext ctx) {
context.foundVarDefinition(VariableDeclaratorsContextHelper.getVariables((ctx.variableDeclarators())),
ClassTypeContextHelper.getClassName(ctx.typeType()));
super.enterLocalVariableDeclaration(ctx);
}
public void enterEnhancedForControl(EnhancedForControlContext ctx) {
context.foundVarDefinition(VariableDeclaratorsContextHelper.getVariable((ctx.variableDeclaratorId())),
ClassTypeContextHelper.getClassName(ctx.typeType()));
super.enterEnhancedForControl(ctx);
}
// resource
// : variableModifier* classOrInterfaceType variableDeclaratorId '=' expression
// ;
@Override
public void enterResource(ResourceContext ctx) {
context.foundVarDefintion(ctx.variableDeclaratorId().IDENTIFIER().getText(),
IdentifierContextHelper.getName(ctx.classOrInterfaceType().IDENTIFIER()));
super.enterResource(ctx);
}
@Override
public void enterExpression(ExpressionContext ctx) {
expressionUsage.foundExpression(ctx);
super.enterExpression(ctx);
}
/////////////////////////////////////////////
// Block
@Override
public void enterBlock(BlockContext ctx) {
// TODO Auto-generated method stub
super.enterBlock(ctx);
}
@Override
public void exitBlock(BlockContext ctx) {
// TODO Auto-generated method stub
super.exitBlock(ctx);
}
/* type parameters <T> <T1,T2>, <> treat as USE */
private void foundTypeParametersUse(TypeParametersContext typeParameters) {
for (int i = 0; i < typeParameters.typeParameter().size(); i++) {
TypeParameterContext typeParam = typeParameters.typeParameter(i);
if (typeParam.typeBound() != null) {
for (int j = 0; j < typeParam.typeBound().typeType().size(); j++) {
context.foundTypeParametes(ClassTypeContextHelper.getClassName(typeParam.typeBound().typeType(j)));
}
}
context.currentType().addTypeParameter(typeParam.IDENTIFIER().getText());
}
}
}

View File

@ -0,0 +1,36 @@
package depends.extractor.java;
import java.io.IOException;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.Lexer;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import depends.entity.repo.EntityRepo;
import depends.extractor.java.JavaLexer;
import depends.extractor.java.JavaParser;
import depends.relations.Inferer;
public class JavaFileParser implements depends.extractor.FileParser{
private String fileFullPath;
private EntityRepo entityRepo;
public JavaFileParser(String fileFullPath,EntityRepo entityRepo, Inferer inferer) {
this.fileFullPath = fileFullPath;
this.entityRepo = entityRepo;
}
public void parse() throws IOException {
CharStream input = CharStreams.fromFileName(fileFullPath);
Lexer lexer = new JavaLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
JavaParser parser = new JavaParser(tokens);
JavaEntitiesListener bridge = new JavaEntitiesListener(fileFullPath, entityRepo);
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(bridge, parser.compilationUnit());
}
}

View File

@ -0,0 +1,23 @@
package depends.extractor.java;
import depends.entity.Entity;
import depends.entity.PackageEntity;
import depends.entity.repo.EntityRepo;
import depends.extractor.HandlerContext;
public class JavaHandlerContext extends HandlerContext {
public JavaHandlerContext(EntityRepo entityRepo) {
super(entityRepo);
}
public Entity foundNewPackage(String packageName) {
Entity pkgEntity = entityRepo.getEntity(packageName);
if (pkgEntity == null) {
pkgEntity = new PackageEntity(packageName, idGenerator.generateId());
entityRepo.add(pkgEntity);
}
entityRepo.setParent(currentFileEntity,pkgEntity);
return pkgEntity;
}
}

View File

@ -0,0 +1,54 @@
package depends.extractor.java;
import java.util.ArrayList;
import java.util.List;
import depends.entity.Entity;
import depends.entity.FileEntity;
import depends.entity.PackageEntity;
import depends.entity.repo.EntityRepo;
import depends.importtypes.Import;
import depends.relations.ImportLookupStrategy;
import depends.relations.Inferer;
public class JavaImportLookupStrategy implements ImportLookupStrategy{
@Override
public Entity lookupImportedType(String name, FileEntity fileEntity, EntityRepo repo, Inferer inferer) {
//Java Strategy
String importedString = fileEntity.importedSuffixMatch(name);
if (importedString==null) return null;
return repo.getEntity(importedString);
}
@Override
public List<Entity> getImportedRelationEntities(List<Import> importedList, EntityRepo repo) {
ArrayList<Entity> result = new ArrayList<>();
for (Import importedItem:importedList) {
Entity imported = repo.getEntity(importedItem.getContent());
if (imported==null) continue;
if (imported instanceof PackageEntity) {
//expand import of package to all classes under the package due to we dis-courage the behavior
for (Entity child:imported.getChildren()) {
result.add(child);
}
}else {
result.add(imported);
}
}
return result;
}
@Override
public List<Entity> getImportedTypes(List<Import> importedList, EntityRepo repo) {
return getImportedRelationEntities(importedList,repo);
}
@Override
public List<Entity> getImportedFiles(List<Import> importedList, EntityRepo repo) {
return new ArrayList<Entity>();
}
}

View File

@ -0,0 +1,40 @@
package depends.extractor.java;
import java.util.ArrayList;
import java.util.List;
import depends.extractor.AbstractLangWorker;
import depends.extractor.FileParser;
import depends.relations.Inferer;
public class JavaWorker extends AbstractLangWorker {
public static final String JAVA_LANG = "java";
public static final String JAVA_SUFFIX = ".java";
public JavaWorker(String inputDir, String[] includeDir) {
super(inputDir,includeDir);
inferer = new Inferer(entityRepo,new JavaImportLookupStrategy(),new JavaBuiltInType());
}
@Override
public String supportedLanguage() {
return JAVA_LANG;
}
@Override
public String[] fileSuffixes() {
return new String[] {JAVA_SUFFIX};
}
@Override
protected FileParser getFileParser(String fileFullPath) {
return new JavaFileParser(fileFullPath,entityRepo, inferer);
}
@Override
public List<String> getErrors() {
return new ArrayList<String>();
}
}

View File

@ -0,0 +1,70 @@
package depends.extractor.java.context;
import java.lang.reflect.Method;
import java.util.List;
import org.antlr.v4.runtime.RuleContext;
import depends.extractor.HandlerContext;
import depends.extractor.java.JavaParser.AnnotationContext;
public class AnnotationProcessor {
private HandlerContext context;
public AnnotationProcessor(HandlerContext context) {
this.context = context;
}
/**
* for any elements who with modifiers like 'public/static/... @Annotation
* process annotations as "USE"
*
* @param ctx
* @param class1
*/
private boolean containsMethod(RuleContext ctx,String methodName) {
try {
Method m = ctx.getClass().getMethod(methodName);
if (m!=null) return true;
} catch (Exception e) {
return false;
}
return true;
}
private Method getMethod(RuleContext ctx, String methodName) {
try {
Method m = ctx.getClass().getMethod(methodName);
if (m!=null) return m;
} catch (Exception e) {
return null;
}
return null;
}
public void processAnnotationModifier(RuleContext ctx, String methodName) {
while (true) {
if (ctx == null)
break;
if (containsMethod(ctx,methodName))
break;
ctx = ctx.parent;
}
if (ctx==null)return;
Method m = getMethod(ctx,methodName);
if (m==null) return;
try {
List<?> modifiers = (List<?>) m.invoke(ctx);
for (Object modifier : modifiers) {
Method annotationMethod = modifier.getClass().getMethod("annotation");
AnnotationContext annotation = (AnnotationContext) (annotationMethod.invoke(modifier));
if (annotation == null)
return;
String name = QualitiedNameContextHelper.getName(annotation.qualifiedName());
context.foundAnnotation(name);
}
} catch (Exception e) {
return;
}
}
}

View File

@ -0,0 +1,39 @@
package depends.extractor.java.context;
import depends.extractor.java.JavaParser.ClassOrInterfaceTypeContext;
import depends.extractor.java.JavaParser.TypeTypeContext;
import depends.extractor.java.JavaParser.TypeTypeOrVoidContext;
public class ClassTypeContextHelper {
/**
typeType
: annotation? (classOrInterfaceType | primitiveType) ('[' ']')*
;
classOrInterfaceType
: IDENTIFIER typeArguments? ('.' IDENTIFIER typeArguments?)*
;
*/
public static String getClassName(TypeTypeContext ctx) {
if (ctx.primitiveType()!=null)
return ctx.primitiveType().getText();
if (ctx.classOrInterfaceType()!=null)
return getType(ctx.classOrInterfaceType());
return null;
}
private static String getType(ClassOrInterfaceTypeContext ctx) {
String r = "";
for (int i=0;i<ctx.IDENTIFIER().size();i++) {
String dot = r.isEmpty()?"":".";
r = r + dot + ctx.IDENTIFIER(i).getText();
}
return r;
}
public static String getClassName(TypeTypeOrVoidContext typeTypeOrVoid) {
if (typeTypeOrVoid.typeType()!=null) return getClassName(typeTypeOrVoid.typeType());
return "void";
}
}

View File

@ -0,0 +1,16 @@
package depends.extractor.java.context;
import depends.extractor.java.JavaParser.CreatorContext;
public class CreatorContextHelper {
public static String getCreatorType(CreatorContext creator) {
if (creator==null) return null;
if (creator.createdName()==null) return creator.getText();
if (creator.createdName().IDENTIFIER()==null)
return creator.createdName().getText();
if (creator.createdName().IDENTIFIER().size()>0)
return creator.createdName().IDENTIFIER(0).getText();
return null;
}
}

View File

@ -0,0 +1,182 @@
package depends.extractor.java.context;
import org.antlr.v4.runtime.RuleContext;
import depends.entity.Expression;
import depends.entity.repo.IdGenerator;
import depends.extractor.HandlerContext;
import depends.extractor.java.JavaParser.ExpressionContext;
import depends.extractor.java.JavaParser.MethodCallContext;
import depends.extractor.java.JavaParser.PrimaryContext;
public class ExpressionUsage {
HandlerContext context;
IdGenerator idGenerator;
public ExpressionUsage(HandlerContext context,IdGenerator idGenerator) {
this.context = context;
this.idGenerator = idGenerator;
}
public void foundExpression(ExpressionContext ctx) {
Expression parent = findParentInStack(ctx);
/* create expression and link it with parent*/
Expression expression = new Expression(idGenerator.generateId(),parent==null?null:parent.id);
context.lastContainer().addExpression(ctx,expression);
expression.text = ctx.getText(); //for debug purpose. no actual effect
expression.parent = parent;
if (expression.parent!=null) {
if (expression.parent.deduceTypeBasedId==null)
expression.parent.deduceTypeBasedId = expression.id;
}
if (ctx.primary()!=null) {
tryFillExpressionTypeAndIdentifier(ctx.primary(),expression);
return;
}
expression.isSet = isSet(ctx);
expression.isCall = ctx.methodCall()==null?false:true;
expression.isLogic = isLogic(ctx);
expression.isDot = isDot(ctx);
if (ctx.creator()!=null ||ctx.innerCreator()!=null){
expression.isCreate = true;
}
/**
* | expression bop='.'
( IDENTIFIER
| methodCall
| THIS
| NEW nonWildcardTypeArguments? innerCreator
| SUPER superSuffix
| explicitGenericInvocation
)
*/
//method call
if (ctx.methodCall()!=null) {
expression.identifier = getMethodCallIdentifier(ctx.methodCall());
expression.isCall = true;
}
//new
if (ctx.NEW()!=null && ctx.creator()!=null) {
expression.rawType = CreatorContextHelper.getCreatorType(ctx.creator());
expression.isCall = true;
expression.deriveTypeFromChild = false;
}
if (ctx.typeCast()!=null) {
expression.isCast=true;
expression.rawType = ctx.typeCast().typeType().getText();
expression.deriveTypeFromChild = false;
}
if (ctx.bop!=null && ctx.bop.getText().equals("instanceof")) {
expression.isCast=true;
expression.rawType = ctx.typeType().getText();
expression.deriveTypeFromChild = false;
}
if (ctx.creator()!=null) {
expression.deriveTypeFromChild = false;
}
if (expression.isDot) {
if (ctx.IDENTIFIER()!=null)
expression.identifier = ctx.IDENTIFIER().getText();
else if (ctx.methodCall()!=null)
expression.identifier = getMethodCallIdentifier(ctx.methodCall());
else if (ctx.THIS()!=null)
expression.identifier = "this";
else if (ctx.innerCreator()!=null) //innner creator like new List(){}
expression.identifier = ctx.innerCreator().IDENTIFIER().getText();
else if (ctx.SUPER()!=null)
expression.identifier = "super";
return;
}
}
private String getMethodCallIdentifier(MethodCallContext methodCall) {
if (methodCall.THIS()!=null) {
return "this";
}else if (methodCall.SUPER()!=null) {
return "super";
}else {
return methodCall.IDENTIFIER().getText();
}
}
private boolean isDot(ExpressionContext ctx) {
if (ctx.bop!=null)
if (ctx.bop.getText().equals(".")) return true;
return false;
}
private boolean isLogic(ExpressionContext ctx) {
if (ctx.bop != null) {
if (OpHelper.isLogic(ctx.bop.getText())) {
return true;
}
}
return false;
}
public boolean isSet(ExpressionContext ctx) {
if (ctx.bop != null) {
if (OpHelper.isAssigment(ctx.bop.getText())) {
return true;
}
}
if (ctx.prefix != null) {
if (OpHelper.isIncrementalDecremental(ctx.prefix.getText())) {
return true;
}
}
if (ctx.postfix != null) {
if (OpHelper.isIncrementalDecremental(ctx.postfix.getText())) {
return true;
}
}
return false;
}
// primary
// : '(' expression ')'
// | THIS
// | SUPER
// | literal
// | IDENTIFIER
// | typeTypeOrVoid '.' CLASS
// | nonWildcardTypeArguments (explicitGenericInvocationSuffix | THIS arguments) //Just USE relation
//
private void tryFillExpressionTypeAndIdentifier(PrimaryContext ctx, Expression expression) {
if (ctx.expression()!=null) return;
//1. we only handle leaf node. if there is still expression,
// the type will be determined by child node in the expression
if (ctx.literal()!=null) {
//2. if it is a build-in type like "hello"(string), 10(integer), etc.
expression.rawType = "<Built-in>";
expression.identifier = "<Literal>";
}else if (ctx.IDENTIFIER()!=null) {
//2. if it is a var name, dertermine the type based on context.
expression.identifier = ctx.IDENTIFIER().getText();
}else if (ctx.typeTypeOrVoid()!=null) {
//3. if given type directly
expression.rawType = ClassTypeContextHelper.getClassName(ctx.typeTypeOrVoid());
}else if (ctx.THIS()!=null){
expression.identifier = "this";
}else if (ctx.SUPER()!=null){
expression.identifier = "super";
}
}
private Expression findParentInStack(RuleContext ctx) {
if (ctx==null) return null;
if (ctx.parent==null) return null;
if (context.lastContainer()==null) {
return null;
}
if (context.lastContainer().expressions().containsKey(ctx.parent)) return context.lastContainer().expressions().get(ctx.parent);
return findParentInStack(ctx.parent);
}
}

View File

@ -0,0 +1,74 @@
package depends.extractor.java.context;
import java.util.ArrayList;
import java.util.List;
import org.antlr.v4.runtime.tree.TerminalNode;
import depends.entity.FunctionEntity;
import depends.entity.VarEntity;
import depends.entity.repo.IdGenerator;
import depends.extractor.java.JavaParser.FormalParameterContext;
import depends.extractor.java.JavaParser.FormalParameterListContext;
import depends.extractor.java.JavaParser.FormalParametersContext;
import depends.extractor.java.JavaParser.LastFormalParameterContext;
import depends.extractor.java.JavaParser.TypeTypeContext;
import depends.extractor.java.JavaParser.VariableModifierContext;
public class FormalParameterListContextHelper {
FormalParameterListContext context;
private IdGenerator idGenerator;
private List<String> annotations;
private FunctionEntity container;
public FormalParameterListContextHelper(FormalParameterListContext formalParameterListContext,FunctionEntity container, IdGenerator idGenerator) {
this.context = formalParameterListContext;
this.container = container;
annotations = new ArrayList<>();
this.idGenerator = idGenerator;
if (context!=null)
extractParameterTypeList();
}
public FormalParameterListContextHelper(FormalParametersContext formalParameters,FunctionEntity container, IdGenerator idGenerator) {
this(formalParameters.formalParameterList(),container,idGenerator);
}
public void extractParameterTypeList() {
if (context != null) {
if (context.formalParameter() != null) {
for (FormalParameterContext p : context.formalParameter()) {
foundParameterDefintion(p.typeType(),p.variableDeclaratorId().IDENTIFIER(),p.variableModifier());
}
if (context.lastFormalParameter()!=null) {
LastFormalParameterContext p = context.lastFormalParameter();
foundParameterDefintion(p.typeType(),p.variableDeclaratorId().IDENTIFIER(),p.variableModifier());
}
}
}
return;
}
private void foundParameterDefintion(TypeTypeContext typeType, TerminalNode identifier, List<VariableModifierContext> variableModifier) {
String type = ClassTypeContextHelper.getClassName(typeType);
String varName = identifier.getText();
VarEntity varEntity = new VarEntity(varName,type,container,idGenerator.generateId());
container.addParameter(varEntity);
for ( VariableModifierContext modifier:variableModifier) {
if (modifier.annotation()!=null) {
this.annotations.add(QualitiedNameContextHelper.getName(modifier.annotation().qualifiedName()));
}
}
}
public List<String> getAnnotations() {
return annotations;
}
}

View File

@ -0,0 +1,16 @@
package depends.extractor.java.context;
import java.util.List;
import org.antlr.v4.runtime.tree.TerminalNode;
public class IdentifierContextHelper {
public static String getName(List<TerminalNode> identifiers) {
String r = "";
for (TerminalNode id:identifiers) {
String dot = r.isEmpty()?"":".";
r = r + dot + id.getText();
}
return r;
}
}

View File

@ -0,0 +1,37 @@
package depends.extractor.java.context;
//: primary
//| expression bop='.'
// ( IDENTIFIER
// | methodCall
// | THIS
// | NEW nonWildcardTypeArguments? innerCreator
// | SUPER superSuffix
// | explicitGenericInvocation
// )
//| expression '[' expression ']'
//| methodCall
//| NEW creator
//| '(' typeType ')' expression
//| expression ('<' '<' | '>' '>' '>' | '>' '>') expression
//| expression bop=INSTANCEOF typeType
//| <assoc=right> expression
// expression
//| lambdaExpression // Java8
public class OpHelper {
public static boolean isLogic(String op) {
return op.equals("<") || op.equals(">") || op.equals("<=") || op.equals(">=")
|| op.equals("==")
|| op.equals("!=") || op.equals("&&") || op.equals("||") || op.equals("?");
}
public static boolean isAssigment(String op) {
return op.equals("=") || op.equals("+=") || op.equals("-=") || op.equals("*=") || op.equals("/=")
|| op.equals("&=") || op.equals("|=") || op.equals("^=") || op.equals(">>=") || op.equals(">>>=")
|| op.equals("<<=") || op.equals("%=");
}
public static boolean isIncrementalDecremental(String op) {
return op.equals("++") || op.equals("--");
}
}

View File

@ -0,0 +1,28 @@
package depends.extractor.java.context;
import java.util.ArrayList;
import java.util.List;
import depends.extractor.java.JavaParser.QualifiedNameContext;
import depends.extractor.java.JavaParser.QualifiedNameListContext;
public class QualitiedNameContextHelper {
public static String getName(QualifiedNameContext ctx) {
String r = "";
for (int i=0;i<ctx.IDENTIFIER().size();i++) {
String dot = r.isEmpty()?"":".";
r = r + dot + ctx.IDENTIFIER(i).getText();
}
return r;
}
public static List<String> getNames(QualifiedNameListContext qualifiedNameList) {
List<String> names = new ArrayList<>();
if (qualifiedNameList == null)
return names;
for (QualifiedNameContext item : qualifiedNameList.qualifiedName()) {
names.add(getName(item));
}
return names;
}
}

View File

@ -0,0 +1,19 @@
package depends.extractor.java.context;
import java.util.ArrayList;
import java.util.List;
import depends.extractor.java.JavaParser.TypeParameterContext;
import depends.extractor.java.JavaParser.TypeParametersContext;
public class TypeParameterContextHelper {
public static List<String> getTypeParameters(TypeParametersContext typeParameters) {
ArrayList<String> r = new ArrayList<>();
for(TypeParameterContext param:typeParameters.typeParameter()) {
r.add(param.IDENTIFIER().getText());
}
return r;
}
}

View File

@ -0,0 +1,40 @@
package depends.extractor.java.context;
import java.util.ArrayList;
import java.util.List;
import depends.extractor.java.JavaParser.ConstantDeclaratorContext;
import depends.extractor.java.JavaParser.VariableDeclaratorContext;
import depends.extractor.java.JavaParser.VariableDeclaratorIdContext;
import depends.extractor.java.JavaParser.VariableDeclaratorsContext;
public class VariableDeclaratorsContextHelper {
public static List<String> getVariables(VariableDeclaratorsContext variableDeclarators) {
List<String> vars = new ArrayList<>();
if (variableDeclarators==null) return vars;
for (VariableDeclaratorContext vContext:variableDeclarators.variableDeclarator()) {
vars.add(vContext.variableDeclaratorId().IDENTIFIER().getText());
}
return vars;
}
public static List<String> getVariables(List<ConstantDeclaratorContext> constantDeclarator) {
List<String> vars = new ArrayList<>();
if (constantDeclarator==null) return vars;
for (ConstantDeclaratorContext vContext:constantDeclarator) {
vars.add(vContext.IDENTIFIER().getText());
}
return vars;
}
public static List<String> getVariable(VariableDeclaratorIdContext variableDeclaratorIdContext) {
List<String> vars = new ArrayList<>();
if (variableDeclaratorIdContext==null) return vars;
vars.add(variableDeclaratorIdContext.IDENTIFIER().getText());
return vars;
}
}

View File

@ -0,0 +1,23 @@
package depends.extractor.ruby;
import depends.entity.repo.BuiltInType;
public class RubyBuiltInType extends BuiltInType {
public RubyBuiltInType() {
super.createBuiltInTypes();
}
@Override
public String[] getBuiltInTypeStr() {
return new String[] { "__ENCODING__", "__LINE__", "__FILE__", "BEGIN", "END", "alias", "and", "begin", "break",
"case", "class", "def", "defined?", "do", "else", "elsif", "end", "ensure", "false", "for", "if", "in",
"module", "next", "nil", "not", "or", "redo", "rescue", "retry", "return", "self", "super", "then",
"true", "undef", "unless", "until", "when", "while", "yield" };
}
@Override
public String[] getBuiltInPrefixStr() {
return new String[] {};
}
}

View File

@ -0,0 +1,35 @@
package depends.extractor.ruby;
import java.io.IOException;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.Lexer;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import depends.entity.repo.EntityRepo;
import depends.extractor.FileParser;
import depends.extractor.java.JavaLexer;
public class RubyFileParser implements FileParser {
private String fileFullPath;
private EntityRepo entityRepo;
public RubyFileParser(String fileFullPath, EntityRepo entityRepo) {
this.fileFullPath = fileFullPath;
this.entityRepo = entityRepo;
}
@Override
public void parse() throws IOException {
CharStream input = CharStreams.fromFileName(fileFullPath);
Lexer lexer = new JavaLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
CorundumParser parser = new CorundumParser(tokens);
RubyListener bridge = new RubyListener(fileFullPath, entityRepo);
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(bridge, parser.prog());
}
}

View File

@ -0,0 +1,38 @@
package depends.extractor.ruby;
import java.util.List;
import depends.entity.Entity;
import depends.entity.FileEntity;
import depends.entity.repo.EntityRepo;
import depends.importtypes.Import;
import depends.relations.ImportLookupStrategy;
import depends.relations.Inferer;
public class RubyImportLookupStrategy implements ImportLookupStrategy {
@Override
public Entity lookupImportedType(String name, FileEntity fileEntity, EntityRepo repo, Inferer inferer) {
// TODO Auto-generated method stub
return null;
}
@Override
public List<Entity> getImportedRelationEntities(List<Import> importedNames, EntityRepo repo) {
// TODO Auto-generated method stub
return null;
}
@Override
public List<Entity> getImportedTypes(List<Import> importedNames, EntityRepo repo) {
// TODO Auto-generated method stub
return null;
}
@Override
public List<Entity> getImportedFiles(List<Import> importedNames, EntityRepo repo) {
// TODO Auto-generated method stub
return null;
}
}

View File

@ -0,0 +1,9 @@
package depends.extractor.ruby;
import depends.entity.repo.EntityRepo;
public class RubyListener extends CorundumBaseListener{
public RubyListener(String fileFullPath, EntityRepo entityRepo) {
}
}

View File

@ -0,0 +1,41 @@
package depends.extractor.ruby;
import java.util.ArrayList;
import java.util.List;
import depends.extractor.AbstractLangWorker;
import depends.extractor.FileParser;
import depends.extractor.cpp.cdt.PreprocessorHandler;
import depends.relations.Inferer;
public class RubyWorker extends AbstractLangWorker {
private static final String LANG = "ruby";
private static final String[] SUFFIX = new String[] {".rb",".ruby"};
PreprocessorHandler preprocessorHandler;
public RubyWorker(String inputDir, String[] includeDir) {
super(inputDir,includeDir);
preprocessorHandler = new PreprocessorHandler(super.includePaths());
inferer = new Inferer(entityRepo,new RubyImportLookupStrategy(),new RubyBuiltInType());
}
@Override
public String supportedLanguage() {
return LANG;
}
@Override
public String[] fileSuffixes() {
return SUFFIX;
}
@Override
protected FileParser getFileParser(String fileFullPath) {
return new RubyFileParser(fileFullPath,entityRepo);
}
public List<String> getErrors(){
return new ArrayList<String>(preprocessorHandler.getNotExistedIncludedFiles());
}
}

View File

@ -0,0 +1,23 @@
package depends.format;
import java.io.File;
import depends.matrix.DependencyMatrix;
public abstract class AbstractFormatDependencyDumper {
protected String name;
protected DependencyMatrix matrix;
protected String outputDir;
public AbstractFormatDependencyDumper(DependencyMatrix matrix, String projectName, String outputDir) {
this.matrix = matrix;
this.name = projectName;
this.outputDir = outputDir;
}
public abstract boolean output();
public abstract String getFormatName();
protected String composeFilename() {
return outputDir+File.separator+name;
}
}

View File

@ -0,0 +1,49 @@
package depends.format;
import java.util.List;
import depends.format.detail.DetailTextFormatDependencyDumper;
import depends.format.dot.DotFormatDependencyDumper;
import depends.format.excel.ExcelFormatDependencyDumper;
import depends.format.json.JsonFormatDependencyDumper;
import depends.format.xml.XmlFormatDependencyDumper;
import depends.matrix.DependencyMatrix;
import edu.emory.mathcs.backport.java.util.Arrays;
public class DependencyDumper {
private DependencyMatrix dependencyMatrix;
private List<String> errors;
public DependencyDumper(DependencyMatrix dependencies, List<String> errors) {
this.dependencyMatrix = dependencies;
this.errors = errors;
}
public void outputResult(String projectName, String outputDir, String[] outputFormat) {
outputErrors();
outputDeps(projectName,outputDir,outputFormat);
}
private final void outputDeps(String projectName, String outputDir, String[] outputFormat) {
List<String> formatList = Arrays.asList(outputFormat);
AbstractFormatDependencyDumper[] builders = new AbstractFormatDependencyDumper[] {
new DetailTextFormatDependencyDumper(dependencyMatrix,projectName,outputDir),
new XmlFormatDependencyDumper(dependencyMatrix,projectName,outputDir),
new JsonFormatDependencyDumper(dependencyMatrix,projectName,outputDir),
new ExcelFormatDependencyDumper(dependencyMatrix,projectName,outputDir),
new DotFormatDependencyDumper(dependencyMatrix,projectName,outputDir),
};
for (AbstractFormatDependencyDumper builder:builders) {
if (formatList.contains(builder.getFormatName())){
builder.output();
}
}
}
private void outputErrors() {
for (String e:errors) {
System.err.println(e);
}
}
}

View File

@ -0,0 +1,18 @@
package depends.format;
public class FileAttributes {
private String schemaVersion = "1.0";
private String attributeName;
public FileAttributes( String projectName) {
this.attributeName = projectName + "-sdsm";
}
public String getSchemaVersion() {
return schemaVersion;
}
public String getAttributeName() {
return this.attributeName;
}
}

View File

@ -0,0 +1,48 @@
package depends.format.detail;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import depends.format.AbstractFormatDependencyDumper;
import depends.matrix.DependencyMatrix;
import depends.matrix.DependencyPair;
import depends.matrix.DependencyValue;
public class DetailTextFormatDependencyDumper extends AbstractFormatDependencyDumper{
ArrayList<String> files;
@Override
public String getFormatName() {
return "detail";
}
public DetailTextFormatDependencyDumper(DependencyMatrix matrix, String name, String outputDir) {
super(matrix,name,outputDir);
}
@Override
public boolean output() {
PrintWriter writer;
try {
files = matrix.getNodes();
writer = new PrintWriter(composeFilename() +".txt");
Collection<DependencyPair> dependencyPairs = matrix.getDependencyPairs();
addRelations(writer,dependencyPairs);
writer.close();
return true;
} catch (FileNotFoundException e) {
e.printStackTrace();
return false;
}
}
private void addRelations(PrintWriter writer, Collection<DependencyPair> dependencyPairs) {
for (DependencyPair dependencyPair:dependencyPairs) {
int src = dependencyPair.getFrom();
int dst = dependencyPair.getTo();
writer.println("======="+files.get(src) + " -> " + files.get(dst) + "=========");
for (DependencyValue dependency:dependencyPair.getDependencies()) {
writer.println(dependency.getDetails());
}
}
}
}

View File

@ -0,0 +1,52 @@
package depends.format.dot;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import depends.format.AbstractFormatDependencyDumper;
import depends.matrix.DependencyMatrix;
import depends.matrix.DependencyPair;
public class DotFormatDependencyDumper extends AbstractFormatDependencyDumper{
@Override
public String getFormatName() {
return "dot";
}
public DotFormatDependencyDumper(DependencyMatrix dependencyMatrix, String projectName, String outputDir) {
super(dependencyMatrix,projectName,outputDir);
}
@Override
public boolean output() {
PrintWriter writer;
try {
writer = new PrintWriter(composeFilename()+".dot");
ArrayList<String> files = matrix.getNodes();
for (int i=0;i<files.size();i++) {
String file = files.get(i);
writer.println("// "+i + ":"+file);
}
writer.println("digraph");
writer.println("{");
Collection<DependencyPair> dependencyPairs = matrix.getDependencyPairs();
addRelations(writer,dependencyPairs);
writer.println("}");
writer.close();
return true;
} catch (FileNotFoundException e) {
e.printStackTrace();
return false;
}
}
private void addRelations(PrintWriter writer, Collection<DependencyPair> dependencyPairs) {
for (DependencyPair dependencyPair:dependencyPairs) {
int src = dependencyPair.getFrom();
int dst = dependencyPair.getTo();
writer.println("\t"+src + " -> " + dst + ";");
}
}
}

View File

@ -0,0 +1,96 @@
package depends.format.excel;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import depends.format.AbstractFormatDependencyDumper;
import depends.matrix.DependencyMatrix;
import depends.matrix.DependencyPair;
import depends.matrix.DependencyValue;
public class ExcelFormatDependencyDumper extends AbstractFormatDependencyDumper {
private HSSFWorkbook workbook;
private HSSFSheet sheet;
@Override
public String getFormatName() {
return "excel";
}
public ExcelFormatDependencyDumper(DependencyMatrix dependencyMatrix, String projectName, String outputDir) {
super(dependencyMatrix, projectName,outputDir);
}
@Override
public boolean output() {
String filename = composeFilename() + ".xls";
if (matrix.getNodes().size() > 255) {
System.out.println("We can only export small matrix(<256 items) to excel" + "due to MS Office limitation");
return false;
}
startFile();
Collection<DependencyPair> dependencyPairs = matrix.getDependencyPairs();
HSSFRow[] row = new HSSFRow[matrix.getNodes().size()];
// create header row
HSSFRow header = sheet.createRow(0);
for (int i = 0; i < matrix.getNodes().size(); i++) {
HSSFCell cell = header.createCell(i + 2);
cell.setCellValue(i);
}
;
// create header col
for (int i = 0; i < matrix.getNodes().size(); i++) {
row[i] = sheet.createRow(i + 1);
String node = matrix.getNodes().get(i);
HSSFCell cell = row[i].createCell(0);
cell.setCellValue(i);
cell = row[i].createCell(1);
cell.setCellValue(node);
}
;
// create header col
for (int i = 0; i < matrix.getNodes().size(); i++) {
HSSFCell cell = row[i].createCell(i + 2);
cell.setCellValue("(" + i + ")");
}
;
for (DependencyPair dependencyPair : dependencyPairs) {
HSSFCell cell = row[dependencyPair.getFrom()].createCell(dependencyPair.getTo() + 2);
cell.setCellValue(buildDependencyValues(dependencyPair.getDependencies()));
}
closeFile(filename);
return true;
}
private String buildDependencyValues(Collection<DependencyValue> dependencies) {
StringBuilder sb = new StringBuilder();
for (DependencyValue dependency : dependencies) {
String comma = sb.length() > 0 ? "," : "";
sb.append(comma).append(dependency.getType()).append("(").append(dependency.getWeight()).append(")");
}
return sb.toString();
}
private void closeFile(String filename) {
try {
workbook.write(new File(filename));
workbook.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private void startFile() {
workbook = new HSSFWorkbook();
sheet = workbook.createSheet("DSM");
}
}

View File

@ -0,0 +1,41 @@
package depends.format.json;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.Map;
@XmlRootElement(name = "cell")
public class JCellObject {
private int src;
private int dest;
private Map<String, Float> values;
public int getSrc() {
return src;
}
@XmlAttribute(name = "src")
public void setSrc(int src) {
this.src = src;
}
public int getDest() {
return dest;
}
@XmlAttribute(name = "dest")
public void setDest(int dest) {
this.dest = dest;
}
public void setValues(Map<String, Float> values) {
this.values = values;
}
@XmlElement
public Map<String, Float> getValues() {
return values;
}
}

View File

@ -0,0 +1,49 @@
package depends.format.json;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import depends.format.FileAttributes;
import depends.matrix.DependencyMatrix;
import depends.matrix.DependencyPair;
import depends.matrix.DependencyValue;
public class JDataBuilder {
public JDepObject build(DependencyMatrix dependencyMatrix, FileAttributes attribute) {
ArrayList<String> files = dependencyMatrix.getNodes();
Collection<DependencyPair> dependencyPairs = dependencyMatrix.getDependencyPairs();
ArrayList<JCellObject> cellObjects = buildCellObjects(dependencyPairs); // transform finalRes into cellObjects
JDepObject depObject = new JDepObject();
depObject.setVariables(files);
depObject.setName(attribute.getAttributeName());
depObject.setSchemaVersion(attribute.getSchemaVersion());
depObject.setCells(cellObjects);
return depObject;
}
private ArrayList<JCellObject> buildCellObjects(Collection<DependencyPair> dependencyPairs) {
ArrayList<JCellObject> cellObjects = new ArrayList<JCellObject>();
for (DependencyPair dependencyPair : dependencyPairs) {
Map<String, Float> valueObject = buildValueObject(dependencyPair.getDependencies());
JCellObject cellObject = new JCellObject();
cellObject.setSrc(dependencyPair.getFrom());
cellObject.setDest(dependencyPair.getTo());
cellObject.setValues(valueObject);
cellObjects.add(cellObject);
}
return cellObjects;
}
private Map<String, Float> buildValueObject(Collection<DependencyValue> dependencies) {
Map<String, Float> valueObject = new HashMap<String, Float>();
for (DependencyValue dependency : dependencies) {
valueObject.put(dependency.getType(), (float) dependency.getWeight());
}
return valueObject;
}
}

View File

@ -0,0 +1,50 @@
package depends.format.json;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.ArrayList;
@XmlRootElement(name = "matrix")
public class JDepObject {
private String schemaVersion;
private String name;
private ArrayList<String> variables;
private ArrayList<JCellObject> cells;
public String getName() {
return name;
}
@XmlAttribute(name = "name")
public void setName(String name) {
this.name = name;
}
public String getSchemaVersion() {
return schemaVersion;
}
@XmlAttribute(name = "schema-version")
public void setSchemaVersion(String schemaVersion) {
this.schemaVersion = schemaVersion;
}
public ArrayList<String> getVariables() {
return variables;
}
@XmlElement
public void setVariables(ArrayList<String> variables) {
this.variables = variables;
}
public ArrayList<JCellObject> getCells() {
return cells;
}
@XmlElement
public void setCells(ArrayList<JCellObject> cells) {
this.cells = cells;
}
}

View File

@ -0,0 +1,41 @@
package depends.format.json;
import java.io.File;
import com.fasterxml.jackson.databind.ObjectMapper;
import depends.format.AbstractFormatDependencyDumper;
import depends.format.FileAttributes;
import depends.matrix.DependencyMatrix;
public class JsonFormatDependencyDumper extends AbstractFormatDependencyDumper {
@Override
public String getFormatName() {
return "json";
}
public JsonFormatDependencyDumper(DependencyMatrix dependencyMatrix, String projectName, String outputDir) {
super(dependencyMatrix, projectName,outputDir);
}
@Override
public boolean output() {
JDataBuilder jBuilder = new JDataBuilder();
JDepObject jDepObject = jBuilder.build(matrix, new FileAttributes(name));
toJson(jDepObject, composeFilename()+ ".json");
return true;
}
private void toJson(JDepObject depObject, String jsonFileName) {
ObjectMapper mapper = new ObjectMapper();
try {
mapper.writerWithDefaultPrettyPrinter().writeValue(new File(jsonFileName), depObject);
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,26 @@
package depends.format.path;
import java.io.File;
import org.apache.commons.io.FilenameUtils;
import depends.matrix.FilenameWritter;
public class DotPathFilenameWritter implements FilenameWritter {
@Override
public String reWrite(String originalPath) {
String ext = FilenameUtils.getExtension(originalPath);
String path = replaceExt(originalPath,ext);
path = path.replace('/', '.');
path = path.replace('\\', '.');
return path;
}
private String replaceExt(String path, String ext) {
if (ext==null) return path;
if (ext.length()==0) return path;
if (!path.endsWith(ext)) return path;
path = path.substring(0,path.length()-ext.length()-1) + "_" + ext;
return path;
}
}

View File

@ -0,0 +1,10 @@
package depends.format.path;
import depends.matrix.FilenameWritter;
public class EmptyFilenameWritter implements FilenameWritter {
@Override
public String reWrite(String originalPath) {
return originalPath;
}
}

View File

@ -0,0 +1,38 @@
package depends.format.xml;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import java.util.ArrayList;
public class XCell {
private int src;
private int dest;
private ArrayList<XDepend> depends;
@XmlAttribute(name = "src")
public void setSrc(int src) {
this.src = src;
}
public int getSrc() {
return src;
}
@XmlAttribute(name = "dest")
public void setDest(int dest) {
this.dest = dest;
}
public int getDest() {
return dest;
}
@XmlElement(name = "depend")
public void setDepends(ArrayList<XDepend> depends) {
this.depends = depends;
}
public ArrayList<XDepend> getDepends() {
return depends;
}
}

View File

@ -0,0 +1,17 @@
package depends.format.xml;
import javax.xml.bind.annotation.XmlElement;
import java.util.ArrayList;
public class XCells {
private ArrayList<XCell> cells;
@XmlElement(name = "cell")
public void setCells(ArrayList<XCell> cells) {
this.cells = cells;
}
public ArrayList<XCell> getCells() {
return cells;
}
}

View File

@ -0,0 +1,58 @@
package depends.format.xml;
import java.util.ArrayList;
import java.util.Collection;
import depends.format.FileAttributes;
import depends.matrix.DependencyMatrix;
import depends.matrix.DependencyPair;
import depends.matrix.DependencyValue;
public class XDataBuilder {
public XDepObject build(DependencyMatrix matrix,FileAttributes attribute) {
ArrayList<String> files = matrix.getNodes();
Collection<DependencyPair> dependencyPairs = matrix.getDependencyPairs();
XFiles xFiles = new XFiles();
xFiles.setFiles(files);
ArrayList<XCell> xCellList = buildCellList(dependencyPairs);
XCells xCells = new XCells();
xCells.setCells(xCellList);
XDepObject xDepObject = new XDepObject();
xDepObject.setName(attribute.getAttributeName());
xDepObject.setSchemaVersion(attribute.getSchemaVersion());
xDepObject.setVariables(xFiles);
xDepObject.setCells(xCells);
return xDepObject;
}
private ArrayList<XCell> buildCellList(Collection<DependencyPair> dependencyPairs) {
ArrayList<XCell> cellList = new ArrayList<XCell>();
for (DependencyPair pair : dependencyPairs) {
ArrayList<XDepend> xDepends = buildDependList(pair.getDependencies());
XCell xCell = new XCell();
xCell.setSrc(pair.getFrom());
xCell.setDest(pair.getTo());
xCell.setDepends(xDepends);
cellList.add(xCell);
}
return cellList;
}
private ArrayList<XDepend> buildDependList(Collection<DependencyValue> dependencies) {
ArrayList<XDepend> dependList = new ArrayList<XDepend>();
for (DependencyValue dependency : dependencies) {
XDepend xDepend = new XDepend();
xDepend.setWeight(dependency.getWeight());
xDepend.setName(dependency.getType());
dependList.add(xDepend);
}
return dependList;
}
}

View File

@ -0,0 +1,65 @@
package depends.format.xml;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
@XmlRootElement(name = "matrix")
@XmlType(propOrder = {"variables", "cells"})
public class XDepObject {
private String schemaVersion;
private String name;
private XFiles variables;
private XCells cells;
private String xmlns="http://dv8.archdia.com/xml/matrix";
public String getName() {
return name;
}
@XmlAttribute(name = "name")
public void setName(String name) {
this.name = name;
}
public String getSchemaVersion() {
return schemaVersion;
}
@XmlAttribute(name = "schema-version")
public void setSchemaVersion(String schemaVersion) {
this.schemaVersion = schemaVersion;
}
@XmlElement(name = "variables")
public void setVariables(XFiles variables) {
this.variables = variables;
}
public XFiles getVariables() {
return variables;
}
@XmlElement(name = "cells")
public void setCells(XCells cells) {
this.cells = cells;
}
public XCells getCells() {
return cells;
}
public String getXmlns() {
return xmlns;
}
@XmlAttribute(name = "xmlns")
public void setXmlns(String xmlns) {
this.xmlns = xmlns;
}
}

View File

@ -0,0 +1,30 @@
package depends.format.xml;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "depend")
public class XDepend {
private String name;
private float weight;
public String getName() {
return name;
}
@XmlAttribute(name = "name")
public void setName(String name) {
this.name = name;
}
public float getWeight() {
return weight;
}
@XmlAttribute(name = "weight")
public void setWeight(float weight) {
this.weight = weight;
}
}

View File

@ -0,0 +1,18 @@
package depends.format.xml;
import javax.xml.bind.annotation.XmlElement;
import java.util.ArrayList;
public class XFiles {
private ArrayList<String> files;
public ArrayList<String> getFiles() {
return files;
}
@XmlElement(name = "variable")
public void setFiles(ArrayList<String> files) {
this.files = files;
}
}

View File

@ -0,0 +1,39 @@
package depends.format.xml;
import java.io.FileOutputStream;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import depends.format.AbstractFormatDependencyDumper;
import depends.format.FileAttributes;
import depends.matrix.DependencyMatrix;
public class XmlFormatDependencyDumper extends AbstractFormatDependencyDumper{
@Override
public String getFormatName() {
return "xml";
}
public XmlFormatDependencyDumper(DependencyMatrix dependencyMatrix, String projectName, String outputDir) {
super(dependencyMatrix,projectName,outputDir);
}
private void toXml(XDepObject xDepObject, String xmlFileName) {
try {
JAXBContext jaxbContext = JAXBContext.newInstance(XDepObject.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(xDepObject, new FileOutputStream(xmlFileName));
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public boolean output() {
XDataBuilder xBuilder = new XDataBuilder();
XDepObject xDepObject = xBuilder.build(matrix,new FileAttributes(name));
toXml(xDepObject,composeFilename()+".xml");
return true;
}
}

View File

@ -0,0 +1,7 @@
package depends.importtypes;
public class ExactMatchImport extends Import{
public ExactMatchImport(String content) {
super(content);
}
}

View File

@ -0,0 +1,7 @@
package depends.importtypes;
public class FileImport extends Import{
public FileImport(String content) {
super(content);
}
}

View File

@ -0,0 +1,11 @@
package depends.importtypes;
public abstract class Import {
private String content;
public String getContent() {
return content;
}
public Import(String content) {
this.content = content;
}
}

View File

@ -0,0 +1,7 @@
package depends.importtypes;
public class PackageWildCardImport extends Import{
public PackageWildCardImport(String content) {
super(content);
}
}

View File

@ -0,0 +1,7 @@
package depends.matrix;
import depends.entity.repo.EntityRepo;
public interface DependencyGenerator {
DependencyMatrix build(EntityRepo entityRepo);
}

View File

@ -0,0 +1,86 @@
package depends.matrix;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import depends.entity.Entity;
import depends.entity.repo.EntityRepo;
public class DependencyMatrix {
private HashMap<String, DependencyPair> dependencyPairs = new HashMap<>();
private ArrayList<String> nodes;
private ArrayList<String> reMappedNodes;
private Integer relationCount=0;
public DependencyMatrix() {
}
public Collection<DependencyPair> getDependencyPairs() {
return dependencyPairs.values();
}
public void addDependency(String depType, Integer from, Integer to, Entity fromEntity, Entity toEntity) {
if(from.equals(to) || from == -1 || to == -1) {
return;
}
if (dependencyPairs.get(DependencyPair.key(from,to))==null) {
dependencyPairs.put(DependencyPair.key(from,to),new DependencyPair(from,to));
}
DependencyPair dependencyPair = dependencyPairs.get(DependencyPair.key(from,to));
dependencyPair.addDependency(depType,fromEntity, toEntity);
relationCount++;
}
public ArrayList<String> getNodes() {
return reMappedNodes;
}
public void setNodes(ArrayList<String> nodes) {
this.nodes = nodes;
}
private Integer translateToNewId(EntityRepo repo, HashMap<String, Integer> nodesMap, Integer key) {
return nodesMap.get(repo.getEntity(key).getDisplayName());
}
public void remapIds(EntityRepo repo) {
HashMap<String, Integer> nodesMap = new HashMap<>();
reMappedNodes = new ArrayList<>(nodes);
reMappedNodes.sort(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
for (int i=0;i<reMappedNodes.size();i++) {
nodesMap.put(reMappedNodes.get(i), i);
}
for (DependencyPair dependencyPair:dependencyPairs.values()) {
Integer from = dependencyPair.getFrom();
Integer to = dependencyPair.getTo();
dependencyPair.reMap(translateToNewId(repo, nodesMap, from),translateToNewId(repo, nodesMap, to));
}
}
public Integer relationCount() {
return relationCount;
}
public void stripFilenames(String leadingSrcPath) {
for (int i=0;i<reMappedNodes.size();i++) {
String shortPath = reMappedNodes.get(i);
if (shortPath.startsWith(leadingSrcPath))
shortPath = "."+shortPath.substring(leadingSrcPath.length());
reMappedNodes.set(i, shortPath);
}
}
public void reWriteFilenamePattern(FilenameWritter filenameRewritter) {
for (int i=0;i<reMappedNodes.size();i++) {
reMappedNodes.set(i, filenameRewritter.reWrite(reMappedNodes.get(i)));
}
}
}

View File

@ -0,0 +1,39 @@
package depends.matrix;
import java.util.Collection;
import java.util.HashMap;
import depends.entity.Entity;
public class DependencyPair {
private Integer from;
private Integer to;
HashMap<String, DependencyValue> dependencies;
public DependencyPair(Integer from, Integer to) {
this.from = from;
this.to= to;
dependencies = new HashMap<>();
}
public static String key(Integer from, Integer to) {
return ""+from+"-->"+to;
}
public void addDependency(String depType, Entity fromEntity, Entity toEntity) {
if (dependencies.get(depType)==null)
dependencies.put(depType, new DependencyValue(depType));
DependencyValue value = dependencies.get(depType);
value.addDependency(fromEntity, toEntity);
}
public Integer getFrom() {
return from;
}
public Integer getTo() {
return to;
}
public Collection<DependencyValue> getDependencies() {
return dependencies.values();
}
public void reMap(Integer from, Integer to) {
this.from = from;
this.to = to;
}
}

View File

@ -0,0 +1,33 @@
package depends.matrix;
import depends.entity.Entity;
public class DependencyValue{
private int weight;
private String type;
private StringBuffer dependencyDetail;
public DependencyValue(String type) {
this.type = type;
this.weight=0;
dependencyDetail = new StringBuffer();
}
public void addDependency(Entity from, Entity to) {
this.weight++;
dependencyDetail.append("[").append(type).append("]")
.append(from.getQualifiedName()).append("->").append(to.getQualifiedName())
.append("\n");
}
public int getWeight() {
return weight;
}
public String getType() {
return type;
}
public String getDetails() {
return dependencyDetail.toString();
}
}

View File

@ -0,0 +1,45 @@
package depends.matrix;
import java.util.ArrayList;
import depends.entity.Entity;
import depends.entity.FileEntity;
import depends.entity.repo.EntityRepo;
import depends.relations.Relation;
public class FileDependencyGenerator implements DependencyGenerator{
/**
* Build the dependency matrix (without re-mapping file id)
* @param entityRepo which contains entities and relations
* @return the generated dependency matrix
*/
@Override
public DependencyMatrix build(EntityRepo entityRepo) {
DependencyMatrix dependencyMatrix = new DependencyMatrix();
ArrayList<String> files = new ArrayList<String>();
for (Entity entity:entityRepo.getEntities()) {
if (entity instanceof FileEntity){
files.add( entity.getDisplayName());
}
int fileEntityFrom = getFileEntityIdNoException(entityRepo, entity);
if (fileEntityFrom==-1) continue;
for (Relation relation:entity.getRelations()) {
if (relation.getEntity().getId()>=0) {
int fileEntityTo = getFileEntityIdNoException(entityRepo,relation.getEntity());
if (fileEntityTo==-1) continue;
dependencyMatrix.addDependency(relation.getType(), fileEntityFrom,fileEntityTo,entity,relation.getEntity());
}
}
}
dependencyMatrix.setNodes(files);
return dependencyMatrix;
}
private int getFileEntityIdNoException(EntityRepo entityRepo, Entity entity) {
Entity ancestor = entity.getAncestorOfType(FileEntity.class);
if (ancestor==null)
return -1;
return ancestor.getId();
}
}

View File

@ -0,0 +1,5 @@
package depends.matrix;
public interface FilenameWritter {
String reWrite(String originalPath);
}

View File

@ -0,0 +1,50 @@
package depends.matrix;
import java.util.ArrayList;
import depends.entity.Entity;
import depends.entity.FileEntity;
import depends.entity.FunctionEntity;
import depends.entity.repo.EntityRepo;
import depends.relations.Relation;
public class FunctionDependencyGenerator implements DependencyGenerator {
@Override
public DependencyMatrix build(EntityRepo entityRepo) {
DependencyMatrix dependencyMatrix = new DependencyMatrix();
ArrayList<String> elements = new ArrayList<String>();
for (Entity entity : entityRepo.getEntities()) {
if (entity instanceof FunctionEntity) {
elements.add(entity.getDisplayName());
}
int fileEntityFrom = getFunctionEntityIdNoException(entity);
if (fileEntityFrom == -1)
continue;
for (Relation relation : entity.getRelations()) {
if (relation.getEntity().getId() >= 0) {
int fileEntityTo = getFunctionEntityIdNoException(relation.getEntity());
if (fileEntityTo == -1)
continue;
dependencyMatrix.addDependency(relation.getType(), fileEntityFrom, fileEntityTo, entity,
relation.getEntity());
}
}
}
dependencyMatrix.setNodes(elements);
return dependencyMatrix;
}
private String getFileNameNoException(Entity entity) {
Entity ancestor = entity.getAncestorOfType(FileEntity.class);
if (ancestor == null)
return "";
return ancestor.getRawName();
}
private int getFunctionEntityIdNoException(Entity entity) {
Entity ancestor = entity.getAncestorOfType(FunctionEntity.class);
if (ancestor == null)
return -1;
return ancestor.getId();
}
}

View File

@ -0,0 +1,15 @@
package depends.relations;
import java.util.List;
import depends.entity.Entity;
import depends.entity.FileEntity;
import depends.entity.repo.EntityRepo;
import depends.importtypes.Import;
public interface ImportLookupStrategy {
Entity lookupImportedType(String name, FileEntity fileEntity, EntityRepo repo, Inferer inferer);
List<Entity> getImportedRelationEntities(List<Import> importedNames, EntityRepo repo);
List<Entity> getImportedTypes(List<Import> importedNames, EntityRepo repo);
List<Entity> getImportedFiles(List<Import> importedNames, EntityRepo repo);
}

View File

@ -0,0 +1,258 @@
package depends.relations;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import depends.entity.ContainerEntity;
import depends.entity.Entity;
import depends.entity.FileEntity;
import depends.entity.MultiDeclareEntities;
import depends.entity.TypeEntity;
import depends.entity.repo.BuiltInType;
import depends.entity.repo.EntityRepo;
import depends.entity.repo.NullBuiltInType;
import depends.importtypes.Import;
public class Inferer {
private static final Logger logger = LoggerFactory.getLogger(Inferer.class);
static final public TypeEntity buildInType = new TypeEntity("built-in", null, -1);
static final public TypeEntity externalType = new TypeEntity("external", null, -1);
static final public TypeEntity genericParameterType = new TypeEntity("T", null, -1);
private BuiltInType buildInTypeManager = new NullBuiltInType();
private ImportLookupStrategy importLookupStrategy;
private HashSet<String> unsolvedSymbols;
private EntityRepo repo;
public Inferer(EntityRepo repo, ImportLookupStrategy importLookupStrategy, BuiltInType buildInTypeManager) {
this.repo = repo;
this.importLookupStrategy = importLookupStrategy;
this.buildInTypeManager = buildInTypeManager;
unsolvedSymbols= new HashSet<>();
}
/**
* Resolve all bindings
* - Firstly, we resolve all types from there names.
* - Secondly, we resolve all expressions (expression will use type infomation of previous step
*/
public Set<String> resolveAllBindings() {
resolveTypes();
resolveExpressoins();
System.out.println("Dependency analaysing....");
new RelationCounter(repo.getEntities()).computeRelations();
System.out.println("Dependency done....");
return unsolvedSymbols;
}
private void resolveTypes() {
for (Entity entity:repo.getEntities()) {
if (!(entity instanceof FileEntity)) continue;
entity.inferEntities(this);
}
}
private void resolveExpressoins() {
for (Entity entity:repo.getEntities()) {
if ((entity instanceof ContainerEntity))
((ContainerEntity)entity).resolveExpressions(this);
}
}
/**
* For types start with the prefix, it will be treated as built-in type
* For example, java.io.* in Java, or __ in C/C++
* @param prefix
* @return
*/
public boolean isBuiltInTypePrefix(String prefix) {
return buildInTypeManager.isBuiltInTypePrefix(prefix);
}
/**
* Different languages have different strategy on how to compute the imported types
* and the imported files.
* For example, in C/C++, both imported types (using namespace, using <type>) and imported files exists.
* while in java, only 'import class/function, or import wildcard class.* package.* exists.
*/
public List<Entity> getImportedRelationEntities(List<Import> importedNames) {
return importLookupStrategy.getImportedRelationEntities(importedNames, repo);
}
public List<Entity> getImportedTypes(List<Import> importedNames) {
return importLookupStrategy.getImportedTypes(importedNames, repo);
}
public List<Entity> getImportedFiles(List<Import> importedNames) {
return importLookupStrategy.getImportedFiles(importedNames, repo);
}
/**
* By given raw name, to infer the type of the name
* for example
* if it is a class, the class is the type
* if it is a function, the return type is the type
* if it is a variable, type of variable is the type
* @param fromEntity
* @param rawName
* @return
*/
public TypeEntity inferTypeFromName(Entity fromEntity, String rawName) {
Entity data = resolveName(fromEntity, rawName, true);
if (data == null)
return null;
return data.getType();
}
/**
* By given raw name, to infer the entity of the name
* @param fromEntity
* @param rawName
* @param searchImport
* @return
*/
public Entity resolveName(Entity fromEntity, String rawName, boolean searchImport) {
Entity entity = resolveNameInternal(fromEntity,rawName,searchImport);
if (logger.isDebugEnabled()) {
logger.debug("resolve name " + rawName + " from " + fromEntity.getQualifiedName() +" ==> "
+ (entity==null?"null":entity.getQualifiedName()));
}
return entity;
}
private Entity resolveNameInternal(Entity fromEntity, String rawName, boolean searchImport) {
if (rawName == null)
return null;
if (buildInTypeManager.isBuiltInType(rawName)) {
return buildInType;
}
if (buildInTypeManager.isBuiltInTypePrefix(rawName)) {
return buildInType;
}
// qualified name will first try global name directly
if (rawName.contains(".")) {
if (repo.getEntity(rawName) != null)
return repo.getEntity(rawName);
}
// first we lookup the first symbol
String[] names = rawName.split("\\.");
if (names.length == 0)
return null;
Entity type = lookupEntity(fromEntity, names[0], searchImport);
if (type == null)
return null;
if (names.length == 1) {
return type;
}
// then find the subsequent symbols
return findEntitySince(type, names, 1);
}
private Entity lookupEntity(Entity fromEntity, String name, boolean searcImport) {
if (name.equals("this") || name.equals("class")) {
TypeEntity entityType = (TypeEntity) (fromEntity.getAncestorOfType(TypeEntity.class));
return entityType;
} else if (name.equals("super")) {
TypeEntity parent = (TypeEntity) (fromEntity.getAncestorOfType(TypeEntity.class));
if (parent != null) {
TypeEntity parentType = parent.getInheritedType();
if (parentType!=null)
return parentType;
}
}
Entity inferData = findEntityUnderSamePackage(fromEntity, name);
if (inferData != null)
return inferData;
if (searcImport)
inferData = lookupTypeInImported((FileEntity)(fromEntity.getAncestorOfType(FileEntity.class)), name);
return inferData;
}
/**
* To lookup entity in case of a.b.c from a;
* @param precendenceEntity
* @param names
* @param nameIndex
* @return
*/
private Entity findEntitySince(Entity precendenceEntity, String[] names, int nameIndex) {
if (nameIndex >= names.length) {
return precendenceEntity;
}
//If it is not an entity with types (not a type, var, function), fall back to itself
if (precendenceEntity.getType()==null)
return precendenceEntity;
for (Entity child : precendenceEntity.getType().getChildren()) {
if (child.getRawName().equals(names[nameIndex])) {
return findEntitySince(child, names, nameIndex + 1);
}
}
return null;
}
private Entity lookupTypeInImported(FileEntity fileEntity, String name) {
if (fileEntity == null)
return null;
Entity type = importLookupStrategy.lookupImportedType(name, fileEntity, repo,this);
if (type != null)
return type;
return externalType;
}
/**
* In Java/C++ etc, the same package names should take priority of resolving.
* the entity lookup is implemented recursively.
* @param fromEntity
* @param name
* @return
*/
private Entity findEntityUnderSamePackage(Entity fromEntity, String name) {
while (true) {
Entity entity = tryToFindEntityWithName(fromEntity, name);
if (entity != null)
return entity;
for (Entity child : fromEntity.getChildren()) {
entity = tryToFindEntityWithName(child, name);
if (entity != null)
return entity;
if (child instanceof FileEntity) {
for (Entity classUnderFile : child.getChildren()) {
entity = tryToFindEntityWithName(classUnderFile, name);
if (entity != null)
return entity;
}
}
}
fromEntity = fromEntity.getParent();
if (fromEntity == null)
break;
}
return null;
}
/**
* Only used by findEntityUnderSamePackage
* @param fromEntity
* @param name
* @return
*/
private Entity tryToFindEntityWithName(Entity fromEntity, String name) {
if (!fromEntity.getRawName().equals(name))
return null;
if (fromEntity instanceof MultiDeclareEntities) {
for (Entity declaredEntitiy : ((MultiDeclareEntities) fromEntity).getEntities()) {
if (declaredEntitiy.getRawName().equals(name) && declaredEntitiy instanceof TypeEntity) {
return declaredEntitiy;
}
}
}
return fromEntity;
}
}

View File

@ -0,0 +1,28 @@
package depends.relations;
import depends.entity.Entity;
/**
* Dependency relation object
*/
public class Relation {
private String type;
private Entity toEntity;
public Relation(String type, Entity toEntity) {
this.toEntity = toEntity;
this.type = type;
}
public String getType() {
return type;
}
@Override
public String toString() {
return "Relation[" + type + "]-->" + toEntity.getId() + "(" + toEntity.getQualifiedName() + ")";
}
public Entity getEntity() {
return toEntity;
}
}

View File

@ -0,0 +1,118 @@
package depends.relations;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import depends.deptypes.DependencyType;
import depends.entity.ContainerEntity;
import depends.entity.Entity;
import depends.entity.Expression;
import depends.entity.FileEntity;
import depends.entity.FunctionEntity;
import depends.entity.TypeEntity;
import depends.entity.VarEntity;
public class RelationCounter {
private Collection<Entity> entities;
public RelationCounter(Collection<Entity> entities) {
this.entities = entities;
}
public void computeRelations() {
for (Entity entity:entities) {
if (entity instanceof FileEntity) {
computeImports((FileEntity)entity);
}
if (entity instanceof FunctionEntity) {
computeFunctionRelations((FunctionEntity)entity);
}
if (entity instanceof TypeEntity) {
computeTypeRelations((TypeEntity)entity);
}
if (entity instanceof ContainerEntity) {
computeContainerRelations((ContainerEntity)entity);
}
}
}
private void computeContainerRelations(ContainerEntity entity) {
for (VarEntity var:entity.getVars()) {
if (var.getType()!=null)
entity.addRelation(new Relation(DependencyType.CONTAIN,var.getType()));
}
for (TypeEntity type:entity.getResolvedAnnotations()) {
entity.addRelation(new Relation(DependencyType.USE,type));
}
for (TypeEntity type:entity.getResolvedTypeParameters()) {
entity.addRelation(new Relation(DependencyType.USE,type));
}
HashSet<Entity> usedEntities = new HashSet<>();
for (Expression expression:entity.expressions().values()){
Entity referredEntity = expression.getReferredEntity();
if (referredEntity==null) {
continue;
}
if (expression.isCall) {
entity.addRelation(new Relation(DependencyType.CALL,referredEntity));
}
if (expression.isCreate) {
entity.addRelation(new Relation(DependencyType.CREATE,referredEntity));
}
if (expression.isSet) { //SET is merged with USE
entity.addRelation(new Relation(DependencyType.USE,referredEntity));
}
if (expression.isCast) {
entity.addRelation(new Relation(DependencyType.CAST,referredEntity));
}
if (!expression.isCall && !expression.isCreate && !expression.isCast) {
usedEntities.add(expression.getReferredEntity());
}
}
for (Entity usedEntity:usedEntities) {
entity.addRelation(new Relation(DependencyType.USE,usedEntity));
}
}
private void computeTypeRelations(TypeEntity type) {
for (TypeEntity superType:type.getInheritedTypes()) {
type.addRelation(new Relation(DependencyType.INHERIT,superType));
}
for (TypeEntity interfaceType:type.getImplementedTypes()) {
type.addRelation(new Relation(DependencyType.IMPLEMENT,interfaceType));
}
}
private void computeFunctionRelations(FunctionEntity func) {
for (TypeEntity returnType:func.getReturnTypes()) {
func.addRelation(new Relation(DependencyType.RETURN,returnType));
}
for (VarEntity parameter:func.getParameters()) {
if (parameter.getType()!=null)
func.addRelation(new Relation(DependencyType.PARAMETER,parameter.getType()));
}
for (TypeEntity throwType:func.getThrowTypes()) {
func.addRelation(new Relation(DependencyType.THROW,throwType));
}
}
private void computeImports(FileEntity file) {
List<Entity> imports = file.getImportedRelationEntities();
for (Entity imported:imports) {
if (imported instanceof FileEntity)
{
if (((FileEntity)imported).isInProjectScope())
file.addRelation(new Relation(DependencyType.IMPORT,imported));
}else {
file.addRelation(new Relation(DependencyType.IMPORT,imported));
}
}
}
}

View File

@ -0,0 +1,68 @@
package depends.util;
import java.io.File;
import java.util.ArrayList;
/**
* Recursively visit every file in the given root path using the
* extended IFileVisitor
*
*/
public class FileTraversal {
/**
* The visitor interface
* Detail operation should be implemented here
*/
public interface IFileVisitor {
void visit(File file);
}
IFileVisitor visitor;
private ArrayList<String> extensionFilters = new ArrayList<>();
public FileTraversal(IFileVisitor visitor){
this.visitor = visitor;
}
public void travers(String path) {
File dir = new File(path);
travers(dir);
}
public void travers(File root) {
File[] files = root.listFiles();
if (files == null)
return;
for (int i = 0; i < files.length; i++) {
if (files[i].isDirectory()) {
travers(files[i]);
} else {
File f = files[i];
invokeVisitor(f);
}
}
}
private void invokeVisitor(File f) {
if (extensionFilters.size()==0) {
visitor.visit(f);
}else {
for (String ext:extensionFilters) {
if (f.getAbsolutePath().toLowerCase().endsWith(ext.toLowerCase())) {
visitor.visit(f);
}
}
}
}
public FileTraversal extensionFilter(String ext) {
this.extensionFilters.add(ext.toLowerCase());
return this;
}
public void extensionFilter(String[] fileSuffixes) {
for (String fileSuffix:fileSuffixes){
extensionFilter(fileSuffix);
}
}
}

View File

@ -0,0 +1,19 @@
package depends.util;
import java.io.File;
import java.io.IOException;
public class FileUtil {
public static String uniqFilePath(String filePath) {
try {
File f = new File(filePath);
filePath = f.getCanonicalPath();
} catch (IOException e) {
}
return filePath;
}
public static boolean existFile(String path) {
return new File(path).exists();
}
}

View File

@ -142,7 +142,6 @@ BITAND: '&';
BITOR: '|';
CARET: '^';
MOD: '%';
ADD_ASSIGN: '+=';
SUB_ASSIGN: '-=';
MUL_ASSIGN: '*=';

Some files were not shown because too many files have changed in this diff Show More