@@ -1,169 +0,0 @@ | |||
package depends.extractor.cpp.cdt; | |||
import depends.entity.GenericName; | |||
import depends.entity.TypeEntity; | |||
import org.eclipse.cdt.core.dom.ast.*; | |||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNameSpecifier; | |||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; | |||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration; | |||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTTemplateId; | |||
import org.eclipse.cdt.internal.core.model.ASTStringUtil; | |||
import java.lang.reflect.InvocationTargetException; | |||
import java.lang.reflect.Method; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
/** | |||
* This extends the CDT ASTStringUtil class. | |||
* A tricky point here is that we have to use some of the reflection mechanism to invoke | |||
* some private functions in ASTStringUtils class | |||
* It is not good, but it seems the most easiest one to reuse existing functions | |||
*/ | |||
public class ASTStringUtilExt extends ASTStringUtil { | |||
public static String getName(IASTDeclSpecifier decl) { | |||
StringBuilder buffer = new StringBuilder(); | |||
String name = appendBareDeclSpecifierString(buffer, decl).toString().replace("::", ".").replace("...", ""); | |||
return name; | |||
} | |||
public static String getName(IASTLiteralExpression expr) { | |||
return expr.getRawSignature().replace("::", ".").replace("...", ""); | |||
} | |||
public static String getTypeIdString(IASTTypeId typeId) { | |||
StringBuilder sb = new StringBuilder(); | |||
return appendBareTypeIdString(sb, typeId).toString().replace("::", "."); | |||
} | |||
/** | |||
* retrieve template parameters from declSpecifier | |||
*/ | |||
public static List<GenericName> getTemplateParameters(IASTDeclSpecifier declSpecifier) { | |||
List<GenericName> parameters = new ArrayList<>(); | |||
declSpecifier.accept(new TemplateParameterASTVisitor(parameters)); | |||
return parameters; | |||
} | |||
private static StringBuilder appendBareDeclSpecifierString(StringBuilder buffer, IASTDeclSpecifier declSpecifier) { | |||
if (declSpecifier instanceof IASTCompositeTypeSpecifier) { | |||
final IASTCompositeTypeSpecifier compositeTypeSpec = (IASTCompositeTypeSpecifier) declSpecifier; | |||
appendBareNameString(buffer, compositeTypeSpec.getName()); | |||
} else if (declSpecifier instanceof IASTElaboratedTypeSpecifier) { | |||
final IASTElaboratedTypeSpecifier elaboratedTypeSpec = (IASTElaboratedTypeSpecifier) declSpecifier; | |||
appendBareNameString(buffer, elaboratedTypeSpec.getName()); | |||
} else if (declSpecifier instanceof IASTEnumerationSpecifier) { | |||
final IASTEnumerationSpecifier enumerationSpec = (IASTEnumerationSpecifier) declSpecifier; | |||
appendBareNameString(buffer, enumerationSpec.getName()); | |||
} else if (declSpecifier instanceof IASTSimpleDeclSpecifier) { | |||
buffer.append(TypeEntity.buildInType.getRawName()); | |||
} else if (declSpecifier instanceof IASTNamedTypeSpecifier) { | |||
final IASTNamedTypeSpecifier namedTypeSpec = (IASTNamedTypeSpecifier) declSpecifier; | |||
appendBareNameString(buffer, namedTypeSpec.getName()); | |||
} | |||
return buffer; | |||
} | |||
private static StringBuilder appendBareNameString(StringBuilder buffer, IASTName name) { | |||
if (name instanceof ICPPASTQualifiedName) { | |||
final ICPPASTQualifiedName qualifiedName = (ICPPASTQualifiedName) name; | |||
final ICPPASTNameSpecifier[] segments = qualifiedName.getAllSegments(); | |||
for (int i = 0; i < segments.length; i++) { | |||
if (i > 0) { | |||
buffer.append("."); | |||
} | |||
appendQualifiedNameStringWithReflection(buffer, segments[i]); | |||
} | |||
} else if (name instanceof CPPASTTemplateId) { | |||
appendQualifiedNameStringWithReflection(buffer,(CPPASTTemplateId)name); | |||
} else if (name != null) { | |||
buffer.append(name.getSimpleID()); | |||
} | |||
return buffer; | |||
} | |||
private static void appendQualifiedNameStringWithReflection(StringBuilder buffer, IASTName name) { | |||
try { | |||
Method m = ASTStringUtil.class.getDeclaredMethod("appendQualifiedNameString", StringBuilder.class, | |||
IASTName.class); | |||
m.setAccessible(true); // if security settings allow this | |||
m.invoke(null, buffer, name); // use null if the method is static | |||
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | |||
| InvocationTargetException e) { | |||
System.err.println("Error: cannot invoke ASTStringUtils method of <appendQualifiedNameString>"); | |||
} | |||
} | |||
private static void appendQualifiedNameStringWithReflection(StringBuilder buffer, | |||
CPPASTTemplateId templateId) { | |||
appendQualifiedNameStringWithReflection(buffer,templateId.getTemplateName()); | |||
} | |||
private static void appendQualifiedNameStringWithReflection(StringBuilder buffer, | |||
ICPPASTNameSpecifier nameSpecifier) { | |||
if (nameSpecifier instanceof CPPASTTemplateId) { | |||
appendQualifiedNameStringWithReflection(buffer,(CPPASTTemplateId)nameSpecifier); | |||
return; | |||
} | |||
try { | |||
Method m = ASTStringUtil.class.getDeclaredMethod("appendQualifiedNameString", StringBuilder.class, | |||
ICPPASTNameSpecifier.class); | |||
m.setAccessible(true); // if security settings allow this | |||
m.invoke(null, buffer, nameSpecifier); // use null if the method is static | |||
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | |||
| InvocationTargetException e) { | |||
System.err.println("Error: cannot invoke ASTStringUtils method of <appendQualifiedNameString>"); | |||
} | |||
} | |||
private static StringBuilder appendBareTypeIdString(StringBuilder buffer, IASTTypeId typeId) { | |||
return appendBareDeclSpecifierString(buffer, typeId.getDeclSpecifier()); | |||
} | |||
public static String getName(IASTDeclarator declarator) { | |||
return declarator.getName().toString().replace("::", "."); | |||
} | |||
public static String getName(ICPPASTUsingDeclaration declaration) { | |||
return declaration.getName().toString().replace("::", "."); | |||
} | |||
public static String getName(IASTName name) { | |||
return name.getRawSignature().toString().replace("::", "."); | |||
} | |||
private static StringBuilder appendBareNameString(StringBuilder buffer, ICPPASTNameSpecifier name) { | |||
if (name instanceof ICPPASTQualifiedName) { | |||
final ICPPASTQualifiedName qualifiedName = (ICPPASTQualifiedName) name; | |||
final ICPPASTNameSpecifier[] segments = qualifiedName.getAllSegments(); | |||
for (int i = 0; i < segments.length; i++) { | |||
if (i > 0) { | |||
buffer.append("."); | |||
} | |||
appendQualifiedNameStringWithReflection(buffer, segments[i]); | |||
} | |||
} else if (name instanceof CPPASTTemplateId) { | |||
appendQualifiedNameStringWithReflection(buffer,(CPPASTTemplateId)name); | |||
} else if (name != null) { | |||
buffer.append(name.getRawSignature()); | |||
} | |||
return buffer; | |||
} | |||
public static String getName(ICPPASTNameSpecifier nameSpecifier) { | |||
StringBuilder buffer = new StringBuilder(); | |||
String name = appendBareNameString(buffer, nameSpecifier).toString().replace("::", ".").replace("...", ""); | |||
return name; | |||
} | |||
} |
@@ -1,248 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.extractor; | |||
import depends.entity.Entity; | |||
import depends.entity.FileEntity; | |||
import depends.entity.repo.BuiltInType; | |||
import depends.entity.repo.EntityRepo; | |||
import depends.entity.repo.InMemoryEntityRepo; | |||
import depends.relations.ImportLookupStrategy; | |||
import depends.relations.IBindingResolver; | |||
import multilang.depends.util.file.FileTraversal; | |||
import multilang.depends.util.file.FileUtil; | |||
import org.codehaus.plexus.util.FileUtils; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.lang.management.ManagementFactory; | |||
import java.util.ArrayList; | |||
import java.util.HashSet; | |||
import java.util.List; | |||
import java.util.Set; | |||
abstract public class AbstractLangProcessor { | |||
/** | |||
* The name of the lang | |||
* | |||
* @return | |||
*/ | |||
public abstract String supportedLanguage(); | |||
/** | |||
* The file suffixes in the lang | |||
* | |||
* @return | |||
*/ | |||
public abstract String[] fileSuffixes(); | |||
/** | |||
* Strategy of how to lookup types and entities in the lang. | |||
* | |||
* @return | |||
*/ | |||
public abstract ImportLookupStrategy getImportLookupStrategy(); | |||
/** | |||
* The builtInType of the lang. | |||
* | |||
* @return | |||
*/ | |||
public abstract BuiltInType getBuiltInType(); | |||
/** | |||
* The language specific file parser | |||
* | |||
* @param fileFullPath | |||
* @return | |||
*/ | |||
public abstract FileParser createFileParser(); | |||
public IBindingResolver bindingResolver; | |||
protected EntityRepo entityRepo; | |||
protected String inputSrcPath; | |||
public String[] includeDirs; | |||
private Set<UnsolvedBindings> potentialExternalDependencies; | |||
private List<String> includePaths; | |||
private static Logger logger = LoggerFactory.getLogger(AbstractLangProcessor.class); | |||
public AbstractLangProcessor() { | |||
entityRepo = new InMemoryEntityRepo(); | |||
} | |||
/** | |||
* The process steps of build dependencies. Step 1: parse all files, add | |||
* entities and expression into repositories Step 2: resolve bindings of files | |||
* (if not resolved yet) Step 3: identify dependencies | |||
* | |||
* @param inputDir | |||
* @param includeDir | |||
* @param bindingResolver | |||
* @return | |||
*/ | |||
public EntityRepo buildDependencies(String inputDir, String[] includeDir, IBindingResolver bindingResolver) { | |||
this.inputSrcPath = inputDir; | |||
this.includeDirs = includeDir; | |||
this.bindingResolver = bindingResolver; | |||
logger.info("Start parsing files..."); | |||
parseAllFiles(); | |||
markAllEntitiesScope(); | |||
if (logger.isInfoEnabled()) { | |||
logger.info("Resolve types and bindings of variables, methods and expressions.... " + this.inputSrcPath); | |||
logger.info("Heap Information: " + ManagementFactory.getMemoryMXBean().getHeapMemoryUsage()); | |||
} | |||
resolveBindings(); | |||
if (logger.isInfoEnabled()) { | |||
System.gc(); | |||
logger.info("Heap Information: " + ManagementFactory.getMemoryMXBean().getHeapMemoryUsage()); | |||
} | |||
return entityRepo; | |||
} | |||
private void markAllEntitiesScope() { | |||
entityRepo.getFileEntities().stream().forEach(entity -> { | |||
Entity file = entity.getAncestorOfType(FileEntity.class); | |||
try { | |||
if (!file.getQualifiedName().startsWith(this.inputSrcPath)) { | |||
entity.setInScope(false); | |||
} | |||
} catch (Exception e) { | |||
} | |||
}); | |||
} | |||
/** | |||
* @return unsolved bindings | |||
*/ | |||
public void resolveBindings() { | |||
System.out.println("Resolve types and bindings of variables, methods and expressions...."); | |||
this.potentialExternalDependencies = bindingResolver.resolveAllBindings(this.isEagerExpressionResolve()); | |||
if (getExternalDependencies().size() > 0) { | |||
System.out.println("There are " + getExternalDependencies().size() + " items are potential external dependencies."); | |||
} | |||
System.out.println("types and bindings resolved successfully..."); | |||
} | |||
private final void parseAllFiles() { | |||
System.out.println("Start parsing files..."); | |||
Set<String> phase2Files = new HashSet<>(); | |||
FileTraversal fileTransversal = new FileTraversal(new FileTraversal.IFileVisitor() { | |||
@Override | |||
public void visit(File file) { | |||
String fileFullPath = file.getAbsolutePath(); | |||
if (!fileFullPath.startsWith(inputSrcPath)) { | |||
return; | |||
} | |||
parseFile(fileFullPath, phase2Files); | |||
} | |||
}); | |||
fileTransversal.extensionFilter(this.fileSuffixes()); | |||
fileTransversal.travers(this.inputSrcPath); | |||
for (String f : phase2Files) { | |||
parseFile(f, phase2Files); | |||
} | |||
System.out.println("all files procceed successfully..."); | |||
} | |||
protected void parseFile(String fileFullPath, Set<String> phase2Files) { | |||
FileParser fileParser = createFileParser(); | |||
try { | |||
if (fileParser.isPhase2Files(fileFullPath)){ | |||
phase2Files.add(fileFullPath); | |||
}else { | |||
fileParser.parse(fileFullPath); | |||
} | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} catch (Exception e) { | |||
System.err.println("error occoured during parse file " + fileFullPath); | |||
e.printStackTrace(); | |||
} | |||
} | |||
public List<String> includePaths() { | |||
if (this.includePaths ==null) { | |||
this.includePaths = buildIncludePath(); | |||
} | |||
return includePaths; | |||
} | |||
private List<String> buildIncludePath() { | |||
includePaths = new ArrayList<String>(); | |||
for (String path : includeDirs) { | |||
if (FileUtils.fileExists(path)) { | |||
path = FileUtil.uniqFilePath(path); | |||
if (!includePaths.contains(path)) | |||
includePaths.add(path); | |||
} | |||
path = this.inputSrcPath + File.separator + path; | |||
if (FileUtils.fileExists(path)) { | |||
path = FileUtil.uniqFilePath(path); | |||
if (!includePaths.contains(path)) | |||
includePaths.add(path); | |||
} | |||
} | |||
return includePaths; | |||
} | |||
public EntityRepo getEntityRepo() { | |||
return this.entityRepo; | |||
} | |||
public abstract List<String> supportedRelations(); | |||
public Set<UnsolvedBindings> getExternalDependencies() { | |||
return potentialExternalDependencies; | |||
} | |||
public String getRelationMapping(String relation) { | |||
return relation; | |||
} | |||
/** | |||
* Whether to resolve expression immediately during parse | |||
* @return | |||
*/ | |||
public boolean isEagerExpressionResolve(){ | |||
return false; | |||
} | |||
/** | |||
* Call as Impl: | |||
* implicit call (for example polymorphic in cpp) | |||
* @return | |||
*/ | |||
public boolean supportCallAsImpl(){return false;}; | |||
} |
@@ -1,203 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.entity; | |||
import depends.relations.IBindingResolver; | |||
import java.util.*; | |||
public class AliasEntity extends Entity { | |||
private Entity referToEntity = new EmptyTypeEntity(); | |||
private GenericName originName; | |||
private List<Entity> referPath = new ArrayList<>(); | |||
private boolean deepResolve = false; | |||
public AliasEntity() { | |||
} | |||
public AliasEntity(GenericName simpleName, Entity parent, Integer id, GenericName originTypeName) { | |||
super(simpleName, parent, id); | |||
this.originName = originTypeName; | |||
} | |||
public void inferLocalLevelEntities(IBindingResolver bindingResolver) { | |||
if (!(referToEntity instanceof EmptyTypeEntity)) return; | |||
Entity entity = bindingResolver.resolveName(this, originName, true); | |||
while(entity instanceof AliasEntity) { | |||
AliasEntity aliasEntity = (AliasEntity)entity; | |||
if (this.referPath.contains(aliasEntity)) { | |||
entity = null; | |||
break; | |||
} | |||
this.referPath.add(aliasEntity); | |||
entity = bindingResolver.resolveName(aliasEntity, aliasEntity.originName,true); | |||
if (entity==null) break; | |||
if (entity.equals(this)) { | |||
entity = null; | |||
break; | |||
} | |||
} | |||
if (entity != null) | |||
referToEntity = entity; | |||
} | |||
public Collection<Entity> getResolvedTypeParameters() { | |||
if (!(referToEntity instanceof DecoratedEntity)) | |||
return new ArrayList<>(); | |||
DecoratedEntity origin = (DecoratedEntity) referToEntity; | |||
return origin.getResolvedTypeParameters(); | |||
} | |||
public Collection<Entity> getResolvedAnnotations() { | |||
if (!(referToEntity instanceof DecoratedEntity)) | |||
return new ArrayList<>(); | |||
DecoratedEntity origin = (DecoratedEntity) referToEntity; | |||
return origin.getResolvedAnnotations(); | |||
} | |||
public ArrayList<VarEntity> getVars() { | |||
if (!(referToEntity instanceof ContainerEntity)) | |||
return new ArrayList<>(); | |||
ContainerEntity origin = (ContainerEntity) referToEntity; | |||
return origin.getVars(); | |||
} | |||
public ArrayList<FunctionEntity> getFunctions() { | |||
if (!(referToEntity instanceof ContainerEntity)) | |||
return new ArrayList<>(); | |||
ContainerEntity origin = (ContainerEntity) referToEntity; | |||
return origin.getFunctions(); | |||
} | |||
protected FunctionEntity lookupFunctionLocally(GenericName functionName) { | |||
if (!(referToEntity instanceof ContainerEntity)) | |||
return null; | |||
ContainerEntity origin = (ContainerEntity) referToEntity; | |||
return origin.lookupFunctionLocally(functionName); | |||
} | |||
public List<Entity> lookupFunctionInVisibleScope(GenericName functionName) { | |||
if (!(referToEntity instanceof ContainerEntity)) | |||
return null; | |||
ContainerEntity origin = (ContainerEntity) referToEntity; | |||
return origin.lookupFunctionInVisibleScope(functionName); | |||
} | |||
public Entity lookupVarsInVisibleScope(GenericName varName) { | |||
if (!(referToEntity instanceof ContainerEntity)) | |||
return null; | |||
ContainerEntity origin = (ContainerEntity) referToEntity; | |||
return origin.lookupVarInVisibleScope(varName); | |||
} | |||
public Collection<ContainerEntity> getResolvedMixins() { | |||
if (!(referToEntity instanceof ContainerEntity)) | |||
return new ArrayList<>(); | |||
ContainerEntity origin = (ContainerEntity) referToEntity; | |||
return origin.getResolvedMixins(); | |||
} | |||
public Collection<TypeEntity> getInheritedTypes() { | |||
if (referToEntity instanceof TypeEntity) | |||
return ((TypeEntity) referToEntity).getInheritedTypes(); | |||
return new ArrayList<>(); | |||
} | |||
public Collection<TypeEntity> getImplementedTypes() { | |||
if (referToEntity instanceof TypeEntity) | |||
return ((TypeEntity) referToEntity).getImplementedTypes(); | |||
return new ArrayList<>(); | |||
} | |||
public TypeEntity getInheritedType() { | |||
if (referToEntity instanceof TypeEntity) | |||
return ((TypeEntity) referToEntity).getInheritedType(); | |||
return null; | |||
} | |||
public Collection<Entity> getReturnTypes() { | |||
if (!(referToEntity instanceof FunctionEntity)) | |||
return new ArrayList<>(); | |||
FunctionEntity origin = (FunctionEntity) referToEntity; | |||
return origin.getReturnTypes(); | |||
} | |||
public TypeEntity getType() { | |||
return referToEntity.getType(); | |||
} | |||
public Collection<VarEntity> getParameters() { | |||
if (!(referToEntity instanceof FunctionEntity)) | |||
return new ArrayList<>(); | |||
FunctionEntity origin = (FunctionEntity) referToEntity; | |||
return origin.getParameters(); | |||
} | |||
public Collection<Entity> getThrowTypes() { | |||
if (!(referToEntity instanceof FunctionEntity)) | |||
return new ArrayList<>(); | |||
FunctionEntity origin = (FunctionEntity) referToEntity; | |||
return origin.getThrowTypes(); | |||
} | |||
public Entity getOriginType() { | |||
return referToEntity; | |||
} | |||
public Entity getReferToEntity() { | |||
return referToEntity; | |||
} | |||
public void setReferToEntity(Entity referToEntity) { | |||
this.referToEntity = referToEntity; | |||
} | |||
public Entity deepResolve() { | |||
if (!deepResolve) return this; | |||
Set<Entity> searched = new HashSet<>(); | |||
int i=0; | |||
Entity current = this; | |||
while(i<100) { //maximum 100 levels | |||
if (searched.contains(current)) return current; //avoid a loop | |||
if (!(current instanceof AliasEntity)) return current; | |||
searched.add(current); | |||
Entity originalFile = current.getAncestorOfType(FileEntity.class); | |||
current = ((AliasEntity)current).getReferToEntity(); | |||
if (current ==null) return this; | |||
//if already out of current file, return current | |||
if (!current.getAncestorOfType(FileEntity.class).equals(originalFile)) { | |||
return current; | |||
} | |||
i++; | |||
} | |||
return current; | |||
} | |||
public boolean isDeepResolve() { | |||
return deepResolve; | |||
} | |||
public void setDeepResolve(boolean deepResolve) { | |||
this.deepResolve = deepResolve; | |||
} | |||
} |
@@ -1,121 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.extractor.java.context; | |||
import java.lang.reflect.InvocationTargetException; | |||
import java.lang.reflect.Method; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.HashSet; | |||
import java.util.List; | |||
import java.util.stream.Collectors; | |||
import org.antlr.v4.runtime.RuleContext; | |||
import org.codehaus.plexus.util.StringUtils; | |||
import depends.entity.ContainerEntity; | |||
import depends.entity.GenericName; | |||
import depends.extractor.java.JavaParser.AnnotationContext; | |||
public class AnnotationProcessor { | |||
public AnnotationProcessor() { | |||
} | |||
public void processAnnotationModifier(RuleContext ctx, @SuppressWarnings("rawtypes") Class rootClass, | |||
String toAnnotationPath,ContainerEntity container) { | |||
List<ContainerEntity> list = new ArrayList<>() ; | |||
list.add(container); | |||
processAnnotationModifier(ctx, rootClass, | |||
toAnnotationPath, list); | |||
} | |||
public void processAnnotationModifier(RuleContext ctx, @SuppressWarnings("rawtypes") Class rootClass, | |||
String toAnnotationPath, List<?> containers) { | |||
while (true) { | |||
if (ctx == null) | |||
break; | |||
if (ctx.getClass().equals(rootClass)) | |||
break; | |||
ctx = ctx.parent; | |||
} | |||
if (ctx == null) | |||
return; | |||
try { | |||
Object r = ctx; | |||
String[] paths = toAnnotationPath.split("\\."); | |||
for (String path : paths) { | |||
r = invokeMethod(r, path); | |||
if (r == null) | |||
return; | |||
} | |||
Collection<AnnotationContext> contexts = new HashSet<>(); | |||
mergeElements(contexts, r); | |||
for (Object item : contexts) { | |||
AnnotationContext annotation = (AnnotationContext) item; | |||
String name = QualitiedNameContextHelper.getName(annotation.qualifiedName()); | |||
containers.stream().forEach(container->((ContainerEntity)container).addAnnotation(GenericName.build(name))); | |||
} | |||
} catch (Exception e) { | |||
return; | |||
} | |||
} | |||
private void mergeElements(Collection<AnnotationContext> collection, Object r) { | |||
if (r instanceof Collection) { | |||
for (Object item : (Collection<?>) r) { | |||
mergeElements(collection, item); | |||
} | |||
} else { | |||
if (r instanceof AnnotationContext) | |||
collection.add((AnnotationContext) r); | |||
} | |||
} | |||
private Object invokeMethod(Object r, String path) { | |||
if (StringUtils.isEmpty(path)) | |||
return null; | |||
if (r instanceof Collection) { | |||
Collection<?> list = (Collection<?>) r; | |||
return list.stream().map(item -> invokeMethod(item, path)).filter(item -> item != null) | |||
.collect(Collectors.toSet()); | |||
} | |||
try { | |||
Method m = r.getClass().getMethod(path); | |||
return m.invoke(r); | |||
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | |||
| InvocationTargetException e) { | |||
return null; | |||
} | |||
} | |||
} |
@@ -1,297 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.relations; | |||
import depends.entity.*; | |||
import depends.entity.repo.BuiltInType; | |||
import depends.entity.repo.EntityRepo; | |||
import depends.extractor.AbstractLangProcessor; | |||
import depends.extractor.UnsolvedBindings; | |||
import depends.extractor.empty.EmptyBuiltInType; | |||
import depends.importtypes.Import; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import java.lang.management.ManagementFactory; | |||
import java.util.*; | |||
public class BindingResolver implements IBindingResolver{ | |||
private BuiltInType buildInTypeManager = new EmptyBuiltInType(); | |||
private ImportLookupStrategy importLookupStrategy; | |||
private Set<UnsolvedBindings> unsolvedSymbols = new HashSet<>(); | |||
private EntityRepo repo; | |||
private boolean eagerExpressionResolve = false; | |||
private boolean isCollectUnsolvedBindings = false; | |||
private boolean isDuckTypingDeduce = true; | |||
private static Logger logger = LoggerFactory.getLogger(IBindingResolver.class); | |||
public BindingResolver(AbstractLangProcessor langProcessor, | |||
boolean isCollectUnsolvedBindings, boolean isDuckTypingDeduce) { | |||
this.repo = langProcessor.getEntityRepo(); | |||
this.importLookupStrategy = langProcessor.getImportLookupStrategy(); | |||
this.buildInTypeManager = langProcessor.getBuiltInType(); | |||
this.isCollectUnsolvedBindings = isCollectUnsolvedBindings; | |||
this.isDuckTypingDeduce = isDuckTypingDeduce; | |||
unsolvedSymbols= new HashSet<>(); | |||
importLookupStrategy.setBindingResolver(this); | |||
} | |||
@Override | |||
public Set<UnsolvedBindings> resolveAllBindings(boolean isEagerExpressionResolve) { | |||
System.out.println("Resolve type bindings...."); | |||
if (logger.isInfoEnabled()) { | |||
logger.info("Resolve type bindings..."); | |||
} | |||
resolveTypes(isEagerExpressionResolve); | |||
System.out.println("Dependency analaysing...."); | |||
if (logger.isInfoEnabled()) { | |||
logger.info("Dependency analaysing..."); | |||
} | |||
logger.info("Heap Information: " + ManagementFactory.getMemoryMXBean().getHeapMemoryUsage()); | |||
return unsolvedSymbols; | |||
} | |||
private void resolveTypes(boolean eagerExpressionResolve) { | |||
this.eagerExpressionResolve = eagerExpressionResolve; | |||
Iterator<Entity> iterator = repo.sortedFileIterator(); | |||
while(iterator.hasNext()) { | |||
Entity entity= iterator.next(); | |||
entity.inferEntities(this); | |||
} | |||
} | |||
@Override | |||
public Collection<Entity> getImportedRelationEntities(List<Import> importedNames) { | |||
return importLookupStrategy.getImportedRelationEntities(importedNames); | |||
} | |||
@Override | |||
public Collection<Entity> getImportedTypes(List<Import> importedNames, FileEntity fileEntity) { | |||
HashSet<UnsolvedBindings> unsolved = new HashSet<UnsolvedBindings>(); | |||
Collection<Entity> result = importLookupStrategy.getImportedTypes(importedNames,unsolved); | |||
for (UnsolvedBindings item:unsolved) { | |||
item.setFromEntity(fileEntity); | |||
addUnsolvedBinding(item); | |||
} | |||
return result; | |||
} | |||
private void addUnsolvedBinding(UnsolvedBindings item) { | |||
if (!isCollectUnsolvedBindings) return; | |||
this.unsolvedSymbols.add(item); | |||
} | |||
@Override | |||
public Collection<Entity> getImportedFiles(List<Import> importedNames) { | |||
return importLookupStrategy.getImportedFiles(importedNames); | |||
} | |||
@Override | |||
public TypeEntity inferTypeFromName(Entity fromEntity, GenericName rawName) { | |||
Entity data = resolveName(fromEntity, rawName, true); | |||
if (data == null) | |||
return null; | |||
return data.getType(); | |||
} | |||
@Override | |||
public Entity resolveName(Entity fromEntity, GenericName rawName, boolean searchImport) { | |||
if (rawName==null) return null; | |||
Entity entity = resolveNameInternal(fromEntity,rawName,searchImport); | |||
if (entity==null ) { | |||
if (!this.buildInTypeManager.isBuiltInType(rawName.getName())) { | |||
addUnsolvedBinding(new UnsolvedBindings(rawName.getName(), fromEntity)); | |||
} | |||
} | |||
return entity; | |||
} | |||
private Entity resolveNameInternal(Entity fromEntity, GenericName rawName, boolean searchImport) { | |||
if (rawName==null || rawName.getName()==null) | |||
return null; | |||
if (buildInTypeManager.isBuiltInType(rawName.getName())) { | |||
return TypeEntity.buildInType; | |||
} | |||
// qualified name will first try global name directly | |||
if (rawName.startsWith(".")) { | |||
rawName = rawName.substring(1); | |||
if (repo.getEntity(rawName) != null) | |||
return repo.getEntity(rawName); | |||
} | |||
Entity entity = null; | |||
int indexCount = 0; | |||
String name = rawName.getName(); | |||
if (fromEntity==null) return null; | |||
do { | |||
entity = lookupEntity(fromEntity, name, searchImport); | |||
if (entity!=null ) { | |||
break; | |||
} | |||
if (importLookupStrategy.supportGlobalNameLookup()) { | |||
if (repo.getEntity(name) != null) { | |||
entity = repo.getEntity(name); | |||
break; | |||
} | |||
} | |||
indexCount++; | |||
if (name.contains(".")) | |||
name = name.substring(0,name.lastIndexOf('.')); | |||
else | |||
break; | |||
}while (true); | |||
if (entity == null) { | |||
return null; | |||
} | |||
String[] names = rawName.getName().split("\\."); | |||
if (names.length == 0) | |||
return null; | |||
if (names.length == 1) { | |||
return entity; | |||
} | |||
// then find the subsequent symbols | |||
return findEntitySince(entity, names, names.length-indexCount); | |||
} | |||
private Entity lookupEntity(Entity fromEntity, String name, boolean searchImport) { | |||
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 (searchImport) | |||
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 (nameIndex == -1) { | |||
System.err.println("No expected symbols: names"+Arrays.toString(names) +", index=" + nameIndex); | |||
return null; | |||
} | |||
//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().getName().equals(names[nameIndex])) { | |||
return findEntitySince(child, names, nameIndex + 1); | |||
} | |||
} | |||
return null; | |||
} | |||
@Override | |||
public Entity lookupTypeInImported(FileEntity fileEntity, String name) { | |||
if (fileEntity == null) | |||
return null; | |||
Entity type = importLookupStrategy.lookupImportedType(name, fileEntity); | |||
if (type != null) | |||
return type; | |||
return null; | |||
} | |||
/** | |||
* 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 = fromEntity.getByName(name, new HashSet<>()); | |||
if (entity!=null) return entity; | |||
fromEntity = fromEntity.getParent(); | |||
if (fromEntity == null) | |||
break; | |||
} | |||
return null; | |||
} | |||
@Override | |||
public List<TypeEntity> calculateCandidateTypes(VarEntity fromEntity, List<FunctionCall> functionCalls) { | |||
if (buildInTypeManager.isBuildInTypeMethods(functionCalls)) { | |||
return new ArrayList<>(); | |||
} | |||
if (!isDuckTypingDeduce) | |||
return new ArrayList<>(); | |||
return searchTypesInRepo(fromEntity, functionCalls); | |||
} | |||
private List<TypeEntity> searchTypesInRepo(VarEntity fromEntity, List<FunctionCall> functionCalls) { | |||
List<TypeEntity> types = new ArrayList<>(); | |||
Iterator<Entity> iterator = repo.sortedFileIterator(); | |||
while(iterator.hasNext()) { | |||
Entity f = iterator.next(); | |||
if (f instanceof FileEntity) { | |||
for (TypeEntity type:((FileEntity)f).getDeclaredTypes()) { | |||
FunctionMatcher functionMatcher = new FunctionMatcher(type.getFunctions()); | |||
if (functionMatcher.containsAll(functionCalls)) { | |||
types.add(type); | |||
} | |||
} | |||
} | |||
} | |||
return types; | |||
} | |||
@Override | |||
public boolean isEagerExpressionResolve() { | |||
return eagerExpressionResolve; | |||
} | |||
@Override | |||
public EntityRepo getRepo() { | |||
return repo; | |||
} | |||
} |
@@ -1,110 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.entity.repo; | |||
import depends.entity.FunctionCall; | |||
import depends.entity.TypeEntity; | |||
import java.util.HashSet; | |||
import java.util.List; | |||
import java.util.Set; | |||
public abstract class BuiltInType { | |||
public BuiltInType(){ | |||
createBuiltInTypes(); | |||
} | |||
/** | |||
* Init the build in types data | |||
*/ | |||
private void createBuiltInTypes() { | |||
for(String prefix: getBuiltInTypePrefix()) { | |||
builtInPrefix.add(prefix); | |||
} | |||
for (String type: getBuiltInTypeName()) { | |||
builtInType.add(type); | |||
} | |||
for (String method:getBuiltInMethods()) { | |||
builtInMethod.add(method); | |||
} | |||
} | |||
protected String[] getBuiltInMethods(){return new String[]{};} | |||
protected String[] getBuiltInTypeName(){return new String[]{};} | |||
protected String[] getBuiltInTypePrefix() {return new String[]{};} | |||
private Set<String> builtInType = new HashSet<>(); | |||
private Set<String> builtInPrefix = new HashSet<>(); | |||
private Set<String> builtInMethod = new HashSet<>(); | |||
/** | |||
* To determine whether a type name is built-in | |||
* @param typeName | |||
* @return | |||
*/ | |||
public boolean isBuiltInType(String typeName) { | |||
return TypeEntity.buildInType.getRawName().uniqName().equals(typeName) || | |||
builtInType.contains(typeName)|| | |||
isBuiltInTypePrefix(typeName); | |||
} | |||
/** | |||
* To determine a typeName is a built-in type based on prefix. | |||
* For example, in Java language, name start with java.*, javax.*, com.sun.* | |||
* is build-in types | |||
* @param typeName | |||
* @return | |||
*/ | |||
private boolean isBuiltInTypePrefix(String typeName) { | |||
for (String prefix:builtInPrefix) { | |||
if (typeName.startsWith(prefix)) return true; | |||
} | |||
return false; | |||
} | |||
/** | |||
* In some language, there are common methods, like in ruby, | |||
* object_id is a method for all type | |||
* @param name | |||
* @return | |||
*/ | |||
public boolean isBuildInMethod(String name) { | |||
return builtInMethod.contains(name); | |||
} | |||
/** | |||
* Used by duck typing deduce feature: | |||
* - if all calls of a type are build in method, | |||
* then no duck typing is deduced | |||
* Refer to Python built-in type for example | |||
* | |||
* @param functionCalls | |||
* @return | |||
*/ | |||
public boolean isBuildInTypeMethods(List<FunctionCall> functionCalls) { | |||
return false; | |||
} | |||
} |
@@ -1,311 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.entity; | |||
import depends.relations.IBindingResolver; | |||
import depends.relations.Relation; | |||
import java.util.*; | |||
public class CandidateTypes extends TypeEntity { | |||
private List<TypeEntity> candidateTypes; | |||
public CandidateTypes() { | |||
candidateTypes = new ArrayList<>(); | |||
} | |||
public CandidateTypes(List<TypeEntity> candidateTypes, Integer id) { | |||
super(GenericName.build("candidateTypes"), null, id); | |||
this.candidateTypes = candidateTypes; | |||
} | |||
public List<TypeEntity> getCandidateTypes() { | |||
return candidateTypes; | |||
} | |||
@Override | |||
public Collection<TypeEntity> getInheritedTypes() { | |||
List<TypeEntity> result = new ArrayList<>(); | |||
for (TypeEntity type:candidateTypes) { | |||
result.addAll(type.getInheritedTypes()); | |||
} | |||
return result; | |||
} | |||
@Override | |||
public Collection<TypeEntity> getImplementedTypes() { | |||
List<TypeEntity> result = new ArrayList<>(); | |||
for (TypeEntity type:candidateTypes) { | |||
result.addAll(type.getImplementedTypes()); | |||
} | |||
return result; | |||
} | |||
@Override | |||
public ArrayList<FunctionEntity> getFunctions() { | |||
ArrayList<FunctionEntity> result = new ArrayList<>(); | |||
for (TypeEntity type:candidateTypes) { | |||
result.addAll(type.getFunctions()); | |||
} | |||
return result; | |||
} | |||
@Override | |||
public TypeEntity getInheritedType() { | |||
return inheritedType; | |||
} | |||
@Override | |||
public List<Entity> lookupFunctionInVisibleScope(GenericName functionName) { | |||
List<Entity> functions = new ArrayList<>(); | |||
for (TypeEntity type:candidateTypes) { | |||
List<Entity> f = type.lookupFunctionInVisibleScope(functionName); | |||
if (f!=null) { | |||
functions.addAll(f); | |||
} | |||
} | |||
if (functions.size()==0) | |||
return null; | |||
return functions; | |||
} | |||
@Override | |||
public Entity lookupVarInVisibleScope(GenericName varName) { | |||
for (TypeEntity type:candidateTypes) { | |||
Entity v = type.lookupVarInVisibleScope(varName); | |||
if (v!=null) return v; | |||
} | |||
return null; | |||
} | |||
@Override | |||
public VarEntity lookupVarLocally(String varName) { | |||
for (TypeEntity type:candidateTypes) { | |||
VarEntity v = type.lookupVarLocally(varName); | |||
if (v!=null) return v; | |||
} | |||
return null; | |||
} | |||
@Override | |||
public TypeEntity getType() { | |||
if (candidateTypes.size()>0) return candidateTypes.get(0); | |||
return null; | |||
} | |||
@Override | |||
public void inferLocalLevelEntities(IBindingResolver bindingResolver) { | |||
System.err.println("error: inferLocalLevelEntities should not been invoked"); | |||
super.inferLocalLevelEntities(bindingResolver); | |||
} | |||
@Override | |||
public void addImplements(GenericName typeName) { | |||
System.err.println("error: addImplements should not been invoked"); | |||
super.addImplements(typeName); | |||
} | |||
@Override | |||
public void addExtends(GenericName typeName) { | |||
System.err.println("error: addExtends should not been invoked"); | |||
super.addExtends(typeName); | |||
} | |||
@Override | |||
public void addVar(VarEntity var) { | |||
System.err.println("error: addVar should not been invoked"); | |||
super.addVar(var); | |||
} | |||
@Override | |||
public ArrayList<VarEntity> getVars() { | |||
System.err.println("error: getVars should not been invoked"); | |||
return super.getVars(); | |||
} | |||
@Override | |||
public void addFunction(FunctionEntity functionEntity) { | |||
System.err.println("error: addFunction should not been invoked"); | |||
super.addFunction(functionEntity); | |||
} | |||
@Override | |||
public HashMap<Object, Expression> expressions() { | |||
System.err.println("error: expressions should not been invoked"); | |||
return super.expressions(); | |||
} | |||
@Override | |||
public void addExpression(Object key, Expression expression) { | |||
System.err.println("error: addExpression should not been invoked"); | |||
super.addExpression(key, expression); | |||
} | |||
public void resolveExpressions(IBindingResolver bindingResolver) { | |||
System.err.println("error: resolveExpressions should not been invoked"); | |||
super.resolveExpressions(bindingResolver); | |||
} | |||
@Override | |||
public void addMixin(GenericName moduleName) { | |||
System.err.println("error: addMixin should not been invoked"); | |||
super.addMixin(moduleName); | |||
} | |||
@Override | |||
public Collection<ContainerEntity> getResolvedMixins() { | |||
System.err.println("error: getResolvedMixins should not been invoked"); | |||
return super.getResolvedMixins(); | |||
} | |||
@Override | |||
public void addAnnotation(GenericName name) { | |||
System.err.println("error: addAnnotation should not been invoked"); | |||
super.addAnnotation(name); | |||
} | |||
@Override | |||
public Collection<Entity> getResolvedTypeParameters() { | |||
System.err.println("error: getResolvedTypeParameters should not been invoked"); | |||
return super.getResolvedTypeParameters(); | |||
} | |||
@Override | |||
public Collection<Entity> getResolvedAnnotations() { | |||
System.err.println("error: getResolvedAnnotations should not been invoked"); | |||
return super.getResolvedAnnotations(); | |||
} | |||
@Override | |||
public boolean isGenericTypeParameter(GenericName rawType) { | |||
System.err.println("error: isGenericTypeParameter should not been invoked"); | |||
return super.isGenericTypeParameter(rawType); | |||
} | |||
@Override | |||
protected Collection<Entity> identiferToEntities(IBindingResolver bindingResolver, Collection<GenericName> identifiers) { | |||
System.err.println("error: identiferToTypes should not been invoked"); | |||
return super.identiferToEntities(bindingResolver, identifiers); | |||
} | |||
@Override | |||
public GenericName getRawName() { | |||
return super.getRawName(); | |||
} | |||
@Override | |||
public Integer getId() { | |||
return super.getId(); | |||
} | |||
@Override | |||
public void addRelation(Relation relation) { | |||
System.err.println("error: addRelation should not been invoked"); | |||
super.addRelation(relation); | |||
} | |||
@Override | |||
public ArrayList<Relation> getRelations() { | |||
System.err.println("error: getRelations should not been invoked"); | |||
return super.getRelations(); | |||
} | |||
@Override | |||
public void addChild(Entity child) { | |||
System.err.println("error: addChild should not been invoked"); | |||
super.addChild(child); | |||
} | |||
@Override | |||
public Entity getParent() { | |||
return null; | |||
} | |||
@Override | |||
public void setParent(Entity parent) { | |||
System.err.println("error: setParent should not been invoked"); | |||
super.setParent(parent); | |||
} | |||
@Override | |||
public Collection<Entity> getChildren() { | |||
List<Entity> children = new ArrayList<>(); | |||
for (Entity entity:this.candidateTypes) { | |||
children.addAll(entity.getChildren()); | |||
} | |||
return children; | |||
} | |||
@Override | |||
public void setQualifiedName(String qualifiedName) { | |||
System.err.println("error: setQualifiedName should not been invoked"); | |||
super.setQualifiedName(qualifiedName); | |||
} | |||
@Override | |||
public void setRawName(GenericName rawName) { | |||
System.err.println("error: setRawName should not been invoked"); | |||
super.setRawName(rawName); | |||
} | |||
@Override | |||
public String getQualifiedName(boolean overrideFileWithPackage) { | |||
System.err.println("error: getQualifiedName should not been invoked"); | |||
return super.getQualifiedName(overrideFileWithPackage); | |||
} | |||
@Override | |||
public Entity getAncestorOfType(@SuppressWarnings("rawtypes") Class classType) { | |||
return null; | |||
} | |||
@Override | |||
public void inferEntities(IBindingResolver bindingResolver) { | |||
System.err.println("error: inferEntities should not been invoked"); | |||
super.inferEntities(bindingResolver); | |||
} | |||
@Override | |||
public String getDisplayName() { | |||
System.err.println("error: getDisplayName should not been invoked"); | |||
return super.getDisplayName(); | |||
} | |||
@Override | |||
public Entity getByName(String name, HashSet<Entity> searched) { | |||
Entity entity = super.getByName(name, searched); | |||
if (entity!=null) return entity; | |||
for (TypeEntity type:getCandidateTypes()) { | |||
if (searched.contains(type)) continue; | |||
Entity e = type.getByName(name, searched); | |||
if (e !=null) return e; | |||
} | |||
return null; | |||
} | |||
} |
@@ -1,86 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.extractor.cpp.cdt; | |||
import depends.entity.repo.EntityRepo; | |||
import depends.extractor.cpp.CppFileParser; | |||
import depends.extractor.cpp.MacroRepo; | |||
import depends.relations.IBindingResolver; | |||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; | |||
import java.io.IOException; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
public class CdtCppFileParser extends CppFileParser { | |||
private PreprocessorHandler preprocessorHandler ; | |||
private IBindingResolver bindingResolver; | |||
private MacroRepo macroRepo; | |||
public CdtCppFileParser(EntityRepo entityRepo, PreprocessorHandler preprocessorHandler, IBindingResolver bindingResolver, MacroRepo macroRepo) { | |||
super(entityRepo); | |||
this.preprocessorHandler = preprocessorHandler; | |||
this.bindingResolver = bindingResolver; | |||
this.macroRepo= macroRepo; | |||
} | |||
@Override | |||
protected void parseFile(String fileFullPath) throws IOException { | |||
Map<String, String> macroMap = new HashMap<>(macroRepo.getDefaultMap()); | |||
parse(fileFullPath,macroMap); | |||
} | |||
/** | |||
* | |||
* @param isInScope whether the parse is invoked by project file or an 'indirect' included file | |||
* @return | |||
*/ | |||
public void parse(String fileFullPath,Map<String, String> macroMap) throws IOException { | |||
CppVisitor bridge = new CppVisitor(fileFullPath, entityRepo, preprocessorHandler, bindingResolver); | |||
IASTTranslationUnit tu = (new CDTParser(preprocessorHandler.getIncludePaths())).parse(fileFullPath,macroMap); | |||
boolean containsIncludes = false; | |||
for (String incl:preprocessorHandler.getDirectIncludedFiles(tu.getAllPreprocessorStatements(),fileFullPath)) { | |||
CdtCppFileParser importedParser = new CdtCppFileParser(entityRepo, preprocessorHandler, bindingResolver,macroRepo); | |||
importedParser.parse(incl); | |||
Map<String, String> macros = macroRepo.get(incl); | |||
if (macros!=null) | |||
macroMap.putAll(macros); | |||
containsIncludes = true; | |||
} | |||
if (containsIncludes) { | |||
tu = (new CDTParser(preprocessorHandler.getIncludePaths())).parse(fileFullPath,macroMap); | |||
} | |||
macroRepo.putMacros(fileFullPath,macroMap,tu.getMacroDefinitions()); | |||
tu.accept(bridge); | |||
return; | |||
} | |||
@Override | |||
protected boolean isPhase2Files(String fileFullPath) { | |||
if (fileFullPath.endsWith(".h") || fileFullPath.endsWith(".hh") || fileFullPath.endsWith(".hpp") | |||
|| fileFullPath.endsWith(".hxx")) | |||
return true; | |||
return false; | |||
} | |||
} |
@@ -1,467 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.entity; | |||
import depends.entity.repo.EntityRepo; | |||
import depends.relations.IBindingResolver; | |||
import depends.relations.Relation; | |||
import multilang.depends.util.file.TemporaryFile; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import java.io.*; | |||
import java.lang.ref.WeakReference; | |||
import java.util.*; | |||
/** | |||
* ContainerEntity for example file, class, method, etc. they could contain | |||
* vars, functions, ecpressions, type parameters, etc. | |||
*/ | |||
public abstract class ContainerEntity extends DecoratedEntity { | |||
private static final Logger logger = LoggerFactory.getLogger(ContainerEntity.class); | |||
private ArrayList<VarEntity> vars; | |||
private ArrayList<FunctionEntity> functions; | |||
WeakReference<HashMap<Object, Expression>> expressionWeakReference; | |||
private ArrayList<Expression> expressionList; | |||
private int expressionCount = 0; | |||
private Collection<GenericName> mixins; | |||
private Collection<ContainerEntity> resolvedMixins; | |||
private ArrayList<VarEntity> vars() { | |||
if (vars==null) | |||
vars = new ArrayList<>(); | |||
return this.vars; | |||
} | |||
private Collection<GenericName> mixins() { | |||
if (mixins==null) | |||
mixins = new ArrayList<>(); | |||
return this.mixins; | |||
} | |||
private ArrayList<FunctionEntity> functions() { | |||
if (functions==null) | |||
functions = new ArrayList<>(); | |||
return this.functions; | |||
} | |||
public ContainerEntity() { | |||
} | |||
public ContainerEntity(GenericName rawName, Entity parent, Integer id) { | |||
super(rawName, parent, id); | |||
} | |||
public void addVar(VarEntity var) { | |||
if (logger.isDebugEnabled()) { | |||
logger.debug("var found: " + var.getRawName() + ":" + var.getRawType()); | |||
} | |||
this.vars().add(var); | |||
} | |||
public ArrayList<VarEntity> getVars() { | |||
if (vars==null) | |||
return new ArrayList<>(); | |||
return this.vars(); | |||
} | |||
public void addFunction(FunctionEntity functionEntity) { | |||
this.functions().add(functionEntity); | |||
} | |||
public ArrayList<FunctionEntity> getFunctions() { | |||
if (functions==null) | |||
return new ArrayList<>(); | |||
return this.functions; | |||
} | |||
public HashMap<Object, Expression> expressions() { | |||
if (expressionWeakReference==null) | |||
expressionWeakReference= new WeakReference<HashMap<Object, Expression>>(new HashMap<>()); | |||
HashMap<Object, Expression> r = expressionWeakReference.get(); | |||
if (r==null) return new HashMap<>(); | |||
return r; | |||
} | |||
public void addExpression(Object key, Expression expression) { | |||
expressions().put(key, expression); | |||
expressionList().add(expression); | |||
expressionCount = expressionList.size(); | |||
} | |||
public boolean containsExpression(Object key) { | |||
return expressions().containsKey(key); | |||
} | |||
/** | |||
* For all data in the class, infer their types. Should be override in | |||
* sub-classes | |||
*/ | |||
public void inferLocalLevelEntities(IBindingResolver bindingResolver) { | |||
super.inferLocalLevelEntities(bindingResolver); | |||
for (VarEntity var : this.vars()) { | |||
if (var.getParent()!=this) { | |||
var.inferLocalLevelEntities(bindingResolver); | |||
} | |||
} | |||
for (FunctionEntity func : this.getFunctions()) { | |||
if (func.getParent()!=this) { | |||
func.inferLocalLevelEntities(bindingResolver); | |||
} | |||
} | |||
if (bindingResolver.isEagerExpressionResolve()) { | |||
reloadExpression(bindingResolver.getRepo()); | |||
resolveExpressions(bindingResolver); | |||
cacheExpressions(); | |||
} | |||
resolvedMixins = identiferToContainerEntity(bindingResolver, getMixins()); | |||
} | |||
private Collection<GenericName> getMixins() { | |||
if (mixins==null) | |||
return new ArrayList<>(); | |||
return mixins; | |||
} | |||
private Collection<ContainerEntity> identiferToContainerEntity(IBindingResolver bindingResolver, Collection<GenericName> identifiers) { | |||
if (identifiers.size()==0) return null; | |||
ArrayList<ContainerEntity> r = new ArrayList<>(); | |||
for (GenericName identifier : identifiers) { | |||
Entity entity = bindingResolver.resolveName(this, identifier, true); | |||
if (entity == null) { | |||
continue; | |||
} | |||
if (entity instanceof ContainerEntity) | |||
r.add((ContainerEntity) entity); | |||
} | |||
return r; | |||
} | |||
/** | |||
* Resolve all expression's type | |||
* | |||
* @param bindingResolver | |||
*/ | |||
public void resolveExpressions(IBindingResolver bindingResolver) { | |||
if (this instanceof FunctionEntity) { | |||
((FunctionEntity)this).linkReturnToLastExpression(); | |||
} | |||
if (expressionList==null) return; | |||
if(expressionList.size()>10000) return; | |||
for (Expression expression : expressionList) { | |||
// 1. if expression's type existed, break; | |||
if (expression.getType() != null) | |||
continue; | |||
if (expression.isDot()) { // wait for previous | |||
continue; | |||
} | |||
if (expression.getRawType() == null && expression.getIdentifier() == 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.getRawType() != null) { | |||
expression.setType(bindingResolver.inferTypeFromName(this, expression.getRawType()), null, bindingResolver); | |||
if (expression.getType() != null) { | |||
continue; | |||
} | |||
} | |||
if (expression.getIdentifier() != null) { | |||
Entity entity = bindingResolver.resolveName(this, expression.getIdentifier(), true); | |||
String composedName = expression.getIdentifier().toString(); | |||
Expression theExpr = expression; | |||
if (entity==null) { | |||
while(theExpr.getParent()!=null && theExpr.getParent().isDot()) { | |||
theExpr = theExpr.getParent(); | |||
if (theExpr.getIdentifier()==null) break; | |||
composedName = composedName + "." + theExpr.getIdentifier().toString(); | |||
entity = bindingResolver.resolveName(this, GenericName.build(composedName), true); | |||
if (entity!=null) | |||
break; | |||
} | |||
} | |||
if (entity != null) { | |||
expression.setType(entity.getType(), entity, bindingResolver); | |||
continue; | |||
} | |||
if (expression.isCall()) { | |||
List<Entity> funcs = this.lookupFunctionInVisibleScope(expression.getIdentifier()); | |||
if (funcs != null) { | |||
for (Entity func:funcs) { | |||
expression.setType(func.getType(), func, bindingResolver); | |||
} | |||
} | |||
} else { | |||
Entity varEntity = this.lookupVarInVisibleScope(expression.getIdentifier()); | |||
if (varEntity != null) { | |||
expression.setType(varEntity.getType(), varEntity, bindingResolver); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
public void cacheChildExpressions() { | |||
cacheExpressions(); | |||
for (Entity child:getChildren()) { | |||
if (child instanceof ContainerEntity) { | |||
((ContainerEntity)child).cacheChildExpressions(); | |||
} | |||
} | |||
} | |||
public void cacheExpressions() { | |||
if (expressionWeakReference==null) return; | |||
if (expressionList==null) return; | |||
this.expressions().clear(); | |||
this.expressionWeakReference.clear(); | |||
cacheExpressionListToFile(); | |||
this.expressionList.clear(); | |||
this.expressionList=null; | |||
this.expressionList = new ArrayList<>(); | |||
} | |||
public void clearExpressions() { | |||
if (expressionWeakReference==null) return; | |||
if (expressionList==null) return; | |||
this.expressions().clear(); | |||
this.expressionWeakReference.clear(); | |||
this.expressionList.clear(); | |||
this.expressionList=null; | |||
this.expressionList = new ArrayList<>(); | |||
this.expressionUseList = null; | |||
} | |||
private void cacheExpressionListToFile() { | |||
if (expressionCount ==0) return; | |||
try { | |||
FileOutputStream fileOut = new FileOutputStream(TemporaryFile.getInstance().exprPath(this.id)); | |||
ObjectOutputStream out = new ObjectOutputStream(fileOut); | |||
out.writeObject(this.expressionList); | |||
out.close(); | |||
fileOut.close(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
@SuppressWarnings("unchecked") | |||
public void reloadExpression(EntityRepo repo) { | |||
if (expressionCount ==0) return; | |||
try | |||
{ | |||
FileInputStream fileIn = new FileInputStream(TemporaryFile.getInstance().exprPath(this.id)); | |||
ObjectInputStream in = new ObjectInputStream(fileIn); | |||
expressionList = (ArrayList<Expression>) in.readObject(); | |||
if (expressionList==null) expressionList = new ArrayList<>(); | |||
for (Expression expr:expressionList) { | |||
expr.reload(repo,expressionList); | |||
} | |||
in.close(); | |||
fileIn.close(); | |||
}catch(IOException | ClassNotFoundException i) | |||
{ | |||
return; | |||
} | |||
} | |||
public List<Expression> expressionList() { | |||
if (expressionList==null) | |||
expressionList = new ArrayList<>(); | |||
return expressionList; | |||
} | |||
public boolean containsExpression() { | |||
return expressions().size() > 0; | |||
} | |||
/** | |||
* The entry point of lookup functions. It will treat multi-declare entities and | |||
* normal entity differently. - for multiDeclare entity, it means to lookup all | |||
* entities - for normal entity, it means to lookup entities from current scope | |||
* still root | |||
* | |||
* @param functionName | |||
* @return | |||
*/ | |||
public List<Entity> lookupFunctionInVisibleScope(GenericName functionName) { | |||
List<Entity> functions = new ArrayList<>(); | |||
if (this.getMutliDeclare() != null) { | |||
for (Entity fromEntity : this.getMutliDeclare().getEntities()) { | |||
Entity f = lookupFunctionBottomUpTillTopContainer(functionName, fromEntity); | |||
if (f != null) { | |||
functions.add(f); | |||
return functions; | |||
} | |||
} | |||
} else { | |||
ContainerEntity fromEntity = this; | |||
Entity f = lookupFunctionBottomUpTillTopContainer(functionName, fromEntity); | |||
if (f != null) { | |||
functions.add(f); | |||
return functions; | |||
} | |||
} | |||
return null; | |||
} | |||
/** | |||
* lookup function bottom up till the most outside container | |||
* | |||
* @param functionName | |||
* @param fromEntity | |||
* @return | |||
*/ | |||
private Entity lookupFunctionBottomUpTillTopContainer(GenericName functionName, Entity fromEntity) { | |||
while (fromEntity != null) { | |||
if (fromEntity instanceof ContainerEntity) { | |||
FunctionEntity func = ((ContainerEntity) fromEntity).lookupFunctionLocally(functionName); | |||
if (func != null) | |||
return func; | |||
} | |||
for (Entity child:this.getChildren()) { | |||
if (child instanceof AliasEntity) { | |||
if (child.getRawName().equals(functionName)) | |||
return child; | |||
} | |||
} | |||
fromEntity = (ContainerEntity) this.getAncestorOfType(ContainerEntity.class); | |||
} | |||
return null; | |||
} | |||
/** | |||
* lookup function in local entity. It could be override such as the type entity | |||
* (it should also lookup the inherit/implemented types | |||
* | |||
* @param functionName | |||
* @return | |||
*/ | |||
public FunctionEntity lookupFunctionLocally(GenericName functionName) { | |||
for (FunctionEntity func : getFunctions()) { | |||
if (func.getRawName().equals(functionName)) | |||
return func; | |||
} | |||
return null; | |||
} | |||
/** | |||
* The entry point of lookup var. It will treat multi-declare entities and | |||
* normal entity differently. - for multiDeclare entity, it means to lookup all | |||
* entities - for normal entity, it means to lookup entities from current scope | |||
* still root | |||
* | |||
* @param varName | |||
* @return | |||
*/ | |||
public Entity lookupVarInVisibleScope(GenericName varName) { | |||
ContainerEntity fromEntity = this; | |||
return lookupVarBottomUpTillTopContainer(varName, fromEntity); | |||
} | |||
/** | |||
* To found the var. | |||
* | |||
* @param fromEntity | |||
* @param varName | |||
* @return | |||
*/ | |||
private Entity lookupVarBottomUpTillTopContainer(GenericName varName, ContainerEntity fromEntity) { | |||
while (fromEntity != null) { | |||
if (fromEntity instanceof ContainerEntity) { | |||
VarEntity var = ((ContainerEntity) fromEntity).lookupVarLocally(varName); | |||
if (var != null) | |||
return var; | |||
} | |||
for (Entity child:this.getChildren()) { | |||
if (child instanceof AliasEntity) { | |||
if (child.getRawName().equals(varName)) | |||
return child; | |||
} | |||
} | |||
fromEntity = (ContainerEntity) this.getAncestorOfType(ContainerEntity.class); | |||
} | |||
return null; | |||
} | |||
public VarEntity lookupVarLocally(GenericName varName) { | |||
for (VarEntity var : getVars()) { | |||
if (var.getRawName().equals(varName)) | |||
return var; | |||
} | |||
return null; | |||
} | |||
public VarEntity lookupVarLocally(String varName) { | |||
return this.lookupVarLocally(GenericName.build(varName)); | |||
} | |||
public void addMixin(GenericName moduleName) { | |||
mixins().add(moduleName); | |||
} | |||
public Collection<ContainerEntity> getResolvedMixins() { | |||
if (resolvedMixins==null) return new ArrayList<>(); | |||
return resolvedMixins; | |||
} | |||
HashMap<String,Set<Expression>> expressionUseList = null; | |||
public void addRelation(Expression expression, Relation relation) { | |||
String key = relation.getEntity().qualifiedName+relation.getType(); | |||
if (this.expressionUseList==null) | |||
expressionUseList = new HashMap<>(); | |||
if (expressionUseList.containsKey(key)){ | |||
Set<Expression> expressions = expressionUseList.get(key); | |||
for (Expression expr:expressions){ | |||
if (linkedExpr(expr,expression)) return; | |||
} | |||
}else{ | |||
expressionUseList.put(key,new HashSet<>()); | |||
} | |||
expressionUseList.get(key).add(expression); | |||
super.addRelation(relation); | |||
} | |||
private boolean linkedExpr(Expression a, Expression b) { | |||
Expression parent = a.getParent(); | |||
while(parent!=null){ | |||
if (parent==b) return true; | |||
parent = parent.getParent(); | |||
} | |||
parent = b.getParent(); | |||
while(parent!=null){ | |||
if (parent==a) return true; | |||
parent = parent.getParent(); | |||
} | |||
return false; | |||
} | |||
} |
@@ -1,66 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.extractor.cpp; | |||
import depends.entity.repo.BuiltInType; | |||
public class CppBuiltInType extends BuiltInType { | |||
@Override | |||
protected String[] getBuiltInTypeName() { | |||
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 | |||
protected String[] getBuiltInTypePrefix() { | |||
return new String[] {"__"}; | |||
} | |||
} |
@@ -1,133 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.extractor.cpp; | |||
import depends.entity.Entity; | |||
import depends.entity.FileEntity; | |||
import depends.entity.GenericName; | |||
import depends.entity.repo.EntityRepo; | |||
import depends.extractor.UnsolvedBindings; | |||
import depends.importtypes.FileImport; | |||
import depends.importtypes.Import; | |||
import depends.relations.ImportLookupStrategy; | |||
import java.util.*; | |||
public class CppImportLookupStrategy extends ImportLookupStrategy { | |||
public CppImportLookupStrategy(EntityRepo repo){ | |||
super(repo); | |||
} | |||
@Override | |||
public Entity lookupImportedType(String name, FileEntity fileEntity) { | |||
String importedString = fileEntity.importedSuffixMatch(name); | |||
if (importedString!=null) { | |||
Entity r = repo.getEntity(importedString); | |||
if (r!=null) return r; | |||
} | |||
HashSet<Integer> fileSet = getIncludedFiles(fileEntity); | |||
for (Integer file:fileSet) { | |||
Entity importedItem = repo.getEntity(file); | |||
if (importedItem instanceof FileEntity) { | |||
FileEntity importedFile = (FileEntity) repo.getEntity(file); | |||
if (importedFile==null) continue; | |||
Entity entity = bindingResolver.resolveName(importedFile,GenericName.build(name), false); | |||
if (entity!=null) return entity; | |||
Collection<Entity> namespaces = fileEntity.getImportedTypes(); | |||
for (Entity ns:namespaces) { | |||
String nameWithPrefix = ns.getQualifiedName() + "." + name; | |||
entity = bindingResolver.resolveName(importedFile,GenericName.build(nameWithPrefix), false); | |||
if (entity!=null) return entity; | |||
} | |||
} | |||
} | |||
return null; | |||
} | |||
private Map<Integer, HashSet<Integer> > includedFiles = new HashMap<>(); | |||
private HashSet<Integer> getIncludedFiles(FileEntity fileEntity) { | |||
if (includedFiles.containsKey(fileEntity.getId())) { | |||
return includedFiles.get(fileEntity.getId()); | |||
} | |||
HashSet<Integer> fileSet = new HashSet<>(); | |||
foundIncludedFiles(fileSet, fileEntity.getImportedFiles()); | |||
includedFiles.put(fileEntity.getId(), fileSet); | |||
return fileSet; | |||
} | |||
private void foundIncludedFiles(HashSet<Integer> fileSet, Collection<Entity> importedFiles) { | |||
for (Entity file:importedFiles) { | |||
if (file==null ) continue; | |||
if (!(file instanceof FileEntity)) continue; | |||
if (fileSet.contains(file.getId())) continue; | |||
fileSet.add(file.getId()); | |||
foundIncludedFiles(fileSet,((FileEntity)file).getImportedFiles()); | |||
} | |||
} | |||
@Override | |||
public List<Entity> getImportedRelationEntities(List<Import> importedList) { | |||
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, Set<UnsolvedBindings> unsolvedBindings) { | |||
ArrayList<Entity> result = new ArrayList<>(); | |||
for (Import importedItem:importedList) { | |||
if (!(importedItem instanceof FileImport)) { | |||
Entity imported = repo.getEntity(importedItem.getContent()); | |||
if (imported==null) { | |||
unsolvedBindings.add(new UnsolvedBindings(importedItem.getContent(),null)); | |||
continue; | |||
} | |||
result.add(imported); | |||
} | |||
} | |||
return result; | |||
} | |||
@Override | |||
public List<Entity> getImportedFiles(List<Import> importedList) { | |||
return getImportedRelationEntities(importedList); | |||
} | |||
@Override | |||
public boolean supportGlobalNameLookup() { | |||
return false; | |||
} | |||
} |
@@ -1,338 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.extractor.cpp.cdt; | |||
import depends.entity.*; | |||
import depends.entity.repo.EntityRepo; | |||
import depends.entity.repo.IdGenerator; | |||
import depends.extractor.cpp.CppHandlerContext; | |||
import depends.importtypes.ExactMatchImport; | |||
import depends.importtypes.FileImport; | |||
import depends.importtypes.PackageWildCardImport; | |||
import depends.relations.IBindingResolver; | |||
import org.codehaus.plexus.util.StringUtils; | |||
import org.eclipse.cdt.core.dom.ast.*; | |||
import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator; | |||
import org.eclipse.cdt.core.dom.ast.cpp.*; | |||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier; | |||
import org.eclipse.cdt.internal.core.dom.parser.cpp.*; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import java.util.ArrayList; | |||
import java.util.HashSet; | |||
import java.util.List; | |||
public class CppVisitor extends ASTVisitor { | |||
private static final Logger logger = LoggerFactory.getLogger(CppVisitor.class); | |||
private CppHandlerContext context; | |||
private IdGenerator idGenerator; | |||
private PreprocessorHandler preprocessorHandler; | |||
IBindingResolver bindingResolver; | |||
private ExpressionUsage expressionUsage; | |||
HashSet<String> file; | |||
public CppVisitor(String fileFullPath, EntityRepo entityRepo, PreprocessorHandler preprocessorHandler, IBindingResolver bindingResolver) { | |||
super(true); | |||
this.shouldVisitAmbiguousNodes = true; | |||
this.shouldVisitImplicitNames = true; | |||
this.includeInactiveNodes = true; | |||
this.context = new CppHandlerContext(entityRepo, bindingResolver); | |||
idGenerator = entityRepo; | |||
this.bindingResolver = bindingResolver; | |||
this.preprocessorHandler = preprocessorHandler; | |||
expressionUsage = new ExpressionUsage(context,entityRepo); | |||
file = new HashSet<>(); | |||
context.startFile(fileFullPath); | |||
file.add(this.context.currentFile().getQualifiedName()); | |||
} | |||
@Override | |||
public int visit(IASTTranslationUnit tu) { | |||
for (String incl:preprocessorHandler.getDirectIncludedFiles(tu.getAllPreprocessorStatements(),context.currentFile().getQualifiedName())) { | |||
context.foundNewImport(new FileImport(incl)); | |||
} | |||
MacroExtractor macroExtractor = new MacroExtractor(tu.getAllPreprocessorStatements(),context.currentFile().getQualifiedName()); | |||
macroExtractor.extract(context); | |||
for (IASTNode child:tu.getChildren()) { | |||
if (notLocalFile(child)) continue; | |||
child.accept(this); | |||
} | |||
return ASTVisitor.PROCESS_SKIP; | |||
} | |||
@Override | |||
public int visit(IASTProblem problem) { | |||
if (notLocalFile(problem)) return ASTVisitor.PROCESS_SKIP; | |||
System.out.println("warning: parse error " + problem.getOriginalNode().getRawSignature() + problem.getMessageWithLocation()); | |||
return super.visit(problem); | |||
} | |||
private boolean notLocalFile(IASTNode node) { | |||
if (file.contains(node.getFileLocation().getFileName())) { | |||
return false; | |||
} | |||
return true; | |||
} | |||
// PACKAGES | |||
@Override | |||
public int visit(ICPPASTNamespaceDefinition namespaceDefinition) { | |||
if (notLocalFile(namespaceDefinition)) return ASTVisitor.PROCESS_SKIP; | |||
String ns = namespaceDefinition.getName().toString().replace("::", "."); | |||
logger.trace("enter ICPPASTNamespaceDefinition " + ns); | |||
Entity pkg = context.foundNamespace(ns,namespaceDefinition.getFileLocation().getStartingLineNumber()); | |||
context.foundNewImport(new PackageWildCardImport(ns)); | |||
return super.visit(namespaceDefinition); | |||
} | |||
@Override | |||
public int leave(ICPPASTNamespaceDefinition namespaceDefinition) { | |||
if (notLocalFile(namespaceDefinition)) return ASTVisitor.PROCESS_SKIP; | |||
context.exitLastedEntity(); | |||
return super.leave(namespaceDefinition); | |||
} | |||
// Types | |||
@Override | |||
public int visit(IASTDeclSpecifier declSpec) { | |||
if (notLocalFile(declSpec)) return ASTVisitor.PROCESS_SKIP; | |||
logger.trace("enter IASTDeclSpecifier " + declSpec.getClass().getSimpleName()); | |||
if (declSpec instanceof IASTCompositeTypeSpecifier) { | |||
IASTCompositeTypeSpecifier type = (IASTCompositeTypeSpecifier)declSpec; | |||
String name = ASTStringUtilExt.getName(type); | |||
List<GenericName> param = ASTStringUtilExt.getTemplateParameters(type); | |||
TypeEntity typeEntity = context.foundNewType(name, type.getFileLocation().getStartingLineNumber()); | |||
if (declSpec instanceof ICPPASTCompositeTypeSpecifier) { | |||
ICPPASTBaseSpecifier[] baseSpecififers = ((ICPPASTCompositeTypeSpecifier)declSpec).getBaseSpecifiers(); | |||
for (ICPPASTBaseSpecifier baseSpecififer:baseSpecififers) { | |||
String extendName = ASTStringUtilExt.getName(baseSpecififer.getNameSpecifier()); | |||
context.foundExtends(extendName); | |||
} | |||
} | |||
} | |||
else if (declSpec instanceof IASTEnumerationSpecifier) { | |||
context.foundNewType(ASTStringUtilExt.getName(declSpec), declSpec.getFileLocation().getStartingLineNumber()); | |||
}else { | |||
//we do not care other types | |||
} | |||
return super.visit(declSpec); | |||
} | |||
@Override | |||
public int leave(IASTDeclSpecifier declSpec) { | |||
if (notLocalFile(declSpec)) return ASTVisitor.PROCESS_SKIP; | |||
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 (notLocalFile(declarator)) return ASTVisitor.PROCESS_SKIP; | |||
logger.trace("enter IASTDeclarator " + declarator.getClass().getSimpleName()); | |||
if (declarator instanceof IASTFunctionDeclarator){ | |||
GenericName returnType = null; | |||
if ( declarator.getParent() instanceof IASTSimpleDeclaration) { | |||
IASTSimpleDeclaration decl = (IASTSimpleDeclaration)(declarator.getParent()); | |||
returnType = buildGenericNameFromDeclSpecifier(decl.getDeclSpecifier()); | |||
String rawName = ASTStringUtilExt.getName(declarator); | |||
List<Entity> namedEntity = context.currentFile().lookupFunctionInVisibleScope(GenericName.build(rawName)); | |||
if (namedEntity!=null) { | |||
rawName = namedEntity.get(0).getQualifiedName(); | |||
} | |||
returnType = reMapIfConstructDeconstruct(rawName,returnType); | |||
context.foundMethodDeclaratorProto(rawName, returnType,decl.getFileLocation().getStartingLineNumber()); | |||
} | |||
else if ( declarator.getParent() instanceof IASTFunctionDefinition) { | |||
IASTFunctionDefinition decl = (IASTFunctionDefinition)declarator.getParent(); | |||
returnType = buildGenericNameFromDeclSpecifier(decl.getDeclSpecifier()); | |||
String rawName = ASTStringUtilExt.getName(declarator); | |||
List<Entity> namedEntity = context.currentFile().lookupFunctionInVisibleScope(GenericName.build(rawName)); | |||
if (namedEntity!=null) { | |||
rawName = namedEntity.get(0).getQualifiedName(); | |||
} | |||
returnType = reMapIfConstructDeconstruct(rawName,returnType); | |||
context.foundMethodDeclaratorImplementation(rawName, returnType,decl.getFileLocation().getStartingLineNumber()); | |||
} | |||
} | |||
return super.visit(declarator); | |||
} | |||
private GenericName buildGenericNameFromDeclSpecifier(IASTDeclSpecifier decl) { | |||
String name = ASTStringUtilExt.getName(decl); | |||
List<GenericName> templateParams = ASTStringUtilExt.getTemplateParameters(decl); | |||
if (name==null) | |||
return null; | |||
return new GenericName(name,templateParams); | |||
} | |||
/** | |||
* In case of return type is empty, it maybe a construct/deconstruct function | |||
* @param functionname | |||
* @param returnType | |||
* @return | |||
*/ | |||
private GenericName reMapIfConstructDeconstruct(String functionname, GenericName returnType) { | |||
if (returnType!=null && returnType.uniqName().length()>0) | |||
return returnType; | |||
if (functionname.contains("::")) { | |||
return new GenericName(functionname.substring(0, functionname.indexOf("::"))); | |||
}else { | |||
return new GenericName(functionname); | |||
} | |||
} | |||
@Override | |||
public int leave(IASTDeclarator declarator) { | |||
if (notLocalFile(declarator)) return ASTVisitor.PROCESS_SKIP; | |||
if (declarator instanceof IASTFunctionDeclarator){ | |||
if ( declarator.getParent() instanceof IASTSimpleDeclaration) { | |||
String rawName = ASTStringUtilExt.getName(declarator); | |||
if (rawName.equals(context.lastContainer().getRawName().getName())) { | |||
context.exitLastedEntity(); | |||
}else { | |||
System.err.println("unexpected symbol"); | |||
} | |||
} | |||
} | |||
return super.leave(declarator); | |||
} | |||
@Override | |||
public int leave(IASTDeclaration declaration) { | |||
if (notLocalFile(declaration)) return ASTVisitor.PROCESS_SKIP; | |||
if ( declaration instanceof IASTFunctionDefinition) { | |||
context.exitLastedEntity(); | |||
} | |||
return super.leave(declaration); | |||
} | |||
// Variables | |||
@Override | |||
public int visit(IASTDeclaration declaration) { | |||
if (notLocalFile(declaration)) return ASTVisitor.PROCESS_SKIP; | |||
logger.trace("enter IASTDeclaration " + declaration.getClass().getSimpleName()); | |||
if (declaration instanceof ICPPASTUsingDeclaration) { | |||
String ns = ASTStringUtilExt.getName((ICPPASTUsingDeclaration)declaration); | |||
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.foundNewAlias(ASTStringUtilExt.getName(declarator),ASTStringUtilExt.getName(declSpecifier)); | |||
}else if (!(declarator instanceof IASTFunctionDeclarator)) { | |||
String varType = ASTStringUtilExt.getName(declSpecifier); | |||
String varName = ASTStringUtilExt.getName(declarator); | |||
if (!StringUtils.isEmpty(varType)) { | |||
context.foundVarDefinition(varName, GenericName.build(varType), ASTStringUtilExt.getTemplateParameters(declSpecifier),declarator.getFileLocation().getStartingLineNumber()); | |||
}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 CPPASTTemplateDeclaration){ | |||
}else if (declaration instanceof CPPASTProblemDeclaration){ | |||
System.err.println("parsing error \n" + declaration.getRawSignature()); | |||
}else if (declaration instanceof ICPPASTAliasDeclaration){ | |||
IASTName name = ((ICPPASTAliasDeclaration)declaration).getAlias(); | |||
String alias = ASTStringUtilExt.getSimpleName(name).replace("::", "."); | |||
ICPPASTTypeId mapped = ((ICPPASTAliasDeclaration)declaration).getMappingTypeId(); | |||
String originalName1 = ASTStringUtilExt.getTypeIdString(mapped); | |||
context.foundNewAlias(alias, originalName1); | |||
}else if (declaration instanceof CPPASTNamespaceAlias){ | |||
IASTName name = ((CPPASTNamespaceAlias)declaration).getAlias(); | |||
String alias = ASTStringUtilExt.getSimpleName(name).replace("::", "."); | |||
IASTName mapped = ((CPPASTNamespaceAlias)declaration).getMappingName(); | |||
String originalName = ASTStringUtilExt.getName(mapped); | |||
context.foundNewAlias(alias, originalName); | |||
} | |||
else if(declaration instanceof CPPASTStaticAssertionDeclaration) | |||
{ | |||
}else if (declaration instanceof CPPASTTemplateSpecialization) { | |||
} | |||
else{ | |||
System.out.println("not handled type: " + declaration.getClass().getName()); | |||
System.out.println(declaration.getRawSignature()); | |||
} | |||
return super.visit(declaration); | |||
} | |||
@Override | |||
public int visit(IASTEnumerator enumerator) { | |||
if (notLocalFile(enumerator)) return ASTVisitor.PROCESS_SKIP; | |||
logger.trace("enter IASTEnumerator " + enumerator.getClass().getSimpleName()); | |||
VarEntity var = context.foundVarDefinition(enumerator.getName().toString(), context.currentType().getRawName(), new ArrayList<>(),enumerator.getFileLocation().getStartingLineNumber()); | |||
return super.visit(enumerator); | |||
} | |||
@Override | |||
public int visit(IASTExpression expression) { | |||
if (notLocalFile(expression)) return ASTVisitor.PROCESS_SKIP; | |||
Expression expr = expressionUsage.foundExpression(expression); | |||
expr.setLine(expression.getFileLocation().getStartingLineNumber()); | |||
return super.visit(expression); | |||
} | |||
@Override | |||
public int visit(IASTParameterDeclaration parameterDeclaration) { | |||
if (notLocalFile(parameterDeclaration)) return ASTVisitor.PROCESS_SKIP; | |||
logger.trace("enter IASTParameterDeclaration " + parameterDeclaration.getClass().getSimpleName()); | |||
String parameterName = ASTStringUtilExt.getName(parameterDeclaration.getDeclarator()); | |||
String parameterType = ASTStringUtilExt.getName(parameterDeclaration.getDeclSpecifier()); | |||
if (context.currentFunction()!=null) { | |||
VarEntity var = new VarEntity(GenericName.build(parameterName),GenericName.build(parameterType),context.currentFunction(),idGenerator.generateId()); | |||
context.currentFunction().addParameter(var ); | |||
}else { | |||
//System.out.println("** parameterDeclaration = " + parameter); | |||
} | |||
return super.visit(parameterDeclaration); | |||
} | |||
} |
@@ -1,148 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.entity; | |||
import depends.relations.IBindingResolver; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.List; | |||
public abstract class DecoratedEntity extends Entity{ | |||
private Collection<GenericName> annotations; | |||
private Collection<Entity> resolvedAnnotations; | |||
private Collection<Entity> resolvedTypeParameters; | |||
public DecoratedEntity() { | |||
} | |||
public DecoratedEntity(GenericName rawName, Entity parent, Integer id) { | |||
super(rawName, parent, id); | |||
} | |||
public void addAnnotation(GenericName name) { | |||
if(this.annotations==null) | |||
annotations = new ArrayList<>(); | |||
this.annotations.add(name); | |||
} | |||
public void addTypeParameter(List<GenericName> parameters) { | |||
this.getRawName().appendArguments(parameters); | |||
} | |||
public void addTypeParameter(GenericName parameter) { | |||
this.getRawName().appendArguments(parameter); | |||
} | |||
protected void appendTypeParameters(Collection<Entity> typeParameterEntities) { | |||
if (resolvedTypeParameters==null) | |||
resolvedTypeParameters = new ArrayList<>(); | |||
resolvedTypeParameters.addAll(typeParameterEntities); | |||
} | |||
/** | |||
* For all data in the class, infer their types. | |||
* Should be override in sub-classes | |||
*/ | |||
public void inferLocalLevelEntities(IBindingResolver bindingResolver) { | |||
Collection<Entity> typeParameterEntities = typeParametersToEntities(bindingResolver); | |||
appendTypeParameters(typeParameterEntities); | |||
// if (this.getAncestorOfType(FileEntity.class).getRawName().contains("/examples/usersession/server.py") | |||
// ) { | |||
// System.out.print("dd"); | |||
// } | |||
resolvedAnnotations = identiferToEntities(bindingResolver, annotations); | |||
} | |||
private Collection<Entity> typeParametersToEntities(IBindingResolver bindingResolver) { | |||
ArrayList<Entity> r = new ArrayList<>(); | |||
for (GenericName typeParameter:this.getRawName().getArguments()) { | |||
toEntityList(bindingResolver, r,typeParameter); | |||
} | |||
return r; | |||
} | |||
protected void toEntityList(IBindingResolver bindingResolver, ArrayList<Entity> r, GenericName typeParameter) { | |||
Entity entity = resolveEntity(bindingResolver, typeParameter); | |||
if (entity != null) | |||
r.add(entity); | |||
for (GenericName arg: typeParameter.getArguments()) { | |||
toEntityList(bindingResolver,r,arg); | |||
} | |||
} | |||
public Collection<Entity> getResolvedTypeParameters() { | |||
if (resolvedTypeParameters==null) | |||
return new ArrayList<>(); | |||
return resolvedTypeParameters; | |||
} | |||
public Collection<Entity> getResolvedAnnotations() { | |||
if (resolvedAnnotations==null) | |||
return new ArrayList<>(); | |||
return resolvedAnnotations; | |||
} | |||
public boolean isGenericTypeParameter(GenericName rawType) { | |||
boolean foundInCurrentLevel = rawType.find(rawType); | |||
if (foundInCurrentLevel) return true; | |||
if (this.getParent()==null || !(this.getParent() instanceof ContainerEntity)) | |||
return false; | |||
return ((ContainerEntity)getParent()).isGenericTypeParameter(rawType); | |||
} | |||
/** | |||
* A common utility function used to transfer the identifiers | |||
* to types. | |||
* @param bindingResolver - the inferer object | |||
* @param identifiers - the identifiers will be translated | |||
* @return The translated Types | |||
*/ | |||
protected Collection<Entity> identiferToEntities(IBindingResolver bindingResolver, Collection<GenericName> identifiers) { | |||
if (identifiers==null) return null; | |||
if (identifiers.size()==0) return null; | |||
ArrayList<Entity> r = new ArrayList<>(); | |||
for (GenericName name : identifiers) { | |||
Entity entity = resolveEntity(bindingResolver, name); | |||
if (entity != null) | |||
r.add(entity); | |||
} | |||
return r; | |||
} | |||
private Entity resolveEntity(IBindingResolver bindingResolver, GenericName name) { | |||
Entity entity = bindingResolver.resolveName(this, name, true); | |||
if (entity==null) { | |||
if (((ContainerEntity)getParent()).isGenericTypeParameter(name)) { | |||
entity = TypeEntity.genericParameterType; | |||
} | |||
} | |||
return entity; | |||
} | |||
} |
@@ -1,160 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.generator; | |||
import depends.entity.CandidateTypes; | |||
import depends.entity.Entity; | |||
import depends.entity.EntityNameBuilder; | |||
import depends.entity.FileEntity; | |||
import depends.entity.repo.EntityRepo; | |||
import depends.matrix.core.DependencyDetail; | |||
import depends.matrix.core.DependencyMatrix; | |||
import depends.matrix.core.LocationInfo; | |||
import depends.matrix.transform.OrderedMatrixGenerator; | |||
import depends.relations.Relation; | |||
import multilang.depends.util.file.path.EmptyFilenameWritter; | |||
import multilang.depends.util.file.path.FilenameWritter; | |||
import multilang.depends.util.file.strip.EmptyLeadingNameStripper; | |||
import multilang.depends.util.file.strip.ILeadingNameStrippper; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import java.util.ArrayList; | |||
import java.util.Collections; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import static depends.deptypes.DependencyType.DuckTypingLabel; | |||
public abstract class DependencyGenerator { | |||
private static Logger logger = LoggerFactory.getLogger(DependencyGenerator.class); | |||
public DependencyMatrix identifyDependencies(EntityRepo entityRepo, List<String> typeFilter) { | |||
System.out.println("dependencie data generating..."); | |||
DependencyMatrix dependencyMatrix = build(entityRepo, typeFilter); | |||
entityRepo.clear(); | |||
System.out.println("reorder dependency matrix..."); | |||
dependencyMatrix = new OrderedMatrixGenerator(dependencyMatrix).build(); | |||
System.out.println("Dependencies data generating done successfully..."); | |||
logger.info("Dependencies data generating done successfully..."); | |||
return dependencyMatrix; | |||
} | |||
/** | |||
* Build the dependency matrix (without re-mapping file id) | |||
* @param entityRepo which contains entities and relations | |||
* @return the generated dependency matrix | |||
*/ | |||
public DependencyMatrix build(EntityRepo entityRepo,List<String> typeFilter) { | |||
DependencyMatrix dependencyMatrix = new DependencyMatrix(typeFilter); | |||
Iterator<Entity> iterator = entityRepo.entityIterator(); | |||
System.out.println("Start create dependencies matrix...."); | |||
while(iterator.hasNext()) { | |||
Entity entity = iterator.next(); | |||
if (!entity.inScope()) continue; | |||
if (outputLevelMatch(entity)){ | |||
dependencyMatrix.addNode(nameOf(entity),entity.getId()); | |||
} | |||
int entityFrom = upToOutputLevelEntityId(entityRepo, entity); | |||
if (entityFrom==-1) continue; | |||
for (Relation relation:entity.getRelations()) { | |||
Entity relatedEntity = relation.getEntity(); | |||
if (relatedEntity==null) continue; | |||
List<Entity> relatedEntities = expandEntity(relatedEntity); | |||
String duckTypingFlag = relatedEntity instanceof CandidateTypes? DuckTypingLabel:""; | |||
relatedEntities.forEach(theEntity->{ | |||
if (theEntity.getId()>=0) { | |||
int entityTo = upToOutputLevelEntityId(entityRepo,theEntity); | |||
if (entityTo!=-1) { | |||
DependencyDetail detail = buildDescription(entity, theEntity, relation.getFromLine()); | |||
detail = rewriteDetail(detail); | |||
dependencyMatrix.addDependency(relation.getType()+duckTypingFlag, entityFrom,entityTo,1,detail); | |||
} | |||
} | |||
}); | |||
} | |||
} | |||
System.out.println("Finish create dependencies matrix...."); | |||
return dependencyMatrix; | |||
} | |||
private List<Entity> expandEntity(Entity relatedEntity) { | |||
List<Entity> entities = new ArrayList<>(); | |||
if (relatedEntity instanceof CandidateTypes) { | |||
entities = Collections.unmodifiableList((List) ((CandidateTypes) relatedEntity).getCandidateTypes()); | |||
}else { | |||
entities.add(relatedEntity); | |||
} | |||
return entities; | |||
} | |||
private DependencyDetail rewriteDetail(DependencyDetail detail) { | |||
if (detail==null) return null; | |||
String srcFile = filenameWritter.reWrite( | |||
stripper.stripFilename(detail.getSrc().getFile()) | |||
); | |||
String dstFile = filenameWritter.reWrite( | |||
stripper.stripFilename(detail.getDest().getFile())); | |||
return new DependencyDetail( | |||
new LocationInfo(detail.getSrc().getObject(), | |||
srcFile, detail.getSrc().getLineNumber()) | |||
, | |||
new LocationInfo(detail.getDest().getObject(), | |||
dstFile, detail.getDest().getLineNumber())); | |||
} | |||
protected abstract int upToOutputLevelEntityId(EntityRepo entityRepo, Entity entity); | |||
protected abstract String nameOf(Entity entity); | |||
protected abstract boolean outputLevelMatch(Entity entity); | |||
protected ILeadingNameStrippper stripper = new EmptyLeadingNameStripper(); | |||
protected FilenameWritter filenameWritter = new EmptyFilenameWritter(); | |||
private boolean generateDetail = false; | |||
public void setLeadingStripper(ILeadingNameStrippper stripper) { | |||
this.stripper = stripper; | |||
} | |||
protected DependencyDetail buildDescription(Entity fromEntity, Entity toEntity, Integer fromLineNumber) { | |||
if (!generateDetail) return null; | |||
String fromObject = EntityNameBuilder.build(fromEntity); | |||
String toObject = EntityNameBuilder.build(toEntity); | |||
Entity fromFile = fromEntity.getAncestorOfType(FileEntity.class); | |||
Entity toFile = toEntity.getAncestorOfType(FileEntity.class); | |||
return new DependencyDetail( | |||
new LocationInfo(stripper.stripFilename(fromObject),stripper.stripFilename(fromFile.getQualifiedName()),fromLineNumber), | |||
new LocationInfo(stripper.stripFilename(toObject),stripper.stripFilename(toFile.getQualifiedName()),toEntity.getLine())); | |||
} | |||
public void setFilenameRewritter(FilenameWritter filenameWritter) { | |||
this.filenameWritter = filenameWritter; | |||
} | |||
public void setGenerateDetail(boolean generateDetail) { | |||
this.generateDetail = generateDetail; | |||
} | |||
} |
@@ -1,102 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.matrix.core; | |||
import multilang.depends.util.file.path.FilenameWritter; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
import static depends.deptypes.DependencyType.DuckTypingLabel; | |||
public class DependencyMatrix { | |||
private HashMap<String, DependencyPair> dependencyPairs = new HashMap<>(); | |||
private ArrayList<String> nodes = new ArrayList<>(); | |||
private HashMap<Integer,String> nodeIdToName = new HashMap<>(); | |||
private List<String> typeFilter; | |||
public DependencyMatrix() { | |||
} | |||
public DependencyMatrix(int size) { | |||
dependencyPairs = new HashMap<>(size); | |||
} | |||
public DependencyMatrix(List<String> typeFilter) { | |||
this.typeFilter = typeFilter; | |||
} | |||
public Collection<DependencyPair> getDependencyPairs() { | |||
return dependencyPairs.values(); | |||
} | |||
public void addNode(String name, int id) { | |||
this.nodes.add(name); | |||
this.nodeIdToName.put(id, name); | |||
} | |||
public void addDependency(String depType, Integer from, Integer to, int weight,List<DependencyDetail> details) { | |||
if (typeFilter!=null && (!typeFilter.contains(depType))) | |||
return; | |||
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,weight,details); | |||
} | |||
public void addDependency(String depType, Integer from, Integer to, int weight,DependencyDetail detail) { | |||
if (typeFilter!=null && (!typeFilter.contains(depType.replace(DuckTypingLabel,"")))) | |||
return; | |||
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,weight,detail); | |||
} | |||
public ArrayList<String> getNodes() { | |||
return nodes; | |||
} | |||
public DependencyMatrix reWriteFilenamePattern(FilenameWritter filenameRewritter) { | |||
this.nodeIdToName = new HashMap<>(); | |||
for (int i=0;i<nodes.size();i++) { | |||
String name = filenameRewritter.reWrite(nodes.get(i)); | |||
nodes.set(i, name ); | |||
nodeIdToName.put(i, name); | |||
} | |||
return this; | |||
} | |||
public String getNodeName(Integer key) { | |||
return nodeIdToName.get(key); | |||
} | |||
} |
@@ -1,161 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import depends.deptypes.DependencyType; | |||
import depends.extractor.LangProcessorRegistration; | |||
import picocli.CommandLine.Command; | |||
import picocli.CommandLine.Option; | |||
import picocli.CommandLine.Parameters; | |||
@Command(name = "depends") | |||
public class DependsCommand { | |||
public static class SupportedLangs extends ArrayList<String> { | |||
private static final long serialVersionUID = 1L; | |||
public SupportedLangs() { super( LangProcessorRegistration.getRegistry().getLangs()); } | |||
} | |||
public static class SupportedTypes extends ArrayList<String> { | |||
private static final long serialVersionUID = 1L; | |||
public SupportedTypes() { super( DependencyType.allDependencies()); } | |||
} | |||
@Parameters(index = "0", completionCandidates = DependsCommand.SupportedLangs.class, description = "The lanauge of project files: [${COMPLETION-CANDIDATES}]") | |||
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,dot,plantuml]") | |||
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 = {"--strip-paths"}, split=",", description = "The path(s) to be stripped. if -s enabled, the path(s) start after <src>. " | |||
+ "Otherwise, the path(s) should be valid.") | |||
private String[] strippedPaths = new String[]{}; | |||
@Option(names = {"-g", "--granularity"}, description = "Granularity of dependency.[file(default),method,structure,L#(the level of folder. e.g. L1=1st level folder)]") | |||
private String granularity="file"; | |||
@Option(names = {"-p", "--namepattern"}, description = "The name path pattern.[dot(.), unix(/) or windows(\\)") | |||
private String namePathPattern=""; | |||
@Option(names = {"-i","--includes"},split=",", description = "The files of searching path") | |||
private String[] includes = new String[] {}; | |||
@Option(names = {"--auto-include"},split=",", description = "auto include all paths under the source path (please notice the potential side effect)") | |||
private boolean autoInclude = false; | |||
@Option(names = {"--detail"},split=",", description = "add detail dependency information to output (only applicable for JSON output format)") | |||
private boolean detail = false; | |||
@Option(names = {"--auto-stub"},split=",", description = "create stub files for unsolved symbols (exprimental feature, only for java)") | |||
private boolean autoStub = false; | |||
@Option(names = {"--type-filter"},split=",", completionCandidates = DependsCommand.SupportedTypes.class, description = "only filter the listed dependency types[${COMPLETION-CANDIDATES}]") | |||
private String[] typeFilter=new String[]{}; | |||
@Option(names = {"--external-deps"}, description = "Output external dependencies") | |||
private boolean outputExternalDependencies = false; | |||
@Option(names = {"--duck-typing-deduce"}, description = "Deduce implicit variable types") | |||
private boolean duckTypingDeduce = true; | |||
@Option(names = {"-h","--help"}, usageHelp = true, description = "display this help and exit") | |||
boolean help; | |||
public DependsCommand() { | |||
} | |||
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; | |||
} | |||
public boolean isAutoInclude () { | |||
return autoInclude; | |||
} | |||
public boolean isDetail () { | |||
return detail; | |||
} | |||
public String[] getStrippedPaths() { | |||
return strippedPaths; | |||
} | |||
public void setStrippedPaths(String[] strippedPaths) { | |||
this.strippedPaths = strippedPaths; | |||
} | |||
public boolean isAutoStub() { | |||
return autoStub; | |||
} | |||
public List<String> getTypeFilter() { | |||
if (typeFilter.length==0) { | |||
return DependencyType.allDependencies(); | |||
} | |||
return java.util.Arrays.asList(typeFilter); | |||
} | |||
public boolean isOutputExternalDependencies() { | |||
return outputExternalDependencies; | |||
} | |||
public boolean isDuckTypingDeduce() { | |||
return this.duckTypingDeduce; | |||
} | |||
} |
@@ -1,222 +0,0 @@ | |||
/******************************************************************************* | |||
* Copyright (c) 2007, 2014 BEA Systems, Inc. and others. | |||
* | |||
* This program and the accompanying materials | |||
* are made available under the terms of the Eclipse Public License 2.0 | |||
* which accompanies this distribution, and is available at | |||
* https://www.eclipse.org/legal/epl-2.0/ | |||
* | |||
* SPDX-License-Identifier: EPL-2.0 | |||
* | |||
* Contributors: | |||
* BEA Systems, Inc. - initial API and implementation | |||
* Jesper Steen Moller - Bug 412150 [1.8] [compiler] Enable reflected parameter names during annotation processing | |||
*******************************************************************************/ | |||
package org.eclipse.jdt.apt.pluggable.tests; | |||
import java.io.File; | |||
import java.io.InputStream; | |||
import java.net.URL; | |||
import java.util.Map; | |||
import javax.lang.model.SourceVersion; | |||
import org.eclipse.core.resources.IFile; | |||
import org.eclipse.core.resources.IProject; | |||
import org.eclipse.core.runtime.CoreException; | |||
import org.eclipse.core.runtime.IPath; | |||
import org.eclipse.jdt.apt.core.internal.util.FactoryContainer; | |||
import org.eclipse.jdt.apt.core.internal.util.FactoryContainer.FactoryType; | |||
import org.eclipse.jdt.apt.core.internal.util.FactoryPath; | |||
import org.eclipse.jdt.apt.core.util.AptConfig; | |||
import org.eclipse.jdt.core.IClasspathAttribute; | |||
import org.eclipse.jdt.core.IJavaProject; | |||
import org.eclipse.jdt.core.JavaCore; | |||
import org.eclipse.jdt.core.tests.builder.BuilderTests; | |||
import org.eclipse.jdt.core.tests.util.Util; | |||
import org.eclipse.jdt.internal.core.ClasspathEntry; | |||
import junit.framework.Test; | |||
public class TestBase extends BuilderTests | |||
{ | |||
protected static final String JAVA_16_COMPLIANCE = "1.6"; | |||
protected static final String JAVA_18_COMPLIANCE = "1.8"; | |||
protected static final String JAVA_9_COMPLIANCE = "9"; | |||
protected String _projectName; | |||
protected static int _projectSerial = 0; // used to create unique project names, to avoid resource deletion problems | |||
public TestBase(String name) { | |||
super(name); | |||
} | |||
public static Test suite() { | |||
throw new IllegalStateException("This is a base test class whose suite() method must not be called.\n" | |||
+ "This exception is thrown to avoid running org.eclipse.jdt.core.tests.builder.BuilderTests#suite() twice."); | |||
} | |||
/** | |||
* Extract lib/annotations.jar from the test bundle and add it to the specified project | |||
*/ | |||
private static void addAnnotationJar(IJavaProject jproj, boolean addToModulePath) throws Exception { | |||
final String resName = "lib/annotations.jar"; // name in bundle | |||
final String libName = resName; // name in destination project | |||
InputStream is = null; | |||
URL resURL = Apt6TestsPlugin.thePlugin().getBundle().getEntry(resName); | |||
is = resURL.openStream(); | |||
IPath projPath = jproj.getPath(); | |||
IProject proj = jproj.getProject(); | |||
IFile libFile = proj.getFile(libName); | |||
env.addFolder(projPath, "lib"); | |||
if (libFile.exists()) { | |||
libFile.setContents(is, true, false, null); | |||
} else { | |||
libFile.create(is, true, null); | |||
} | |||
if (addToModulePath) { | |||
IClasspathAttribute[] attributes = { JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, "true") }; | |||
env.addEntry(projPath, JavaCore.newLibraryEntry(libFile.getFullPath(), null, null, | |||
ClasspathEntry.NO_ACCESS_RULES, attributes, false)); | |||
} else { | |||
env.addLibrary(projPath, libFile.getFullPath(), null, null); | |||
} | |||
} | |||
/** | |||
* Create a java project with java libraries and test annotations on classpath | |||
* (compiler level is 1.6). Use "src" as source folder and "bin" as output folder. APT | |||
* is not enabled. | |||
* | |||
* @param projectName | |||
* @return a java project that has been added to the current workspace. | |||
* @throws Exception | |||
*/ | |||
protected static IJavaProject createJavaProject(final String projectName) throws Exception | |||
{ | |||
IPath projectPath = env.addProject(projectName, JAVA_16_COMPLIANCE); | |||
env.addExternalJars(projectPath, Util.getJavaClassLibs()); | |||
// remove old package fragment root so that names don't collide | |||
env.removePackageFragmentRoot(projectPath, ""); //$NON-NLS-1$ | |||
env.addPackageFragmentRoot(projectPath, "src"); //$NON-NLS-1$ | |||
env.setOutputFolder(projectPath, "bin"); //$NON-NLS-1$ | |||
final IJavaProject javaProj = env.getJavaProject(projectPath); | |||
addAnnotationJar(javaProj, false); | |||
return javaProj; | |||
} | |||
/** | |||
* Create a java project with java libraries and test annotations on classpath | |||
* (compiler level is 1.8). Use "src" as source folder and "bin" as output folder. APT | |||
* is not enabled. | |||
* | |||
* @param projectName | |||
* @return a java project that has been added to the current workspace. | |||
* @throws Exception | |||
*/ | |||
protected static IJavaProject createJava8Project(final String projectName) throws Exception { | |||
// Note, make sure this is run only with a JRE 8 and above. | |||
IPath projectPath = env.addProject(projectName, JAVA_18_COMPLIANCE); | |||
env.addExternalJars(projectPath, Util.getJavaClassLibs()); | |||
// remove old package fragment root so that names don't collide | |||
env.removePackageFragmentRoot(projectPath, ""); //$NON-NLS-1$ | |||
env.addPackageFragmentRoot(projectPath, "src"); //$NON-NLS-1$ | |||
env.setOutputFolder(projectPath, "bin"); //$NON-NLS-1$ | |||
final IJavaProject javaProj = env.getJavaProject(projectPath); | |||
javaProj.getProject().getFolder("prebuilt").create(true, true, null); | |||
javaProj.getProject().getFolder("prebuilt").getFolder("p").create(true, true, null); | |||
env.addClassFolder(projectPath, projectPath.append("prebuilt"), true); | |||
addAnnotationJar(javaProj, false); | |||
return javaProj; | |||
} | |||
/** | |||
* Create a java project with java libraries and test annotations on modulepath | |||
* (compiler level is 1.9). Use "src" as source folder and "bin" as output folder. APT | |||
* is not enabled. | |||
* | |||
* @param projectName | |||
* @return a java project that has been added to the current workspace. | |||
* @throws Exception | |||
*/ | |||
protected static IJavaProject createJava9Project(final String projectName) throws Exception { | |||
// Note, make sure this is run only with a JRE 9 and above. | |||
IPath projectPath = env.addProject(projectName, JAVA_9_COMPLIANCE); | |||
env.addExternalJars(projectPath, Util.getJavaClassLibs()); | |||
// remove old package fragment root so that names don't collide | |||
env.removePackageFragmentRoot(projectPath, ""); //$NON-NLS-1$ | |||
env.addPackageFragmentRoot(projectPath, "src"); //$NON-NLS-1$ | |||
env.setOutputFolder(projectPath, "bin"); //$NON-NLS-1$ | |||
final IJavaProject javaProj = env.getJavaProject(projectPath); | |||
addAnnotationJar(javaProj, true); | |||
return javaProj; | |||
} | |||
/** | |||
* Ensure that there are no Java 5 processors on the factory path, as they can cause | |||
* units to be multiply compiled, which can mess up tests that expect a certain number | |||
* of compilations to occur. | |||
* @param jproj the project whose factory path will be edited | |||
* @throws CoreException | |||
*/ | |||
protected void disableJava5Factories(IJavaProject jproj) throws CoreException { | |||
FactoryPath fp = (FactoryPath) AptConfig.getFactoryPath(jproj); | |||
for (Map.Entry<FactoryContainer, FactoryPath.Attributes> entry : fp.getAllContainers().entrySet()) { | |||
if (entry.getKey().getType() == FactoryType.PLUGIN) { | |||
String id = entry.getKey().getId(); | |||
if (!Apt6TestsPlugin.PLUGIN_ID.equals(id)) { | |||
fp.disablePlugin(id); | |||
} | |||
} | |||
} | |||
AptConfig.setFactoryPath(jproj, fp); | |||
} | |||
/** | |||
* Verify that an expected file exists within a project. | |||
* @param fileName the filename relative to the project root. | |||
*/ | |||
protected void expectingFile(IProject proj, String fileName) throws Exception | |||
{ | |||
IPath path = proj.getLocation().append(fileName); | |||
File file = new File(path.toOSString()); | |||
assertTrue("Expected file " + fileName + " was missing from project", file != null && file.exists()); | |||
} | |||
/** | |||
* Verify that an expected file exists within a project. | |||
* @param fileName the filename relative to the project root. | |||
*/ | |||
protected void expectingNoFile(IProject proj, String fileName) throws Exception | |||
{ | |||
IPath path = proj.getLocation().append(fileName); | |||
File file = new File(path.toOSString()); | |||
boolean exists = file.exists(); | |||
// work around a timing bug in some versions of JRE 1.6 on Linux: | |||
// Before assuming the test has failed, wait half a second and try again. | |||
// This delay is not encountered when the test is passing normally. | |||
if (exists) { | |||
Thread.sleep(500); | |||
exists = file.exists(); | |||
} | |||
assertTrue("File " + fileName + " was expected to not exist", file == null || !exists); | |||
} | |||
@Override | |||
protected void setUp() throws Exception | |||
{ | |||
super.setUp(); | |||
env.setAutoBuilding(false); | |||
_projectName = String.format("testproj%04d", ++_projectSerial); | |||
} | |||
public boolean canRunJava9() { | |||
try { | |||
SourceVersion.valueOf("RELEASE_9"); | |||
} catch(IllegalArgumentException iae) { | |||
return false; | |||
} | |||
return true; | |||
} | |||
} |
@@ -1,275 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.entity; | |||
import depends.relations.IBindingResolver; | |||
import depends.relations.Relation; | |||
import java.util.*; | |||
/** | |||
* 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 { | |||
Integer id=-1; | |||
String qualifiedName = null; | |||
GenericName rawName = GenericName.build(""); | |||
Entity parent; | |||
private MultiDeclareEntities mutliDeclare = null; | |||
private Set<Entity> children; | |||
ArrayList<Relation> relations; | |||
private Entity actualReferTo = null; | |||
private boolean inScope = true; | |||
protected HashMap<String, Entity> visibleNames = new HashMap<>(); | |||
private Location location = new Location(); | |||
public Entity() {}; | |||
public Entity(GenericName rawName, Entity parent, Integer id) { | |||
this.qualifiedName = null; | |||
this.rawName = rawName; | |||
this.parent = parent; | |||
this.id = id; | |||
if (parent!=null) | |||
parent.addChild(this); | |||
deduceQualifiedName(); | |||
visibleNames.put(rawName.getName(), this); | |||
visibleNames.put(qualifiedName, this); | |||
} | |||
private Set<Entity> children() { | |||
if (children==null) | |||
children = new HashSet<>(); | |||
return children; | |||
} | |||
/** | |||
* Rule 1: if it start with '.' , 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 '.' | |||
*/ | |||
private void deduceQualifiedName() { | |||
rawName = rawName.replace("::","." ); | |||
if (this.rawName.startsWith(".")) { | |||
this.qualifiedName = this.rawName.uniqName().substring(1); | |||
return; //already qualified | |||
} | |||
if (parent==null) { | |||
this.qualifiedName = this.rawName.uniqName(); | |||
return; | |||
} | |||
if (parent.getQualifiedName(true)==null) { | |||
this.qualifiedName = this.rawName.uniqName(); | |||
return; | |||
} | |||
if (parent.getQualifiedName(true).isEmpty()) { | |||
this.qualifiedName = rawName.uniqName(); | |||
return; | |||
} | |||
this.qualifiedName= parent.getQualifiedName(true)+"." + rawName.uniqName(); | |||
} | |||
public GenericName getRawName() { | |||
return rawName; | |||
} | |||
public Integer getId() { | |||
return id; | |||
} | |||
public void addRelation(Relation relation) { | |||
if (relations==null) | |||
relations = new ArrayList<>(); | |||
if (relation.getEntity()==null) return; | |||
relations.add(relation); | |||
} | |||
public ArrayList<Relation> getRelations() { | |||
if (relations==null) | |||
return new ArrayList<>(); | |||
return relations; | |||
} | |||
public void addChild(Entity child) { | |||
children().add(child); | |||
visibleNames.put(child.getRawName().getName(), child); | |||
visibleNames.put(child.getQualifiedName(), child); | |||
} | |||
public Entity getParent() { | |||
return parent; | |||
} | |||
public void setParent(Entity parent) { | |||
this.parent = parent; | |||
} | |||
public Collection<Entity> getChildren() { | |||
if (children==null) | |||
return new HashSet<>(); | |||
return children; | |||
} | |||
public void setQualifiedName(String qualifiedName) { | |||
this.qualifiedName = qualifiedName; | |||
} | |||
public void setRawName(GenericName rawName) { | |||
this.rawName = rawName; | |||
deduceQualifiedName(); | |||
} | |||
public final String getQualifiedName() { | |||
return qualifiedName; | |||
} | |||
public String getQualifiedName(boolean overrideFileWithPackage) { | |||
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(IBindingResolver bindingResolver) { | |||
inferLocalLevelEntities(bindingResolver); | |||
for (Entity child:this.getChildren()) { | |||
child.inferEntities(bindingResolver); | |||
} | |||
} | |||
public abstract void inferLocalLevelEntities(IBindingResolver bindingResolver); | |||
public TypeEntity getType() { | |||
return null; | |||
} | |||
public String getDisplayName() { | |||
return getRawName().uniqName(); | |||
} | |||
public MultiDeclareEntities getMutliDeclare() { | |||
return mutliDeclare; | |||
} | |||
public void setMutliDeclare(MultiDeclareEntities mutliDeclare) { | |||
this.mutliDeclare = mutliDeclare; | |||
} | |||
public Entity getActualReferTo() { | |||
if (this.actualReferTo ==null) | |||
return this; | |||
return actualReferTo; | |||
} | |||
public void setActualReferTo(Entity actualReferTo) { | |||
this.actualReferTo = actualReferTo; | |||
} | |||
public static void setParent(Entity child, Entity parent) { | |||
if (parent == null) | |||
return; | |||
if (child == null) | |||
return; | |||
if (parent.equals(child.getParent())) | |||
return; | |||
child.setParent(parent); | |||
parent.addChild(child); | |||
} | |||
@Override | |||
public int hashCode() { | |||
final int prime = 31; | |||
int result = 1; | |||
result = prime * result + ((id == null) ? 0 : id.hashCode()); | |||
return result; | |||
} | |||
@Override | |||
public boolean equals(Object obj) { | |||
if (this == obj) | |||
return true; | |||
if (obj == null) | |||
return false; | |||
if (getClass() != obj.getClass()) | |||
return false; | |||
Entity other = (Entity) obj; | |||
if (id == null) { | |||
if (other.id != null) | |||
return false; | |||
} else if (!id.equals(other.id)) | |||
return false; | |||
return true; | |||
} | |||
public void setInScope(boolean value) { | |||
this.inScope = value; | |||
children().forEach(child->child.setInScope(value)); | |||
} | |||
public boolean inScope() { | |||
return inScope; | |||
} | |||
public Entity getByName(String name, HashSet<Entity> searched) { | |||
if (searched.contains(this)) return null; | |||
searched.add(this); | |||
return visibleNames.get(name); | |||
} | |||
public Integer getLine() { | |||
return location.getLine(); | |||
} | |||
public void setLine(int lineNumber) { | |||
this.location.setLine(lineNumber); | |||
} | |||
public Location getLocation() { | |||
return this.location; | |||
} | |||
} |
@@ -1,101 +0,0 @@ | |||
package depends.extractor.pom; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import java.io.IOException; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertNotNull; | |||
public class EntityExtractTest extends MavenParserTest{ | |||
@Before | |||
public void setUp() { | |||
super.init(); | |||
} | |||
@Test | |||
public void use_package_contains() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/maven-code-examples/simple/log4j.pom", | |||
}; | |||
for (String src:srcs) { | |||
PomFileParser parser = createParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
assertEquals(0,entityRepo.getEntity("org.log4j-test.log4j_1.2.12_").getRelations().size()); | |||
} | |||
@Test | |||
public void should_use_parent_groupId() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/maven-code-examples/use_parent_groupId_and_version.pom", | |||
}; | |||
for (String src:srcs) { | |||
PomFileParser parser = createParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
assertNotNull(entityRepo.getEntity("org.apache.maven.surefire.surefire-junit4_2.12.4_")); | |||
} | |||
@Test | |||
public void should_parse_properties_in_same_pom() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/maven-code-examples/properties-test1.pom", | |||
}; | |||
for (String src:srcs) { | |||
PomFileParser parser = createParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
PomArtifactEntity entity = (PomArtifactEntity)(entityRepo.getEntity("properties-test.test_1_")); | |||
/* | |||
<project.version>1.00</project.version> | |||
<activeio-version>3.1.4</activeio-version> | |||
<projectName>Apache ActiveMQ</projectName> | |||
<siteId>activemq-${project.version}</siteId> */ | |||
assertEquals("1.00",entity.getProperty("project.version")); | |||
assertEquals("activemq-1.00",entity.getProperty("siteId")); | |||
} | |||
@Test | |||
public void should_parse_multiple_properties_in_same_pom() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/maven-code-examples/properties-test1.pom", | |||
}; | |||
for (String src:srcs) { | |||
PomFileParser parser = createParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
PomArtifactEntity entity = (PomArtifactEntity)(entityRepo.getEntity("properties-test.test_1_")); | |||
/* | |||
<project.version>1.00</project.version> | |||
<activeio-version>3.1.4</activeio-version> | |||
<projectName>Apache ActiveMQ</projectName> | |||
<anotherId>activemq-${project.version}--${activeio-version}</anotherId> */ | |||
assertEquals("activemq-1.00-3.1.4",entity.getProperty("anotherId")); | |||
} | |||
@Test | |||
public void should_parse_multiple_properties_in_parent_pom() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/maven-code-examples/properties-test-child.pom" | |||
}; | |||
for (String src:srcs) { | |||
PomFileParser parser = createParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
PomArtifactEntity entity = (PomArtifactEntity)(entityRepo.getEntity("properties-test.test_1_")); | |||
assertEquals("13",entity.getProperty("project.version")); | |||
} | |||
} |
@@ -1,120 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
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.core.DependencyMatrix; | |||
import depends.matrix.core.DependencyPair; | |||
import depends.matrix.core.DependencyValue; | |||
public class ExcelXlsFormatDependencyDumper extends AbstractFormatDependencyDumper { | |||
private HSSFWorkbook workbook; | |||
private HSSFSheet sheet; | |||
@Override | |||
public String getFormatName() { | |||
return "xls"; | |||
} | |||
public ExcelXlsFormatDependencyDumper(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"); | |||
} | |||
} |
@@ -1,119 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.format.excel; | |||
import java.io.FileOutputStream; | |||
import java.io.IOException; | |||
import java.util.Collection; | |||
import org.apache.poi.xssf.usermodel.XSSFCell; | |||
import org.apache.poi.xssf.usermodel.XSSFRow; | |||
import org.apache.poi.xssf.usermodel.XSSFSheet; | |||
import org.apache.poi.xssf.usermodel.XSSFWorkbook; | |||
import depends.format.AbstractFormatDependencyDumper; | |||
import depends.matrix.core.DependencyMatrix; | |||
import depends.matrix.core.DependencyPair; | |||
import depends.matrix.core.DependencyValue; | |||
public class ExcelXlsxFormatDependencyDumper extends AbstractFormatDependencyDumper { | |||
private XSSFWorkbook workbook; | |||
private XSSFSheet sheet; | |||
@Override | |||
public String getFormatName() { | |||
return "xlsx"; | |||
} | |||
public ExcelXlsxFormatDependencyDumper(DependencyMatrix dependencyMatrix, String projectName, String outputDir) { | |||
super(dependencyMatrix, projectName,outputDir); | |||
} | |||
@Override | |||
public boolean output() { | |||
String filename = composeFilename() + ".xlsx"; | |||
startFile(); | |||
Collection<DependencyPair> dependencyPairs = matrix.getDependencyPairs(); | |||
XSSFRow[] row = new XSSFRow[matrix.getNodes().size()]; | |||
// create header row | |||
XSSFRow header = sheet.createRow(0); | |||
for (int i = 0; i < matrix.getNodes().size(); i++) { | |||
XSSFCell 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); | |||
XSSFCell 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++) { | |||
XSSFCell cell = row[i].createCell(i + 2); | |||
cell.setCellValue("(" + i + ")"); | |||
} | |||
; | |||
for (DependencyPair dependencyPair : dependencyPairs) { | |||
XSSFCell 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 { | |||
FileOutputStream out = new FileOutputStream(filename); | |||
workbook.write(out); | |||
workbook.close(); | |||
out.close(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
private void startFile() { | |||
workbook = new XSSFWorkbook(); | |||
sheet = workbook.createSheet("DSM"); | |||
} | |||
} |
@@ -1,413 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.entity; | |||
import depends.entity.repo.EntityRepo; | |||
import depends.relations.IBindingResolver; | |||
import java.io.Serializable; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
/** | |||
* Expression | |||
*/ | |||
public class Expression implements Serializable{ | |||
private static final long serialVersionUID = 1L; | |||
public Integer id; | |||
private String text; // for debug purpose | |||
private GenericName rawType; // the raw type name | |||
private GenericName identifier; // the varName, or method name, etc. | |||
private boolean isSet = false; // is a set relation from right to leftHand | |||
private boolean isDot = false; // is a dot expression, will decuce variable tfype left to right | |||
private boolean isCall = false; | |||
private boolean isLogic = false; | |||
private boolean isCreate = false; | |||
private boolean isCast = false; | |||
private boolean isThrow = false; | |||
private boolean isStatement = false; //statement is only used for return type calcuation in some langs such as ruby | |||
//they will not be treat as real expressions in case of relation calculation | |||
private boolean deriveTypeFromChild = true; | |||
private Integer deduceTypeBasedId; //by default, parent expression type determined by most left child | |||
private Integer parentId = -1; | |||
private transient Expression parent; | |||
private transient List<VarEntity> deducedTypeVars = new ArrayList<>(); | |||
private List<Integer> deducedTypeVarsId = new ArrayList<>(); | |||
private transient List<FunctionEntity> deducedTypeFunctions= new ArrayList<>(); | |||
private List<Integer> deducedTypeFunctionsId = new ArrayList<>(); | |||
private Integer referredEntityId; | |||
private transient Entity referredEntity; | |||
private transient TypeEntity type; // the type we care - for relation calculation. | |||
private Location location = new Location(); | |||
//for leaf, it equals to referredEntity.getType. otherwise, depends on child's type strategy | |||
/* | |||
* */ | |||
public Expression() { | |||
deducedTypeVars = new ArrayList<>(); | |||
deducedTypeFunctions = new ArrayList<>(); | |||
} | |||
public Expression(Integer id) { | |||
this.id = id; | |||
deducedTypeVars = new ArrayList<>(); | |||
deducedTypeFunctions = new ArrayList<>(); | |||
} | |||
public void reload(EntityRepo repo, ArrayList<Expression> expressionList) { | |||
this.deducedTypeFunctions = new ArrayList<>(); | |||
this.deducedTypeVars = new ArrayList<>(); | |||
//recover parent relation | |||
if (parentId!=-1) { | |||
for (Expression expr:expressionList) { | |||
if (expr.id==parentId) { | |||
parent = expr; | |||
break; | |||
} | |||
} | |||
} | |||
//recover deducedTypeFunctionsId | |||
if (deducedTypeFunctionsId!=null) { | |||
for (Integer funcId:this.deducedTypeFunctionsId) { | |||
this.deducedTypeFunctions.add((FunctionEntity) repo.getEntity(funcId)); | |||
} | |||
} | |||
//recover deducedTypeVars | |||
if (deducedTypeVarsId!=null) { | |||
for (Integer varId:this.deducedTypeVarsId) { | |||
this.deducedTypeVars.add((VarEntity) repo.getEntity(varId)); | |||
} | |||
} | |||
//referer referredEntity -- TODO:maybe not require | |||
if (this.referredEntityId!=null && this.referredEntity==null) { | |||
this.referredEntity = repo.getEntity(this.referredEntityId); | |||
if (this.referredEntity ==null){ | |||
System.err.println("unexpected: referred Entity is null" + this.referredEntityId + this.text+this.id); | |||
} | |||
} | |||
} | |||
/** | |||
* Set type of the expression | |||
* @param type | |||
* @param referredEntity | |||
* @param bindingResolver | |||
*/ | |||
public void setType(TypeEntity type, Entity referredEntity, IBindingResolver bindingResolver) { | |||
if (this.getReferredEntity()==null && referredEntity!=null) { | |||
this.setReferredEntity(referredEntity); | |||
} | |||
boolean changedType = false; | |||
if (this.type==null && type!=null) { | |||
this.type = type; | |||
for (VarEntity var:deducedTypeVars) { | |||
if (var!=null) { | |||
var.setType(this.type); | |||
} | |||
} | |||
for (FunctionEntity func:deducedTypeFunctions) { | |||
if (func!=null) { | |||
func.addReturnType(this.type); | |||
} | |||
} | |||
changedType = true; | |||
} | |||
if (this.referredEntity==null) | |||
this.setReferredEntity(this.type); | |||
if (changedType) | |||
deduceTheParentType(bindingResolver); | |||
} | |||
/** | |||
* deduce type of parent based on child's type | |||
* @param bindingResolver | |||
*/ | |||
private void deduceTheParentType(IBindingResolver bindingResolver) { | |||
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(TypeEntity.buildInType)) { | |||
parent.setType(TypeEntity.buildInType,TypeEntity.buildInType, bindingResolver); | |||
return; | |||
} | |||
/* if it is a logic expression, the return type/type is boolean. */ | |||
if (parent.isLogic) { | |||
parent.setType(TypeEntity.buildInType,null, bindingResolver); | |||
} | |||
/* 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()) { | |||
List<Entity> funcs = this.getType().lookupFunctionInVisibleScope(parent.identifier); | |||
setReferredFunctions(bindingResolver, parent, funcs); | |||
}else { | |||
Entity var = this.getType().lookupVarInVisibleScope(parent.identifier); | |||
if (var!=null) { | |||
parent.setType(var.getType(),var, bindingResolver); | |||
parent.setReferredEntity(var); | |||
}else { | |||
List<Entity> funcs = this.getType().lookupFunctionInVisibleScope(parent.identifier); | |||
setReferredFunctions(bindingResolver,parent,funcs); | |||
} | |||
} | |||
if (parent.getType()==null) { | |||
parent.setType(bindingResolver.inferTypeFromName(this.getType(), parent.identifier),null, bindingResolver); | |||
} | |||
} | |||
/* if other situation, simple make the parent and child type same */ | |||
else { | |||
parent.setType(type, null, bindingResolver); | |||
} | |||
if (parent.getReferredEntity()==null) | |||
parent.setReferredEntity(parent.type); | |||
} | |||
private void setReferredFunctions(IBindingResolver bindingResolver, Expression expr, List<Entity> funcs) { | |||
if (funcs ==null ||funcs.size()==0) return; | |||
Entity func = funcs.get(0); | |||
if (funcs.size()==1){ | |||
expr.setType(func.getType(), func, bindingResolver); | |||
expr.setReferredEntity(func); | |||
return; | |||
} | |||
MultiDeclareEntities m = new MultiDeclareEntities(func, bindingResolver.getRepo().generateId()); | |||
bindingResolver.getRepo().add(m); | |||
for (int i = 1; i< funcs.size(); i++) { | |||
m.add(funcs.get(i)); | |||
} | |||
expr.setType(func.getType(), m, bindingResolver); | |||
expr.setReferredEntity(m); | |||
} | |||
private void setReferredEntity(Entity referredEntity) { | |||
this.referredEntity = referredEntity; | |||
if (this.referredEntity!=null) { | |||
this.referredEntityId = referredEntity.getId(); | |||
} | |||
} | |||
public void addDeducedTypeVar(VarEntity var) { | |||
this.deducedTypeVars.add(var); | |||
this.deducedTypeVarsId.add(var.getId()); | |||
} | |||
public void addDeducedTypeFunction(FunctionEntity function) { | |||
this.deducedTypeFunctions.add(function); | |||
this.deducedTypeFunctionsId.add(function.id); | |||
} | |||
public void setParent(Expression parent) { | |||
this.parent = parent; | |||
if (parent!=null) | |||
this.parentId = parent.id; | |||
if (parent!=null) { | |||
if (parent.deduceTypeBasedId==null) | |||
parent.deduceTypeBasedId = id; | |||
if (parent.isSet) { | |||
parent.deduceTypeBasedId = id; | |||
} | |||
} | |||
} | |||
public GenericName getIdentifier() { | |||
return this.identifier; | |||
} | |||
public GenericName getRawType() { | |||
return this.rawType; | |||
} | |||
public void setIdentifier(String name) { | |||
if (!validName(name)){ | |||
return; | |||
} | |||
this.identifier = GenericName.build(name); | |||
} | |||
public void setIdentifier(GenericName name) { | |||
if (name==null) return; | |||
if (!validName(name.getName())){ | |||
return; | |||
} | |||
this.identifier = name; | |||
} | |||
public void setRawType(GenericName name) { | |||
if (name==null) return; | |||
if (!validName(name.getName())){ | |||
return; | |||
} | |||
this.rawType = name; | |||
} | |||
public void setRawType(String name) { | |||
if (name==null) return; | |||
if (!validName(name)){ | |||
return; | |||
} | |||
this.rawType = GenericName.build(name); | |||
} | |||
public Expression getParent() { | |||
return this.parent; | |||
} | |||
public void setText(String text) { | |||
this.text = text; | |||
} | |||
public boolean isCall() { | |||
return isCall; | |||
} | |||
public boolean isSet() { | |||
return isSet; | |||
} | |||
public void setSet(boolean isSet) { | |||
this.isSet = isSet; | |||
} | |||
public boolean isDot() { | |||
return isDot; | |||
} | |||
public void setDot(boolean isDot) { | |||
this.isDot = isDot; | |||
} | |||
public boolean isLogic() { | |||
return isLogic; | |||
} | |||
public void setLogic(boolean isLogic) { | |||
this.isLogic = isLogic; | |||
} | |||
public boolean isCreate() { | |||
return isCreate; | |||
} | |||
public void setCreate(boolean isCreate) { | |||
this.isCreate = isCreate; | |||
} | |||
public boolean isCast() { | |||
return isCast; | |||
} | |||
public void setCast(boolean isCast) { | |||
this.isCast = isCast; | |||
} | |||
public boolean isThrow() { | |||
return isThrow; | |||
} | |||
public void setThrow(boolean isThrow) { | |||
this.isThrow = isThrow; | |||
} | |||
public boolean isStatement() { | |||
return isStatement; | |||
} | |||
public void setStatement(boolean isStatement) { | |||
this.isStatement = isStatement; | |||
} | |||
public void setCall(boolean isCall) { | |||
this.isCall = isCall; | |||
} | |||
public void disableDriveTypeFromChild() { | |||
deriveTypeFromChild = false ; | |||
} | |||
public Entity getReferredEntity() { | |||
return referredEntity; | |||
} | |||
public TypeEntity getType() { | |||
return type; | |||
} | |||
private boolean validName(String name) { | |||
if (name==null) return false; | |||
if (name.toLowerCase().equals("<literal>")) return true; | |||
if (name.toLowerCase().equals("<built-in>")) return true; | |||
return true; | |||
} | |||
@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(isCreate?"[new]":"") | |||
.append(isThrow?"[throw]":"").append("|") | |||
.append("parent:").append(parent==null?"nil":parent.text).append("|") | |||
.append("type:").append(type).append("|"); | |||
return s.toString(); | |||
} | |||
public void setLine(int lineNumber) { | |||
this.location.setLine(lineNumber); | |||
} | |||
public Location getLocation() { | |||
return location; | |||
} | |||
} |
@@ -1,298 +0,0 @@ | |||
package depends.extractor.python.union; | |||
import depends.entity.*; | |||
import depends.entity.repo.IdGenerator; | |||
import depends.extractor.HandlerContext; | |||
import depends.extractor.python.PythonHandlerContext; | |||
import depends.extractor.python.PythonParser.*; | |||
import depends.extractor.python.PythonParserBaseVisitor; | |||
import depends.relations.IBindingResolver; | |||
import org.antlr.v4.runtime.ParserRuleContext; | |||
import org.antlr.v4.runtime.RuleContext; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import java.util.regex.Matcher; | |||
import java.util.regex.Pattern; | |||
public class ExpressionUsage { | |||
HandlerContext context; | |||
IdGenerator idGenerator; | |||
private boolean exprStarted=false; | |||
private IBindingResolver bindingResolver; | |||
public ExpressionUsage(PythonHandlerContext context, IdGenerator idGenerator, IBindingResolver bindingResolver) { | |||
this.context = context; | |||
this.idGenerator = idGenerator; | |||
this.bindingResolver = bindingResolver; | |||
} | |||
/** | |||
* Auto deduce variable type from assignment. for example: c = new C() then c is | |||
* type of C | |||
* | |||
*/ | |||
private void deduceVarTypeInCaseOfAssignment(Expr_stmtContext expr, Expression expression) { | |||
List<String> names = getName(expr.testlist_star_expr()); | |||
// TODO: should handle list properly; | |||
String varName = null; | |||
if (names.size() == 1) | |||
varName = names.get(0); | |||
if (varName == null) | |||
return; | |||
VarEntity var = context.lastContainer().lookupVarLocally(varName); | |||
if (var != null) { | |||
expression.addDeducedTypeVar(var); | |||
} | |||
} | |||
private List<String> getName(Testlist_star_exprContext testlist_star_expr) { | |||
List<String> names = new ArrayList<>(); | |||
testlist_star_expr.accept(new NameCollector(names)); | |||
return names; | |||
} | |||
public void foundExpression(ParserRuleContext ctx) { | |||
if (!isStartOfContainerRule(ctx)) { | |||
return ; | |||
} | |||
if (context.lastContainer().containsExpression(ctx)) return; | |||
if (ctx.getParent() instanceof TrailerContext) return; | |||
Expression parent = findParentInStack(ctx); | |||
Expression expression = parent; | |||
if (ctx.getParent().getChildCount()==1 && parent!=null) { | |||
//如果就是自己,则无需创建新的Expression | |||
}else { | |||
/* create expression and link it with parent*/ | |||
expression = new Expression(idGenerator.generateId()); | |||
expression.setLine(ctx.getStart().getLine()); | |||
expression.setText(ctx.getText()); | |||
context.lastContainer().addExpression(ctx,expression); | |||
expression.setParent(parent); | |||
} | |||
if (ctx instanceof Expr_stmtContext) { | |||
Expr_stmtContext exprAssign = (Expr_stmtContext)ctx; | |||
if (exprAssign.assign_part()!=null) { | |||
expression.setSet(true); | |||
expression.setIdentifier(exprAssign.testlist_star_expr().getText()); | |||
if (isValidIdentifier(expression.getIdentifier())) { | |||
makeSureVarExist(expression.getIdentifier(), ctx); | |||
} | |||
deduceVarTypeInCaseOfAssignment((Expr_stmtContext)ctx,expression); | |||
} | |||
} | |||
if (ctx instanceof Raise_stmtContext) { | |||
expression.setThrow (true); | |||
} | |||
if (ctx instanceof Return_stmtContext) { | |||
deduceReturnTypeInCaseOfReturn((Return_stmtContext)ctx,expression); | |||
} | |||
if (ctx instanceof ExprContext) { | |||
processExprContext((ExprContext)ctx, expression); | |||
} | |||
} | |||
private void deduceReturnTypeInCaseOfReturn(Return_stmtContext ctx, Expression expression) { | |||
FunctionEntity currentFunction = context.currentFunction(); | |||
if (currentFunction == null) | |||
return; | |||
expression.addDeducedTypeFunction(currentFunction); | |||
} | |||
private void makeSureVarExist(GenericName identifier, ParserRuleContext ctx) { | |||
if (null==context.foundEntityWithName(identifier)) { | |||
VarEntity var = context.foundVarDefinition(context.lastContainer(), identifier.getName(),ctx.getStart().getLine()); | |||
var.setLine(ctx.getStart().getLine()); | |||
} | |||
} | |||
private boolean isValidIdentifier(GenericName identifier) { | |||
Pattern p = Pattern.compile("[a-zA-Z_][a-zA-Z0-9_]*"); | |||
Matcher m = p.matcher(identifier.getName()); | |||
return m.matches(); | |||
} | |||
private void processExprContext(ExprContext exprCtx, Expression expression) { | |||
//func_call, member_access, subscript member, and atom | |||
Expression lastExpression = null; | |||
if (exprCtx.atom()!=null) { | |||
//atom | |||
Expression atomExpr = new Expression(idGenerator.generateId()); | |||
atomExpr.setLine(exprCtx.atom().getStart().getLine()); | |||
atomExpr.setParent(expression); | |||
atomExpr.setText(exprCtx.atom().getText()); | |||
atomExpr.setIdentifier(exprCtx.atom().getText()); | |||
context.lastContainer().addExpression(exprCtx.atom(),atomExpr); | |||
processAtom(exprCtx.atom(),atomExpr); | |||
lastExpression = atomExpr; | |||
if (exprCtx.trailer()==null || exprCtx.trailer().size()==0) { | |||
//do nothing; it is just an id; | |||
}else { | |||
for (TrailerContext trailer:exprCtx.trailer()) { | |||
if (trailer.name()!=null) { | |||
Expression trailerExpr = new Expression(idGenerator.generateId()); | |||
trailerExpr.setLine(trailer.getStart().getLine()); | |||
trailerExpr.setText(trailer.getText()); | |||
context.lastContainer().addExpression(trailer,trailerExpr); | |||
trailerExpr.setParent(expression); | |||
//doted name = member access or method call | |||
trailerExpr.setDot(true);; | |||
trailerExpr.setIdentifier(trailer.name().getText()); | |||
if (trailer.arguments()!=null) { | |||
if (trailer.arguments().OPEN_PAREN()!=null) { | |||
foundCallStyleExpressionWithDot(trailerExpr,lastExpression.getIdentifier(), trailer); | |||
}else { | |||
//subscript list, do nothing | |||
} | |||
} | |||
lastExpression.setParent(trailerExpr); | |||
lastExpression = trailerExpr; | |||
}else { | |||
//direct call, or direct data access | |||
if (trailer.arguments()!=null) { | |||
if (trailer.arguments().OPEN_PAREN()!=null) { | |||
foundCallStyleExpressionWithoutDot(lastExpression, trailer.arguments()); | |||
}else { | |||
//subscript list, do nothing | |||
} | |||
} | |||
} | |||
} | |||
} | |||
}else { | |||
/** expr | |||
| <assoc=right> expr op=POWER expr | |||
| op=(ADD | MINUS | NOT_OP) expr | |||
| expr op=(STAR | DIV | MOD | IDIV | AT) expr | |||
| expr op=(ADD | MINUS) expr | |||
| expr op=(LEFT_SHIFT | RIGHT_SHIFT) expr | |||
| expr op=AND_OP expr | |||
| expr op=XOR expr | |||
| expr op=OR_OP expr | |||
;*/ | |||
} | |||
} | |||
private boolean isStartOfContainerRule(ParserRuleContext ctx) { | |||
if (this.exprStarted) return true; | |||
return ctx instanceof ExprContext || | |||
ctx instanceof Expr_stmtContext || | |||
ctx instanceof Del_stmtContext || | |||
ctx instanceof Return_stmtContext || | |||
ctx instanceof Raise_stmtContext || | |||
ctx instanceof Raise_stmtContext || | |||
ctx instanceof Yield_stmtContext || | |||
ctx instanceof Assert_stmtContext; | |||
} | |||
private void foundCallStyleExpressionWithDot(Expression theExpression, GenericName varName, ParserRuleContext ctx) { | |||
GenericName funcName = theExpression.getIdentifier(); | |||
Entity prefixEntity = context.foundEntityWithName(varName); | |||
if (prefixEntity instanceof VarEntity) { | |||
((VarEntity) prefixEntity).addFunctionCall(funcName); | |||
} | |||
Entity typeEntity = context.foundEntityWithName(funcName); | |||
if (typeEntity instanceof TypeEntity && typeEntity.getId() > 0) { | |||
theExpression.setCreate(true); | |||
theExpression.setType(typeEntity.getType(), typeEntity, bindingResolver); | |||
theExpression.setRawType(typeEntity.getRawName()); | |||
return; | |||
} | |||
theExpression.setCall(true); | |||
} | |||
private void foundCallStyleExpressionWithoutDot(Expression theExpression, ParserRuleContext ctx) { | |||
GenericName funcName = theExpression.getIdentifier(); | |||
Entity typeEntity = context.foundEntityWithName(funcName); | |||
if (typeEntity instanceof TypeEntity && typeEntity.getId() > 0) { | |||
theExpression.getParent().setCreate(true); | |||
theExpression.setType(typeEntity.getType(), typeEntity, bindingResolver); | |||
theExpression.getParent().setRawType(typeEntity.getRawName()); | |||
return; | |||
} | |||
theExpression.setCall(true); | |||
} | |||
private void processAtom(AtomContext atom, Expression expression) { | |||
if (atom.name()!=null) { | |||
expression.setIdentifier(atom.getText()); | |||
return; | |||
} | |||
if (atom.STRING()!=null | |||
|| atom.NONE()!=null | |||
|| atom.number()!=null) { | |||
expression.setRawType("<Built-in>"); | |||
expression.setIdentifier("<Literal>"); | |||
return; | |||
} | |||
if (atom.EXEC()!=null | |||
|| atom.PRINT()!=null | |||
|| atom.ELLIPSIS()!=null) { | |||
return; | |||
} | |||
// : OPEN_PAREN (yield_expr | testlist_comp)? CLOSE_PAREN | |||
// | OPEN_BRACKET testlist_comp? CLOSE_BRACKET | |||
// | OPEN_BRACE dictorsetmaker? CLOSE_BRACE | |||
// | REVERSE_QUOTE testlist COMMA? REVERSE_QUOTE | |||
return; | |||
} | |||
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); | |||
} | |||
public void startExpr() { | |||
this.exprStarted = true; | |||
} | |||
public void stopExpr() { | |||
this.exprStarted = false; | |||
} | |||
} | |||
class NameCollector extends PythonParserBaseVisitor<Void>{ | |||
private List<String> names; | |||
NameCollector(List<String> names){ | |||
this.names = names; | |||
} | |||
@Override | |||
public Void visitAtom(AtomContext ctx) { | |||
if (ctx.name()!=null) | |||
names.add(ctx.name().getText()); | |||
return super.visitAtom(ctx); | |||
} | |||
} |
@@ -1,129 +0,0 @@ | |||
import java.io.FileInputStream; | |||
import java.io.FileNotFoundException; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.lang.StringBuffer; | |||
// https://svn.apache.org/repos/asf/poi/trunk/src/ooxml/testcases/org/apache/poi/extractor/TestExtractorFactory.java | |||
import org.apache.poi.POIOLE2TextExtractor; | |||
import org.apache.poi.POITextExtractor; | |||
//import org.apache.poi.POIDataSamples; | |||
//import org.apache.poi.extractor.*; | |||
import org.apache.poi.extractor.ExtractorFactory; | |||
import org.apache.poi.hdgf.extractor.VisioTextExtractor; | |||
import org.apache.poi.hpbf.extractor.PublisherTextExtractor; | |||
import org.apache.poi.hslf.extractor.PowerPointExtractor; | |||
import org.apache.poi.hsmf.extractor.OutlookTextExtactor; | |||
import org.apache.poi.hssf.extractor.EventBasedExcelExtractor; | |||
import org.apache.poi.hssf.extractor.ExcelExtractor; | |||
import org.apache.poi.hwpf.extractor.Word6Extractor; | |||
import org.apache.poi.hwpf.extractor.WordExtractor; | |||
import org.apache.poi.poifs.filesystem.POIFSFileSystem; | |||
import org.apache.poi.xslf.extractor.XSLFPowerPointExtractor; | |||
import org.apache.poi.xssf.extractor.XSSFEventBasedExcelExtractor; | |||
import org.apache.poi.xssf.extractor.XSSFExcelExtractor; | |||
import org.apache.poi.xwpf.extractor.XWPFWordExtractor; | |||
import org.apache.poi.openxml4j.exceptions.InvalidFormatException; | |||
import org.apache.poi.poifs.filesystem.OfficeXmlFileException; | |||
import org.apache.poi.xslf.usermodel.XMLSlideShow; // pptx 2007, http://poi.apache.org/apidocs/org/apache/poi/xslf/ | |||
import org.apache.poi.xwpf.usermodel.XWPFDocument; // docx 2007, http://poi.apache.org/apidocs/org/apache/poi/xwpf/ | |||
import org.apache.poi.xssf.usermodel.XSSFWorkbook; // xlsx 2007, http://poi.apache.org/apidocs/org/apache/poi/xssf/ | |||
class ExtractText | |||
{ | |||
public static String file(String path) { | |||
try { return pptx(new FileInputStream(path)); } catch(Exception e) { } | |||
try { return docx(new FileInputStream(path)); } catch(Exception e) { } | |||
try { return xlsx(new FileInputStream(path)); } catch(Exception e) { } | |||
return ""; | |||
} | |||
public static String pptx(InputStream in) throws Exception { | |||
XSLFPowerPointExtractor o = new XSLFPowerPointExtractor( new XMLSlideShow(in) ); | |||
o.setSlidesByDefault(true); | |||
o.setNotesByDefault(true); | |||
return o.getText(); | |||
} | |||
public static String docx(InputStream in) throws Exception { | |||
XWPFWordExtractor o = new XWPFWordExtractor(new XWPFDocument(in)); | |||
return o.getText(); | |||
} | |||
public static String xlsx(InputStream in) throws Exception { | |||
XSSFExcelExtractor o = new XSSFExcelExtractor(new XSSFWorkbook(in)); | |||
return o.getText(); | |||
} | |||
public static void main(String argv[]) { | |||
try { | |||
InputStream in = null; | |||
if (argv.length < 1) | |||
in = System.in; | |||
else | |||
in = new FileInputStream(argv[0]); | |||
StringBuffer output = new StringBuffer(); | |||
POITextExtractor textExtractor = ExtractorFactory.createExtractor(in); | |||
if (textExtractor instanceof ExcelExtractor) // xls, excel 97-2003 | |||
{ | |||
ExcelExtractor extractor = (ExcelExtractor) textExtractor; | |||
output.append(extractor.getText()); | |||
} | |||
else if (textExtractor instanceof XSSFExcelExtractor) // xlsx, excel 2007 | |||
{ | |||
XSSFExcelExtractor extractor = (XSSFExcelExtractor) textExtractor; | |||
output.append(extractor.getText()); | |||
} | |||
else if (textExtractor instanceof Word6Extractor) // doc, word 95 | |||
{ | |||
Word6Extractor extractor = (Word6Extractor) textExtractor; | |||
output.append(extractor.getText()); | |||
} | |||
else if (textExtractor instanceof WordExtractor) // doc, word 97-2003 | |||
{ | |||
WordExtractor extractor = (WordExtractor) textExtractor; | |||
output.append(extractor.getText()); | |||
} | |||
else if (textExtractor instanceof XWPFWordExtractor) // docx, word 2007 | |||
{ | |||
XWPFWordExtractor extractor = (XWPFWordExtractor) textExtractor; | |||
output.append(extractor.getText()); | |||
} | |||
else if (textExtractor instanceof PowerPointExtractor) // ppt, ppt 97-2003 | |||
{ | |||
PowerPointExtractor extractor = (PowerPointExtractor) textExtractor; | |||
output.append(extractor.getText()); | |||
output.append(extractor.getNotes()); | |||
} | |||
else if (textExtractor instanceof XSLFPowerPointExtractor ) // pptx, powerpoint 2007 | |||
{ | |||
XSLFPowerPointExtractor extractor = (XSLFPowerPointExtractor) textExtractor; | |||
extractor.setSlidesByDefault(true); | |||
extractor.setNotesByDefault(true); | |||
output.append(extractor.getText()); | |||
} | |||
else if (textExtractor instanceof VisioTextExtractor) // vsd, visio | |||
{ | |||
VisioTextExtractor extractor = (VisioTextExtractor) textExtractor; | |||
output.append(extractor.getText()); | |||
} | |||
else if (textExtractor instanceof PublisherTextExtractor) // pub, publisher | |||
{ | |||
PublisherTextExtractor extractor = (PublisherTextExtractor) textExtractor; | |||
output.append(extractor.getText()); | |||
} | |||
else if (textExtractor instanceof OutlookTextExtactor) // msg, outlook | |||
{ | |||
OutlookTextExtactor extractor = (OutlookTextExtactor) textExtractor; | |||
output.append(extractor.getText()); | |||
} | |||
System.out.println(output.toString().replaceAll( "[\n\t\r ]+"," ")); | |||
} | |||
catch (Exception e) | |||
{ | |||
// TODO Auto-generated catch block | |||
//e.printStackTrace(); | |||
//System.out.println(e); | |||
} | |||
} | |||
} |
@@ -1,169 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.entity; | |||
import depends.importtypes.Import; | |||
import depends.relations.IBindingResolver; | |||
import java.util.*; | |||
public class FileEntity extends TypeEntity { | |||
private List<Import> importedNames = new ArrayList<>(); | |||
private boolean isInProjectScope = false; | |||
private Collection<Entity> importedRelationEntities = new ArrayList<>(); | |||
private Collection<Entity> importedFiles = new ArrayList<>(); | |||
private Collection<Entity> importedTypes = new ArrayList<>(); | |||
private List<TypeEntity> declaredTypes = new ArrayList<>(); | |||
private ImportedFileCollector importedFileCollector = null; | |||
public FileEntity() {} | |||
public FileEntity(String fullName, int fileId, boolean isInProjectScope) { | |||
super(GenericName.build(fullName), null, fileId); | |||
setQualifiedName(fullName); | |||
this.isInProjectScope = isInProjectScope; | |||
} | |||
public FileEntity(String fullName, int fileId) { | |||
this(fullName, fileId, true); | |||
} | |||
public void addImport(Import imported) { | |||
if (!importedNames.contains(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(true); | |||
if (!name.startsWith(".")) | |||
name = "." + name; | |||
if (imported.getQualifiedName(true).endsWith(lastName)) | |||
return imported.getQualifiedName(true); | |||
} | |||
return null; | |||
} | |||
@Override | |||
public String getQualifiedName(boolean overrideFileWithPackage) { | |||
if (!overrideFileWithPackage) { | |||
return super.getQualifiedName(); | |||
} | |||
if (this.getParent() == null) { | |||
return ""; | |||
} | |||
if (this.getParent() instanceof PackageEntity) | |||
return this.getParent().getQualifiedName(); | |||
else | |||
return super.getQualifiedName(); | |||
} | |||
@Override | |||
public void inferLocalLevelEntities(IBindingResolver bindingResolver) { | |||
this.importedRelationEntities = bindingResolver.getImportedRelationEntities(importedNames); | |||
this.importedTypes = bindingResolver.getImportedTypes(importedNames,this); | |||
this.importedFiles = bindingResolver.getImportedFiles(importedNames); | |||
super.inferLocalLevelEntities(bindingResolver); | |||
} | |||
public boolean isInProjectScope() { | |||
return isInProjectScope; | |||
} | |||
public void setInProjectScope(boolean isInProjectScope) { | |||
this.isInProjectScope = isInProjectScope; | |||
} | |||
public Collection<Entity> getImportedRelationEntities() { | |||
return importedRelationEntities; | |||
} | |||
public Collection<Entity> getImportedFiles() { | |||
return importedFiles; | |||
} | |||
public Collection<Entity> getImportedTypes() { | |||
return importedTypes; | |||
} | |||
public List<TypeEntity> getDeclaredTypes() { | |||
return this.declaredTypes; | |||
} | |||
public void addType(TypeEntity currentTypeEntity) { | |||
this.declaredTypes.add(currentTypeEntity); | |||
} | |||
public Set<FileEntity> getImportedFilesInAllLevel() { | |||
if (importedFileCollector==null) | |||
importedFileCollector = new ImportedFileCollector(this); | |||
return importedFileCollector.getFiles(); | |||
} | |||
public List<Import> getImportedNames() { | |||
return importedNames; | |||
} | |||
public void cacheAllExpressions() { | |||
this.cacheChildExpressions(); | |||
} | |||
@Override | |||
public Entity getByName(String name, HashSet<Entity> searched) { | |||
Entity entity = super.getByName(name, searched); | |||
if (entity!=null) return entity; | |||
for (TypeEntity type:getDeclaredTypes()) { | |||
if (type.getRawName().getName().equals(name)|| | |||
suffixMatch(name,type.getQualifiedName())) { | |||
return type; | |||
} | |||
} | |||
return null; | |||
} | |||
private boolean suffixMatch(String name, String qualifiedName) { | |||
if (qualifiedName.contains(".")) { | |||
if (!name.startsWith(".")) name = "." +name; | |||
return qualifiedName.endsWith(name); | |||
} | |||
else { | |||
return qualifiedName.equals(name); | |||
} | |||
} | |||
} |
@@ -1,99 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
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.GenericName; | |||
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) { | |||
GenericName type = GenericName.build(ClassTypeContextHelper.getClassName(typeType)); | |||
GenericName varName = GenericName.build(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; | |||
} | |||
} |
@@ -1,149 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.entity; | |||
import depends.relations.IBindingResolver; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.List; | |||
public class FunctionEntity extends ContainerEntity{ | |||
private List<GenericName> returnTypeIdentifiers = new ArrayList<>(); | |||
Collection<VarEntity> parameters; | |||
Collection<GenericName> throwTypesIdentifiers = new ArrayList<>(); | |||
private Collection<Entity> returnTypes = new ArrayList<>(); | |||
private Collection<Entity> throwTypes = new ArrayList<>(); | |||
public FunctionEntity() { | |||
this.parameters = new ArrayList<>(); | |||
} | |||
public FunctionEntity(GenericName simpleName, Entity parent, Integer id, GenericName returnType) { | |||
super(simpleName, parent,id); | |||
this.returnTypes = new ArrayList<>(); | |||
returnTypeIdentifiers = new ArrayList<>(); | |||
this.parameters = new ArrayList<>(); | |||
throwTypesIdentifiers = new ArrayList<>(); | |||
addReturnType(returnType); | |||
} | |||
public Collection<Entity> getReturnTypes() { | |||
return returnTypes; | |||
} | |||
@Override | |||
public TypeEntity getType() { | |||
if (returnTypes.size()>0){ | |||
Object type = returnTypes.iterator().next(); | |||
if (type instanceof TypeEntity) | |||
return (TypeEntity)type; | |||
} | |||
return null; | |||
} | |||
public void addReturnType(GenericName returnType) { | |||
if (returnType==null) return; | |||
this.returnTypeIdentifiers.add(returnType); | |||
} | |||
public void addReturnType(TypeEntity returnType) { | |||
if (returnType==null) return; | |||
if (!this.returnTypeIdentifiers.contains(returnType.rawName)){ | |||
this.returnTypeIdentifiers.add(returnType.rawName); | |||
this.returnTypes.add(returnType); | |||
} | |||
} | |||
public void addThrowTypes(List<GenericName> throwedType) { | |||
throwTypesIdentifiers.addAll(throwedType); | |||
} | |||
@Override | |||
public void inferLocalLevelEntities(IBindingResolver bindingResolver) { | |||
for (VarEntity param:parameters) { | |||
param.fillCandidateTypes(bindingResolver); | |||
param.inferLocalLevelEntities(bindingResolver); | |||
} | |||
if (returnTypes.size()<returnTypeIdentifiers.size()) { | |||
returnTypes = identiferToEntities(bindingResolver,this.returnTypeIdentifiers); | |||
for ( GenericName returnTypeName: returnTypeIdentifiers) { | |||
Collection<Entity> typeEntities = typeParametersToEntities(bindingResolver, returnTypeName); | |||
this.appendTypeParameters(typeEntities); | |||
} | |||
} | |||
if (throwTypes.size()<throwTypesIdentifiers.size()) | |||
throwTypes = identiferToEntities(bindingResolver,this.throwTypesIdentifiers); | |||
super.inferLocalLevelEntities(bindingResolver); | |||
} | |||
private Collection<Entity> typeParametersToEntities(IBindingResolver bindingResolver, GenericName name) { | |||
ArrayList<Entity> r = new ArrayList<>(); | |||
for (GenericName typeParameter:name.getArguments()) { | |||
toEntityList(bindingResolver, r,typeParameter); | |||
} | |||
return r; | |||
} | |||
public Collection<VarEntity> getParameters() { | |||
return parameters; | |||
} | |||
public Collection<Entity> getThrowTypes() { | |||
return throwTypes; | |||
} | |||
@Override | |||
public Entity lookupVarInVisibleScope(GenericName varName) { | |||
for (VarEntity param:parameters) { | |||
if (varName.equals(param.getRawName())) { | |||
return param; | |||
} | |||
} | |||
return super.lookupVarInVisibleScope(varName); | |||
} | |||
public void addParameter(VarEntity var) { | |||
this.parameters.add(var); | |||
} | |||
@Override | |||
public String getDisplayName() { | |||
FileEntity f = (FileEntity) this.getAncestorOfType(FileEntity.class); | |||
return f.getRawName()+"("+this.getQualifiedName()+")"; | |||
} | |||
@Override | |||
public VarEntity lookupVarLocally(GenericName varName) { | |||
for (VarEntity var:this.parameters) { | |||
if (var.getRawName().equals(varName)) | |||
return var; | |||
} | |||
return super.lookupVarLocally(varName); | |||
} | |||
public void linkReturnToLastExpression() { | |||
if (expressionList()==null) return; | |||
for (int i = expressionList().size() - 1; i >= 0; i--) { | |||
Expression expr = expressionList().get(i); | |||
if (expr.isStatement()) | |||
expr.addDeducedTypeFunction(this); | |||
} | |||
} | |||
} |
@@ -1,117 +0,0 @@ | |||
package depends.entity; | |||
import java.io.Serializable; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
public class GenericName implements Serializable{ | |||
private static final long serialVersionUID = 1L; | |||
private char[] name; | |||
List<GenericName> arguments; | |||
public GenericName(String name) { | |||
this.name = name.toCharArray(); | |||
} | |||
public GenericName(String name, List<GenericName> arguments) { | |||
this.name = name.toCharArray(); | |||
this.arguments = arguments; | |||
} | |||
public boolean contains(String rawType) { | |||
if (new String(name).contains(rawType)) return true; | |||
return false; | |||
} | |||
public String getName() { | |||
return new String(name); | |||
} | |||
public List<GenericName> getArguments() { | |||
if (arguments==null) return new ArrayList<>(); | |||
return arguments; | |||
} | |||
@Override | |||
public String toString() { | |||
return new String(name) + (getArguments().size()>0?"(" + arguments + ")":""); | |||
} | |||
public GenericName replace(String from, String to) { | |||
name = new String(name).replace(from, to).toCharArray(); | |||
for (GenericName arg:getArguments()) { | |||
arg.replace(from, to); | |||
} | |||
return this; | |||
} | |||
public boolean startsWith(String prefix) { | |||
if (name==null) return false; | |||
return new String(name).startsWith(prefix); | |||
} | |||
public String uniqName() { | |||
if (getArguments().size()==0) return new String(name); | |||
StringBuffer sb = new StringBuffer(); | |||
sb.append(name); | |||
if (getArguments().size()>0) { | |||
for (GenericName arg:getArguments()) { | |||
sb.append("__").append(arg.uniqName()).append("__"); | |||
} | |||
} | |||
return sb.toString(); | |||
} | |||
public GenericName substring(int start) { | |||
return new GenericName(new String(this.name).substring(start)); | |||
} | |||
public boolean isNull() { | |||
return name==null; | |||
} | |||
public static GenericName build(String name) { | |||
if (name==null) return null; | |||
return new GenericName(name); | |||
} | |||
public static GenericName build(String name, List<GenericName> arguments) { | |||
return new GenericName(name,arguments); | |||
} | |||
public boolean find(GenericName rawType) { | |||
//if (this.equals(rawType)) return true; | |||
for (GenericName subType:this.getArguments()) { | |||
if (subType.equals(rawType)) return true; | |||
boolean found = subType.find(rawType); | |||
if (found) return true; | |||
} | |||
return false; | |||
} | |||
public void appendArguments(List<GenericName> parameters) { | |||
if (this.arguments==null) this.arguments = new ArrayList<>(); | |||
this.arguments.addAll(parameters); | |||
} | |||
public void appendArguments(GenericName parameter) { | |||
if (this.arguments==null) this.arguments = new ArrayList<>(); | |||
this.arguments.add(parameter); | |||
} | |||
@Override | |||
public int hashCode() { | |||
final int prime = 31; | |||
int result = 1; | |||
result = prime * result + ((arguments == null) ? 0 : arguments.hashCode()); | |||
result = prime * result + Arrays.hashCode(name); | |||
return result; | |||
} | |||
@Override | |||
public boolean equals(Object obj) { | |||
if (this == obj) | |||
return true; | |||
if (obj == null) | |||
return false; | |||
if (getClass() != obj.getClass()) | |||
return false; | |||
GenericName other = (GenericName) obj; | |||
if (this.getArguments() == null) { | |||
if (other.getArguments() != null) | |||
return false; | |||
} else if (!getArguments().equals(other.getArguments())) | |||
return false; | |||
if (!Arrays.equals(name, other.name)) | |||
return false; | |||
return true; | |||
} | |||
} |
@@ -1,103 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.extractor.golang; | |||
import depends.entity.Entity; | |||
import depends.entity.FileEntity; | |||
import depends.entity.PackageEntity; | |||
import depends.entity.repo.EntityRepo; | |||
import depends.extractor.UnsolvedBindings; | |||
import depends.importtypes.Import; | |||
import depends.relations.ImportLookupStrategy; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import java.util.Set; | |||
public class GoImportLookupStrategy extends ImportLookupStrategy{ | |||
public GoImportLookupStrategy(EntityRepo repo) { | |||
super(repo); | |||
} | |||
public Entity lookupImportedType(String name, FileEntity fileEntity) { | |||
//Java Strategy | |||
String importedString = fileEntity.importedSuffixMatch(name); | |||
if (importedString==null) return null; | |||
return repo.getEntity(importedString); | |||
} | |||
@Override | |||
public List<Entity> getImportedRelationEntities(List<Import> importedList) { | |||
ArrayList<Entity> result = new ArrayList<>(); | |||
for (Import importedItem:importedList) { | |||
Entity imported = repo.getEntity(importedItem.getContent()); | |||
if (imported==null) continue; | |||
if (imported instanceof PackageEntity) { | |||
//ignore wildcard import relation | |||
}else { | |||
result.add(imported); | |||
} | |||
} | |||
return result; | |||
} | |||
@Override | |||
public List<Entity> getImportedTypes(List<Import> importedList, Set<UnsolvedBindings> unsolvedBindings) { | |||
ArrayList<Entity> result = new ArrayList<>(); | |||
for (Import importedItem:importedList) { | |||
Entity imported = repo.getEntity(importedItem.getContent()); | |||
if (imported==null) { | |||
unsolvedBindings.add(new UnsolvedBindings(importedItem.getContent(),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()) { | |||
if (child instanceof FileEntity) { | |||
child.getChildren().forEach(item->result.add(item)); | |||
}else { | |||
result.add(child); | |||
} | |||
} | |||
}else { | |||
result.add(imported); | |||
} | |||
} | |||
return result; | |||
} | |||
@Override | |||
public List<Entity> getImportedFiles(List<Import> importedList) { | |||
return new ArrayList<Entity>(); | |||
} | |||
@Override | |||
public boolean supportGlobalNameLookup() { | |||
return true; | |||
} | |||
} |
@@ -1,136 +0,0 @@ | |||
package depends.extractor.golang; | |||
import depends.entity.FunctionEntity; | |||
import depends.entity.GenericName; | |||
import depends.entity.VarEntity; | |||
import depends.entity.repo.EntityRepo; | |||
import depends.relations.IBindingResolver; | |||
import org.antlr.v4.runtime.tree.TerminalNode; | |||
import java.util.ArrayList; | |||
public class GoListener extends GoParserBaseListener { | |||
private final EntityRepo entityRepo; | |||
GoHandlerContext context; | |||
@Override | |||
public void enterSourceFile(GoParser.SourceFileContext ctx) { | |||
super.enterSourceFile(ctx); | |||
} | |||
public GoListener(String fileFullPath, EntityRepo entityRepo, IBindingResolver bindingResolver) { | |||
context = new GoHandlerContext(entityRepo, bindingResolver); | |||
context.startFile(fileFullPath); | |||
this.entityRepo = entityRepo; | |||
} | |||
@Override | |||
public void enterFunctionDecl(GoParser.FunctionDeclContext ctx) { | |||
String funcName = ctx.IDENTIFIER().getText(); | |||
context.foundMethodDeclarator(funcName,ctx.getStart().getLine()); | |||
foundFuncSignature(ctx.signature()); | |||
super.enterFunctionDecl(ctx); | |||
} | |||
@Override | |||
public void exitFunctionDecl(GoParser.FunctionDeclContext ctx) { | |||
context.exitLastedEntity(); | |||
super.exitFunctionDecl(ctx); | |||
} | |||
@Override | |||
public void enterPackageClause(GoParser.PackageClauseContext ctx) { | |||
context.foundPackageDeclaration(ctx.IDENTIFIER().getText()); | |||
super.enterPackageClause(ctx); | |||
} | |||
private void foundFuncSignature(GoParser.SignatureContext signature) { | |||
FunctionEntity func = (FunctionEntity) context.lastContainer(); | |||
if (signature.parameters()!=null) { | |||
for (GoParser.ParameterDeclContext param : signature.parameters().parameterDecl()) { | |||
if (param.identifierList() != null) { | |||
TypeDefHelper typeDefHelper = new TypeDefHelper(param.type_()); | |||
for (TerminalNode id : param.identifierList().IDENTIFIER()) { | |||
VarEntity varEntity = new VarEntity(GenericName.build(id.getText()), | |||
GenericName.build(typeDefHelper.getTypeRefName()), context.lastContainer(), | |||
entityRepo.generateId()); | |||
func.addParameter(varEntity); | |||
} | |||
} else/* with ... parameters*/ { | |||
} | |||
} | |||
} | |||
if (signature.result()!=null){ | |||
if(signature.result().parameters()!=null){ | |||
for (GoParser.ParameterDeclContext paramDecl:signature.result().parameters().parameterDecl()){ | |||
TypeDefHelper typeDefHelper = new TypeDefHelper(paramDecl.type_()); | |||
if (typeDefHelper.isTypeRef()) { | |||
func.addReturnType(GenericName.build(typeDefHelper.getTypeRefName())); | |||
}else{ | |||
System.err.println("TODO: unsupport return type"); | |||
} | |||
} | |||
} | |||
if (signature.result().type_()!=null){ | |||
TypeDefHelper typeDefHelper = new TypeDefHelper(signature.result().type_()); | |||
if (typeDefHelper.isTypeRef()) { | |||
func.addReturnType(GenericName.build(typeDefHelper.getTypeRefName())); | |||
}else{ | |||
System.err.println("TODO: unsupport return type"); | |||
} | |||
} | |||
System.err.println(signature.result().getText()); | |||
} | |||
} | |||
@Override | |||
public void enterTypeSpec(GoParser.TypeSpecContext ctx) { | |||
TypeSpecHelper specHelper = new TypeSpecHelper(ctx); | |||
if (specHelper.getTypeDefHelper().isTypeRef()){ | |||
context.foundNewAlias(specHelper.getIdentifier(),specHelper.getTypeDefHelper().getTypeRefName()); | |||
}else if (specHelper.getTypeDefHelper().isStruct()){ | |||
context.foundNewType(specHelper.getIdentifier(),ctx.getStart().getLine()); | |||
} | |||
super.enterTypeSpec(ctx); | |||
} | |||
@Override | |||
public void exitTypeSpec(GoParser.TypeSpecContext ctx) { | |||
TypeSpecHelper specHelper = new TypeSpecHelper(ctx); | |||
if (specHelper.getTypeDefHelper().isStruct()){ | |||
context.exitLastedEntity(); | |||
} | |||
super.exitTypeSpec(ctx); | |||
} | |||
// fieldDecl | |||
// : ({noTerminatorBetween(2)}? identifierList type_ | anonymousField) string_? | |||
// ; | |||
@Override | |||
public void enterFieldDecl(GoParser.FieldDeclContext ctx) { | |||
FieldDeclHelper fieldDeclHelper = new FieldDeclHelper(ctx); | |||
String typeName = fieldDeclHelper.getTypeName(); | |||
if (fieldDeclHelper.getIdentifiers()!=null){ | |||
for (String id:fieldDeclHelper.getIdentifiers()){ | |||
if (typeName==null){ | |||
System.err.println("TODO: unsupport fieldDecl without type"); | |||
} | |||
context.foundVarDefinition(id, GenericName.build(typeName),new ArrayList<>(),ctx.getStart().getLine()); | |||
} | |||
} | |||
if (fieldDeclHelper.getAnonymousField()!=null){ | |||
System.err.println("TODO: unsupport anonymousField"); | |||
} | |||
if (fieldDeclHelper.getString()!=null){ | |||
System.err.println("TODO: unsupport field with string " + fieldDeclHelper.getString()); | |||
} | |||
super.enterFieldDecl(ctx); | |||
} | |||
public void done() { | |||
} | |||
} |
@@ -1,132 +0,0 @@ | |||
package depends.extractor.golang; | |||
import org.antlr.v4.runtime.*; | |||
import java.util.List; | |||
/** | |||
* All parser methods that used in grammar (p, prev, notLineTerminator, etc.) | |||
* should start with lower case char similar to parser rules. | |||
*/ | |||
public abstract class GoParserBase extends Parser | |||
{ | |||
protected GoParserBase(TokenStream input) { | |||
super(input); | |||
} | |||
/** | |||
* Returns {@code true} iff on the current index of the parser's | |||
* token stream a token exists on the {@code HIDDEN} channel which | |||
* either is a line terminator, or is a multi line comment that | |||
* contains a line terminator. | |||
* | |||
* @return {@code true} iff on the current index of the parser's | |||
* token stream a token exists on the {@code HIDDEN} channel which | |||
* either is a line terminator, or is a multi line comment that | |||
* contains a line terminator. | |||
*/ | |||
protected boolean lineTerminatorAhead() { | |||
// Get the token ahead of the current index. | |||
int possibleIndexEosToken = this.getCurrentToken().getTokenIndex() - 1; | |||
if (possibleIndexEosToken == -1) | |||
{ | |||
return true; | |||
} | |||
Token ahead = _input.get(possibleIndexEosToken); | |||
if (ahead.getChannel() != Lexer.HIDDEN) { | |||
// We're only interested in tokens on the HIDDEN channel. | |||
return false; | |||
} | |||
if (ahead.getType() == GoLexer.TERMINATOR) { | |||
// There is definitely a line terminator ahead. | |||
return true; | |||
} | |||
if (ahead.getType() == GoLexer.WS) { | |||
// Get the token ahead of the current whitespaces. | |||
possibleIndexEosToken = this.getCurrentToken().getTokenIndex() - 2; | |||
ahead = _input.get(possibleIndexEosToken); | |||
} | |||
// Get the token's text and type. | |||
String text = ahead.getText(); | |||
int type = ahead.getType(); | |||
// Check if the token is, or contains a line terminator. | |||
return (type == GoLexer.COMMENT && (text.contains("\r") || text.contains("\n"))) || | |||
(type == GoLexer.TERMINATOR); | |||
} | |||
/** | |||
* Returns {@code true} if no line terminator exists between the specified | |||
* token offset and the prior one on the {@code HIDDEN} channel. | |||
* | |||
* @return {@code true} if no line terminator exists between the specified | |||
* token offset and the prior one on the {@code HIDDEN} channel. | |||
*/ | |||
protected boolean noTerminatorBetween(int tokenOffset) { | |||
BufferedTokenStream stream = (BufferedTokenStream)_input; | |||
List<Token> tokens = stream.getHiddenTokensToLeft(stream.LT(tokenOffset).getTokenIndex()); | |||
if (tokens == null) { | |||
return true; | |||
} | |||
for (Token token : tokens) { | |||
if (token.getText().contains("\n")) | |||
return false; | |||
} | |||
return true; | |||
} | |||
/** | |||
* Returns {@code true} if no line terminator exists after any encounterd | |||
* parameters beyond the specified token offset and the next on the | |||
* {@code HIDDEN} channel. | |||
* | |||
* @return {@code true} if no line terminator exists after any encounterd | |||
* parameters beyond the specified token offset and the next on the | |||
* {@code HIDDEN} channel. | |||
*/ | |||
protected boolean noTerminatorAfterParams(int tokenOffset) { | |||
BufferedTokenStream stream = (BufferedTokenStream)_input; | |||
int leftParams = 1; | |||
int rightParams = 0; | |||
int valueType; | |||
if (stream.LT(tokenOffset).getType() == GoLexer.L_PAREN) { | |||
// Scan past parameters | |||
while (leftParams != rightParams) { | |||
tokenOffset++; | |||
valueType = stream.LT(tokenOffset).getType(); | |||
if (valueType == GoLexer.L_PAREN){ | |||
leftParams++; | |||
} | |||
else if (valueType == GoLexer.R_PAREN) { | |||
rightParams++; | |||
} | |||
} | |||
tokenOffset++; | |||
return noTerminatorBetween(tokenOffset); | |||
} | |||
return true; | |||
} | |||
protected boolean checkPreviousTokenText(String text) | |||
{ | |||
BufferedTokenStream stream = (BufferedTokenStream)_input; | |||
String prevTokenText = stream.LT(1).getText(); | |||
if (prevTokenText == null) | |||
return false; | |||
return prevTokenText.equals(text); | |||
} | |||
} |
@@ -1,333 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.extractor; | |||
import depends.entity.*; | |||
import depends.entity.repo.EntityRepo; | |||
import depends.entity.repo.IdGenerator; | |||
import depends.importtypes.Import; | |||
import depends.relations.IBindingResolver; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import java.util.Stack; | |||
import java.util.stream.Collectors; | |||
public abstract class HandlerContext { | |||
protected EntityRepo entityRepo; | |||
protected IdGenerator idGenerator; | |||
protected FileEntity currentFileEntity; | |||
protected IBindingResolver bindingResolver; | |||
public HandlerContext(EntityRepo entityRepo, IBindingResolver bindingResolver) { | |||
this.entityRepo = entityRepo; | |||
this.idGenerator = entityRepo; | |||
entityStack = new Stack<Entity>(); | |||
this.bindingResolver = bindingResolver; | |||
} | |||
public FileEntity startFile(String fileName) { | |||
currentFileEntity = new FileEntity(fileName, idGenerator.generateId(),true); | |||
pushToStack(currentFileEntity); | |||
addToRepo(currentFileEntity); | |||
return currentFileEntity; | |||
} | |||
public TypeEntity foundNewType(GenericName name, Integer startLine) { | |||
TypeEntity currentTypeEntity = new TypeEntity(name, this.latestValidContainer(), | |||
idGenerator.generateId()); | |||
currentTypeEntity.setLine(startLine); | |||
pushToStack(currentTypeEntity); | |||
addToRepo(currentTypeEntity); | |||
currentFileEntity.addType(currentTypeEntity); | |||
return currentTypeEntity; | |||
} | |||
/** | |||
* Tell the context object that a new type founded. | |||
* @param name | |||
* @param startLine | |||
* @return | |||
*/ | |||
public TypeEntity foundNewType(String name, Integer startLine) { | |||
return foundNewType(GenericName.build(name),startLine); | |||
} | |||
public AliasEntity foundNewAlias(String aliasName, String originalName) { | |||
if (aliasName.equals(originalName)) return null; //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" | |||
AliasEntity currentTypeEntity = new AliasEntity(GenericName.build(aliasName), this.latestValidContainer(), | |||
idGenerator.generateId(),GenericName.build(originalName) ); | |||
addToRepo(currentTypeEntity); | |||
return currentTypeEntity; | |||
} | |||
public AliasEntity foundNewAlias(GenericName aliasName, Entity referToEntity) { | |||
AliasEntity currentTypeEntity = new AliasEntity(aliasName, this.latestValidContainer(), | |||
idGenerator.generateId(),aliasName); | |||
currentTypeEntity.setReferToEntity(referToEntity); | |||
addToRepo(currentTypeEntity); | |||
return currentTypeEntity; | |||
} | |||
/** | |||
* Tell the context that a new method was found. | |||
* Do not forget to tell the context leave the method when you finish | |||
* the process of the method | |||
* @param methodName | |||
* @param returnType - if no return type information avaliable, keep it as null; | |||
* @param throwedType - if no throwed type information avaliable, keep it as empty list; | |||
* @return the new function enity | |||
*/ | |||
public FunctionEntity foundMethodDeclarator(String methodName, String returnType, List<String> throwedType, Integer startLine) { | |||
FunctionEntity functionEntity = new FunctionEntity(GenericName.build(methodName), this.latestValidContainer(), | |||
idGenerator.generateId(),GenericName.build(returnType)); | |||
functionEntity.setLine(startLine); | |||
addToRepo(functionEntity); | |||
this.typeOrFileContainer().addFunction(functionEntity); | |||
pushToStack(functionEntity); | |||
functionEntity.addThrowTypes(throwedType.stream().map(item->GenericName.build(item)).collect(Collectors.toList())); | |||
return functionEntity; | |||
} | |||
public FunctionEntity foundMethodDeclarator(String methodName, Integer startLine) { | |||
FunctionEntity functionEntity = new FunctionEntity(GenericName.build(methodName), this.latestValidContainer(), | |||
idGenerator.generateId(),null); | |||
functionEntity.setLine(startLine); | |||
addToRepo(functionEntity); | |||
this.typeOrFileContainer().addFunction(functionEntity); | |||
pushToStack(functionEntity); | |||
return functionEntity; | |||
} | |||
public FunctionEntity foundMethodDeclarator(ContainerEntity containerEntity, String methodName, Integer startLine) { | |||
FunctionEntity functionEntity = new FunctionEntity(GenericName.build(methodName), containerEntity, | |||
idGenerator.generateId(),null); | |||
functionEntity.setLine(startLine); | |||
addToRepo(functionEntity); | |||
containerEntity.addFunction(functionEntity); | |||
pushToStack(functionEntity); | |||
functionEntity.addThrowTypes(new ArrayList<>()); | |||
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 ContainerEntity globalScope() { | |||
Entity global = entityRepo.getEntity(EntityRepo.GLOBAL_SCOPE_NAME); | |||
if (global==null) { | |||
global = new PackageEntity(EntityRepo.GLOBAL_SCOPE_NAME,idGenerator.generateId()); | |||
addToRepo(global); | |||
} | |||
return (ContainerEntity)global; | |||
} | |||
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 foundImplements(GenericName typeName) { | |||
currentType().addImplements(typeName); | |||
} | |||
public void foundExtends(String className) { | |||
foundExtends(GenericName.build(className)); | |||
} | |||
public void foundExtends(GenericName typeName) { | |||
if (currentType()==null) { | |||
System.out.println("error: type do not exist"); | |||
return ; | |||
} | |||
currentType().addExtends(typeName); | |||
} | |||
public void foundMixin(String name) { | |||
foundMixin(GenericName.build(name)); | |||
} | |||
public void foundMixin(GenericName name) { | |||
lastContainer().addMixin(name); | |||
} | |||
public void foundTypeParametes(GenericName typeName) { | |||
lastContainer().addTypeParameter(typeName); | |||
} | |||
public List<VarEntity> foundVarDefinitions(List<String> varNames, String type, List<GenericName> typeArguments, Integer line) { | |||
return varNames.stream().map(item->foundVarDefinition(item,GenericName.build(type),typeArguments,line)).collect(Collectors.toList()); | |||
} | |||
public VarEntity foundVarDefinition(ContainerEntity container,String varName,Integer line) { | |||
if (container==null) { | |||
System.out.println("fallback to file container for var " + varName + " in file "+ currentFile().getRawName()); | |||
container = currentFile(); | |||
} | |||
VarEntity var = getVarInLocalFile(container,GenericName.build(varName)); | |||
if (var!=null) return var; | |||
var = new VarEntity(GenericName.build(varName), null, container, idGenerator.generateId()); | |||
var.setLine(line); | |||
container.addVar(var); | |||
addToRepo(var); | |||
return var; | |||
} | |||
public VarEntity foundGlobalVarDefinition(ContainerEntity container,String varName,Integer line) { | |||
if (container==null) { | |||
System.out.println("fallback to file container for var " + varName + " in file "+ currentFile().getRawName()); | |||
container = currentFile(); | |||
} | |||
VarEntity var = getVarInLocalFile(container,GenericName.build(varName)); | |||
if (var!=null) return var; | |||
var = new VarEntity(GenericName.build(varName), null, container, idGenerator.generateId()); | |||
container.addVar(var); | |||
var.setLine(line); | |||
var.setQualifiedName(var.getRawName().toString()); | |||
addToRepo(var); | |||
return var; | |||
} | |||
public VarEntity foundVarDefinition(String varName, GenericName type, List<GenericName> typeArguments,Integer line) { | |||
VarEntity var = new VarEntity(GenericName.build(varName), type, lastContainer(), idGenerator.generateId()); | |||
var.setLine(line); | |||
var.addTypeParameter(typeArguments); | |||
lastContainer().addVar(var); | |||
addToRepo(var); | |||
return var; | |||
} | |||
public VarEntity addMethodParameter(String paramName) { | |||
if (currentFunction()==null) return null; | |||
VarEntity varEntity = new VarEntity(GenericName.build(paramName),null,currentFunction(),idGenerator.generateId()); | |||
currentFunction().addParameter(varEntity); | |||
addToRepo(varEntity); | |||
return varEntity; | |||
} | |||
public VarEntity foundEnumConstDefinition(String varName,Integer line) { | |||
GenericName type = lastContainer().getRawName(); | |||
return foundVarDefinition(varName,type,new ArrayList<>(),line); | |||
} | |||
protected Stack<Entity> entityStack = new Stack<Entity>(); | |||
protected void pushToStack(Entity entity) { | |||
entityStack.push(entity); | |||
} | |||
public void exitLastedEntity() { | |||
//we never pop up the lastest one (FileEntity) | |||
if (entityStack.size()>1) | |||
entityStack.pop(); | |||
} | |||
private VarEntity getVarInLocalFile(ContainerEntity container, GenericName varName) { | |||
Entity entity = bindingResolver.resolveName(container, varName, false); | |||
if (entity ==null ) return null; | |||
Entity fileEntity = entity.getAncestorOfType(FileEntity.class); | |||
if (fileEntity ==null ){ | |||
//may not exist in fileEntity, for example global vars | |||
}else{ | |||
if (!fileEntity.equals(currentFileEntity)) return null; | |||
if (entity instanceof VarEntity) return (VarEntity)entity; | |||
} | |||
return null; | |||
} | |||
public Entity foundEntityWithName(GenericName rawName) { | |||
return bindingResolver.resolveName(lastContainer(), rawName, true); | |||
} | |||
public void addToRepo(Entity entity) { | |||
entityRepo.add(entity); | |||
} | |||
} |
@@ -1,135 +0,0 @@ | |||
package depends.entity.repo; | |||
import depends.entity.Entity; | |||
import depends.entity.FileEntity; | |||
import depends.entity.GenericName; | |||
import depends.entity.MultiDeclareEntities; | |||
import multilang.depends.util.file.FileUtil; | |||
import java.util.*; | |||
import java.util.Map.Entry; | |||
public class InMemoryEntityRepo extends SimpleIdGenerator implements EntityRepo { | |||
public class EntityMapIterator implements Iterator<Entity>{ | |||
private Iterator<Entry<Integer, Entity>> entryIterator; | |||
public EntityMapIterator(Set<Entry<Integer, Entity>> entries) { | |||
this.entryIterator = entries.iterator(); | |||
} | |||
@Override | |||
public boolean hasNext() { | |||
return entryIterator.hasNext(); | |||
} | |||
@Override | |||
public Entity next() { | |||
return entryIterator.next().getValue(); | |||
} | |||
} | |||
private Map<String, Entity> allEntieisByName; | |||
private Map<Integer, Entity> allEntitiesById; | |||
private List<Entity> allFileEntitiesByOrder; | |||
public InMemoryEntityRepo() { | |||
allEntieisByName = new TreeMap<>(); | |||
allEntitiesById = new TreeMap<>(); | |||
allFileEntitiesByOrder = new LinkedList<>(); | |||
} | |||
@Override | |||
public Entity getEntity(String entityName) { | |||
return allEntieisByName.get(entityName); | |||
} | |||
@Override | |||
public Entity getEntity(Integer entityId) { | |||
return allEntitiesById.get(entityId); | |||
} | |||
@Override | |||
public void add(Entity entity) { | |||
allEntitiesById.put(entity.getId(), entity); | |||
String name = entity.getRawName().uniqName(); | |||
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) | |||
Entity.setParent(entity, entity.getParent()); | |||
} | |||
@Override | |||
public Iterator<Entity> entityIterator() { | |||
return new EntityMapIterator(allEntitiesById.entrySet()); | |||
} | |||
@Override | |||
public void update(Entity entity) { | |||
} | |||
@Override | |||
public Entity getEntity(GenericName rawName) { | |||
return this.getEntity(rawName.uniqName()); | |||
} | |||
@Override | |||
public Collection<Entity> getFileEntities() { | |||
return allFileEntitiesByOrder; | |||
} | |||
@Override | |||
public Iterator<Entity> sortedFileIterator() { | |||
return allFileEntitiesByOrder.iterator(); | |||
} | |||
@Override | |||
public void clear() { | |||
allEntieisByName.clear(); | |||
allEntitiesById.clear(); | |||
allFileEntitiesByOrder.clear(); | |||
} | |||
@Override | |||
public FileEntity getFileEntity(String fileFullPath) { | |||
fileFullPath = FileUtil.uniqFilePath(fileFullPath); | |||
Entity entity = this.getEntity(fileFullPath); | |||
if (entity ==null) return null; | |||
if (entity instanceof FileEntity) return (FileEntity) entity; | |||
if (entity instanceof MultiDeclareEntities){ | |||
MultiDeclareEntities multiDeclare = (MultiDeclareEntities) entity; | |||
for (Entity theEntity: multiDeclare.getEntities()){ | |||
if (theEntity instanceof FileEntity){ | |||
return (FileEntity) theEntity; | |||
} | |||
} | |||
} | |||
return null; | |||
} | |||
@Override | |||
public void completeFile(String fileFullPath) { | |||
FileEntity fileEntity = getFileEntity(fileFullPath); | |||
// in case of parse error(throw exception), the file entity may not exists | |||
if (fileEntity!=null) { | |||
fileEntity.cacheAllExpressions(); | |||
allFileEntitiesByOrder.add(fileEntity); | |||
} | |||
} | |||
} |
@@ -1,109 +0,0 @@ | |||
package depends.extractor.cpp; | |||
import static org.junit.Assert.assertEquals; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import depends.deptypes.DependencyType; | |||
import depends.entity.AliasEntity; | |||
import multilang.depends.util.file.FileUtil; | |||
public class IncludeRelationTest extends CppParserTest{ | |||
@Before | |||
public void setUp() { | |||
super.init(); | |||
} | |||
@Test | |||
public void test_includefiles_should_be_imported_relations() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/cpp-code-examples/includesTest/EntryFile.cpp", | |||
"./src/test/resources/cpp-code-examples/includesTest/LocalHeader.h", | |||
"./src/test/resources/cpp-code-examples/includesTest/IndirectIncluded.h", | |||
"./src/test/resources/cpp-code-examples/includesTest/RelativeInclude.h", | |||
"./src/test/resources/cpp-code-examples/includesTest/path/Header.h", | |||
}; | |||
for (String src:srcs) { | |||
CppFileParser parser = createParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
File f = new File(srcs[0]); | |||
assertEquals(3, entityRepo.getEntity(f.getCanonicalPath()).getRelations().size()); | |||
} | |||
@Test | |||
public void test_could_found_files_in_include_path() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/cpp-code-examples/includesTest/EntryFileIncludePathTest.cpp", | |||
"./src/test/resources/cpp-code-examples/includesTest/path/HeadersWithoutPath.h", | |||
}; | |||
List<String> includePaths = new ArrayList<>(); | |||
includePaths.add("./src/test/resources/cpp-code-examples/includesTest/path/"); | |||
for (String src:srcs) { | |||
CppFileParser parser = createParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
File f = new File(srcs[0]); | |||
assertEquals(1, entityRepo.getEntity(f.getCanonicalPath()).getRelations().size()); | |||
} | |||
@Test | |||
public void test_type_t_should_be_treat_as_structure() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/cpp-code-examples/typedeftest2.cpp", | |||
}; | |||
for (String src:srcs) { | |||
CppFileParser parser = createParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
assertEquals("abc",((AliasEntity) entityRepo.getEntity("abc_t")).getOriginType().getRawName().uniqName()); | |||
} | |||
@Test | |||
public void test_call_should_only_in_relations_with_include() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/cpp-code-examples/includeTest2/f0.cpp", | |||
"./src/test/resources/cpp-code-examples/includeTest2/f_with_include.cpp", | |||
"./src/test/resources/cpp-code-examples/includeTest2/f_without_include.cpp", | |||
}; | |||
for (String src:srcs) { | |||
CppFileParser parser = createParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
this.assertContainsRelation(this.entityRepo.getEntity("foo"), DependencyType.CALL, "bar"); | |||
this.assertNotContainsRelation(this.entityRepo.getEntity("foo2"), DependencyType.CALL, "bar"); | |||
} | |||
@Test | |||
public void should_find_include_relation_in_conditional_macro_block() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/cpp-code-examples/includeTest3/inc_macro_test.c", | |||
"./src/test/resources/cpp-code-examples/includeTest3/fx.h", | |||
"./src/test/resources/cpp-code-examples/includeTest3/fy.h", | |||
}; | |||
for (String src:srcs) { | |||
CppFileParser parser = createParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
this.assertContainsRelation(this.entityRepo.getEntity(FileUtil.uniqFilePath(srcs[0])), DependencyType.IMPORT, FileUtil.uniqFilePath(srcs[1])); | |||
this.assertContainsRelation(this.entityRepo.getEntity(FileUtil.uniqFilePath(srcs[0])), DependencyType.IMPORT, FileUtil.uniqFilePath(srcs[2])); | |||
} | |||
} |
@@ -1,88 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.format.json; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import depends.format.FileAttributes; | |||
import depends.matrix.core.DependencyDetail; | |||
import depends.matrix.core.DependencyMatrix; | |||
import depends.matrix.core.DependencyPair; | |||
import depends.matrix.core.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()); | |||
List<DetailItem> details = buildDetails(dependencyPair.getDependencies()); | |||
JCellObject cellObject = new JCellObject(); | |||
cellObject.setSrc(dependencyPair.getFrom()); | |||
cellObject.setDest(dependencyPair.getTo()); | |||
cellObject.setValues(valueObject); | |||
cellObject.setDetails(details); | |||
cellObjects.add(cellObject); | |||
} | |||
return cellObjects; | |||
} | |||
private List<DetailItem> buildDetails(Collection<DependencyValue> dependencies) { | |||
List<DetailItem> r = new ArrayList<>(); | |||
for (DependencyValue dependency : dependencies) { | |||
for (DependencyDetail detail:dependency.getDetails()) { | |||
r.add(new DetailItem(detail.getSrc(),detail.getDest(),dependency.getType())); | |||
} | |||
} | |||
if (r.size()==0) return null; | |||
return r; | |||
} | |||
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; | |||
} | |||
} |
@@ -1,281 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.extractor.ruby.jruby; | |||
import depends.entity.*; | |||
import depends.entity.repo.EntityRepo; | |||
import depends.extractor.ParserCreator; | |||
import depends.extractor.IncludedFileLocator; | |||
import depends.extractor.ruby.RubyHandlerContext; | |||
import depends.relations.IBindingResolver; | |||
import org.jrubyparser.ast.*; | |||
import org.jrubyparser.util.NoopVisitor; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
public class JRubyVisitor extends NoopVisitor { | |||
private RubyHandlerContext context; | |||
RubyParserHelper helper = RubyParserHelper.getInst(); | |||
private ExpressionUsage expressionUsage; | |||
public JRubyVisitor(String fileFullPath, EntityRepo entityRepo, IncludedFileLocator includedFileLocator, | |||
IBindingResolver bindingResolver, ParserCreator parserCreator) { | |||
this.context = new RubyHandlerContext(entityRepo, includedFileLocator, bindingResolver, parserCreator); | |||
expressionUsage = new ExpressionUsage(context, entityRepo, helper, bindingResolver); | |||
context.startFile(fileFullPath); | |||
} | |||
@Override | |||
public Object visitAliasNode(AliasNode node) { | |||
context.foundNewAlias(node.getNewNameString(), node.getOldNameString()); | |||
return super.visitAliasNode(node); | |||
} | |||
@Override | |||
public Object visitModuleNode(ModuleNode node) { | |||
String name = helper.getName(node.getCPath()); | |||
context.foundNamespace(name,node.getPosition().getStartLine()+1); | |||
super.visitModuleNode(node); | |||
context.exitLastedEntity(); | |||
return null; | |||
} | |||
@Override | |||
public Object visitClassNode(ClassNode node) { | |||
TypeEntity type = context.foundNewType(helper.getName(node.getCPath()),node.getPosition().getStartLine()+1); | |||
Node superNode = node.getSuper(); | |||
if (superNode instanceof ConstNode || | |||
superNode instanceof SymbolNode || | |||
superNode instanceof Colon2ConstNode || | |||
superNode instanceof Colon3Node) { | |||
String superName = helper.getName(superNode); | |||
context.foundExtends(superName); | |||
}else{ | |||
if (superNode != null) { | |||
System.err.println("cannot support the super node style" + superNode.toString()); | |||
} | |||
} | |||
super.visitClassNode(node); | |||
context.exitLastedEntity(); | |||
return null; | |||
} | |||
@Override | |||
public Object visitRootNode(RootNode node) { | |||
return super.visitRootNode(node); | |||
} | |||
@Override | |||
public Object visitFCallNode(FCallNode node) { | |||
String fname = helper.getName(node); | |||
Collection<String> params = getParams(node); | |||
context.processSpecialFuncCall(fname, params, node.getPosition().getStartLine()+1); | |||
return super.visitFCallNode(node); | |||
} | |||
private Collection<String> getParams(IArgumentNode node) { | |||
Node args = node.getArgs(); | |||
Collection<String> params = new ArrayList<>(); | |||
if (args instanceof ArrayNode) { | |||
ArrayNode argArray = (ArrayNode) args; | |||
for (Node arg : argArray.childNodes()) { | |||
if (arg instanceof StrNode) { | |||
params.add(((StrNode) arg).getValue()); | |||
} else if (arg instanceof ConstNode) { | |||
params.add(((ConstNode) arg).getName()); | |||
} | |||
} | |||
} | |||
return params; | |||
} | |||
@Override | |||
public Object visitCallNode(CallNode node) { | |||
String fname = helper.getName(node); | |||
Collection<String> params = getParams(node); | |||
addCallToReceiverVar(node, fname); | |||
context.processSpecialFuncCall(fname, params, node.getPosition().getStartLine()+1); | |||
return super.visitCallNode(node); | |||
} | |||
private void addCallToReceiverVar(CallNode node, String fname) { | |||
if (helper.isCommonOperator(fname))return; | |||
Node varNode = node.getReceiver(); | |||
GenericName varName = GenericName.build(helper.getName(varNode)); | |||
if (varName==null) return; | |||
Entity var = context.foundEntityWithName(varName); | |||
if (var != null && var instanceof VarEntity) { | |||
VarEntity varEntity = (VarEntity) var; | |||
varEntity.addFunctionCall(GenericName.build(fname)); | |||
} | |||
} | |||
@Override | |||
public Object visitUnaryCallNode(UnaryCallNode node) { | |||
String fname = helper.getName(node); | |||
Collection<String> params = new ArrayList<>(); | |||
context.processSpecialFuncCall(fname, params, node.getPosition().getStartLine()+1); | |||
return super.visitUnaryCallNode(node); | |||
} | |||
/** | |||
* VCallNode is just a function call without parameter | |||
*/ | |||
@Override | |||
public Object visitVCallNode(VCallNode node) { | |||
return super.visitVCallNode(node); | |||
} | |||
@Override | |||
public Object visitDefnNode(DefnNode node) { | |||
FunctionEntity method = context.foundMethodDeclarator(node.getName(),node.getPosition().getStartLine()+1); | |||
method.setLine(node.getPosition().getStartLine()+1); | |||
super.visitDefnNode(node); | |||
context.exitLastedEntity(); | |||
return null; | |||
} | |||
@Override | |||
public Object visitDefsNode(DefsNode node) { | |||
boolean handled = false; | |||
Node varNode = node.getReceiver(); | |||
if (varNode instanceof SelfNode) { | |||
//will be handled by context.foundMethodDeclarator(node.getName(), null, new ArrayList<>()); | |||
} else if (varNode instanceof ConstNode) { | |||
String className = ((INameNode) varNode).getName(); | |||
Entity entity = context.foundEntityWithName(GenericName.build(className)); | |||
if (entity != null && entity instanceof ContainerEntity) { | |||
FunctionEntity method = context.foundMethodDeclarator(((ContainerEntity) entity), node.getName(),node.getPosition().getStartLine()+1); | |||
method.setLine(node.getPosition().getStartLine()+1); | |||
handled = true; | |||
} | |||
} else if (varNode instanceof INameNode) { | |||
String varName = ((INameNode) varNode).getName(); | |||
Entity var = context.foundEntityWithName(GenericName.build(varName)); | |||
if (var != null && var instanceof ContainerEntity) { | |||
FunctionEntity method = context.foundMethodDeclarator(((ContainerEntity) var), node.getName(),node.getPosition().getStartLine()+1); | |||
method.setLine(node.getPosition().getStartLine()+1); | |||
handled = true; | |||
} | |||
} | |||
if (!handled) { | |||
// fallback to add it to last container | |||
FunctionEntity method = context.foundMethodDeclarator(node.getName(),node.getPosition().getStartLine()+1); | |||
method.setLine(node.getPosition().getStartLine()+1); | |||
} | |||
super.visitDefsNode(node); | |||
context.exitLastedEntity(); | |||
return null; | |||
} | |||
@Override | |||
public Object visitGlobalVarNode(GlobalVarNode node) { | |||
context.foundVarDefinition(context.globalScope(), node.getName(),node.getPosition().getStartLine()+1); | |||
return super.visitGlobalVarNode(node); | |||
} | |||
@Override | |||
public Object visitInstVarNode(InstVarNode node) { | |||
context.foundVarDefinition(context.currentType(), node.getName(),node.getPosition().getStartLine()+1); | |||
return super.visitInstVarNode(node); | |||
} | |||
@Override | |||
public Object visitClassVarAsgnNode(ClassVarAsgnNode node) { | |||
context.foundVarDefinition(helper.getScopeOfVar(node,context), node.getName(),node.getPosition().getStartLine()+1); | |||
return super.visitClassVarAsgnNode(node); | |||
} | |||
@Override | |||
public Object visitClassVarDeclNode(ClassVarDeclNode node) { | |||
context.foundVarDefinition(context.currentType(), node.getName(),node.getPosition().getStartLine()+1); | |||
return super.visitClassVarDeclNode(node); | |||
} | |||
@Override | |||
public Object visitClassVarNode(ClassVarNode node) { | |||
context.foundVarDefinition(context.currentType(), node.getName(),node.getPosition().getStartLine()+1); | |||
return super.visitClassVarNode(node); | |||
} | |||
@Override | |||
public Object visitLocalVarNode(LocalVarNode node) { | |||
return super.visitLocalVarNode(node); | |||
} | |||
@Override | |||
public Object visitDVarNode(DVarNode node) { | |||
context.foundVarDefinition(context.lastContainer(), node.getName(),node.getPosition().getStartLine()+1); | |||
return super.visitDVarNode(node); | |||
} | |||
@Override | |||
public Object visitDAsgnNode(DAsgnNode node) { | |||
context.foundVarDefinition(helper.getScopeOfVar(node,context), node.getName(),node.getPosition().getStartLine()+1); | |||
expressionUsage.foundExpression(node.getValue()); | |||
return super.visitDAsgnNode(node); | |||
} | |||
@Override | |||
public Object visitGlobalAsgnNode(GlobalAsgnNode node) { | |||
context.foundVarDefinition(helper.getScopeOfVar(node,context), node.getName(),node.getPosition().getStartLine()+1); | |||
return super.visitGlobalAsgnNode(node); | |||
} | |||
@Override | |||
public Object visitInstAsgnNode(InstAsgnNode node) { | |||
context.foundVarDefinition(helper.getScopeOfVar(node,context), node.getName(),node.getPosition().getStartLine()+1); | |||
return super.visitInstAsgnNode(node); | |||
} | |||
@Override | |||
public Object visitArgumentNode(ArgumentNode node) { | |||
String paramName = node.getName(); | |||
context.addMethodParameter(paramName); | |||
return super.visitArgumentNode(node); | |||
} | |||
@Override | |||
public Object visitLocalAsgnNode(LocalAsgnNode node) { | |||
context.foundVarDefinition(helper.getScopeOfVar(node,context), node.getName(),node.getPosition().getStartLine()+1); | |||
return super.visitLocalAsgnNode(node); | |||
} | |||
@Override | |||
protected Object visit(Node node) { | |||
expressionUsage.foundExpression(node); | |||
return super.visit(node); | |||
} | |||
} |
@@ -1,84 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.extractor.java; | |||
import depends.entity.repo.BuiltInType; | |||
public class JavaBuiltInType extends BuiltInType{ | |||
@Override | |||
protected String[] getBuiltInTypeName() { | |||
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 | |||
protected String[] getBuiltInTypePrefix() { | |||
return new String[]{ | |||
"java.","javax.","com.sun." | |||
}; | |||
} | |||
} |
@@ -1,105 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.extractor.java; | |||
import depends.entity.Entity; | |||
import depends.entity.FileEntity; | |||
import depends.entity.PackageEntity; | |||
import depends.entity.repo.EntityRepo; | |||
import depends.extractor.UnsolvedBindings; | |||
import depends.importtypes.Import; | |||
import depends.relations.ImportLookupStrategy; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import java.util.Set; | |||
public class JavaImportLookupStrategy extends ImportLookupStrategy{ | |||
public JavaImportLookupStrategy(EntityRepo repo) { | |||
super(repo); | |||
} | |||
@Override | |||
public Entity lookupImportedType(String name, FileEntity fileEntity) { | |||
//Java Strategy | |||
String importedString = fileEntity.importedSuffixMatch(name); | |||
if (importedString==null) return null; | |||
return repo.getEntity(importedString); | |||
} | |||
@Override | |||
public List<Entity> getImportedRelationEntities(List<Import> importedList) { | |||
ArrayList<Entity> result = new ArrayList<>(); | |||
for (Import importedItem:importedList) { | |||
Entity imported = repo.getEntity(importedItem.getContent()); | |||
if (imported==null) continue; | |||
if (imported instanceof PackageEntity) { | |||
//ignore wildcard import relation | |||
}else { | |||
result.add(imported); | |||
} | |||
} | |||
return result; | |||
} | |||
@Override | |||
public List<Entity> getImportedTypes(List<Import> importedList,Set<UnsolvedBindings> unsolvedBindings) { | |||
ArrayList<Entity> result = new ArrayList<>(); | |||
for (Import importedItem:importedList) { | |||
Entity imported = repo.getEntity(importedItem.getContent()); | |||
if (imported==null) { | |||
unsolvedBindings.add(new UnsolvedBindings(importedItem.getContent(),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()) { | |||
if (child instanceof FileEntity) { | |||
child.getChildren().forEach(item->result.add(item)); | |||
}else { | |||
result.add(child); | |||
} | |||
} | |||
}else { | |||
result.add(imported); | |||
} | |||
} | |||
return result; | |||
} | |||
@Override | |||
public List<Entity> getImportedFiles(List<Import> importedList) { | |||
return new ArrayList<Entity>(); | |||
} | |||
@Override | |||
public boolean supportGlobalNameLookup() { | |||
return true; | |||
} | |||
} |
@@ -1,337 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.extractor.java; | |||
import depends.entity.*; | |||
import depends.entity.repo.EntityRepo; | |||
import depends.extractor.java.JavaParser.*; | |||
import depends.extractor.java.context.*; | |||
import depends.importtypes.ExactMatchImport; | |||
import depends.relations.IBindingResolver; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
public class JavaListener extends JavaParserBaseListener { | |||
private final JavaHandlerContext context; | |||
private final AnnotationProcessor annotationProcessor; | |||
private final ExpressionUsage expressionUsage; | |||
private final EntityRepo entityRepo; | |||
public JavaListener(String fileFullPath, EntityRepo entityRepo, IBindingResolver bindingResolver) { | |||
this.context = new JavaHandlerContext(entityRepo, bindingResolver); | |||
this.entityRepo = entityRepo; | |||
annotationProcessor = new AnnotationProcessor(); | |||
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) { | |||
if (ctx.IDENTIFIER()==null) return; | |||
context.foundNewType(GenericName.build(ctx.IDENTIFIER().getText()), ctx.getStart().getLine()); | |||
// implements | |||
if (ctx.typeList() != null) { | |||
for (int i = 0; i < ctx.typeList().typeType().size(); i++) { | |||
context.foundImplements(GenericName.build(ClassTypeContextHelper.getClassName(ctx.typeList().typeType().get(i)))); | |||
} | |||
} | |||
// extends relation | |||
if (ctx.typeType() != null) { | |||
context.foundExtends(GenericName.build(ClassTypeContextHelper.getClassName(ctx.typeType()))); | |||
} | |||
if (ctx.typeParameters() != null) { | |||
foundTypeParametersUse(ctx.typeParameters()); | |||
} | |||
annotationProcessor.processAnnotationModifier(ctx, TypeDeclarationContext.class ,"classOrInterfaceModifier.annotation",context.lastContainer()); | |||
super.enterClassDeclaration(ctx); | |||
} | |||
@Override | |||
public void exitClassDeclaration(ClassDeclarationContext ctx) { | |||
exitLastEntity(); | |||
super.exitClassDeclaration(ctx); | |||
} | |||
@Override | |||
public void enterEnumDeclaration(EnumDeclarationContext ctx) { | |||
context.foundNewType(GenericName.build(ctx.IDENTIFIER().getText()), ctx.getStart().getLine()); | |||
annotationProcessor.processAnnotationModifier(ctx, TypeDeclarationContext.class ,"classOrInterfaceModifier.annotation",context.lastContainer()); | |||
super.enterEnumDeclaration(ctx); | |||
} | |||
@Override | |||
public void enterAnnotationTypeDeclaration(AnnotationTypeDeclarationContext ctx) { | |||
context.foundNewType(GenericName.build(ctx.IDENTIFIER().getText()), ctx.getStart().getLine()); | |||
annotationProcessor.processAnnotationModifier(ctx, TypeDeclarationContext.class ,"classOrInterfaceModifier.annotation",context.lastContainer()); | |||
super.enterAnnotationTypeDeclaration(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(GenericName.build(ctx.IDENTIFIER().getText()), ctx.getStart().getLine()); | |||
// 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, TypeDeclarationContext.class ,"classOrInterfaceModifier.annotation",context.lastContainer()); | |||
super.enterInterfaceDeclaration(ctx); | |||
} | |||
@Override | |||
public void exitInterfaceDeclaration(InterfaceDeclarationContext ctx) { | |||
exitLastEntity(); | |||
super.exitInterfaceDeclaration(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,ctx.getStart().getLine()); | |||
new FormalParameterListContextHelper(ctx.formalParameters(), method, entityRepo); | |||
if (ctx.typeParameters() != null) { | |||
List<GenericName> parameters = TypeParameterContextHelper.getTypeParameters(ctx.typeParameters()); | |||
method.addTypeParameter(parameters); | |||
} | |||
annotationProcessor.processAnnotationModifier(ctx, ClassBodyDeclarationContext.class,"modifier.classOrInterfaceModifier.annotation",context.lastContainer()); | |||
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,ctx.getStart().getLine()); | |||
new FormalParameterListContextHelper(ctx.formalParameters(), method, entityRepo); | |||
if (ctx.typeParameters() != null) { | |||
foundTypeParametersUse(ctx.typeParameters()); | |||
} | |||
annotationProcessor.processAnnotationModifier(ctx, InterfaceBodyDeclarationContext.class,"modifier.classOrInterfaceModifier.annotation",context.lastContainer()); | |||
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,ctx.getStart().getLine()); | |||
new FormalParameterListContextHelper(ctx.formalParameters(), method, entityRepo); | |||
method.addReturnType(context.currentType()); | |||
annotationProcessor.processAnnotationModifier(ctx, ClassBodyDeclarationContext.class,"modifier.classOrInterfaceModifier.annotation",context.lastContainer()); | |||
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()); | |||
List<GenericName> typeArguments = ClassTypeContextHelper.getTypeArguments(ctx.typeType()); | |||
List<VarEntity> vars = context.foundVarDefinitions(varNames, type,typeArguments,ctx.getStart().getLine()); | |||
annotationProcessor.processAnnotationModifier(ctx, ClassBodyDeclarationContext.class,"modifier.classOrInterfaceModifier.annotation",vars); | |||
super.enterFieldDeclaration(ctx); | |||
} | |||
@Override | |||
public void enterConstDeclaration(ConstDeclarationContext ctx) { | |||
List<GenericName> typeArguments = ClassTypeContextHelper.getTypeArguments(ctx.typeType()); | |||
List<VarEntity> vars = context.foundVarDefinitions(VariableDeclaratorsContextHelper.getVariables(ctx.constantDeclarator()), | |||
ClassTypeContextHelper.getClassName(ctx.typeType()),typeArguments, ctx.getStart().getLine()); | |||
annotationProcessor.processAnnotationModifier(ctx, InterfaceBodyDeclarationContext.class,"modifier.classOrInterfaceModifier.annotation",vars); | |||
super.enterConstDeclaration(ctx); | |||
} | |||
@Override | |||
public void enterEnumConstant(EnumConstantContext ctx) { | |||
if (ctx.IDENTIFIER() != null) { | |||
context.foundEnumConstDefinition(ctx.IDENTIFIER().getText(),ctx.getStart().getLine()); | |||
} | |||
super.enterEnumConstant(ctx); | |||
} | |||
@Override | |||
public void enterAnnotationMethodRest(AnnotationMethodRestContext ctx) { | |||
context.foundMethodDeclarator(ctx.IDENTIFIER().getText(), ClassTypeContextHelper.getClassName(ctx.typeType()), | |||
new ArrayList<>(),ctx.getStart().getLine()); | |||
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.foundVarDefinitions(VariableDeclaratorsContextHelper.getVariables(ctx.variableDeclarators()), "", new ArrayList<>(), ctx.getStart().getLine()); | |||
super.enterAnnotationConstantRest(ctx); | |||
} | |||
/////////////////////////////////////////// | |||
// variables | |||
// TODO: all modifier have not processed yet. | |||
@Override | |||
public void enterLocalVariableDeclaration(LocalVariableDeclarationContext ctx) { | |||
List<GenericName> typeArguments = ClassTypeContextHelper.getTypeArguments(ctx.typeType()); | |||
context.foundVarDefinitions(VariableDeclaratorsContextHelper.getVariables((ctx.variableDeclarators())), | |||
ClassTypeContextHelper.getClassName(ctx.typeType()), typeArguments, ctx.getStart().getLine()); | |||
super.enterLocalVariableDeclaration(ctx); | |||
} | |||
public void enterEnhancedForControl(EnhancedForControlContext ctx) { | |||
List<GenericName> typeArguments = ClassTypeContextHelper.getTypeArguments(ctx.typeType()); | |||
context.foundVarDefinitions(VariableDeclaratorsContextHelper.getVariable((ctx.variableDeclaratorId())), | |||
ClassTypeContextHelper.getClassName(ctx.typeType()), typeArguments, ctx.getStart().getLine()); | |||
super.enterEnhancedForControl(ctx); | |||
} | |||
// resource | |||
// : variableModifier* classOrInterfaceType variableDeclaratorId '=' expression | |||
// ; | |||
@Override | |||
public void enterResource(ResourceContext ctx) { | |||
List<GenericName> typeArguments = ClassTypeContextHelper.getTypeArguments(ctx.classOrInterfaceType()); | |||
context.foundVarDefinition(ctx.variableDeclaratorId().IDENTIFIER().getText(), | |||
GenericName.build(IdentifierContextHelper.getName(ctx.classOrInterfaceType().IDENTIFIER())), typeArguments,ctx.getStart().getLine()); | |||
super.enterResource(ctx); | |||
} | |||
@Override | |||
public void enterExpression(ExpressionContext ctx) { | |||
Expression expr = expressionUsage.foundExpression(ctx); | |||
expr.setLine(ctx.getStart().getLine()); | |||
super.enterExpression(ctx); | |||
} | |||
///////////////////////////////////////////// | |||
// Block | |||
@Override | |||
public void enterBlock(BlockContext ctx) { | |||
// TODO support block in java | |||
super.enterBlock(ctx); | |||
} | |||
@Override | |||
public void exitBlock(BlockContext ctx) { | |||
// TODO support block in java | |||
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(GenericName.build(ClassTypeContextHelper.getClassName(typeParam.typeBound().typeType(j)))); | |||
} | |||
} | |||
context.currentType().addTypeParameter(GenericName.build(typeParam.IDENTIFIER().getText())); | |||
} | |||
} | |||
} |
@@ -1,100 +0,0 @@ | |||
package depends.extractor.java; | |||
import depends.deptypes.DependencyType; | |||
import depends.entity.ContainerEntity; | |||
import depends.entity.Entity; | |||
import depends.entity.FunctionEntity; | |||
import depends.entity.TypeEntity; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import java.io.IOException; | |||
import static org.junit.Assert.assertEquals; | |||
public class JavaVarResolveTest extends JavaParserTest{ | |||
@Before | |||
public void setUp() { | |||
super.init(); | |||
} | |||
@Test | |||
public void test_field_var_should_be_parsed() throws IOException { | |||
String src = "./src/test/resources/java-code-examples/FieldVar.java"; | |||
JavaFileParser parser = createParser(); | |||
parser.parse(src); | |||
resolveAllBindings(); | |||
Entity classEntity = entityRepo.getEntity("FieldVar"); | |||
assertEquals(3,((TypeEntity)classEntity).getVars().size()); | |||
} | |||
@Test | |||
public void test_local_var_should_be_parsed() throws IOException { | |||
String src = "./src/test/resources/java-code-examples/LocalVar.java"; | |||
JavaFileParser parser = createParser(); | |||
parser.parse(src); | |||
resolveAllBindings(); | |||
assertEquals(1,((TypeEntity)entityRepo.getEntity("LocalVar")).getVars().size()); | |||
assertEquals(1,((FunctionEntity)entityRepo.getEntity("LocalVar.foo")).getVars().size()); | |||
} | |||
@Test | |||
public void test_local_var_type_could_be_inferred() throws IOException { | |||
String src = "./src/test/resources/java-code-examples/LocalVarInferExample.java"; | |||
JavaFileParser parser = createParser(); | |||
parser.parse(src); | |||
resolveAllBindings(); | |||
ContainerEntity e = (ContainerEntity) entityRepo.getEntity("LocalVarInferExample.setExample"); | |||
this.assertContainsRelation(e, DependencyType.CONTAIN, "MyInteger"); | |||
} | |||
@Test | |||
public void test_field_access_could_be_inferred() throws IOException { | |||
String src = "./src/test/resources/java-code-examples/ComplexExpressionExample.java"; | |||
JavaFileParser parser = createParser(); | |||
parser.parse(src); | |||
resolveAllBindings(); | |||
Entity e = entityRepo.getEntity("test.ComplexExpressionExample.setExample"); | |||
this.assertContainsRelation(e, DependencyType.PARAMETER, "test.ClassA"); | |||
this.assertContainsRelation(e, DependencyType.CREATE, "test.ClassA"); | |||
this.assertContainsRelation(e, DependencyType.CALL, "test.ClassA"); | |||
this.assertContainsRelation(e, DependencyType.CAST, "test.ClassA"); | |||
this.assertContainsRelation(e, DependencyType.CALL, "test.ClassA.foo"); | |||
this.assertContainsRelation(e, DependencyType.CALL, "test.ClassA"); | |||
this.assertContainsRelation(e, DependencyType.USE, "test.ComplexExpressionExample.setExample.a3"); | |||
this.assertContainsRelation(e, DependencyType.USE, "test.ClassX.m"); | |||
this.assertContainsRelation(e, DependencyType.USE, "test.ComplexExpressionExample.setExample.a2"); | |||
this.assertContainsRelation(e, DependencyType.USE, "test.ClassA.x"); | |||
this.assertContainsRelation(e, DependencyType.USE, "test.ComplexExpressionExample.setExample.a"); | |||
} | |||
@Test | |||
public void test_long_static_function_should_be_inferred() throws IOException { | |||
String src = "./src/test/resources/java-code-examples/LongExpressionWithAbsolutePath.java"; | |||
JavaFileParser parser = createParser(); | |||
parser.parse(src); | |||
resolveAllBindings(); | |||
assertEquals(5,entityRepo.getEntity("x.LongExpressionWithAbsolutePath.setExample").getRelations().size()); | |||
} | |||
@Test | |||
public void test_call_should_be_referred() throws IOException { | |||
String src = "./src/test/resources/java-code-examples/ExpressionCallTest.java"; | |||
JavaFileParser parser = createParser(); | |||
parser.parse(src); | |||
resolveAllBindings(); | |||
assertEquals(10,entityRepo.getEntity("ValidateAll.validate").getRelations().size()); | |||
} | |||
@Test | |||
public void test_could_detect_type_argument_in_field() throws IOException { | |||
String src = "./src/test/resources/java-code-examples/TypeArgument.java"; | |||
JavaFileParser parser = createParser(); | |||
parser.parse(src); | |||
resolveAllBindings(); | |||
this.assertContainsRelation(entityRepo.getEntity("JDepObject.cells"),DependencyType.PARAMETER, "JCellObject"); | |||
} | |||
} |
@@ -1,261 +0,0 @@ | |||
package com.educoder.bridge.service; | |||
import com.alibaba.fastjson.JSONObject; | |||
import com.educoder.bridge.model.SSHInfo; | |||
import com.educoder.bridge.model.SSHSession; | |||
import com.educoder.bridge.utils.Base64Util; | |||
import com.jcraft.jsch.ChannelShell; | |||
import com.jcraft.jsch.JSch; | |||
import com.jcraft.jsch.Session; | |||
import com.jcraft.jsch.UserInfo; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.springframework.stereotype.Service; | |||
import org.springframework.web.socket.TextMessage; | |||
import org.springframework.web.socket.WebSocketSession; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.OutputStream; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
import java.util.Optional; | |||
import java.util.concurrent.CopyOnWriteArrayList; | |||
import java.util.concurrent.ExecutorService; | |||
import java.util.concurrent.Executors; | |||
@Service | |||
public class JchService { | |||
private static List<SSHSession> sshSessionQueue = new CopyOnWriteArrayList<>(); | |||
private ExecutorService executorService = Executors.newCachedThreadPool(); | |||
private Logger logger = LoggerFactory.getLogger(getClass()); | |||
com.jcraft.jsch.Logger jschLogger = new com.jcraft.jsch.Logger() { | |||
@Override | |||
public boolean isEnabled(int arg0) { | |||
return true; | |||
} | |||
@Override | |||
public void log(int arg0, String arg1) { | |||
if (logger.isTraceEnabled()) { | |||
logger.trace("JSch Log [Level " + arg0 + "]: " + arg1); | |||
} | |||
} | |||
}; | |||
/** | |||
* 在webSocket连接时,初始化一个ssh连接 | |||
* | |||
* @param webSocketSession webSocket连接 | |||
*/ | |||
public void add(WebSocketSession webSocketSession) { | |||
SSHSession sshSession = new SSHSession(); | |||
sshSession.setWebSocketSession(webSocketSession); | |||
sshSessionQueue.add(sshSession); | |||
} | |||
/** | |||
* 处理客户端发过来的数据 | |||
* @param buffer 数据 | |||
* @param webSocketSession webSocket连接 | |||
*/ | |||
public void recv(String buffer, WebSocketSession webSocketSession) { | |||
SSHSession sshSession = null; | |||
try { | |||
logger.debug("webSocketSessionID: {}, 信息: {}", webSocketSession.getId(), buffer); | |||
JSONObject info = JSONObject.parseObject(buffer); | |||
String tp = info.getString("tp"); | |||
sshSession = findByWebSocketSession(webSocketSession); | |||
//初始化连接 | |||
if ("init".equals(tp)) { | |||
// {"tp":"init","data":{"host":"127.0.0.1","port":"41080","username":"root","password":"123123"}} | |||
SSHInfo sshInfo = info.getObject("data", SSHInfo.class); | |||
sshSession.setSSHInfo(sshInfo); | |||
if (sshSession != null) { | |||
SSHSession finalSSHSession = sshSession; | |||
// 新开一个线程建立连接,连接开启之后以一直监听来自客户端的输入 | |||
executorService.execute(() -> { | |||
connectTossh(finalSSHSession); | |||
}); | |||
} | |||
} else if ("client".equals(tp)) { | |||
String data = info.getString("data"); | |||
// 将网页输入的数据传送给后端服务器 | |||
if (sshSession != null) { | |||
transTossh(sshSession.getOutputStream(), data); | |||
} | |||
} | |||
} catch (Exception e) { | |||
logger.error("转发命令到ssh出错: {}", e); | |||
close(sshSession); | |||
} | |||
} | |||
/** | |||
* 将数据传送给服务端作为SSH的输入 | |||
* | |||
* @param outputStream | |||
* @param data | |||
* @throws IOException | |||
*/ | |||
private void transTossh(OutputStream outputStream, String data) throws IOException { | |||
if (outputStream != null) { | |||
outputStream.write(data.getBytes()); | |||
outputStream.flush(); | |||
} | |||
} | |||
/** | |||
* 连接ssh | |||
* | |||
* @param sshSession ssh连接需要的信息 | |||
*/ | |||
private void connectTossh(SSHSession sshSession){ | |||
Session jschSession = null; | |||
SSHInfo SSHInfo = sshSession.getSSHInfo(); | |||
try { | |||
JSch jsch = new JSch(); | |||
JSch.setLogger(jschLogger); | |||
//启动线程 | |||
java.util.Properties config = new java.util.Properties(); | |||
config.put("StrictHostKeyChecking", "no"); | |||
jschSession = jsch.getSession(SSHInfo.getUsername(), SSHInfo.getHost(), SSHInfo.getPort()); | |||
jschSession.setConfig(config); | |||
jschSession.setPassword(SSHInfo.getPassword()); | |||
jschSession.setUserInfo(new UserInfo() { | |||
@Override | |||
public String getPassphrase() { | |||
return null; | |||
} | |||
@Override | |||
public String getPassword() { | |||
return null; | |||
} | |||
@Override | |||
public boolean promptPassword(String s) { | |||
return false; | |||
} | |||
@Override | |||
public boolean promptPassphrase(String s) { | |||
return false; | |||
} | |||
@Override | |||
public boolean promptYesNo(String s) { | |||
return true; | |||
} // Accept all server keys | |||
@Override | |||
public void showMessage(String s) { | |||
} | |||
}); | |||
jschSession.connect(); | |||
ChannelShell channel = (ChannelShell) jschSession.openChannel("shell"); | |||
channel.setPtyType("xterm"); | |||
channel.connect(); | |||
sshSession.setChannel(channel); | |||
InputStream inputStream = channel.getInputStream(); | |||
sshSession.setOutputStream(channel.getOutputStream()); | |||
sshSession.setSSHInfo(SSHInfo); | |||
logger.debug("主机: {} 连接成功!", SSHInfo.getHost()); | |||
// 循环读取,jsch的输入为服务器执行命令之后的返回数据 | |||
byte[] buf = new byte[1024]; | |||
while (true) { | |||
int length = inputStream.read(buf); | |||
if (length < 0) { | |||
close(sshSession); | |||
throw new Exception("读取出错,数据长度:" + length); | |||
} | |||
sendMsg(sshSession.getWebSocketSession(), Arrays.copyOfRange(buf, 0, length)); | |||
} | |||
} catch (Exception e) { | |||
logger.error("ssh连接出错, e: {}", e); | |||
} finally { | |||
logger.info("连接关闭, {}", SSHInfo.getHost()); | |||
if (jschSession != null) { | |||
jschSession.disconnect(); | |||
} | |||
close(sshSession); | |||
} | |||
} | |||
/** | |||
* 发送数据回websocket | |||
* | |||
* @param webSocketSession webSocket连接 | |||
* @param buffer 数据 | |||
* @throws IOException | |||
*/ | |||
public void sendMsg(WebSocketSession webSocketSession, byte[] buffer) throws IOException { | |||
logger.debug("服务端返回的数据: {}", new String(buffer, "UTF-8")); | |||
webSocketSession.sendMessage(new TextMessage(Base64Util.encodeBytes(buffer))); | |||
} | |||
/** | |||
* 通过webSocket连接在队列中找到对应的SSH连接 | |||
* | |||
* @param webSocketSession webSocket连接 | |||
*/ | |||
public SSHSession findByWebSocketSession(WebSocketSession webSocketSession) { | |||
Optional<SSHSession> optional = sshSessionQueue.stream().filter(webscoketObj -> webscoketObj.getWebSocketSession() == webSocketSession).findFirst(); | |||
if (optional.isPresent()) { | |||
return optional.get(); | |||
} | |||
return null; | |||
} | |||
/** | |||
* 关闭ssh和websocket连接 | |||
* | |||
* @param sshSession ssh连接 | |||
*/ | |||
private void close(SSHSession sshSession) { | |||
if (sshSession != null) { | |||
sshSession.getChannel().disconnect(); | |||
try { | |||
sshSession.getWebSocketSession().close(); | |||
sshSession.getOutputStream().close(); | |||
} catch (IOException e) { | |||
logger.error("连接关闭失败!e: {}", e); | |||
} | |||
sshSessionQueue.remove(sshSession); | |||
} | |||
} | |||
/** | |||
* 通过webSocketSession关闭ssh与webSocket连接 | |||
* | |||
* @param webSocketSession | |||
*/ | |||
public void closeByWebSocket(WebSocketSession webSocketSession) { | |||
close(findByWebSocketSession(webSocketSession)); | |||
} | |||
} |
@@ -1,197 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends; | |||
import depends.addons.DV8MappingFileBuilder; | |||
import depends.entity.repo.EntityRepo; | |||
import depends.extractor.AbstractLangProcessor; | |||
import depends.extractor.LangProcessorRegistration; | |||
import depends.extractor.UnsolvedBindings; | |||
import depends.format.DependencyDumper; | |||
import depends.format.detail.UnsolvedSymbolDumper; | |||
import depends.generator.DependencyGenerator; | |||
import depends.generator.FileDependencyGenerator; | |||
import depends.generator.FunctionDependencyGenerator; | |||
import depends.generator.StructureDependencyGenerator; | |||
import depends.matrix.core.DependencyMatrix; | |||
import depends.matrix.transform.MatrixLevelReducer; | |||
import depends.relations.BindingResolver; | |||
import depends.relations.IBindingResolver; | |||
import depends.relations.RelationCounter; | |||
import edu.emory.mathcs.backport.java.util.Arrays; | |||
import multilang.depends.util.file.FileUtil; | |||
import multilang.depends.util.file.FolderCollector; | |||
import multilang.depends.util.file.TemporaryFile; | |||
import multilang.depends.util.file.path.*; | |||
import multilang.depends.util.file.strip.LeadingNameStripper; | |||
import net.sf.ehcache.CacheManager; | |||
import org.codehaus.plexus.util.StringUtils; | |||
import picocli.CommandLine; | |||
import picocli.CommandLine.PicocliException; | |||
import java.io.File; | |||
import java.util.List; | |||
import java.util.Set; | |||
/** | |||
* The entry pooint of depends | |||
*/ | |||
public class Main { | |||
public static void main(String[] args) { | |||
try { | |||
LangRegister langRegister = new LangRegister(); | |||
langRegister.register(); | |||
DependsCommand appArgs = CommandLine.populateCommand(new DependsCommand(), args); | |||
if (appArgs.help) { | |||
CommandLine.usage(new DependsCommand(), System.out); | |||
System.exit(0); | |||
} | |||
executeCommand(appArgs); | |||
} catch (Exception e) { | |||
if (e instanceof PicocliException) { | |||
CommandLine.usage(new DependsCommand(), System.out); | |||
} else if (e instanceof ParameterException){ | |||
System.err.println(e.getMessage()); | |||
}else { | |||
System.err.println("Exception encountered. If it is a design error, please report issue to us." ); | |||
e.printStackTrace(); | |||
} | |||
System.exit(0); | |||
} | |||
} | |||
@SuppressWarnings("unchecked") | |||
private static void executeCommand(DependsCommand args) throws ParameterException { | |||
String lang = args.getLang(); | |||
String inputDir = args.getSrc(); | |||
String[] includeDir = args.getIncludes(); | |||
String outputName = args.getOutputName(); | |||
String outputDir = args.getOutputDir(); | |||
String[] outputFormat = args.getFormat(); | |||
inputDir = FileUtil.uniqFilePath(inputDir); | |||
if (args.isAutoInclude()) { | |||
includeDir = appendAllFoldersToIncludePath(inputDir, includeDir); | |||
} | |||
AbstractLangProcessor langProcessor = LangProcessorRegistration.getRegistry().getProcessorOf(lang); | |||
if (langProcessor == null) { | |||
System.err.println("Not support this language: " + lang); | |||
return; | |||
} | |||
IBindingResolver bindingResolver = new BindingResolver(langProcessor, args.isOutputExternalDependencies(), args.isDuckTypingDeduce()); | |||
long startTime = System.currentTimeMillis(); | |||
//step1: build data | |||
EntityRepo entityRepo = langProcessor.buildDependencies(inputDir, includeDir, bindingResolver); | |||
new RelationCounter(entityRepo,langProcessor, bindingResolver).computeRelations(); | |||
System.out.println("Dependency done...."); | |||
//step2: generate dependencies matrix | |||
DependencyGenerator dependencyGenerator = getDependencyGenerator(args, inputDir); | |||
DependencyMatrix matrix = dependencyGenerator.identifyDependencies(entityRepo,args.getTypeFilter()); | |||
//step3: output | |||
if (args.getGranularity().startsWith("L")) { | |||
matrix = new MatrixLevelReducer(matrix,args.getGranularity().substring(1)).shrinkToLevel(); | |||
} | |||
DependencyDumper output = new DependencyDumper(matrix); | |||
output.outputResult(outputName,outputDir,outputFormat); | |||
if (args.isOutputExternalDependencies()) { | |||
Set<UnsolvedBindings> unsolved = langProcessor.getExternalDependencies(); | |||
UnsolvedSymbolDumper unsolvedSymbolDumper = new UnsolvedSymbolDumper(unsolved,args.getOutputName(),args.getOutputDir(), | |||
new LeadingNameStripper(args.isStripLeadingPath(),inputDir,args.getStrippedPaths())); | |||
unsolvedSymbolDumper.output(); | |||
} | |||
long endTime = System.currentTimeMillis(); | |||
TemporaryFile.getInstance().delete(); | |||
CacheManager.create().shutdown(); | |||
System.out.println("Consumed time: " + (float) ((endTime - startTime) / 1000.00) + " s, or " | |||
+ (float) ((endTime - startTime) / 60000.00) + " min."); | |||
if ( args.isDv8map()) { | |||
DV8MappingFileBuilder dv8MapfileBuilder = new DV8MappingFileBuilder(langProcessor.supportedRelations()); | |||
dv8MapfileBuilder.create(outputDir+ File.separator+"depends-dv8map.mapping"); | |||
} | |||
} | |||
private static String[] appendAllFoldersToIncludePath(String inputDir, String[] includeDir) { | |||
FolderCollector includePathCollector = new FolderCollector(); | |||
List<String> additionalIncludePaths = includePathCollector.getFolders(inputDir); | |||
additionalIncludePaths.addAll(Arrays.asList(includeDir)); | |||
includeDir = additionalIncludePaths.toArray(new String[] {}); | |||
return includeDir; | |||
} | |||
private static DependencyGenerator getDependencyGenerator(DependsCommand app, String inputDir) throws ParameterException { | |||
FilenameWritter filenameWritter = new EmptyFilenameWritter(); | |||
if (!StringUtils.isEmpty(app.getNamePathPattern())) { | |||
if (app.getNamePathPattern().equals("dot")|| | |||
app.getNamePathPattern().equals(".")) { | |||
filenameWritter = new DotPathFilenameWritter(); | |||
}else if (app.getNamePathPattern().equals("unix")|| | |||
app.getNamePathPattern().equals("/")) { | |||
filenameWritter = new UnixPathFilenameWritter(); | |||
}else if (app.getNamePathPattern().equals("windows")|| | |||
app.getNamePathPattern().equals("\\")) { | |||
filenameWritter = new WindowsPathFilenameWritter(); | |||
}else{ | |||
throw new ParameterException("Unknown name pattern paremater:" + app.getNamePathPattern()); | |||
} | |||
} | |||
/* by default use file dependency generator */ | |||
DependencyGenerator dependencyGenerator = new FileDependencyGenerator(); | |||
if (!StringUtils.isEmpty(app.getGranularity())) { | |||
/* method parameter means use method generator */ | |||
if (app.getGranularity().equals("method")) | |||
dependencyGenerator = new FunctionDependencyGenerator(); | |||
else if (app.getGranularity().equals("structure")) | |||
dependencyGenerator = new StructureDependencyGenerator(); | |||
else if (app.getGranularity().equals("file")) | |||
/*no action*/; | |||
else if (app.getGranularity().startsWith("L")) | |||
/*no action*/; | |||
else | |||
throw new ParameterException("Unknown granularity parameter:" + app.getGranularity()); | |||
} | |||
if (app.isStripLeadingPath() || | |||
app.getStrippedPaths().length>0) { | |||
dependencyGenerator.setLeadingStripper(new LeadingNameStripper(app.isStripLeadingPath(), inputDir, app.getStrippedPaths())); | |||
} | |||
if (app.isDetail()) { | |||
dependencyGenerator.setGenerateDetail(true); | |||
} | |||
dependencyGenerator.setFilenameRewritter(filenameWritter); | |||
return dependencyGenerator; | |||
} | |||
} |
@@ -1,131 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.matrix.transform; | |||
import java.util.ArrayList; | |||
import java.util.Comparator; | |||
import java.util.HashMap; | |||
import depends.matrix.core.DependencyMatrix; | |||
import depends.matrix.core.DependencyPair; | |||
import depends.matrix.core.DependencyValue; | |||
public class MatrixLevelReducer { | |||
private DependencyMatrix origin; | |||
private int level; | |||
HashMap<String, Integer> nodesMap = new HashMap<>(); | |||
public MatrixLevelReducer(DependencyMatrix matrix, String levelString) { | |||
this.origin = matrix; | |||
this.level = stringToPositiveInt(levelString); | |||
} | |||
public DependencyMatrix shrinkToLevel() { | |||
if (level < 0) | |||
return origin; | |||
ArrayList<String> reMappedNodes = new ArrayList<>(); | |||
for (String node : origin.getNodes()) { | |||
String newNode = calcuateNodeAtLevel(node, level); | |||
if (!reMappedNodes.contains(newNode)) { | |||
reMappedNodes.add(newNode); | |||
} | |||
} | |||
// sort nodes by name | |||
reMappedNodes.sort(new Comparator<String>() { | |||
@Override | |||
public int compare(String o1, String o2) { | |||
return o1.compareTo(o2); | |||
} | |||
}); | |||
DependencyMatrix ordered = new DependencyMatrix(); | |||
for (int id=0;id<reMappedNodes.size();id++) { | |||
nodesMap.put(reMappedNodes.get(id), id); | |||
ordered.addNode(reMappedNodes.get(id), id); | |||
} | |||
// add dependencies | |||
for (DependencyPair dependencyPair : origin.getDependencyPairs()) { | |||
for (DependencyValue dep : dependencyPair.getDependencies()) { | |||
ordered.addDependency(dep.getType(), translateToNewId(dependencyPair.getFrom()), | |||
translateToNewId(dependencyPair.getTo()), dep.getWeight(), dep.getDetails()); | |||
} | |||
} | |||
return ordered; | |||
} | |||
public static String calcuateNodeAtLevel(String node, int level) { | |||
String splitterRegex = "\\."; | |||
String splitter = "."; | |||
String windowsSplitter = "\\"; | |||
String unixSplitter = "/"; | |||
if (node.contains(windowsSplitter)) { | |||
splitter = windowsSplitter; | |||
splitterRegex = windowsSplitter+windowsSplitter; | |||
}else if (node.contains(unixSplitter)) { | |||
splitter = unixSplitter; | |||
splitterRegex = unixSplitter; | |||
} | |||
String prefix = ""; | |||
if (node.startsWith(splitter)) { | |||
prefix = splitter; | |||
} | |||
String[] segments = node.split(splitterRegex); | |||
StringBuffer sb = new StringBuffer(); | |||
int count = 0; | |||
for (int i = 0; i < segments.length; i++) { | |||
if (count == level) | |||
break; | |||
if (segments[i].length() > 0) { | |||
if (sb.length()>0) | |||
sb.append(splitter); | |||
sb.append(segments[i]); | |||
count++; | |||
} | |||
} | |||
return prefix + sb.toString(); | |||
} | |||
private Integer translateToNewId(Integer id) { | |||
String newNode = calcuateNodeAtLevel(origin.getNodeName(id), level); | |||
return nodesMap.get(newNode); | |||
} | |||
private int stringToPositiveInt(String level) { | |||
int result = -1; | |||
try { | |||
result = Integer.parseInt(level); | |||
} catch (Exception e) { | |||
result = -1; | |||
} | |||
if (result <= 0) { | |||
result = -1; | |||
} | |||
return result; | |||
} | |||
} |
@@ -1,109 +0,0 @@ | |||
package depends.extractor; | |||
import depends.entity.ContainerEntity; | |||
import depends.entity.Entity; | |||
import depends.entity.FunctionEntity; | |||
import depends.entity.VarEntity; | |||
import depends.entity.repo.EntityRepo; | |||
import depends.relations.BindingResolver; | |||
import depends.relations.IBindingResolver; | |||
import depends.relations.Relation; | |||
import depends.relations.RelationCounter; | |||
import multilang.depends.util.file.TemporaryFile; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.Set; | |||
import static org.junit.Assert.fail; | |||
public abstract class ParserTest { | |||
protected EntityRepo entityRepo ; | |||
protected IBindingResolver bindingResolver; | |||
protected AbstractLangProcessor langProcessor; | |||
protected void init(){ | |||
entityRepo = langProcessor.getEntityRepo(); | |||
bindingResolver = new BindingResolver(langProcessor,true,false); | |||
langProcessor.bindingResolver = bindingResolver; | |||
TemporaryFile.reset(); | |||
} | |||
protected void init(boolean duckTypingDeduce){ | |||
entityRepo = langProcessor.getEntityRepo(); | |||
bindingResolver = new BindingResolver(langProcessor,false,duckTypingDeduce); | |||
langProcessor.bindingResolver = bindingResolver; | |||
TemporaryFile.reset(); | |||
} | |||
public Set<UnsolvedBindings> resolveAllBindings() { | |||
Set<UnsolvedBindings> result = bindingResolver.resolveAllBindings(langProcessor.isEagerExpressionResolve()); | |||
new RelationCounter(entityRepo,langProcessor, bindingResolver).computeRelations(); | |||
return result; | |||
} | |||
protected Set<UnsolvedBindings> resolveAllBindings(boolean callAsImpl) { | |||
Set<UnsolvedBindings> result = bindingResolver.resolveAllBindings(langProcessor.isEagerExpressionResolve()); | |||
new RelationCounter(entityRepo,langProcessor, bindingResolver).computeRelations(); | |||
return result; | |||
} | |||
protected void assertNotContainsRelation(Entity inEntity, String dependencyType, String dependedEntityFullName) { | |||
for (Relation r:inEntity.getRelations()) { | |||
if (r.getType().equals(dependencyType)) { | |||
if (r.getEntity().getQualifiedName().equals(dependedEntityFullName)) { | |||
fail("found unexpected relation: type = " + dependencyType + " to entity " + dependedEntityFullName); | |||
} | |||
} | |||
} | |||
} | |||
protected void assertContainsRelation(Entity inEntity, String dependencyType, String dependedEntityFullName) { | |||
Relation relation = null; | |||
for (Relation r:inEntity.getRelations()) { | |||
if (r.getType().equals(dependencyType)) { | |||
relation = r; | |||
if (r.getEntity()==null) continue; | |||
if (r.getEntity().getQualifiedName().equals(dependedEntityFullName)) | |||
return; | |||
} | |||
} | |||
if (relation==null) { | |||
fail("cannot found relation type of "+ dependencyType); | |||
}else { | |||
fail("cannot found relation type of " + dependencyType + " to entity " + dependedEntityFullName); | |||
} | |||
} | |||
protected void assertContainsVarWithRawName(Entity entity, String name) { | |||
ContainerEntity container = (ContainerEntity)entity; | |||
ArrayList<VarEntity> vars = container.getVars(); | |||
for (VarEntity var:vars) { | |||
if (var.getRawName().uniqName().equals(name)) { | |||
return; | |||
} | |||
} | |||
fail("cannot found var with rawname " + name); | |||
} | |||
protected void assertContainsParametersWithRawName(FunctionEntity function, String name) { | |||
Collection<VarEntity> vars = function.getParameters(); | |||
for (VarEntity var:vars) { | |||
if (var.getRawName().uniqName().equals(name)) { | |||
return; | |||
} | |||
} | |||
fail("cannot found parameter with rawname " + name); | |||
} | |||
protected void assertContainReturnType(FunctionEntity function, String name) { | |||
Collection<Entity> types = function.getReturnTypes(); | |||
for (Entity type:types) { | |||
if (type.getRawName().uniqName().equals(name)) { | |||
return; | |||
} | |||
} | |||
fail("cannot found return type with rawname " + name); | |||
} | |||
} |
@@ -1,165 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.extractor.pom; | |||
import depends.entity.Expression; | |||
import depends.entity.GenericName; | |||
import depends.entity.VarEntity; | |||
import depends.entity.repo.EntityRepo; | |||
import depends.extractor.FileParser; | |||
import depends.extractor.xml.XMLParser.ElementContext; | |||
import depends.extractor.xml.XMLParserBaseListener; | |||
import depends.relations.IBindingResolver; | |||
import org.antlr.v4.runtime.ParserRuleContext; | |||
import java.io.IOException; | |||
import java.util.List; | |||
import java.util.Stack; | |||
public class PomListener extends XMLParserBaseListener { | |||
private PomHandlerContext context; | |||
private EntityRepo entityRepo; | |||
PomArtifactEntity currentEntity; | |||
private VarEntity currentVar; | |||
Expression currentExpression; | |||
private PomParent pomParent; | |||
private PomProcessor parseCreator; | |||
private List<String> includePaths; | |||
private IBindingResolver IBindingResolver; | |||
private Stack<PomCoords> pomCoords= new Stack<>(); | |||
public PomListener(String fileFullPath, EntityRepo entityRepo, List<String> includePaths, PomProcessor parseCreator, | |||
IBindingResolver bindingResolver) { | |||
this.context = new PomHandlerContext(entityRepo); | |||
this.entityRepo = entityRepo; | |||
this.parseCreator = parseCreator; | |||
this.includePaths = includePaths; | |||
this.IBindingResolver = bindingResolver; | |||
context.startFile(fileFullPath); | |||
} | |||
@Override | |||
public void enterElement(ElementContext ctx) { | |||
String name = ctx.Name(0).getText(); | |||
if (name.equals("project")) { | |||
pomCoords.push(new PomCoords()); | |||
currentEntity = new PomArtifactEntity("", context.currentFile(), entityRepo.generateId()); | |||
} else if (name.equals("plugin")) { | |||
pomCoords.push(new PomCoords()); | |||
currentExpression = new Expression(entityRepo.generateId()); | |||
currentExpression.setRawType(""); | |||
} else if (name.equals("dependency")) { | |||
pomCoords.push(new PomCoords()); | |||
currentVar = new VarEntity(GenericName.build(""), GenericName.build(""), | |||
currentEntity, entityRepo.generateId()); | |||
} else if (name.equals("parent")) { | |||
pomCoords.push(new PomCoords()); | |||
pomParent = new PomParent(""); | |||
} | |||
// Add attribute | |||
else if (name.equals("groupId")) { | |||
peekPomCoords().groupId = getContentValueOf(ctx); | |||
} else if (name.equals("artifactId")) { | |||
peekPomCoords().artifactId = getContentValueOf(ctx); | |||
} else if (name.equals("version")) { | |||
peekPomCoords().version = getContentValueOf(ctx); | |||
} else if ("properties".equals(getParentElementName(ctx))) { | |||
if (ctx.content() != null) { | |||
currentEntity.addProperty(name, getContentValueOf(ctx)); | |||
} | |||
} | |||
super.enterElement(ctx); | |||
} | |||
private PomCoords peekPomCoords() { | |||
return pomCoords.peek(); | |||
} | |||
private String getContentValueOf(ElementContext ctx) { | |||
String text = ctx.content().getText(); | |||
if (text == null) | |||
return ""; | |||
if (text.contains("${")) | |||
text = currentEntity.replaceProperty(text); | |||
return text; | |||
} | |||
@Override | |||
public void exitElement(ElementContext ctx) { | |||
String name = ctx.Name(0).getText(); | |||
if (name.equals("project")) { | |||
if (pomParent != null) { | |||
peekPomCoords().fillFromIfNull(pomParent); | |||
} | |||
currentEntity.setRawName(peekPomCoords().getGenericNamePath()); | |||
currentEntity.setQualifiedName(currentEntity.getRawName().uniqName()); | |||
entityRepo.add(currentEntity); | |||
pomCoords.pop(); | |||
} else if (name.equals("plugin")) { | |||
peekPomCoords().sureFillVersion(includePaths); | |||
currentExpression.setRawType(peekPomCoords().getGenericNamePath()); | |||
currentEntity.addExpression(ctx, currentExpression); | |||
pomCoords.pop(); | |||
} else if (name.equals("dependency")) { | |||
peekPomCoords().sureFillVersion(includePaths); | |||
currentVar.setRawType(peekPomCoords().getGenericNamePath()); | |||
//TODO: Depends currently has a limitation: var name cannot be same as var type | |||
//To be fixed in future | |||
currentVar.setRawName(new GenericName("_" + currentVar.getRawType().getName())); | |||
currentEntity.addVar(currentVar); | |||
pomCoords.pop(); | |||
} else if (name.equals("parent")) { | |||
pomParent.buildFrom(peekPomCoords()); | |||
context.currentFile().addImport(pomParent); | |||
String parentFileName = new PomLocator(includePaths, pomParent).getLocation(); | |||
if (parentFileName != null) { | |||
FileParser importedParser = parseCreator.createFileParser(); | |||
try { | |||
importedParser.parse(parentFileName); | |||
} catch (IOException e) { | |||
System.err.println("error occurred during parse "+ parentFileName); | |||
} | |||
} | |||
pomCoords.pop(); | |||
context.currentFile().inferLocalLevelEntities(IBindingResolver); | |||
} | |||
super.exitElement(ctx); | |||
} | |||
private String getParentElementName(ParserRuleContext node) { | |||
node = node.getParent(); | |||
if (node == null) | |||
return "project"; | |||
node = node.getParent(); | |||
if (!(node instanceof ElementContext)) | |||
return "project"; | |||
ElementContext p = (ElementContext) node; | |||
String name = p.Name().get(0).getText(); | |||
return name; | |||
} | |||
} |
@@ -1,126 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.extractor.cpp.cdt; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.util.ArrayList; | |||
import java.util.HashSet; | |||
import java.util.List; | |||
import org.eclipse.cdt.core.dom.ast.IASTFileLocation; | |||
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement; | |||
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement; | |||
import org.eclipse.cdt.internal.core.parser.scanner.ScannerUtility; | |||
import multilang.depends.util.file.FileTraversal; | |||
import multilang.depends.util.file.FileTraversal.IFileVisitor; | |||
import multilang.depends.util.file.FileUtil; | |||
public class PreprocessorHandler { | |||
private List<String> includePaths; | |||
private String inputSrcPath; | |||
private HashSet<String> allFiles = new HashSet<>(); | |||
public PreprocessorHandler(String inputSrcPath, List<String> includePaths){ | |||
this.inputSrcPath = inputSrcPath; | |||
this.includePaths = includePaths; | |||
buildAllFiles(); | |||
} | |||
class AllFileVisitor implements IFileVisitor{ | |||
@Override | |||
public void visit(File file) { | |||
try { | |||
allFiles.add(file.getCanonicalPath()); | |||
} catch (IOException e) { | |||
} | |||
} | |||
} | |||
private void buildAllFiles() { | |||
allFiles = new HashSet<>(); | |||
AllFileVisitor v = new AllFileVisitor(); | |||
if (inputSrcPath!=null) { | |||
FileTraversal ft = new FileTraversal(v,false,true); | |||
ft.travers(inputSrcPath); | |||
} | |||
for (String includePath:includePaths) { | |||
FileTraversal ft = new FileTraversal(v,false,true); | |||
ft.travers(includePath); | |||
} | |||
} | |||
private boolean existFile(String checkPath) { | |||
checkPath = FileUtil.uniformPath(checkPath); | |||
return allFiles.contains(checkPath); | |||
} | |||
public List<String> getDirectIncludedFiles(IASTPreprocessorStatement[] statements, String fileLocation) { | |||
ArrayList<String> includedFullPathNames = new ArrayList<>(); | |||
for (int statementIndex=0;statementIndex<statements.length;statementIndex++) { | |||
if (statements[statementIndex] instanceof IASTPreprocessorIncludeStatement) | |||
{ | |||
IASTPreprocessorIncludeStatement incl = (IASTPreprocessorIncludeStatement)(statements[statementIndex]); | |||
if (!incl.getFileLocation().getFileName().equals(fileLocation)) | |||
continue; | |||
String path = resolveInclude(incl); | |||
if (!existFile(path)) { | |||
continue; | |||
} | |||
if (FileUtil.isDirectory(path)) { | |||
continue; | |||
} | |||
includedFullPathNames.add(path); | |||
} | |||
} | |||
return includedFullPathNames; | |||
} | |||
private String resolveInclude(IASTPreprocessorIncludeStatement incl) { | |||
String path = incl.toString(); | |||
int pos = path.indexOf(' '); | |||
path = path.substring(pos+1).trim(); | |||
if (path.startsWith("\"") || path.startsWith("<")){ | |||
path = path.substring(1); | |||
path = path.substring(0,path.length()-1); | |||
} | |||
//First search in local directory | |||
IASTFileLocation location = incl.getFileLocation(); | |||
String locationDir = FileUtil.getLocatedDir(location.getFileName()); | |||
ArrayList<String> searchPath = new ArrayList<>(); | |||
searchPath.add(locationDir); | |||
searchPath.addAll(includePaths); | |||
for (String includePath:searchPath) { | |||
String checkPath = ScannerUtility.createReconciledPath(includePath,path); | |||
if (existFile(checkPath)) { | |||
return FileUtil.uniqFilePath(checkPath); | |||
} | |||
} | |||
return ""; | |||
} | |||
public List<String> getIncludePaths() { | |||
return includePaths; | |||
} | |||
} |
@@ -1,96 +0,0 @@ | |||
package depends.extractor.python; | |||
import depends.entity.FunctionCall; | |||
import depends.entity.FunctionEntity; | |||
import depends.entity.GenericName; | |||
import depends.entity.TypeEntity; | |||
import depends.entity.repo.BuiltInType; | |||
import depends.relations.FunctionMatcher; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
public class PythonBuiltInType extends BuiltInType { | |||
public static String[] BUILT_IN_FUNCTIONS = { "abs", "delattr", "hash", "memoryview", "set", "all", "dict", "help", | |||
"min", "setattr", "any", "dir", "hex", "next", "slice", "exit", "ascii", "divmod", "id", "object", "sorted", | |||
"bin", "enumerate", "input", "oct", "staticmethod", "bool", "eval", "int", "open", "str", "breakpoint", | |||
"exec", "isinstance", "ord", "sum", "bytearray", "filter", "issubclass", "pow", "super", "bytes", "float", | |||
"iter", "print", "tuple", "callable", "format", "len", "property", "type", "chr", "frozenset", "list", | |||
"range", "vars", "classmethod", "getattr", "locals", "repr", "zip", "compile", "globals", "map", "reversed", | |||
"__import__", "complex", "hasattr", "max", "round" }; | |||
/** | |||
* methods of built-in String | |||
*/ | |||
public static String[] BUILT_IN_STRING_METHODS = { "capitalize", "center", "casefold", "count", "endswith", | |||
"expandtabs", "encode", "find", "format", "index", "isalnum", "isalpha", "isdecimal", "isdigit", | |||
"isidentifier", "islower", "isnumeric", "isprintable", "isspace", "istitle", "isupper", "join", "ljust", | |||
"rjust", "lower", "upper", "swapcase", "lstrip", "rstrip", "strip", "partition", "maketrans", "rpartition", | |||
"translate", "replace", "rfind", "rindex", "split", "rsplit", "splitlines", "startswith", "title", "zfill", | |||
"format_map" }; | |||
/** | |||
* methods of built-in List | |||
*/ | |||
public static String[] BUILT_IN_LIST_METHODS = { "index", "append", "extend", "insert", "remove", "count", "pop", | |||
"reverse", "sort", "copy", "clear" }; | |||
/** | |||
* methods of built-in Tuple | |||
*/ | |||
public static String[] BUILT_IN_TUPLE_METHODS = { "index", "count" }; | |||
/** | |||
* methods of built-in Dict | |||
*/ | |||
public static String[] BUILT_IN_DICT_METHODS = { "clear", "copy", "fromkeys", "get", "items", "keys", "popitem", | |||
"setdefault", "pop", "values", "update", }; | |||
/** | |||
* methods of built-in Set | |||
*/ | |||
public static String[] BUILT_IN_SET_METHODS = { "remove", "add", "copy", "clear", "difference", "difference_update", | |||
"discard", "intersection", "intersection_update", "isdisjoint", "issubset", "pop", "symmetric_difference", | |||
"symmetric_difference_update", "union", "update" }; | |||
/** | |||
* methods of built-in File | |||
*/ | |||
public static String[] BUILT_IN_FILE_METHOD = { "close", "flush", "fileno", "isatty", "next", "read", "readline", | |||
"readlines", "seek", "tell", "truncate", "write", "writelines" }; | |||
List<TypeEntity> buildInTypes = new ArrayList<>(); | |||
public PythonBuiltInType() { | |||
addBuildInType(BUILT_IN_FILE_METHOD); | |||
addBuildInType(BUILT_IN_SET_METHODS); | |||
addBuildInType(BUILT_IN_DICT_METHODS); | |||
addBuildInType(BUILT_IN_TUPLE_METHODS); | |||
addBuildInType(BUILT_IN_LIST_METHODS); | |||
addBuildInType(BUILT_IN_STRING_METHODS); | |||
} | |||
private void addBuildInType(String[] methods) { | |||
TypeEntity type = new TypeEntity(); | |||
for (String method:methods) { | |||
FunctionEntity func = new FunctionEntity(GenericName.build(method),type,-1,GenericName.build("")); | |||
type.addFunction(func); | |||
} | |||
buildInTypes.add(type); | |||
} | |||
@Override | |||
public boolean isBuildInTypeMethods(List<FunctionCall> functionCalls) { | |||
for (TypeEntity type:buildInTypes) { | |||
FunctionMatcher functionMatcher = new FunctionMatcher(type.getFunctions()); | |||
if (functionMatcher.containsAll(functionCalls)) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
} | |||
} |
@@ -1,371 +0,0 @@ | |||
package depends.extractor.python.union; | |||
import depends.entity.*; | |||
import depends.entity.repo.EntityRepo; | |||
import depends.extractor.python.NameAliasImport; | |||
import depends.extractor.python.PythonHandlerContext; | |||
import depends.extractor.python.PythonParser.*; | |||
import depends.extractor.python.PythonParserBaseListener; | |||
import depends.extractor.IncludedFileLocator; | |||
import depends.importtypes.FileImport; | |||
import depends.relations.IBindingResolver; | |||
import multilang.depends.util.file.FileUtil; | |||
import org.antlr.v4.runtime.ParserRuleContext; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
public class PythonCodeListener extends PythonParserBaseListener{ | |||
private final PythonHandlerContext context; | |||
private final ExpressionUsage expressionUsage; | |||
private final EntityRepo entityRepo; | |||
private final IncludedFileLocator includeFileLocator; | |||
private final PythonProcessor pythonProcessor; | |||
private final IBindingResolver bindingResolver; | |||
public PythonCodeListener(String fileFullPath, EntityRepo entityRepo, IBindingResolver bindingResolver, | |||
IncludedFileLocator includeFileLocator, PythonProcessor pythonProcessor) { | |||
this.context = new PythonHandlerContext(entityRepo, bindingResolver); | |||
this.expressionUsage = new ExpressionUsage(context, entityRepo, bindingResolver); | |||
FileEntity fileEntity = context.startFile(fileFullPath); | |||
this.entityRepo = entityRepo; | |||
this.includeFileLocator = includeFileLocator; | |||
this.bindingResolver = bindingResolver; | |||
this.pythonProcessor = pythonProcessor; | |||
String dir = FileUtil.uniqFilePath(FileUtil.getLocatedDir(fileFullPath)); | |||
if (entityRepo.getEntity(dir) == null) { | |||
PackageEntity pacakgeEntity = new PackageEntity(dir, entityRepo.generateId()); | |||
entityRepo.add(pacakgeEntity); | |||
} | |||
PackageEntity packageEntity = (PackageEntity) entityRepo.getEntity(dir); | |||
String moduleName = fileEntity.getRawName().uniqName().substring(packageEntity.getRawName().uniqName().length() + 1); | |||
if (moduleName.endsWith(".py")) | |||
moduleName.substring(0, moduleName.length() - ".py".length()); | |||
Entity.setParent(fileEntity, packageEntity); | |||
packageEntity.addChild(FileUtil.getShortFileName(fileEntity.getRawName().uniqName()).replace(".py", ""), fileEntity); | |||
} | |||
@Override | |||
public void enterImport_stmt(Import_stmtContext ctx) { | |||
String moduleName = null; | |||
for(Dotted_as_nameContext dotted_as_name:ctx.dotted_as_names().dotted_as_name()){ | |||
moduleName = getName(dotted_as_name.dotted_name()); | |||
String aliasName = moduleName; | |||
if (dotted_as_name.name()!=null) { | |||
aliasName = dotted_as_name.name().getText(); | |||
} | |||
List<String> fullNames = foundImportedModuleOrPackage(0,moduleName); | |||
for (String fullName:fullNames) { | |||
if (FileUtil.existFile(fullName) && !(FileUtil.isDirectory(fullName))) { | |||
context.foundNewImport(new FileImport(fullName)); | |||
} | |||
context.foundNewImport(new NameAliasImport(fullName, entityRepo.getEntity(fullName), aliasName)); | |||
} | |||
} | |||
super.enterImport_stmt(ctx); | |||
} | |||
@Override | |||
public void enterFrom_stmt(From_stmtContext ctx) { | |||
String moduleName = null; | |||
if (ctx.dotted_name() != null) { | |||
moduleName = ctx.dotted_name().getText(); | |||
} | |||
int prefixDotCount = getDotCounter(ctx); | |||
List<String> fullNames = foundImportedModuleOrPackage(prefixDotCount, moduleName); | |||
for (String fullName:fullNames) { | |||
if (ctx.import_as_names() == null) {// import * | |||
ContainerEntity moduleEntity = (ContainerEntity) (entityRepo.getEntity(fullName)); | |||
if (moduleEntity != null) { | |||
for (Entity child:moduleEntity.getChildren()) { | |||
context.foundNewImport(new NameAliasImport(fullName, child, child.getRawName().uniqName())); | |||
context.foundNewAlias(child.getRawName(), child); | |||
} | |||
if (moduleEntity instanceof PackageEntity) { | |||
for (Entity file : moduleEntity.getChildren()) { | |||
if (file instanceof FileEntity) { | |||
String fileName = file.getRawName().uniqName().substring(fullName.length()); | |||
context.foundNewImport(new NameAliasImport(file.getRawName().uniqName(), file, fileName)); | |||
context.foundNewAlias(GenericName.build(FileUtil.getShortFileName(fileName).replace(".py", "")), file); | |||
}else { | |||
context.foundNewImport(new NameAliasImport(file.getRawName().uniqName(), file, file.getRawName().uniqName())); | |||
context.foundNewAlias(GenericName.build(FileUtil.getShortFileName(file.getRawName().uniqName())), file); | |||
} | |||
} | |||
} | |||
if (moduleEntity instanceof FileEntity) { | |||
String fileName = moduleEntity.getRawName().uniqName().substring(fullName.length()); | |||
context.foundNewImport(new NameAliasImport(moduleEntity.getRawName().uniqName(), moduleEntity, fileName)); | |||
} | |||
} | |||
} else { | |||
for (Import_as_nameContext item : ctx.import_as_names().import_as_name()) { | |||
String name = item.name(0).getText(); | |||
String alias = name; | |||
if (item.name().size() > 1) | |||
alias = item.name(1).getText(); | |||
if (FileUtil.isDirectory(fullName)) { | |||
String fileName = fullName + File.separator + name + ".py"; | |||
if (FileUtil.existFile(fileName) && !(FileUtil.isDirectory(fileName))) { | |||
context.foundNewImport(new FileImport(fileName)); | |||
} | |||
} | |||
if (FileUtil.existFile(fullName) && !(FileUtil.isDirectory(fullName))) { | |||
context.foundNewImport(new FileImport(fullName)); | |||
} | |||
Entity itemEntity = bindingResolver.resolveName(entityRepo.getEntity(fullName), GenericName.build(name), true); | |||
if (itemEntity != null) { | |||
context.foundNewAlias(GenericName.build(alias), itemEntity); | |||
context.foundNewImport(new NameAliasImport(itemEntity.getQualifiedName(), itemEntity, alias)); | |||
} | |||
} | |||
} | |||
} | |||
super.enterFrom_stmt(ctx); | |||
} | |||
private int getDotCounter(From_stmtContext ctx) { | |||
int total = 0; | |||
if (ctx.DOT()!=null){ | |||
total = ctx.DOT().size(); | |||
} | |||
if (ctx.ELLIPSIS()!=null) { | |||
total += ctx.ELLIPSIS().size()*3; | |||
} | |||
return total; | |||
} | |||
private List<String> foundImportedModuleOrPackage(int prefixDotCount, String originalName) { | |||
String dir = FileUtil.getLocatedDir(context.currentFile().getRawName().uniqName()); | |||
String preFix = ""; | |||
for (int i = 0; i < prefixDotCount - 1; i++) { | |||
preFix = preFix + ".." + File.separator; | |||
} | |||
dir = dir + File.separator + preFix; | |||
String fullName = null; | |||
if (originalName != null) { | |||
String importedName = originalName.replace(".", File.separator); | |||
fullName = includeFileLocator.uniqFileName(dir, importedName); | |||
if (fullName == null) { | |||
fullName = includeFileLocator.uniqFileName(dir, importedName + ".py"); | |||
} | |||
} else { | |||
fullName = FileUtil.uniqFilePath(dir); | |||
} | |||
if (fullName != null) { | |||
if (FileUtil.isDirectory(fullName)) { | |||
if (!FileUtil.uniqFilePath(fullName).equals(FileUtil.uniqFilePath(dir))) { | |||
File d = new File(fullName); | |||
File[] files = d.listFiles(); | |||
for (File file : files) { | |||
if (!file.isDirectory()) { | |||
if (file.getAbsolutePath().endsWith(".py")) { | |||
visitIncludedFile(FileUtil.uniqFilePath(file.getAbsolutePath())); | |||
} | |||
} | |||
} | |||
} | |||
} else { | |||
visitIncludedFile(fullName); | |||
} | |||
} | |||
ArrayList<String> r = new ArrayList<>(); | |||
if (fullName==null) return r; | |||
r.add(fullName); | |||
if (FileUtil.existFile(fullName+File.separator + "__init__.py")) { | |||
r.add( fullName+File.separator +"__init__.py"); | |||
} | |||
return r; | |||
} | |||
private void visitIncludedFile(String fullName) { | |||
PythonFileParser importedParser = new PythonFileParser(entityRepo, includeFileLocator, bindingResolver, | |||
pythonProcessor); | |||
try { | |||
importedParser.parse(fullName); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
@Override | |||
public void enterFuncdef(FuncdefContext ctx) { | |||
String functionName ="<empty>"; | |||
String name = getName(ctx.name()); | |||
if (name!=null) { | |||
functionName = name; | |||
} | |||
FunctionEntity method = context.foundMethodDeclarator(functionName,ctx.getStart().getLine()); | |||
if (ctx.typedargslist()!=null) { | |||
List<String> parameters = getParameterList(ctx.typedargslist().def_parameters()); | |||
for (String param : parameters) { | |||
VarEntity paramEntity = context.addMethodParameter(param); | |||
if (param.equals("self")) { | |||
paramEntity.setType(context.currentType()); | |||
} | |||
} | |||
} | |||
super.enterFuncdef(ctx); | |||
} | |||
@Override | |||
public void exitFuncdef(FuncdefContext ctx) { | |||
context.exitLastedEntity(); | |||
super.exitFuncdef(ctx); | |||
} | |||
@Override | |||
public void enterClassdef(ClassdefContext ctx) { | |||
String name = getName(ctx.name()); | |||
TypeEntity type = context.foundNewType(name, ctx.getStart().getLine()); | |||
List<String> baseClasses = getArgList(ctx.arglist()); | |||
baseClasses.forEach(base -> type.addExtends(GenericName.build(base))); | |||
super.enterClassdef(ctx); | |||
} | |||
@Override | |||
public void exitClassdef(ClassdefContext ctx) { | |||
context.exitLastedEntity(); | |||
super.exitClassdef(ctx); | |||
} | |||
private List<String> getParameterList(List<Def_parametersContext> def_parameters) { | |||
List<String> result = new ArrayList<>(); | |||
for (Def_parametersContext params:def_parameters) { | |||
for (Def_parameterContext param:params.def_parameter()) { | |||
String p = getName( param.named_parameter().name()); | |||
result.add(p); | |||
} | |||
} | |||
return result; | |||
} | |||
private String getName(NameContext name) { | |||
return name.getText(); | |||
} | |||
private String getName(Dotted_nameContext dotted_name) { | |||
return dotted_name.getText(); | |||
} | |||
private String getDecoratedName(Class_or_func_def_stmtContext ctx) { | |||
if (ctx.classdef()!=null) { | |||
return getName(ctx.classdef().name()); | |||
}else if (ctx.funcdef()!=null) { | |||
return getName(ctx.funcdef().name()); | |||
} | |||
return null; | |||
} | |||
private List<String> getArgList(ArglistContext arglist) { | |||
List<String> r = new ArrayList<>(); | |||
if (arglist==null) return r; | |||
if (arglist.argument() == null) return r; | |||
if (arglist.argument().isEmpty()) return r; | |||
arglist.argument().forEach(arg->r.add(arg.getText())); | |||
return r; | |||
} | |||
/** | |||
* class_or_func_def_stmt: decorator+ (classdef | funcdef); | |||
*/ | |||
@Override | |||
public void exitClass_or_func_def_stmt(Class_or_func_def_stmtContext ctx) { | |||
String decoratedName = getDecoratedName(ctx); | |||
if (decoratedName!=null) { | |||
Entity entity = context.foundEntityWithName(GenericName.build(decoratedName)); | |||
entity.setLine(ctx.getStart().getLine()); | |||
if (entity instanceof DecoratedEntity) { | |||
for (DecoratorContext decorator: ctx.decorator()) { | |||
String decoratorName = getName(decorator.dotted_name()); | |||
((DecoratedEntity) entity).addAnnotation(GenericName.build(decoratorName)); | |||
} | |||
} | |||
} | |||
super.exitClass_or_func_def_stmt(ctx); | |||
} | |||
@Override | |||
public void enterGlobal_stmt(Global_stmtContext ctx) { | |||
for (NameContext name:ctx.name()){ | |||
VarEntity var = context.foundGlobalVarDefinition(context.currentFile(), name.getText(),ctx.getStart().getLine()); | |||
} | |||
super.enterGlobal_stmt(ctx); | |||
} | |||
@Override | |||
public void enterEveryRule(ParserRuleContext ctx) { | |||
expressionUsage.foundExpression(ctx); | |||
super.enterEveryRule(ctx); | |||
} | |||
@Override | |||
public void enterExpr_stmt(Expr_stmtContext ctx) { | |||
expressionUsage.startExpr(); | |||
super.enterExpr_stmt(ctx); | |||
} | |||
@Override | |||
public void exitExpr_stmt(Expr_stmtContext ctx) { | |||
expressionUsage.stopExpr(); | |||
super.exitExpr_stmt(ctx); | |||
} | |||
@Override | |||
public void enterDel_stmt(Del_stmtContext ctx) { | |||
expressionUsage.startExpr(); | |||
super.enterDel_stmt(ctx); | |||
} | |||
@Override | |||
public void exitDel_stmt(Del_stmtContext ctx) { | |||
expressionUsage.stopExpr(); | |||
super.exitDel_stmt(ctx); | |||
} | |||
@Override | |||
public void enterReturn_stmt(Return_stmtContext ctx) { | |||
expressionUsage.startExpr(); | |||
super.enterReturn_stmt(ctx); | |||
} | |||
@Override | |||
public void exitReturn_stmt(Return_stmtContext ctx) { | |||
expressionUsage.stopExpr(); | |||
super.exitReturn_stmt(ctx); | |||
} | |||
@Override | |||
public void enterRaise_stmt(Raise_stmtContext ctx) { | |||
expressionUsage.startExpr(); | |||
super.enterRaise_stmt(ctx); | |||
} | |||
@Override | |||
public void exitRaise_stmt(Raise_stmtContext ctx) { | |||
expressionUsage.stopExpr(); | |||
super.exitRaise_stmt(ctx); | |||
} | |||
@Override | |||
public void enterYield_stmt(Yield_stmtContext ctx) { | |||
expressionUsage.startExpr(); | |||
super.enterYield_stmt(ctx); | |||
} | |||
@Override | |||
public void exitYield_stmt(Yield_stmtContext ctx) { | |||
expressionUsage.stopExpr(); | |||
super.exitYield_stmt(ctx); | |||
} | |||
@Override | |||
public void enterAssert_stmt(Assert_stmtContext ctx) { | |||
expressionUsage.startExpr(); | |||
super.enterAssert_stmt(ctx); | |||
} | |||
@Override | |||
public void exitAssert_stmt(Assert_stmtContext ctx) { | |||
expressionUsage.stopExpr(); | |||
super.exitAssert_stmt(ctx); | |||
} | |||
} |
@@ -1,284 +0,0 @@ | |||
package depends.extractor.python; | |||
import depends.deptypes.DependencyType; | |||
import depends.entity.Entity; | |||
import depends.entity.FileEntity; | |||
import depends.entity.FunctionEntity; | |||
import depends.entity.MultiDeclareEntities; | |||
import depends.extractor.python.union.PythonFileParser; | |||
import multilang.depends.util.file.FileUtil; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import java.io.IOException; | |||
public class PythonImportTest extends PythonParserTest { | |||
@Before | |||
public void setUp() { | |||
super.init(); | |||
} | |||
@Test | |||
public void should_parse_module_in_same_package() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/python-code-examples/imported_a.py", | |||
"./src/test/resources/python-code-examples/importing.py", | |||
}; | |||
for (String src:srcs) { | |||
PythonFileParser parser = createParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
Entity file = entityRepo.getEntity(FileUtil.uniqFilePath(srcs[1])); | |||
this.assertContainsRelation(file, DependencyType.IMPORT,FileUtil.uniqFilePath(srcs[0])); | |||
} | |||
@Test | |||
public void should_parse_module_in_same_package_order_robust() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/python-code-examples/importing.py", | |||
"./src/test/resources/python-code-examples/imported_a.py", | |||
}; | |||
for (String src:srcs) { | |||
PythonFileParser parser = createParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
Entity file = entityRepo.getEntity(FileUtil.uniqFilePath(srcs[0])); | |||
this.assertContainsRelation(file, DependencyType.IMPORT,FileUtil.uniqFilePath(srcs[1])); | |||
this.assertContainsRelation(file, DependencyType.CALL,withPackageName(srcs[0],"foo")); | |||
} | |||
@Test | |||
public void should_parse_module_in_same_package_with_alias() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/python-code-examples/importing_with_alias.py", | |||
"./src/test/resources/python-code-examples/imported_a.py", | |||
}; | |||
for (String src:srcs) { | |||
PythonFileParser parser = createParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
Entity file = entityRepo.getEntity(FileUtil.uniqFilePath(srcs[0])); | |||
this.assertContainsRelation(file, DependencyType.IMPORT,FileUtil.uniqFilePath(srcs[1])); | |||
this.assertContainsRelation(file, DependencyType.CALL,withPackageName(srcs[0],"foo")); | |||
} | |||
@Test | |||
public void should_parse_module_in_from_importing() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/python-code-examples/from_importing.py", | |||
"./src/test/resources/python-code-examples/imported_a.py", | |||
}; | |||
for (String src:srcs) { | |||
PythonFileParser parser = createParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
Entity file = entityRepo.getEntity(FileUtil.uniqFilePath(srcs[0])); | |||
this.assertContainsRelation(file, DependencyType.CALL,withPackageName(srcs[0],"foo")); | |||
this.assertContainsRelation(file, DependencyType.IMPORT,FileUtil.uniqFilePath(srcs[1])); | |||
} | |||
@Test | |||
public void should_parse_module_in_from_importing_star() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/python-code-examples/from_importing_star.py", | |||
"./src/test/resources/python-code-examples/imported_a.py", | |||
}; | |||
for (String src:srcs) { | |||
PythonFileParser parser = createParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
Entity file = entityRepo.getEntity(FileUtil.uniqFilePath(srcs[0])); | |||
this.assertContainsRelation(file, DependencyType.CALL,withPackageName(srcs[0],"foo")); | |||
this.assertContainsRelation(file, DependencyType.IMPORT,FileUtil.uniqFilePath(srcs[1])); | |||
} | |||
@Test | |||
public void should_parse_import_with_multi_dots() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/python-code-examples/from_importing_multidot.py", | |||
"./src/test/resources/python-code-examples/pkg/imported.py", | |||
}; | |||
for (String src:srcs) { | |||
PythonFileParser parser = createParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
Entity file = entityRepo.getEntity(FileUtil.uniqFilePath(srcs[0])); | |||
this.assertContainsRelation(file, DependencyType.IMPORT,FileUtil.uniqFilePath(srcs[1])); | |||
this.assertContainsRelation(file, DependencyType.CALL,withPackageName(srcs[1],"foo")); | |||
} | |||
@Test | |||
public void should_parse_import_with_prefix_dots() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/python-code-examples/import_with_dir/importing.py", | |||
"./src/test/resources/python-code-examples/import_with_dir/imported_a.py", | |||
"./src/test/resources/python-code-examples/import_with_dir/subdir/importing.py", | |||
"./src/test/resources/python-code-examples/import_with_dir/subdir/importing2.py", | |||
}; | |||
for (String src:srcs) { | |||
PythonFileParser parser = createParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
this.assertContainsRelation(entityRepo.getEntity(FileUtil.uniqFilePath(srcs[0])), DependencyType.IMPORT,FileUtil.uniqFilePath(srcs[1])); | |||
this.assertContainsRelation(entityRepo.getEntity(FileUtil.uniqFilePath(srcs[2])), DependencyType.IMPORT,FileUtil.uniqFilePath(srcs[1])); | |||
this.assertContainsRelation(entityRepo.getEntity(FileUtil.uniqFilePath(srcs[3])), DependencyType.IMPORT,FileUtil.uniqFilePath(srcs[1])); | |||
} | |||
@Test | |||
public void should_parse_import_with_prefix_dots2() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/python-code-examples/import_with_dir/subdir/importing2.py", | |||
}; | |||
for (String src:srcs) { | |||
PythonFileParser parser = createParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
} | |||
@Test | |||
public void should_import_from_package__init__file() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/python-code-examples/import_from_init/importing.py", | |||
"./src/test/resources/python-code-examples/import_from_init/pkg/__init__.py", | |||
}; | |||
for (String src:srcs) { | |||
PythonFileParser parser = createParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
this.assertContainsRelation(entityRepo.getEntity(FileUtil.uniqFilePath(srcs[0])), DependencyType.IMPORT,FileUtil.uniqFilePath(srcs[1])); | |||
} | |||
@Test | |||
public void should_not_bypass_import_in_same_dir() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/python-code-examples/import_of_same_dir/pkg/importing.py", | |||
"./src/test/resources/python-code-examples/import_of_same_dir/pkg/a.py", | |||
}; | |||
for (String src:srcs) { | |||
PythonFileParser parser = createParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
this.assertContainsRelation(entityRepo.getEntity(FileUtil.uniqFilePath(srcs[0])), DependencyType.IMPORT,FileUtil.uniqFilePath(srcs[1])); | |||
} | |||
@Test | |||
public void should_resolve_symbols_of_imported_in_same_dir() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/python-code-examples/import_of_same_dir/pkg/importing.py", | |||
"./src/test/resources/python-code-examples/import_of_same_dir/pkg/a.py", | |||
}; | |||
for (String src:srcs) { | |||
PythonFileParser parser = createParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
FunctionEntity func = (FunctionEntity) entityRepo.getEntity(withPackageName(srcs[0],"test")); | |||
this.assertContainsRelation(func, DependencyType.CALL, withPackageName(srcs[1],"foo")); | |||
} | |||
@Test | |||
public void should_resolve_symbols_of_ducktyping() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/python-code-examples/duck_typing/forest.py", | |||
"./src/test/resources/python-code-examples/duck_typing/animals.py", | |||
"./src/test/resources/python-code-examples/duck_typing/controller.py", | |||
}; | |||
for (String src:srcs) { | |||
PythonFileParser parser = createParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
MultiDeclareEntities funcs = (MultiDeclareEntities) entityRepo.getEntity(withPackageName(srcs[1],"in_the_forest")); | |||
Entity func = funcs.getEntities().get(0); | |||
this.assertContainsRelation(func, DependencyType.CALL, withPackageName(srcs[1],"Duck.quack")); | |||
this.assertContainsRelation(func, DependencyType.CALL, withPackageName(srcs[1],"Doge.quack")); | |||
this.assertContainsRelation(func, DependencyType.CALL, withPackageName(srcs[1],"Bird.quack")); | |||
} | |||
@Test | |||
public void should_resolve_symbols_of_ducktyping2() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/python-code-examples/duck_typing/animals.py", | |||
"./src/test/resources/python-code-examples/duck_typing/forest.py", | |||
"./src/test/resources/python-code-examples/duck_typing/controller.py", | |||
}; | |||
for (String src:srcs) { | |||
PythonFileParser parser = createParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
MultiDeclareEntities funcs = (MultiDeclareEntities) entityRepo.getEntity(withPackageName(srcs[1],"in_the_forest")); | |||
Entity func = funcs.getEntities().get(0); | |||
this.assertContainsRelation(func, DependencyType.CALL, withPackageName(srcs[0],"Duck.quack")); | |||
this.assertContainsRelation(func, DependencyType.CALL, withPackageName(srcs[0],"Bird.quack")); | |||
this.assertContainsRelation(func, DependencyType.CALL, withPackageName(srcs[0],"Doge.quack")); | |||
} | |||
@Test | |||
public void should_resolve_imported_symbols() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/python-code-examples/import_from_init/use_imported.py", | |||
"./src/test/resources/python-code-examples/import_from_init/pkg/__init__.py", | |||
"./src/test/resources/python-code-examples/import_from_init/pkg/core.py", | |||
}; | |||
for (String src:srcs) { | |||
PythonFileParser parser = createParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
FunctionEntity func = (FunctionEntity) entityRepo.getEntity(withPackageName(srcs[0],"bar")); | |||
this.assertContainsRelation(func, DependencyType.CALL, withPackageName(srcs[2],"C")); | |||
} | |||
@Test | |||
public void should_resolve_imported_vars() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/python-code-examples/import_from_var/use_imported.py", | |||
"./src/test/resources/python-code-examples/import_from_var/pkg/core.py", | |||
}; | |||
for (String src:srcs) { | |||
PythonFileParser parser = createParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
FileEntity f = (FileEntity) entityRepo.getEntity(FileUtil.uniqFilePath(srcs[0])); | |||
this.assertContainsRelation(f, DependencyType.CALL, withPackageName(srcs[1],"Core.foo")); | |||
} | |||
} |
@@ -1,186 +0,0 @@ | |||
package depends.extractor.python.union; | |||
import org.antlr.v4.runtime.CharStream; | |||
import org.antlr.v4.runtime.CommonToken; | |||
import org.antlr.v4.runtime.Lexer; | |||
import org.antlr.v4.runtime.Token; | |||
import depends.extractor.python.PythonLexer; | |||
import java.util.Stack; | |||
public abstract class PythonLexerBase extends Lexer { | |||
public static int TabSize = 8; | |||
// The amount of opened braces, brackets and parenthesis. | |||
private int _opened; | |||
// The stack that keeps track of the indentation level. | |||
private Stack<Integer> _indents = new Stack<>(); | |||
// A circular buffer where extra tokens are pushed on (see the NEWLINE and WS lexer rules). | |||
private int _firstTokensInd; | |||
private int _lastTokenInd; | |||
private Token[] _buffer = new Token[32]; | |||
private Token _lastToken; | |||
protected PythonLexerBase(CharStream input) { | |||
super(input); | |||
} | |||
@Override | |||
public void emit(Token token) { | |||
super.setToken(token); | |||
if (_buffer[_firstTokensInd] != null) | |||
{ | |||
_lastTokenInd = IncTokenInd(_lastTokenInd); | |||
if (_lastTokenInd == _firstTokensInd) | |||
{ | |||
// Enlarge buffer | |||
Token[] newArray = new Token[_buffer.length * 2]; | |||
int destInd = newArray.length - (_buffer.length - _firstTokensInd); | |||
System.arraycopy(_buffer, 0, newArray, 0, _firstTokensInd); | |||
System.arraycopy(_buffer, _firstTokensInd, newArray, destInd, _buffer.length - _firstTokensInd); | |||
_firstTokensInd = destInd; | |||
_buffer = newArray; | |||
} | |||
} | |||
_buffer[_lastTokenInd] = token; | |||
_lastToken = token; | |||
} | |||
@Override | |||
public Token nextToken() { | |||
// Check if the end-of-file is ahead and there are still some DEDENTS expected. | |||
if (_input.LA(1) == EOF && _indents.size() > 0) | |||
{ | |||
if (_buffer[_lastTokenInd] == null || _buffer[_lastTokenInd].getType() != PythonLexer.LINE_BREAK) | |||
{ | |||
// First emit an extra line break that serves as the end of the statement. | |||
emit(PythonLexer.LINE_BREAK); | |||
} | |||
// Now emit as much DEDENT tokens as needed. | |||
while (_indents.size() != 0) | |||
{ | |||
emit(PythonLexer.DEDENT); | |||
_indents.pop(); | |||
} | |||
} | |||
Token next = super.nextToken(); | |||
if (_buffer[_firstTokensInd] == null) | |||
{ | |||
return next; | |||
} | |||
Token result = _buffer[_firstTokensInd]; | |||
_buffer[_firstTokensInd] = null; | |||
if (_firstTokensInd != _lastTokenInd) | |||
{ | |||
_firstTokensInd = IncTokenInd(_firstTokensInd); | |||
} | |||
return result; | |||
} | |||
protected void HandleNewLine() { | |||
emit(PythonLexer.NEWLINE, HIDDEN, getText()); | |||
char next = (char) _input.LA(1); | |||
// Process whitespaces in HandleSpaces | |||
if (next != ' ' && next != '\t' && IsNotNewLineOrComment(next)) | |||
{ | |||
ProcessNewLine(0); | |||
} | |||
} | |||
protected void HandleSpaces() { | |||
char next = (char) _input.LA(1); | |||
if ((_lastToken == null || _lastToken.getType() == PythonLexer.NEWLINE) && IsNotNewLineOrComment(next)) | |||
{ | |||
// Calculates the indentation of the provided spaces, taking the | |||
// following rules into account: | |||
// | |||
// "Tabs are replaced (from left to right) by one to eight spaces | |||
// such that the total number of characters up to and including | |||
// the replacement is a multiple of eight [...]" | |||
// | |||
// -- https://docs.python.org/3.1/reference/lexical_analysis.html#indentation | |||
int indent = 0; | |||
String text = getText(); | |||
for (int i = 0; i < text.length(); i++) { | |||
indent += text.charAt(i) == '\t' ? TabSize - indent % TabSize : 1; | |||
} | |||
ProcessNewLine(indent); | |||
} | |||
emit(PythonLexer.WS, HIDDEN, getText()); | |||
} | |||
protected void IncIndentLevel() { | |||
_opened++; | |||
} | |||
protected void DecIndentLevel() { | |||
if (_opened > 0) { | |||
--_opened; | |||
} | |||
} | |||
private boolean IsNotNewLineOrComment(char next) { | |||
return _opened == 0 && next != '\r' && next != '\n' && next != '\f' && next != '#'; | |||
} | |||
private void ProcessNewLine(int indent) { | |||
emit(PythonLexer.LINE_BREAK); | |||
int previous = _indents.size() == 0 ? 0 : _indents.peek(); | |||
if (indent > previous) | |||
{ | |||
_indents.push(indent); | |||
emit(PythonLexer.INDENT); | |||
} | |||
else | |||
{ | |||
// Possibly emit more than 1 DEDENT token. | |||
while (_indents.size() != 0 && _indents.peek() > indent) | |||
{ | |||
emit(PythonLexer.DEDENT); | |||
_indents.pop(); | |||
} | |||
} | |||
} | |||
private int IncTokenInd(int ind) { | |||
return (ind + 1) % _buffer.length; | |||
} | |||
private void emit(int tokenType) { | |||
emit(tokenType, DEFAULT_TOKEN_CHANNEL, ""); | |||
} | |||
private void emit(int tokenType, int channel, String text) { | |||
int charIndex = getCharIndex(); | |||
CommonToken token = new CommonToken(_tokenFactorySourcePair, tokenType, channel, charIndex - text.length(), charIndex); | |||
token.setLine(getLine()); | |||
token.setCharPositionInLine(getCharPositionInLine()); | |||
token.setText(text); | |||
emit(token); | |||
} | |||
} | |||
@@ -1,118 +0,0 @@ | |||
package depends.extractor.python; | |||
import depends.entity.CandidateTypes; | |||
import depends.entity.FunctionEntity; | |||
import depends.entity.TypeEntity; | |||
import depends.entity.VarEntity; | |||
import depends.extractor.FileParser; | |||
import org.junit.Before; | |||
import org.junit.Ignore; | |||
import org.junit.Test; | |||
import java.io.IOException; | |||
import static org.junit.Assert.*; | |||
public class PythonParameterTypeDedudceTest extends PythonParserTest { | |||
@Before | |||
public void setUp() { | |||
super.init(); | |||
} | |||
@Test | |||
public void test_deduce_type_of_parameter() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/python-code-examples/deducetype_parameter.py", | |||
}; | |||
for (String src:srcs) { | |||
FileParser parser = createFileParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
String name = withPackageName(srcs[0],"test"); | |||
FunctionEntity function = (FunctionEntity)( entityRepo.getEntity(name)); | |||
VarEntity var = function.lookupVarLocally("t1"); | |||
TypeEntity type = var.getType(); | |||
assertTrue(type instanceof CandidateTypes); | |||
assertEquals(2,((CandidateTypes)type).getCandidateTypes().size()); | |||
} | |||
@Test | |||
public void test_deduce_type_of_builtIn() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/python-code-examples/deducetype_builtin.py", | |||
}; | |||
for (String src:srcs) { | |||
FileParser parser = createFileParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
String name = withPackageName(srcs[0],"test"); | |||
FunctionEntity function = (FunctionEntity)( entityRepo.getEntity(name)); | |||
VarEntity var = function.lookupVarLocally("t1"); | |||
TypeEntity type = var.getType(); | |||
assertTrue(type == null); | |||
} | |||
@Test | |||
public void test_deduce_type_of_builtIn_cannot_override() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/python-code-examples/deducetype_builtin.py", | |||
}; | |||
for (String src:srcs) { | |||
FileParser parser = createFileParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
String name = withPackageName(srcs[0],"test2"); | |||
FunctionEntity function = (FunctionEntity)( entityRepo.getEntity(name)); | |||
VarEntity var = function.lookupVarLocally("t1"); | |||
TypeEntity type = var.getType(); | |||
assertTrue(type instanceof CandidateTypes); | |||
assertEquals(1,((CandidateTypes)type).getCandidateTypes().size()); | |||
} | |||
@Ignore | |||
public void test_deduce_type_of_non_param_var() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/python-code-examples/deducetype_nonparam.py", | |||
}; | |||
for (String src:srcs) { | |||
FileParser parser = createFileParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
String name = withPackageName(srcs[0],"test"); | |||
FunctionEntity function = (FunctionEntity)( entityRepo.getEntity(name)); | |||
VarEntity var = function.lookupVarLocally("t2"); | |||
TypeEntity type = var.getType(); | |||
assertTrue(type instanceof CandidateTypes); | |||
assertEquals(2,((CandidateTypes)type).getCandidateTypes().size()); | |||
} | |||
@Test | |||
public void test_expression_count_should_be_() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/python-code-examples/expression_reload_issue_test.py", | |||
}; | |||
for (String src:srcs) { | |||
FileParser parser = createFileParser(); | |||
parser.parse(src); | |||
} | |||
resolveAllBindings(); | |||
String name = withPackageName(srcs[0],"test_expression"); | |||
FunctionEntity function = (FunctionEntity)( entityRepo.getEntity(name)); | |||
assertNotNull(function); | |||
} | |||
} | |||
@@ -1,246 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.relations; | |||
import depends.deptypes.DependencyType; | |||
import depends.entity.*; | |||
import depends.entity.repo.EntityRepo; | |||
import depends.extractor.AbstractLangProcessor; | |||
import java.util.Collection; | |||
import java.util.List; | |||
import java.util.stream.Collectors; | |||
public class RelationCounter { | |||
private Collection<Entity> entities; | |||
private IBindingResolver bindingResolver; | |||
private EntityRepo repo; | |||
private boolean callAsImpl; | |||
private AbstractLangProcessor langProcessor; | |||
public RelationCounter(EntityRepo repo, AbstractLangProcessor langProcessor, IBindingResolver bindingResolver) { | |||
this.entities = repo.getFileEntities(); | |||
this.bindingResolver = bindingResolver; | |||
this.repo = repo; | |||
this.callAsImpl = langProcessor.supportCallAsImpl(); | |||
this.langProcessor = langProcessor; | |||
} | |||
public void computeRelations() { | |||
entities.forEach(entity-> | |||
computeRelationOf(entity)); | |||
} | |||
private void computeRelationOf(Entity entity) { | |||
if (!entity.inScope()) | |||
return; | |||
if (entity instanceof FileEntity) { | |||
computeImports((FileEntity)entity); | |||
} | |||
else if (entity instanceof FunctionEntity) { | |||
computeFunctionRelations((FunctionEntity)entity); | |||
} | |||
else if (entity instanceof TypeEntity) { | |||
computeTypeRelations((TypeEntity)entity); | |||
} | |||
if (entity instanceof ContainerEntity) { | |||
computeContainerRelations((ContainerEntity)entity); | |||
} | |||
entity.getChildren().forEach(child->computeRelationOf(child)); | |||
} | |||
private void computeContainerRelations(ContainerEntity entity) { | |||
for (VarEntity var:entity.getVars()) { | |||
if (var.getType()!=null) | |||
entity.addRelation(buildRelation(entity,DependencyType.CONTAIN,var.getType(),var.getLocation())); | |||
for (Entity type:var.getResolvedTypeParameters()) { | |||
var.addRelation(buildRelation(var, DependencyType.PARAMETER,type,type.getLocation())); | |||
} | |||
} | |||
for (Entity type:entity.getResolvedAnnotations()) { | |||
entity.addRelation(buildRelation(entity,DependencyType.ANNOTATION,type)); | |||
} | |||
for (Entity type:entity.getResolvedTypeParameters()) { | |||
entity.addRelation(buildRelation(entity,DependencyType.USE,type)); | |||
} | |||
for (ContainerEntity mixin:entity.getResolvedMixins()) { | |||
entity.addRelation(buildRelation(entity,DependencyType.MIXIN,mixin)); | |||
} | |||
entity.reloadExpression(repo); | |||
if (!bindingResolver.isEagerExpressionResolve()) | |||
{ | |||
entity.resolveExpressions(bindingResolver); | |||
} | |||
for (Expression expression:entity.expressionList()){ | |||
if (expression.isStatement()) { | |||
continue; | |||
} | |||
Entity referredEntity = expression.getReferredEntity(); | |||
addRelationFromExpression(entity, expression, referredEntity); | |||
} | |||
entity.clearExpressions(); | |||
} | |||
private void addRelationFromExpression(ContainerEntity entity, Expression expression, Entity referredEntity) { | |||
if (referredEntity==null) { | |||
return; | |||
} | |||
if (referredEntity.getId()<0){ | |||
return; | |||
} | |||
if (referredEntity instanceof MultiDeclareEntities) { | |||
for (Entity e:((MultiDeclareEntities)referredEntity).getEntities()) { | |||
addRelationFromExpression(entity,expression,e); | |||
} | |||
return; | |||
} | |||
boolean matched = false; | |||
if (expression.isCall()) { | |||
/* if it is a FunctionEntityProto, add Relation to all Impl Entities*/ | |||
if (callAsImpl && referredEntity instanceof FunctionEntityProto) { | |||
if (entity.getAncestorOfType(FileEntity.class).getId().equals(referredEntity.getAncestorOfType(FileEntity.class).getId())){ | |||
entity.addRelation(buildRelation(entity,DependencyType.CALL,referredEntity,expression.getLocation())); | |||
}else { | |||
Entity multiDeclare = repo.getEntity(referredEntity.getQualifiedName()); | |||
if (multiDeclare instanceof MultiDeclareEntities) { | |||
MultiDeclareEntities m = (MultiDeclareEntities) multiDeclare; | |||
List<Entity> entities = m.getEntities().stream().filter(item -> (item instanceof FunctionEntityImpl)) | |||
.collect(Collectors.toList()); | |||
for (Entity e : entities) { | |||
entity.addRelation(expression, buildRelation(entity, DependencyType.IMPLLINK, e, expression.getLocation())); | |||
matched = true; | |||
} | |||
} | |||
} | |||
} | |||
entity.addRelation(buildRelation(entity,DependencyType.CALL,referredEntity,expression.getLocation())); | |||
matched = true; | |||
} | |||
if (expression.isCreate()) { | |||
entity.addRelation(buildRelation(entity,DependencyType.CREATE,referredEntity,expression.getLocation())); | |||
matched = true; | |||
} | |||
if (expression.isThrow()) { | |||
entity.addRelation(buildRelation(entity,DependencyType.THROW,referredEntity,expression.getLocation())); | |||
matched = true; | |||
} | |||
if (expression.isCast()) { | |||
entity.addRelation(buildRelation(entity,DependencyType.CAST,referredEntity,expression.getLocation())); | |||
matched = true; | |||
} | |||
if (!matched) { | |||
if (callAsImpl && repo.getEntity(referredEntity.getQualifiedName()) instanceof MultiDeclareEntities && | |||
(referredEntity instanceof VarEntity ||referredEntity instanceof FunctionEntity)) { | |||
if (entity.getAncestorOfType(FileEntity.class).getId().equals(referredEntity.getAncestorOfType(FileEntity.class).getId())){ | |||
entity.addRelation(buildRelation(entity,DependencyType.USE,referredEntity,expression.getLocation())); | |||
}else { | |||
MultiDeclareEntities m = (MultiDeclareEntities) (repo.getEntity(referredEntity.getQualifiedName())); | |||
for (Entity e : m.getEntities()) { | |||
if (e == referredEntity) { | |||
entity.addRelation(expression, buildRelation(entity, DependencyType.USE, e, expression.getLocation())); | |||
} else { | |||
entity.addRelation(expression, buildRelation(entity, DependencyType.IMPLLINK, e, expression.getLocation())); | |||
} | |||
matched = true; | |||
} | |||
} | |||
} | |||
else { | |||
entity.addRelation(expression,buildRelation(entity,DependencyType.USE,referredEntity,expression.getLocation())); | |||
} | |||
} | |||
} | |||
private Relation buildRelation(Entity from, String type, Entity referredEntity) { | |||
return buildRelation(from,type,referredEntity,from.getLocation()); | |||
} | |||
private Relation buildRelation(Entity from, String type, Entity referredEntity,Location location) { | |||
if (referredEntity instanceof AliasEntity) { | |||
if (from.getAncestorOfType(FileEntity.class).equals(referredEntity.getAncestorOfType(FileEntity.class))) { | |||
AliasEntity alias = ((AliasEntity) referredEntity); | |||
if (alias.deepResolve()!=null) { | |||
referredEntity = alias.deepResolve(); | |||
} | |||
} | |||
} | |||
if (this.langProcessor==null) | |||
return new Relation(type,referredEntity,location); | |||
return new Relation(langProcessor.getRelationMapping(type),referredEntity,location); | |||
} | |||
private void computeTypeRelations(TypeEntity type) { | |||
for (TypeEntity superType:type.getInheritedTypes()) { | |||
type.addRelation(buildRelation(type,DependencyType.INHERIT,superType)); | |||
} | |||
for (TypeEntity interfaceType:type.getImplementedTypes()) { | |||
type.addRelation(buildRelation(type,DependencyType.IMPLEMENT,interfaceType)); | |||
} | |||
} | |||
private void computeFunctionRelations(FunctionEntity func) { | |||
for (Entity returnType:func.getReturnTypes()) { | |||
func.addRelation(buildRelation(func,DependencyType.RETURN,returnType.getActualReferTo())); | |||
} | |||
for (VarEntity parameter:func.getParameters()) { | |||
if (parameter.getType()!=null) | |||
func.addRelation(buildRelation(func,DependencyType.PARAMETER,parameter.getActualReferTo())); | |||
} | |||
for (Entity throwType:func.getThrowTypes()) { | |||
func.addRelation(buildRelation(func,DependencyType.THROW,throwType)); | |||
} | |||
for (Entity type:func.getResolvedTypeParameters()) { | |||
func.addRelation(buildRelation(func,DependencyType.PARAMETER,type)); | |||
} | |||
if (func instanceof FunctionEntityImpl) { | |||
FunctionEntityImpl funcImpl = (FunctionEntityImpl)func; | |||
if(funcImpl.getImplemented()!=null) { | |||
func.addRelation(buildRelation(func,DependencyType.IMPLEMENT,funcImpl.getImplemented())); | |||
} | |||
} | |||
} | |||
private void computeImports(FileEntity file) { | |||
Collection<Entity> imports = file.getImportedRelationEntities(); | |||
if (imports==null) return; | |||
for (Entity imported:imports) { | |||
if (imported instanceof FileEntity) | |||
{ | |||
if (((FileEntity)imported).isInProjectScope()) | |||
file.addRelation(buildRelation(file,DependencyType.IMPORT,imported)); | |||
}else { | |||
file.addRelation(buildRelation(file,DependencyType.IMPORT,imported)); | |||
} | |||
} | |||
} | |||
} |
@@ -1,105 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.extractor.ruby; | |||
import depends.entity.Entity; | |||
import depends.entity.PackageEntity; | |||
import depends.entity.repo.EntityRepo; | |||
import depends.extractor.FileParser; | |||
import depends.extractor.HandlerContext; | |||
import depends.extractor.IncludedFileLocator; | |||
import depends.extractor.ParserCreator; | |||
import depends.importtypes.FileImport; | |||
import depends.relations.IBindingResolver; | |||
import multilang.depends.util.file.FileUtil; | |||
import java.util.Collection; | |||
public class RubyHandlerContext extends HandlerContext { | |||
private IncludedFileLocator includedFileLocator; | |||
private ParserCreator parserCreator; | |||
public RubyHandlerContext(EntityRepo entityRepo, | |||
IncludedFileLocator includedFileLocator, | |||
IBindingResolver bindingResolver, ParserCreator parserCreator) { | |||
super(entityRepo, bindingResolver); | |||
this.includedFileLocator = includedFileLocator; | |||
this.parserCreator = parserCreator; | |||
} | |||
public Entity foundNamespace(String nampespaceName, Integer startLine) { | |||
Entity parentEntity = currentFile(); | |||
if (latestValidContainer()!=null) | |||
parentEntity = latestValidContainer(); | |||
PackageEntity pkgEntity = new PackageEntity(nampespaceName, parentEntity,idGenerator.generateId()); | |||
entityRepo.add(pkgEntity); | |||
entityStack.push(pkgEntity); | |||
return pkgEntity; | |||
} | |||
public void processSpecialFuncCall(String methodName, Collection<String> params, Integer startLine) { | |||
// Handle Import relation | |||
if(methodName.equals("require") || methodName.equals("require_relative")) { | |||
for (String importedFilename:params) { | |||
if (!importedFilename.endsWith(".rb")) importedFilename = importedFilename + ".rb"; | |||
String dir = FileUtil.getLocatedDir(currentFile().getRawName().uniqName()); | |||
String inclFileName = includedFileLocator.uniqFileName(dir,importedFilename); | |||
if (inclFileName==null) { | |||
System.err.println("Warning: cannot found included file " + importedFilename ); | |||
continue; | |||
} | |||
FileParser importedParser = parserCreator.createFileParser(); | |||
try { | |||
importedParser.parse(inclFileName); | |||
} catch (Exception e) { | |||
System.err.println("parsing error in "+inclFileName); | |||
} | |||
foundNewImport(new FileImport(inclFileName)); | |||
} | |||
} | |||
// Handle Extend relation | |||
else if (methodName.equals("extend")) { | |||
for (String moduleName:params) { | |||
foundExtends(moduleName); | |||
} | |||
} | |||
// Handle mixin relation | |||
else if (methodName.equals("include")) { | |||
for (String moduleName:params) { | |||
foundMixin(moduleName); | |||
} | |||
} | |||
// attribute methods | |||
else if (methodName.equals("attr_accessor")||methodName.equals("attr_writer")||methodName.equals("attr_reader")) { | |||
for (String name:params) { | |||
name = name.replace(":", ""); //remove symbol | |||
foundMethodDeclarator(name,startLine); | |||
} | |||
} | |||
} | |||
} |
@@ -1,165 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.extractor.ruby.jruby; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import org.jrubyparser.ast.AssignableNode; | |||
import org.jrubyparser.ast.CallNode; | |||
import org.jrubyparser.ast.ClassVarAsgnNode; | |||
import org.jrubyparser.ast.ClassVarDeclNode; | |||
import org.jrubyparser.ast.Colon2Node; | |||
import org.jrubyparser.ast.Colon3Node; | |||
import org.jrubyparser.ast.ConstDeclNode; | |||
import org.jrubyparser.ast.DAsgnNode; | |||
import org.jrubyparser.ast.DefsNode; | |||
import org.jrubyparser.ast.FCallNode; | |||
import org.jrubyparser.ast.GlobalAsgnNode; | |||
import org.jrubyparser.ast.INameNode; | |||
import org.jrubyparser.ast.InstAsgnNode; | |||
import org.jrubyparser.ast.ListNode; | |||
import org.jrubyparser.ast.LocalAsgnNode; | |||
import org.jrubyparser.ast.MultipleAsgnNode; | |||
import org.jrubyparser.ast.Node; | |||
import org.jrubyparser.ast.UnaryCallNode; | |||
import org.jrubyparser.ast.VCallNode; | |||
import depends.entity.ContainerEntity; | |||
import depends.extractor.ruby.RubyBuiltInType; | |||
import depends.extractor.ruby.RubyHandlerContext; | |||
public class RubyParserHelper { | |||
private static RubyParserHelper inst = new RubyParserHelper(); | |||
public static RubyParserHelper getInst() { | |||
return inst; | |||
} | |||
private RubyBuiltInType buildInType; | |||
private RubyParserHelper() { | |||
this.buildInType = new RubyBuiltInType(); | |||
} | |||
public String getName(Node node) { | |||
String name = ""; | |||
if (node instanceof INameNode) { | |||
name = ((INameNode)node).getName(); | |||
if (node instanceof Colon2Node) { | |||
Node left = ((Colon2Node)node).getLeftNode(); | |||
if (left!=null) { | |||
name = getName(left) + "."+name; | |||
} | |||
}else if (node instanceof Colon3Node) { | |||
name = "."+name; | |||
} | |||
} | |||
return name.length()>0?name:null; | |||
} | |||
public boolean isFunctionCall(Node ctx) { | |||
return ctx instanceof CallNode || | |||
ctx instanceof FCallNode || | |||
ctx instanceof UnaryCallNode || | |||
ctx instanceof VCallNode; | |||
} | |||
public List<String> getName(AssignableNode ctx) { | |||
List<String> names = new ArrayList<>(); | |||
if (ctx instanceof ClassVarAsgnNode) { | |||
names.add(((ClassVarAsgnNode)ctx).getName()); | |||
}else if (ctx instanceof ClassVarDeclNode) { | |||
names.add(((ClassVarDeclNode)ctx).getName()); | |||
}else if (ctx instanceof ConstDeclNode) { | |||
names.add(((ConstDeclNode)ctx).getName()); | |||
}else if (ctx instanceof DAsgnNode) { | |||
names.add(((DAsgnNode)ctx).getName()); | |||
}else if (ctx instanceof GlobalAsgnNode) { | |||
names.add(((GlobalAsgnNode)ctx).getName()); | |||
}else if (ctx instanceof InstAsgnNode) { | |||
names.add(((InstAsgnNode)ctx).getName()); | |||
}else if (ctx instanceof LocalAsgnNode) { | |||
names.add(((LocalAsgnNode)ctx).getName()); | |||
}else if (ctx instanceof MultipleAsgnNode) { | |||
ListNode pre = ((MultipleAsgnNode)ctx).getPre(); | |||
if (pre!=null) { | |||
//TODO: support multiple assignment | |||
} | |||
} | |||
return names; | |||
} | |||
public String getReciever(Node ctx) { | |||
Node receiver = null; | |||
if (ctx instanceof CallNode) { | |||
receiver = ((CallNode)ctx).getReceiver(); | |||
}else if (ctx instanceof DefsNode) { | |||
receiver = ((DefsNode)ctx).getReceiver(); | |||
} | |||
if (receiver==null) { | |||
return null; | |||
} | |||
if (receiver instanceof INameNode) { | |||
return this.getName(receiver); | |||
} | |||
return null; | |||
} | |||
public ContainerEntity getScopeOfVar(AssignableNode node, RubyHandlerContext context) { | |||
if (node instanceof LocalAsgnNode) return context.lastContainer(); | |||
if (node instanceof InstAsgnNode) return context.currentType(); | |||
if (node instanceof ClassVarAsgnNode) return context.currentType(); | |||
if (node instanceof GlobalAsgnNode) return context.globalScope(); | |||
if (node instanceof DAsgnNode) return context.lastContainer(); | |||
return context.lastContainer(); | |||
} | |||
public boolean isArithMeticOperator(String name) { | |||
return name.equals("+") || | |||
name.equals("-") || | |||
name.equals("*") || | |||
name.equals("/") || | |||
name.equals("**") || | |||
name.equals("%") || | |||
name.equals("&") || | |||
name.equals("<") || | |||
name.equals("<=") || | |||
name.equals(">") || | |||
name.equals(">=") || | |||
name.equals("==") || | |||
name.equals("!=") || | |||
name.equals("===") || | |||
name.equals("<<") || | |||
name.equals(">>") || | |||
name.equals("~") || | |||
name.equals("!") || | |||
name.equals("^"); | |||
} | |||
public boolean isCommonOperator(String name) { | |||
return this.buildInType.isBuildInMethod(name); | |||
} | |||
} |
@@ -1,172 +0,0 @@ | |||
package depends.extractor.ruby; | |||
import static org.junit.Assert.assertEquals; | |||
import java.io.IOException; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import depends.entity.ContainerEntity; | |||
import depends.entity.FunctionEntity; | |||
import depends.entity.TypeEntity; | |||
import depends.entity.repo.EntityRepo; | |||
import depends.extractor.FileParser; | |||
public class RubyVarTest extends RubyParserTest { | |||
@Before | |||
public void setUp() { | |||
super.init(); | |||
} | |||
@Test | |||
public void test_parameter_should_be_created() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/ruby-code-examples/auto_var.rb", | |||
}; | |||
for (String src:srcs) { | |||
FileParser parser = createFileParser(); | |||
parser.parse(src); | |||
} | |||
FunctionEntity function = (FunctionEntity)(entityRepo.getEntity("method1")); | |||
assertEquals(1,function.getParameters().size()); | |||
assertContainsParametersWithRawName(function, "param1"); | |||
} | |||
@Test | |||
public void test_var_should_be_created_if_not_declared() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/ruby-code-examples/auto_var.rb", | |||
}; | |||
for (String src:srcs) { | |||
FileParser parser = createFileParser(); | |||
parser.parse(src); | |||
} | |||
FunctionEntity function = (FunctionEntity)(entityRepo.getEntity("method_with_local_var")); | |||
assertEquals(1,function.getVars().size()); | |||
assertContainsVarWithRawName(function, "var_1"); | |||
} | |||
@Test | |||
public void test_var_should_only_create_once() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/ruby-code-examples/auto_var.rb", | |||
}; | |||
for (String src:srcs) { | |||
FileParser parser = createFileParser(); | |||
parser.parse(src); | |||
} | |||
FunctionEntity function = (FunctionEntity)(entityRepo.getEntity("method_with_local_var_2times")); | |||
assertEquals(1,function.getVars().size()); | |||
} | |||
@Test | |||
public void test_var_should_not_be_created_if_it_actually_parameter() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/ruby-code-examples/auto_var.rb", | |||
}; | |||
for (String src:srcs) { | |||
FileParser parser = createFileParser(); | |||
parser.parse(src); | |||
} | |||
FunctionEntity function = (FunctionEntity)(entityRepo.getEntity("method_without_local_var_and_param")); | |||
assertEquals(0,function.getVars().size()); | |||
} | |||
@Test | |||
public void test_var_should_not_be_created_if_it_actually_a_file_level_var() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/ruby-code-examples/auto_var.rb", | |||
}; | |||
for (String src:srcs) { | |||
FileParser parser = createFileParser(); | |||
parser.parse(src); | |||
} | |||
FunctionEntity function = (FunctionEntity)(entityRepo.getEntity("method_access_file_level_var")); | |||
assertEquals(0,function.getVars().size()); | |||
} | |||
@Test | |||
public void test_var_should_not_be_created_with_a_lot_of_levels() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/ruby-code-examples/auto_var.rb", | |||
}; | |||
for (String src:srcs) { | |||
FileParser parser = createFileParser(); | |||
parser.parse(src); | |||
} | |||
FunctionEntity function = (FunctionEntity)(entityRepo.getEntity("M.C.method")); | |||
assertEquals(1,function.getVars().size()); | |||
} | |||
@Test | |||
public void test_var_should_not_be_created_not_in_scope() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/ruby-code-examples/auto_var.rb", | |||
}; | |||
for (String src:srcs) { | |||
FileParser parser = createFileParser(); | |||
parser.parse(src); | |||
} | |||
FunctionEntity function = (FunctionEntity)(entityRepo.getEntity("M.C.method2")); | |||
assertEquals(1,function.getVars().size()); | |||
} | |||
@Test | |||
public void test_var_should_created_at_class_level() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/ruby-code-examples/auto_var.rb", | |||
}; | |||
for (String src:srcs) { | |||
FileParser parser = createFileParser(); | |||
parser.parse(src); | |||
} | |||
TypeEntity c = (TypeEntity)(entityRepo.getEntity("M.C")); | |||
assertEquals(3,c.getVars().size()); | |||
assertContainsVarWithRawName(c,"class_level_var"); | |||
assertContainsVarWithRawName(c,"class_var"); | |||
assertContainsVarWithRawName(c,"instance_var"); | |||
} | |||
@Test | |||
public void test_var_in_block() throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/ruby-code-examples/auto_var.rb", | |||
}; | |||
for (String src:srcs) { | |||
FileParser parser = createFileParser(); | |||
parser.parse(src); | |||
} | |||
ContainerEntity c = (ContainerEntity)(entityRepo.getEntity("Block")); | |||
assertEquals(1,c.getVars().size()); | |||
assertContainsVarWithRawName(c,"a"); | |||
} | |||
@Test | |||
public void test_global_var()throws IOException { | |||
String[] srcs = new String[] { | |||
"./src/test/resources/ruby-code-examples/auto_var.rb", | |||
}; | |||
for (String src:srcs) { | |||
FileParser parser = createFileParser(); | |||
parser.parse(src); | |||
} | |||
ContainerEntity c = (ContainerEntity)(entityRepo.getEntity(EntityRepo.GLOBAL_SCOPE_NAME)); | |||
assertEquals(1,c.getVars().size()); | |||
assertContainsVarWithRawName(c,"global_var"); | |||
} | |||
} | |||
@@ -1,204 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.entity; | |||
import depends.relations.IBindingResolver; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.HashSet; | |||
public class TypeEntity extends ContainerEntity { | |||
static final public TypeEntity buildInType = new TypeEntity(GenericName.build("built-in"), null, -1); | |||
static final public TypeEntity genericParameterType = new TypeEntity(GenericName.build("T"), null, -3); | |||
Collection<TypeEntity> inheritedTypes = new ArrayList<>(); | |||
Collection<TypeEntity> implementedTypes = new ArrayList<>(); | |||
Collection<GenericName> inhertedTypeIdentifiers; | |||
Collection<GenericName> implementedIdentifiers; | |||
TypeEntity inheritedType; | |||
public TypeEntity() {} | |||
public TypeEntity(GenericName simpleName, Entity parent, Integer id) { | |||
super(simpleName, parent, id); | |||
inhertedTypeIdentifiers = new ArrayList<>(); | |||
implementedIdentifiers = new ArrayList<>(); | |||
} | |||
@Override | |||
public void inferLocalLevelEntities(IBindingResolver bindingResolver) { | |||
inheritedTypes = new ArrayList<>(); | |||
Collection<Entity> r = identiferToEntities(bindingResolver, this.inhertedTypeIdentifiers); | |||
if (r!=null) { | |||
r.forEach(item -> { | |||
Entity typeItem = getTypeEntity(item); | |||
if (typeItem !=null) { | |||
inheritedTypes.add((TypeEntity) typeItem); | |||
}else { | |||
System.err.println(item.getRawName() + " expected a type, but actually it is "+ item.getClass().getSimpleName()); | |||
} | |||
}); | |||
} | |||
inheritedTypes.remove(this); | |||
implementedTypes = new ArrayList<>(); | |||
r = identiferToEntities(bindingResolver, this.implementedIdentifiers); | |||
if (r!=null) { | |||
r.forEach(item -> { | |||
Entity typeItem = getTypeEntity(item); | |||
if (typeItem !=null) { | |||
implementedTypes.add((TypeEntity) typeItem); | |||
}else { | |||
System.err.println(item.getRawName() + " expected a type, but actually it is "+ item.getClass().getSimpleName()); | |||
} | |||
}); | |||
} | |||
implementedTypes.remove(this); | |||
if (inheritedTypes.size() > 0) | |||
inheritedType = inheritedTypes.iterator().next(); | |||
super.inferLocalLevelEntities(bindingResolver); | |||
} | |||
private Entity getTypeEntity(Entity item) { | |||
if (item==null) return null; | |||
if (item instanceof TypeEntity) return item; | |||
if (item instanceof MultiDeclareEntities) return ((MultiDeclareEntities)item).getType(); | |||
if (item instanceof AliasEntity) return item.getType(); | |||
return null; | |||
} | |||
public void addImplements(GenericName typeName) { | |||
if (typeName==null) { | |||
return; | |||
} | |||
if (typeName.equals(this.getRawName())) | |||
return; | |||
if (implementedIdentifiers.contains(typeName)) | |||
return; | |||
if (typeName.equals(this.rawName)) | |||
return; | |||
this.implementedIdentifiers.add(typeName); | |||
} | |||
public void addExtends(GenericName typeName) { | |||
if (typeName==null) { | |||
return; | |||
} | |||
if (typeName.equals(this.getRawName())) | |||
return; | |||
if (inhertedTypeIdentifiers.contains(typeName)) | |||
return; | |||
if (typeName.equals(this.rawName)) | |||
return; | |||
this.inhertedTypeIdentifiers.add(typeName); | |||
} | |||
public Collection<TypeEntity> getInheritedTypes() { | |||
return inheritedTypes; | |||
} | |||
public Collection<TypeEntity> getImplementedTypes() { | |||
return implementedTypes; | |||
} | |||
public TypeEntity getInheritedType() { | |||
return inheritedType; | |||
} | |||
@Override | |||
public FunctionEntity lookupFunctionLocally(GenericName functionName) { | |||
Collection<TypeEntity> searchedTypes = new ArrayList<>(); | |||
return lookupFunctionLocally(functionName,searchedTypes); | |||
} | |||
private FunctionEntity lookupFunctionLocally(GenericName functionName, Collection<TypeEntity> searched) { | |||
if (searched.contains(this)) return null; | |||
searched.add(this); | |||
FunctionEntity func = super.lookupFunctionLocally(functionName); | |||
if (func != null) | |||
return func; | |||
for (TypeEntity inhertedType : getInheritedTypes()) { | |||
func = inhertedType.lookupFunctionLocally(functionName, searched); | |||
if (func != null) | |||
break; | |||
} | |||
if (func != null) | |||
return func; | |||
for (TypeEntity implType : getImplementedTypes()) { | |||
func = implType.lookupFunctionLocally(functionName,searched); | |||
if (func != null) | |||
break; | |||
} | |||
return func; | |||
} | |||
@Override | |||
public VarEntity lookupVarLocally(GenericName varName) { | |||
Collection<TypeEntity> searchedTypes = new ArrayList<>(); | |||
return lookupVarLocally(varName,searchedTypes); | |||
} | |||
private VarEntity lookupVarLocally(GenericName varName, Collection<TypeEntity> searched) { | |||
if (searched.contains(this)) return null; | |||
searched.add(this); | |||
VarEntity var = super.lookupVarLocally(varName); | |||
if (var != null) | |||
return var; | |||
for (TypeEntity inhertedType : getInheritedTypes()) { | |||
var = inhertedType.lookupVarLocally(varName,searched); | |||
if (var != null) | |||
break; | |||
} | |||
if (var != null) | |||
return var; | |||
for (TypeEntity implType : getImplementedTypes()) { | |||
var = implType.lookupVarLocally(varName,searched); | |||
if (var != null) | |||
break; | |||
} | |||
return var; | |||
} | |||
@Override | |||
public TypeEntity getType() { | |||
return this; | |||
} | |||
@Override | |||
public Entity getByName(String name, HashSet<Entity> searched) { | |||
Entity entity = super.getByName(name, searched); | |||
if (entity!=null) | |||
return entity; | |||
for (TypeEntity child:getInheritedTypes()) { | |||
if (searched.contains(child)) continue; | |||
entity = child.getByName(name, searched); | |||
if (entity!=null) return entity; | |||
} | |||
for (TypeEntity child:getImplementedTypes()) { | |||
if (searched.contains(child)) continue; | |||
entity = child.getByName(name,searched); | |||
if (entity!=null) return entity; | |||
} | |||
return null; | |||
} | |||
} |
@@ -1,96 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.format.detail; | |||
import java.io.File; | |||
import java.io.FileNotFoundException; | |||
import java.io.PrintWriter; | |||
import java.util.HashSet; | |||
import java.util.Set; | |||
import java.util.TreeMap; | |||
import com.fasterxml.jackson.annotation.JsonInclude.Include; | |||
import com.fasterxml.jackson.databind.ObjectMapper; | |||
import com.fasterxml.jackson.databind.SerializationFeature; | |||
import depends.extractor.UnsolvedBindings; | |||
import multilang.depends.util.file.strip.LeadingNameStripper; | |||
public class UnsolvedSymbolDumper{ | |||
private Set<UnsolvedBindings> unsolved; | |||
private String name; | |||
private String outputDir; | |||
private LeadingNameStripper leadingNameStripper; | |||
public UnsolvedSymbolDumper(Set<UnsolvedBindings> unsolved, String name, String outputDir, LeadingNameStripper leadingNameStripper) { | |||
this.unsolved = unsolved; | |||
this.name = name; | |||
this.outputDir = outputDir; | |||
this.leadingNameStripper = leadingNameStripper; | |||
} | |||
public void output() { | |||
outputDetail(); | |||
outputGrouped(); | |||
} | |||
private void outputGrouped() { | |||
TreeMap<String, Set<String>> grouped = new TreeMap<String, Set<String>>(); | |||
for (UnsolvedBindings symbol: unsolved) { | |||
String depended = symbol.getRawName(); | |||
String from = leadingNameStripper.stripFilename(symbol.getSourceDisplay()); | |||
Set<String> list = grouped.get(depended); | |||
if (list==null) { | |||
list = new HashSet<>(); | |||
grouped.put(depended, list); | |||
} | |||
list.add(from); | |||
} | |||
ObjectMapper om = new ObjectMapper(); | |||
om.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false); | |||
om.configure(SerializationFeature.INDENT_OUTPUT, true); | |||
om.setSerializationInclusion(Include.NON_NULL); | |||
try { | |||
om.writerWithDefaultPrettyPrinter().writeValue(new File(outputDir + File.separator + name +"-PotentialExternalDependencies.json"), grouped); | |||
} catch (Exception e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
private void outputDetail() { | |||
PrintWriter writer; | |||
try { | |||
writer = new PrintWriter(outputDir + File.separator + name +"-PotentialExternalDependencies.txt"); | |||
for (UnsolvedBindings symbol: unsolved) { | |||
String source = leadingNameStripper.stripFilename(symbol.getSourceDisplay()); | |||
writer.println(""+symbol.getRawName()+", "+source); | |||
} | |||
writer.close(); | |||
} catch (FileNotFoundException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
} |
@@ -1,106 +0,0 @@ | |||
/* | |||
MIT License | |||
Copyright (c) 2018-2019 Gang ZHANG | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
*/ | |||
package depends.entity; | |||
import depends.relations.IBindingResolver; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
public class VarEntity extends ContainerEntity { | |||
private GenericName rawType; | |||
private TypeEntity type; | |||
private List<FunctionCall> functionCalls; | |||
public VarEntity() { | |||
} | |||
public VarEntity(GenericName simpleName, GenericName rawType, Entity parent, int id) { | |||
super(simpleName, parent,id); | |||
this.rawType = rawType; | |||
} | |||
public void setRawType(GenericName rawType) { | |||
this.rawType =rawType; | |||
} | |||
public GenericName getRawType() { | |||
return rawType; | |||
} | |||
@Override | |||
public TypeEntity getType() { | |||
return type; | |||
} | |||
public void setType(TypeEntity type) { | |||
this.type = type; | |||
} | |||
@Override | |||
public void inferLocalLevelEntities(IBindingResolver bindingResolver) { | |||
super.inferLocalLevelEntities(bindingResolver); | |||
Entity entity = bindingResolver.resolveName(this, rawType, true); | |||
if (entity!=null) { | |||
this.setActualReferTo(entity); | |||
type = entity.getType(); | |||
if (type==null) { | |||
if (((ContainerEntity)getParent()).isGenericTypeParameter(rawType)) { | |||
type = TypeEntity.genericParameterType; | |||
} | |||
} | |||
} | |||
if (type==null) { | |||
fillCandidateTypes(bindingResolver); | |||
} | |||
} | |||
public List<FunctionCall> getCalledFunctions() { | |||
if (this.functionCalls!=null) | |||
return functionCalls; | |||
return new ArrayList<>(); | |||
} | |||
public void addFunctionCall(GenericName fname) { | |||
if (this.functionCalls==null) | |||
{ | |||
functionCalls = new ArrayList<>(); | |||
} | |||
this.functionCalls.add(new FunctionCall(fname)); | |||
} | |||
public void fillCandidateTypes(IBindingResolver bindingResolver) { | |||
if (!bindingResolver.isEagerExpressionResolve()) return; | |||
if (type!=null && !(type instanceof CandidateTypes)) return ; //it is a strong type lang, do not need deduce candidate types | |||
if (functionCalls==null) return; | |||
if (functionCalls.size()==0) return; //no information avaliable for type deduction | |||
if (this.rawType==null) { | |||
List<TypeEntity> candidateTypes = bindingResolver.calculateCandidateTypes(this,this.functionCalls); | |||
if (candidateTypes.size()>0) { | |||
this.type = new CandidateTypes(candidateTypes, bindingResolver.getRepo().generateId()); | |||
bindingResolver.getRepo().add(this.type); | |||
} | |||
} | |||
} | |||
} |