diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8ae05cd
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,10 @@
+.DS_Store
+.idea/
+*.iml
+target/
+2017*
+.project
+.classpath
+.settings/
+*.log
+bin/
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..3d2baa8
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,257 @@
+
+ 4.0.0
+ com.educoder
+ webssh
+ war
+ 1.0-SNAPSHOT
+ webssh Maven Webapp
+ http://maven.apache.org
+
+
+ 2.6.1
+ 4.3.6.RELEASE
+ 2.3.25-incubating
+ 0.1.54
+ 7.0
+ 2.6
+ 2.4
+ 1.7.21
+ 1.2.20
+ 2.8.6
+ 1.10
+
+ 1.8
+ 1.8
+ UTF-8
+
+
+
+
+
+ org.freemarker
+ freemarker
+ ${freemarker.version}
+
+
+
+ com.jcraft
+ jsch
+ ${jsch.version}
+
+
+
+ io.springfox
+ springfox-swagger2
+ ${swagger2.version}
+
+
+ io.springfox
+ springfox-swagger-ui
+ ${swagger2.version}
+
+
+
+ org.springframework
+ spring-webmvc
+ ${spring.version}
+
+
+
+ org.springframework
+ spring-websocket
+ ${spring.version}
+
+
+
+ org.springframework
+ spring-context-support
+ ${spring.version}
+
+
+
+ org.springframework
+ spring-test
+ ${spring.version}
+
+
+
+ javax
+ javaee-api
+ ${javax.version}
+ provided
+
+
+
+ commons-lang
+ commons-lang
+ ${commons-lang.version}
+
+
+
+ commons-io
+ commons-io
+ ${commons-io.version}
+
+
+
+ junit
+ junit
+ 4.12
+ test
+
+
+
+ org.springframework
+ spring-aop
+ 4.3.6.RELEASE
+
+
+
+ org.aspectj
+ aspectjrt
+ 1.8.10
+
+
+
+ org.springframework
+ spring-aspects
+ ${spring.version}
+
+
+
+ org.springframework
+ spring-test
+ ${spring.version}
+
+
+
+ ch.qos.logback
+ logback-classic
+ 1.2.3
+
+
+ org.logback-extensions
+ logback-ext-spring
+ 0.1.4
+
+
+
+ com.alibaba
+ fastjson
+ ${fastjson.version}
+
+
+
+ commons-codec
+ commons-codec
+ ${codec.version}
+
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ ${jackson.version}
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ ${jackson.version}
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${jackson.version}
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.18.1
+
+ true
+
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.0.0
+
+
+ package
+
+ shade
+
+
+ ${project.build.directory}/dependency-reduced-pom.xml
+
+
+ META-INF/spring.handlers
+
+
+ META-INF/spring.schemas
+
+
+
+
+ *:*
+
+ META-INF/*.SF
+ META-INF/*.DSA
+ META-INF/*.RSA
+
+
+
+
+
+
+
+
+
+ org.apache.tomcat.maven
+ tomcat7-maven-plugin
+ 2.2
+
+ 0.0.0.0
+ 9001
+ /
+ UTF-8
+ webssh
+ tomcat7
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 2.3.2
+
+
+ compile
+ compile
+
+ compile
+
+
+
+ testCompile
+ test-compile
+
+ testCompile
+
+
+
+
+
+ 1.8
+
+
+
+
+ webssh
+
+
diff --git a/src/main/go-mod/excel.go b/src/main/go-mod/excel.go
new file mode 100644
index 0000000..1bfb4a0
--- /dev/null
+++ b/src/main/go-mod/excel.go
@@ -0,0 +1,48 @@
+package excel
+
+import (
+ "fmt"
+ "reflect"
+
+ "github.com/360EntSecGroup-Skylar/excelize"
+)
+
+// WriteXlsx 生成表格到本地服务器
+func WriteXlsx(sheet string, records interface{}) *excelize.File {
+ f := excelize.NewFile() // new file
+ index := f.NewSheet(sheet) // new sheet
+ f.SetActiveSheet(index) // set active (default) sheet
+ firstCharacter := 65 // start from 'A' line
+ t := reflect.TypeOf(records)
+
+ if t.Kind() != reflect.Slice {
+ return f
+ }
+
+ s := reflect.ValueOf(records)
+ for i := 0; i < s.Len(); i++ {
+ elem := s.Index(i).Interface()
+ elemType := reflect.TypeOf(elem)
+ elemValue := reflect.ValueOf(elem)
+ for j := 0; j < elemType.NumField(); j++ {
+ field := elemType.Field(j)
+ // 结构体中xlsx 类似json
+ tag := field.Tag.Get("xlsx")
+ name := tag
+ column := string(firstCharacter + j)
+ if tag == "" {
+ continue
+ }
+ // 设置表头
+ if i == 0 {
+ f.SetCellValue(sheet, fmt.Sprintf("%s%d", column, i+1), name)
+ }
+ // 设置列宽
+ f.SetColWidth(sheet, "A", fmt.Sprintf("%s", column), 20)
+
+ // 设置内容
+ f.SetCellValue(sheet, fmt.Sprintf("%s%d", column, i+2), elemValue.Field(j).Interface())
+ }
+ }
+ return f
+}
diff --git a/src/main/go-mod/func.go b/src/main/go-mod/func.go
new file mode 100644
index 0000000..d88120a
--- /dev/null
+++ b/src/main/go-mod/func.go
@@ -0,0 +1,24 @@
+package main
+
+import "fmt"
+
+type Publisher struct {
+ name string
+ address string
+}
+type Book struct {
+ title, name string
+ publisher Publisher
+}
+
+func main() {
+ var book = Book{"title","name",Publisher{"pub","beijing"}}
+ /* 这是我的第一个简单的程序 */
+ fmt.Println("Hello, World!")
+ fmt.Println(book)
+
+}
+
+func test (book Book) (b1 Book, b2 Book){
+ return book,book
+}
\ No newline at end of file
diff --git a/src/main/go-mod/main.go b/src/main/go-mod/main.go
new file mode 100644
index 0000000..b9754f0
--- /dev/null
+++ b/src/main/go-mod/main.go
@@ -0,0 +1,4 @@
+func main(){
+ printf('hello wold')
+ io.out('ok')
+ }
\ No newline at end of file
diff --git a/src/main/go-mod/struct.go b/src/main/go-mod/struct.go
new file mode 100644
index 0000000..1de4533
--- /dev/null
+++ b/src/main/go-mod/struct.go
@@ -0,0 +1,7 @@
+package test
+type Books struct {
+ title string
+ author string
+ subject string
+ book_id int
+}
diff --git a/src/main/java/com/educoder/bridge/controller/BaseController.java b/src/main/java/com/educoder/bridge/controller/BaseController.java
new file mode 100644
index 0000000..5fafd7d
--- /dev/null
+++ b/src/main/java/com/educoder/bridge/controller/BaseController.java
@@ -0,0 +1,25 @@
+package com.educoder.bridge.controller;
+
+import org.springframework.web.bind.annotation.ModelAttribute;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+
+/**
+ * @author lqk
+ * @version 0.1
+ */
+public class BaseController {
+ protected HttpServletRequest request;
+ protected HttpServletResponse response;
+ protected HttpSession session;
+
+ @ModelAttribute
+ public void setReqAndRes(HttpServletRequest request, HttpServletResponse response) {
+ this.request = request;
+ this.response = response;
+ this.session = request.getSession();
+ }
+}
diff --git a/src/main/java/com/educoder/bridge/controller/MainController.java b/src/main/java/com/educoder/bridge/controller/MainController.java
new file mode 100644
index 0000000..f232380
--- /dev/null
+++ b/src/main/java/com/educoder/bridge/controller/MainController.java
@@ -0,0 +1,49 @@
+package com.educoder.bridge.controller;
+
+import io.swagger.annotations.Api;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.servlet.ModelAndView;
+
+/**
+ * @author guange
+ *
+ * @date 2017/08/02
+ */
+
+@Api(value = "提供webssh连接", hidden = true)
+@RestController
+public class MainController extends BaseController {
+ private final static Logger logger = LoggerFactory.getLogger(MainController.class);
+//
+// @RequestMapping(value={"/"}, method= RequestMethod.GET)
+// public ModelAndView index(@RequestParam("host")String host,
+// @RequestParam("port")int port,
+// @RequestParam("username")String username,
+// @RequestParam("password")String password,
+// @RequestParam("rows")int rows) {
+// logger.debug("/ssh: 接收到连接请求, host: {}, port: {}", host, port);
+// ModelAndView mv = new ModelAndView();
+// mv.setViewName("index");
+// mv.addObject("host", host);
+// mv.addObject("port", port);
+// mv.addObject("username", username);
+// mv.addObject("password", password);
+// mv.addObject("rows", rows);
+// mv.addObject("digest", System.currentTimeMillis());
+// return mv;
+// }
+
+ @RequestMapping(value={"/"}, method= RequestMethod.GET)
+ public ModelAndView index() {
+ ModelAndView mv = new ModelAndView();
+ mv.setViewName("index");
+ mv.addObject("digest", System.currentTimeMillis());
+ return mv;
+ }
+
+}
diff --git a/src/main/java/com/educoder/bridge/handler/WebsshHandler.java b/src/main/java/com/educoder/bridge/handler/WebsshHandler.java
new file mode 100644
index 0000000..34665bc
--- /dev/null
+++ b/src/main/java/com/educoder/bridge/handler/WebsshHandler.java
@@ -0,0 +1,38 @@
+package com.educoder.bridge.handler;
+
+import com.educoder.bridge.service.JchService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.socket.CloseStatus;
+import org.springframework.web.socket.TextMessage;
+import org.springframework.web.socket.WebSocketSession;
+import org.springframework.web.socket.handler.TextWebSocketHandler;
+
+public class WebsshHandler extends TextWebSocketHandler {
+
+ @Autowired
+ JchService jchService;
+
+ @Override
+ public void afterConnectionEstablished(WebSocketSession wsSession) throws Exception {
+ super.afterConnectionEstablished(wsSession);
+ jchService.add(wsSession);
+ }
+
+ /**
+ * 重写handleTextMessage方法,用于处理从websocket接收到的信息
+ */
+ @Override
+ protected void handleTextMessage(WebSocketSession wsSession, TextMessage message) throws Exception {
+ jchService.recv(message.getPayload(), wsSession);
+ super.handleTextMessage(wsSession, message);
+ }
+
+
+ @Override
+ public void afterConnectionClosed(WebSocketSession wsSession, CloseStatus status) throws Exception {
+ super.afterConnectionClosed(wsSession, status);
+ jchService.closeByWebSocket(wsSession);
+ }
+}
diff --git a/src/main/java/com/educoder/bridge/model/SSHInfo.java b/src/main/java/com/educoder/bridge/model/SSHInfo.java
new file mode 100644
index 0000000..4881f63
--- /dev/null
+++ b/src/main/java/com/educoder/bridge/model/SSHInfo.java
@@ -0,0 +1,41 @@
+package com.educoder.bridge.model;
+
+public class SSHInfo {
+ private String host;
+ private String port;
+ private String username;
+ private String password;
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ public void setPort(String port) {
+ this.port = port;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public int getPort() {
+ return Integer.parseInt(port);
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+}
diff --git a/src/main/java/com/educoder/bridge/model/SSHSession.java b/src/main/java/com/educoder/bridge/model/SSHSession.java
new file mode 100644
index 0000000..e9db868
--- /dev/null
+++ b/src/main/java/com/educoder/bridge/model/SSHSession.java
@@ -0,0 +1,45 @@
+package com.educoder.bridge.model;
+
+import com.jcraft.jsch.ChannelShell;
+import org.springframework.web.socket.WebSocketSession;
+
+import java.io.OutputStream;
+
+public class SSHSession {
+ private WebSocketSession webSocketSession;
+ private OutputStream outputStream;
+ private ChannelShell channel;
+ private SSHInfo SSHInfo;
+
+ public SSHInfo getSSHInfo() {
+ return SSHInfo;
+ }
+
+ public void setSSHInfo(SSHInfo SSHInfo) {
+ this.SSHInfo = SSHInfo;
+ }
+
+ public ChannelShell getChannel() {
+ return channel;
+ }
+
+ public void setChannel(ChannelShell channel) {
+ this.channel = channel;
+ }
+
+ public WebSocketSession getWebSocketSession() {
+ return webSocketSession;
+ }
+
+ public void setWebSocketSession(WebSocketSession webSocketSession) {
+ this.webSocketSession = webSocketSession;
+ }
+
+ public OutputStream getOutputStream() {
+ return outputStream;
+ }
+
+ public void setOutputStream(OutputStream outputStream) {
+ this.outputStream = outputStream;
+ }
+}
diff --git a/src/main/java/com/educoder/bridge/service/JchService.java b/src/main/java/com/educoder/bridge/service/JchService.java
new file mode 100644
index 0000000..8657d1d
--- /dev/null
+++ b/src/main/java/com/educoder/bridge/service/JchService.java
@@ -0,0 +1,261 @@
+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 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 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));
+ }
+}
diff --git a/src/main/java/com/educoder/bridge/tmp/ASTStringUtilExt.java b/src/main/java/com/educoder/bridge/tmp/ASTStringUtilExt.java
new file mode 100644
index 0000000..c148844
--- /dev/null
+++ b/src/main/java/com/educoder/bridge/tmp/ASTStringUtilExt.java
@@ -0,0 +1,169 @@
+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 getTemplateParameters(IASTDeclSpecifier declSpecifier) {
+ List 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 ");
+ }
+ }
+
+ 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 ");
+ }
+ }
+
+ 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;
+ }
+
+
+
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/educoder/bridge/tmp/AbstractLangProcessor.java b/src/main/java/com/educoder/bridge/tmp/AbstractLangProcessor.java
new file mode 100644
index 0000000..da5728c
--- /dev/null
+++ b/src/main/java/com/educoder/bridge/tmp/AbstractLangProcessor.java
@@ -0,0 +1,248 @@
+/*
+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 potentialExternalDependencies;
+ private List 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 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 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 includePaths() {
+ if (this.includePaths ==null) {
+ this.includePaths = buildIncludePath();
+ }
+ return includePaths;
+ }
+
+ private List buildIncludePath() {
+ includePaths = new ArrayList();
+ 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 supportedRelations();
+
+ public Set 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;};
+}
diff --git a/src/main/java/com/educoder/bridge/tmp/AliasEntity.java b/src/main/java/com/educoder/bridge/tmp/AliasEntity.java
new file mode 100644
index 0000000..219fba5
--- /dev/null
+++ b/src/main/java/com/educoder/bridge/tmp/AliasEntity.java
@@ -0,0 +1,203 @@
+/*
+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 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 getResolvedTypeParameters() {
+ if (!(referToEntity instanceof DecoratedEntity))
+ return new ArrayList<>();
+ DecoratedEntity origin = (DecoratedEntity) referToEntity;
+ return origin.getResolvedTypeParameters();
+ }
+
+ public Collection getResolvedAnnotations() {
+ if (!(referToEntity instanceof DecoratedEntity))
+ return new ArrayList<>();
+ DecoratedEntity origin = (DecoratedEntity) referToEntity;
+ return origin.getResolvedAnnotations();
+ }
+
+ public ArrayList getVars() {
+ if (!(referToEntity instanceof ContainerEntity))
+ return new ArrayList<>();
+ ContainerEntity origin = (ContainerEntity) referToEntity;
+ return origin.getVars();
+ }
+
+ public ArrayList 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 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 getResolvedMixins() {
+ if (!(referToEntity instanceof ContainerEntity))
+ return new ArrayList<>();
+ ContainerEntity origin = (ContainerEntity) referToEntity;
+ return origin.getResolvedMixins();
+ }
+
+ public Collection getInheritedTypes() {
+ if (referToEntity instanceof TypeEntity)
+ return ((TypeEntity) referToEntity).getInheritedTypes();
+ return new ArrayList<>();
+ }
+
+ public Collection 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 getReturnTypes() {
+ if (!(referToEntity instanceof FunctionEntity))
+ return new ArrayList<>();
+ FunctionEntity origin = (FunctionEntity) referToEntity;
+ return origin.getReturnTypes();
+ }
+
+ public TypeEntity getType() {
+ return referToEntity.getType();
+ }
+
+ public Collection getParameters() {
+ if (!(referToEntity instanceof FunctionEntity))
+ return new ArrayList<>();
+ FunctionEntity origin = (FunctionEntity) referToEntity;
+ return origin.getParameters();
+ }
+
+ public Collection 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 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;
+ }
+
+
+}
diff --git a/src/main/java/com/educoder/bridge/tmp/AnnotationProcessor.java b/src/main/java/com/educoder/bridge/tmp/AnnotationProcessor.java
new file mode 100644
index 0000000..cf40e49
--- /dev/null
+++ b/src/main/java/com/educoder/bridge/tmp/AnnotationProcessor.java
@@ -0,0 +1,121 @@
+/*
+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 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 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 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;
+ }
+ }
+
+
+
+
+}
diff --git a/src/main/java/com/educoder/bridge/tmp/BindingResolver.java b/src/main/java/com/educoder/bridge/tmp/BindingResolver.java
new file mode 100644
index 0000000..66134db
--- /dev/null
+++ b/src/main/java/com/educoder/bridge/tmp/BindingResolver.java
@@ -0,0 +1,297 @@
+/*
+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 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 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 iterator = repo.sortedFileIterator();
+ while(iterator.hasNext()) {
+ Entity entity= iterator.next();
+ entity.inferEntities(this);
+ }
+ }
+
+
+ @Override
+ public Collection getImportedRelationEntities(List importedNames) {
+ return importLookupStrategy.getImportedRelationEntities(importedNames);
+ }
+
+ @Override
+ public Collection getImportedTypes(List importedNames, FileEntity fileEntity) {
+ HashSet unsolved = new HashSet();
+ Collection 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 getImportedFiles(List 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 calculateCandidateTypes(VarEntity fromEntity, List functionCalls) {
+ if (buildInTypeManager.isBuildInTypeMethods(functionCalls)) {
+ return new ArrayList<>();
+ }
+ if (!isDuckTypingDeduce)
+ return new ArrayList<>();
+ return searchTypesInRepo(fromEntity, functionCalls);
+ }
+
+ private List searchTypesInRepo(VarEntity fromEntity, List functionCalls) {
+ List types = new ArrayList<>();
+ Iterator 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;
+ }
+
+}
diff --git a/src/main/java/com/educoder/bridge/tmp/BuiltInType.java b/src/main/java/com/educoder/bridge/tmp/BuiltInType.java
new file mode 100644
index 0000000..1771cc9
--- /dev/null
+++ b/src/main/java/com/educoder/bridge/tmp/BuiltInType.java
@@ -0,0 +1,110 @@
+/*
+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 builtInType = new HashSet<>();
+ private Set builtInPrefix = new HashSet<>();
+ private Set 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 functionCalls) {
+ return false;
+ }
+
+}
diff --git a/src/main/java/com/educoder/bridge/tmp/CandidateTypes.java b/src/main/java/com/educoder/bridge/tmp/CandidateTypes.java
new file mode 100644
index 0000000..04d669b
--- /dev/null
+++ b/src/main/java/com/educoder/bridge/tmp/CandidateTypes.java
@@ -0,0 +1,311 @@
+/*
+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 candidateTypes;
+
+ public CandidateTypes() {
+ candidateTypes = new ArrayList<>();
+ }
+ public CandidateTypes(List candidateTypes, Integer id) {
+ super(GenericName.build("candidateTypes"), null, id);
+ this.candidateTypes = candidateTypes;
+ }
+
+ public List getCandidateTypes() {
+ return candidateTypes;
+ }
+
+ @Override
+ public Collection getInheritedTypes() {
+ List result = new ArrayList<>();
+ for (TypeEntity type:candidateTypes) {
+ result.addAll(type.getInheritedTypes());
+ }
+ return result;
+ }
+
+ @Override
+ public Collection getImplementedTypes() {
+ List result = new ArrayList<>();
+ for (TypeEntity type:candidateTypes) {
+ result.addAll(type.getImplementedTypes());
+ }
+ return result;
+ }
+
+ @Override
+ public ArrayList getFunctions() {
+ ArrayList result = new ArrayList<>();
+ for (TypeEntity type:candidateTypes) {
+ result.addAll(type.getFunctions());
+ }
+ return result;
+ }
+
+ @Override
+ public TypeEntity getInheritedType() {
+ return inheritedType;
+ }
+ @Override
+ public List lookupFunctionInVisibleScope(GenericName functionName) {
+ List functions = new ArrayList<>();
+ for (TypeEntity type:candidateTypes) {
+ List 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 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