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 + 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 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 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 getResolvedTypeParameters() { + System.err.println("error: getResolvedTypeParameters should not been invoked"); + return super.getResolvedTypeParameters(); + } + + @Override + public Collection 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 identiferToEntities(IBindingResolver bindingResolver, Collection 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 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 getChildren() { + List 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 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; + } + + + +} diff --git a/src/main/java/com/educoder/bridge/tmp/CdtCppFileParser.java b/src/main/java/com/educoder/bridge/tmp/CdtCppFileParser.java new file mode 100644 index 0000000..42360f6 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/CdtCppFileParser.java @@ -0,0 +1,86 @@ +/* +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 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 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 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; + } +} diff --git a/src/main/java/com/educoder/bridge/tmp/ContainerEntity.java b/src/main/java/com/educoder/bridge/tmp/ContainerEntity.java new file mode 100644 index 0000000..b299763 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/ContainerEntity.java @@ -0,0 +1,467 @@ +/* +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 vars; + private ArrayList functions; + WeakReference> expressionWeakReference; + private ArrayList expressionList; + private int expressionCount = 0; + private Collection mixins; + private Collection resolvedMixins; + + private ArrayList vars() { + if (vars==null) + vars = new ArrayList<>(); + return this.vars; + } + + private Collection mixins() { + if (mixins==null) + mixins = new ArrayList<>(); + return this.mixins; + } + + private ArrayList 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 getVars() { + if (vars==null) + return new ArrayList<>(); + return this.vars(); + } + + public void addFunction(FunctionEntity functionEntity) { + this.functions().add(functionEntity); + } + + public ArrayList getFunctions() { + if (functions==null) + return new ArrayList<>(); + return this.functions; + } + + public HashMap expressions() { + if (expressionWeakReference==null) + expressionWeakReference= new WeakReference>(new HashMap<>()); + HashMap 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 getMixins() { + if (mixins==null) + return new ArrayList<>(); + return mixins; + } + + private Collection identiferToContainerEntity(IBindingResolver bindingResolver, Collection identifiers) { + if (identifiers.size()==0) return null; + ArrayList 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 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) 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 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 lookupFunctionInVisibleScope(GenericName functionName) { + List 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 getResolvedMixins() { + if (resolvedMixins==null) return new ArrayList<>(); + return resolvedMixins; + } + + HashMap> 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 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; + } +} diff --git a/src/main/java/com/educoder/bridge/tmp/CppBuiltInType.java b/src/main/java/com/educoder/bridge/tmp/CppBuiltInType.java new file mode 100644 index 0000000..e94528f --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/CppBuiltInType.java @@ -0,0 +1,66 @@ +/* +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", "", + "__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[] {"__"}; + } +} \ No newline at end of file diff --git a/src/main/java/com/educoder/bridge/tmp/CppImportLookupStrategy.java b/src/main/java/com/educoder/bridge/tmp/CppImportLookupStrategy.java new file mode 100644 index 0000000..b723455 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/CppImportLookupStrategy.java @@ -0,0 +1,133 @@ +/* +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 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 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 > includedFiles = new HashMap<>(); + private HashSet getIncludedFiles(FileEntity fileEntity) { + + if (includedFiles.containsKey(fileEntity.getId())) { + return includedFiles.get(fileEntity.getId()); + } + HashSet fileSet = new HashSet<>(); + foundIncludedFiles(fileSet, fileEntity.getImportedFiles()); + includedFiles.put(fileEntity.getId(), fileSet); + return fileSet; + } + + private void foundIncludedFiles(HashSet fileSet, Collection 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 getImportedRelationEntities(List importedList) { + ArrayList 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 getImportedTypes(List importedList, Set unsolvedBindings) { + ArrayList 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 getImportedFiles(List importedList) { + return getImportedRelationEntities(importedList); + } + + @Override + public boolean supportGlobalNameLookup() { + return false; + } +} diff --git a/src/main/java/com/educoder/bridge/tmp/CppVisitor.java b/src/main/java/com/educoder/bridge/tmp/CppVisitor.java new file mode 100644 index 0000000..e291c7f --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/CppVisitor.java @@ -0,0 +1,338 @@ +/* +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 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 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 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 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 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); + } +} \ No newline at end of file diff --git a/src/main/java/com/educoder/bridge/tmp/DecoratedEntity.java b/src/main/java/com/educoder/bridge/tmp/DecoratedEntity.java new file mode 100644 index 0000000..a18344d --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/DecoratedEntity.java @@ -0,0 +1,148 @@ +/* +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 annotations; + private Collection resolvedAnnotations; + private Collection 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 parameters) { + this.getRawName().appendArguments(parameters); + } + + + + public void addTypeParameter(GenericName parameter) { + this.getRawName().appendArguments(parameter); + } + + protected void appendTypeParameters(Collection 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 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 typeParametersToEntities(IBindingResolver bindingResolver) { + ArrayList r = new ArrayList<>(); + for (GenericName typeParameter:this.getRawName().getArguments()) { + toEntityList(bindingResolver, r,typeParameter); + } + return r; + } + + protected void toEntityList(IBindingResolver bindingResolver, ArrayList 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 getResolvedTypeParameters() { + if (resolvedTypeParameters==null) + return new ArrayList<>(); + return resolvedTypeParameters; + } + + + public Collection 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 identiferToEntities(IBindingResolver bindingResolver, Collection identifiers) { + if (identifiers==null) return null; + if (identifiers.size()==0) return null; + ArrayList 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; + } +} diff --git a/src/main/java/com/educoder/bridge/tmp/DependencyGenerator.java b/src/main/java/com/educoder/bridge/tmp/DependencyGenerator.java new file mode 100644 index 0000000..6f943f5 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/DependencyGenerator.java @@ -0,0 +1,160 @@ +/* +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 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 typeFilter) { + DependencyMatrix dependencyMatrix = new DependencyMatrix(typeFilter); + Iterator 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 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 expandEntity(Entity relatedEntity) { + List 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; + } +} diff --git a/src/main/java/com/educoder/bridge/tmp/DependencyMatrix.java b/src/main/java/com/educoder/bridge/tmp/DependencyMatrix.java new file mode 100644 index 0000000..f74cc84 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/DependencyMatrix.java @@ -0,0 +1,102 @@ +/* +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 dependencyPairs = new HashMap<>(); + private ArrayList nodes = new ArrayList<>(); + private HashMap nodeIdToName = new HashMap<>(); + private List typeFilter; + public DependencyMatrix() { + } + public DependencyMatrix(int size) { + dependencyPairs = new HashMap<>(size); + } + public DependencyMatrix(List typeFilter) { + this.typeFilter = typeFilter; + } + public Collection 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 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 getNodes() { + return nodes; + } + + + public DependencyMatrix reWriteFilenamePattern(FilenameWritter filenameRewritter) { + this.nodeIdToName = new HashMap<>(); + for (int i=0;i { + private static final long serialVersionUID = 1L; + public SupportedLangs() { super( LangProcessorRegistration.getRegistry().getLangs()); } + } + + public static class SupportedTypes extends ArrayList { + 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 . " + + "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 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; + } +} diff --git a/src/main/java/com/educoder/bridge/tmp/EclipseTestBase_No_ResponseDuirngTypeResolve.java b/src/main/java/com/educoder/bridge/tmp/EclipseTestBase_No_ResponseDuirngTypeResolve.java new file mode 100644 index 0000000..25f2020 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/EclipseTestBase_No_ResponseDuirngTypeResolve.java @@ -0,0 +1,222 @@ +/******************************************************************************* + * 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 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; + } +} \ No newline at end of file diff --git a/src/main/java/com/educoder/bridge/tmp/Entity.java b/src/main/java/com/educoder/bridge/tmp/Entity.java new file mode 100644 index 0000000..75174c5 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/Entity.java @@ -0,0 +1,275 @@ +/* +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 children; + ArrayList relations; + private Entity actualReferTo = null; + private boolean inScope = true; + protected HashMap 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 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 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 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 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; + } + +} diff --git a/src/main/java/com/educoder/bridge/tmp/EntityExtractTest.java b/src/main/java/com/educoder/bridge/tmp/EntityExtractTest.java new file mode 100644 index 0000000..9c5e1a1 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/EntityExtractTest.java @@ -0,0 +1,101 @@ +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_")); + /* + 1.00 + 3.1.4 + Apache ActiveMQ + activemq-${project.version} */ + 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_")); + /* + 1.00 + 3.1.4 + Apache ActiveMQ + activemq-${project.version}--${activeio-version} */ + 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")); + } +} \ No newline at end of file diff --git a/src/main/java/com/educoder/bridge/tmp/ExcelXlsFormatDependencyDumper.java b/src/main/java/com/educoder/bridge/tmp/ExcelXlsFormatDependencyDumper.java new file mode 100644 index 0000000..6831f18 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/ExcelXlsFormatDependencyDumper.java @@ -0,0 +1,120 @@ +/* +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 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 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"); + } + +} diff --git a/src/main/java/com/educoder/bridge/tmp/ExcelXlsxFormatDependencyDumper.java b/src/main/java/com/educoder/bridge/tmp/ExcelXlsxFormatDependencyDumper.java new file mode 100644 index 0000000..c27b68a --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/ExcelXlsxFormatDependencyDumper.java @@ -0,0 +1,119 @@ +/* +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 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 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"); + } + +} diff --git a/src/main/java/com/educoder/bridge/tmp/Expression.java b/src/main/java/com/educoder/bridge/tmp/Expression.java new file mode 100644 index 0000000..5639248 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/Expression.java @@ -0,0 +1,413 @@ +/* +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 deducedTypeVars = new ArrayList<>(); + private List deducedTypeVarsId = new ArrayList<>(); + + private transient List deducedTypeFunctions= new ArrayList<>(); + private List 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 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 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 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 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("")) return true; + if (name.toLowerCase().equals("")) 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; + } +} \ No newline at end of file diff --git a/src/main/java/com/educoder/bridge/tmp/ExpressionUsage.java b/src/main/java/com/educoder/bridge/tmp/ExpressionUsage.java new file mode 100644 index 0000000..2d9762a --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/ExpressionUsage.java @@ -0,0 +1,298 @@ +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 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 getName(Testlist_star_exprContext testlist_star_expr) { + List 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 + | 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(""); + expression.setIdentifier(""); + 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{ + private List names; + NameCollector(List names){ + this.names = names; + } + @Override + public Void visitAtom(AtomContext ctx) { + if (ctx.name()!=null) + names.add(ctx.name().getText()); + return super.visitAtom(ctx); + } +} \ No newline at end of file diff --git a/src/main/java/com/educoder/bridge/tmp/ExtractText.java b/src/main/java/com/educoder/bridge/tmp/ExtractText.java new file mode 100644 index 0000000..4ba8951 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/ExtractText.java @@ -0,0 +1,129 @@ +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); + } + } +} diff --git a/src/main/java/com/educoder/bridge/tmp/FileEntity.java b/src/main/java/com/educoder/bridge/tmp/FileEntity.java new file mode 100644 index 0000000..8765a3a --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/FileEntity.java @@ -0,0 +1,169 @@ +/* +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 importedNames = new ArrayList<>(); + private boolean isInProjectScope = false; + private Collection importedRelationEntities = new ArrayList<>(); + private Collection importedFiles = new ArrayList<>(); + private Collection importedTypes = new ArrayList<>(); + private List 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 getImportedRelationEntities() { + return importedRelationEntities; + } + + public Collection getImportedFiles() { + return importedFiles; + } + + public Collection getImportedTypes() { + return importedTypes; + } + + public List getDeclaredTypes() { + return this.declaredTypes; + } + + public void addType(TypeEntity currentTypeEntity) { + this.declaredTypes.add(currentTypeEntity); + } + + public Set getImportedFilesInAllLevel() { + if (importedFileCollector==null) + importedFileCollector = new ImportedFileCollector(this); + + return importedFileCollector.getFiles(); + } + + public List getImportedNames() { + return importedNames; + } + + public void cacheAllExpressions() { + this.cacheChildExpressions(); + } + + + @Override + public Entity getByName(String name, HashSet 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); + } + } + +} diff --git a/src/main/java/com/educoder/bridge/tmp/FormalParameterListContextHelper.java b/src/main/java/com/educoder/bridge/tmp/FormalParameterListContextHelper.java new file mode 100644 index 0000000..4c24ca9 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/FormalParameterListContextHelper.java @@ -0,0 +1,99 @@ +/* +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 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 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 getAnnotations() { + return annotations; + } + + +} diff --git a/src/main/java/com/educoder/bridge/tmp/FunctionEntity.java b/src/main/java/com/educoder/bridge/tmp/FunctionEntity.java new file mode 100644 index 0000000..91f7e7a --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/FunctionEntity.java @@ -0,0 +1,149 @@ +/* +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 returnTypeIdentifiers = new ArrayList<>(); + Collection parameters; + Collection throwTypesIdentifiers = new ArrayList<>(); + private Collection returnTypes = new ArrayList<>(); + private Collection 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 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 throwedType) { + throwTypesIdentifiers.addAll(throwedType); + } + + @Override + public void inferLocalLevelEntities(IBindingResolver bindingResolver) { + for (VarEntity param:parameters) { + param.fillCandidateTypes(bindingResolver); + param.inferLocalLevelEntities(bindingResolver); + } + if (returnTypes.size() typeEntities = typeParametersToEntities(bindingResolver, returnTypeName); + this.appendTypeParameters(typeEntities); + } + } + if (throwTypes.size() typeParametersToEntities(IBindingResolver bindingResolver, GenericName name) { + ArrayList r = new ArrayList<>(); + for (GenericName typeParameter:name.getArguments()) { + toEntityList(bindingResolver, r,typeParameter); + } + return r; + } + + + public Collection getParameters() { + return parameters; + } + public Collection 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); + } + } +} diff --git a/src/main/java/com/educoder/bridge/tmp/GenericName.java b/src/main/java/com/educoder/bridge/tmp/GenericName.java new file mode 100644 index 0000000..1645f52 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/GenericName.java @@ -0,0 +1,117 @@ +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 arguments; + public GenericName(String name) { + this.name = name.toCharArray(); + } + public GenericName(String name, List 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 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 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 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; + } + + +} diff --git a/src/main/java/com/educoder/bridge/tmp/GoImportLookupStrategy.java b/src/main/java/com/educoder/bridge/tmp/GoImportLookupStrategy.java new file mode 100644 index 0000000..cda04d7 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/GoImportLookupStrategy.java @@ -0,0 +1,103 @@ +/* +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 getImportedRelationEntities(List importedList) { + ArrayList 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 getImportedTypes(List importedList, Set unsolvedBindings) { + ArrayList 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 getImportedFiles(List importedList) { + return new ArrayList(); + } + + + @Override + public boolean supportGlobalNameLookup() { + return true; + } + +} diff --git a/src/main/java/com/educoder/bridge/tmp/GoListener.java b/src/main/java/com/educoder/bridge/tmp/GoListener.java new file mode 100644 index 0000000..b8fafe7 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/GoListener.java @@ -0,0 +1,136 @@ +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() { + + } +} diff --git a/src/main/java/com/educoder/bridge/tmp/GoParserBase.java b/src/main/java/com/educoder/bridge/tmp/GoParserBase.java new file mode 100644 index 0000000..9f3c099 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/GoParserBase.java @@ -0,0 +1,132 @@ +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 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); + } +} diff --git a/src/main/java/com/educoder/bridge/tmp/HandlerContext.java b/src/main/java/com/educoder/bridge/tmp/HandlerContext.java new file mode 100644 index 0000000..a18547c --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/HandlerContext.java @@ -0,0 +1,333 @@ +/* +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(); + 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 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 foundVarDefinitions(List varNames, String type, List 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 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 entityStack = new Stack(); + + 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); + } + + +} \ No newline at end of file diff --git a/src/main/java/com/educoder/bridge/tmp/InMemoryEntityRepo.java b/src/main/java/com/educoder/bridge/tmp/InMemoryEntityRepo.java new file mode 100644 index 0000000..435676b --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/InMemoryEntityRepo.java @@ -0,0 +1,135 @@ +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{ + + private Iterator> entryIterator; + + public EntityMapIterator(Set> entries) { + this.entryIterator = entries.iterator(); + } + @Override + public boolean hasNext() { + return entryIterator.hasNext(); + } + + @Override + public Entity next() { + return entryIterator.next().getValue(); + } + + } + + private Map allEntieisByName; + private Map allEntitiesById; + private List 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 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 getFileEntities() { + return allFileEntitiesByOrder; + } + + @Override + public Iterator 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); + } + } +} diff --git a/src/main/java/com/educoder/bridge/tmp/IncludeRelationTest.java b/src/main/java/com/educoder/bridge/tmp/IncludeRelationTest.java new file mode 100644 index 0000000..3356fb4 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/IncludeRelationTest.java @@ -0,0 +1,109 @@ +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 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])); + } +} diff --git a/src/main/java/com/educoder/bridge/tmp/JDataBuilder.java b/src/main/java/com/educoder/bridge/tmp/JDataBuilder.java new file mode 100644 index 0000000..5e44240 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/JDataBuilder.java @@ -0,0 +1,88 @@ +/* +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 files = dependencyMatrix.getNodes(); + Collection dependencyPairs = dependencyMatrix.getDependencyPairs(); + ArrayList 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 buildCellObjects(Collection dependencyPairs) { + ArrayList cellObjects = new ArrayList(); + + for (DependencyPair dependencyPair : dependencyPairs) { + Map valueObject = buildValueObject(dependencyPair.getDependencies()); + List 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 buildDetails(Collection dependencies) { + List 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 buildValueObject(Collection dependencies) { + Map valueObject = new HashMap(); + for (DependencyValue dependency : dependencies) { + valueObject.put(dependency.getType(), (float) dependency.getWeight()); + } + return valueObject; + } +} diff --git a/src/main/java/com/educoder/bridge/tmp/JRubyVisitor.java b/src/main/java/com/educoder/bridge/tmp/JRubyVisitor.java new file mode 100644 index 0000000..052b755 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/JRubyVisitor.java @@ -0,0 +1,281 @@ +/* +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 params = getParams(node); + context.processSpecialFuncCall(fname, params, node.getPosition().getStartLine()+1); + return super.visitFCallNode(node); + } + + private Collection getParams(IArgumentNode node) { + Node args = node.getArgs(); + Collection 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 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 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); + } + +} diff --git a/src/main/java/com/educoder/bridge/tmp/JavaBuiltInType.java b/src/main/java/com/educoder/bridge/tmp/JavaBuiltInType.java new file mode 100644 index 0000000..7402f58 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/JavaBuiltInType.java @@ -0,0 +1,84 @@ +/* +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", + "" + }; + } + @Override + protected String[] getBuiltInTypePrefix() { + return new String[]{ + "java.","javax.","com.sun." + }; + } +} diff --git a/src/main/java/com/educoder/bridge/tmp/JavaImportLookupStrategy.java b/src/main/java/com/educoder/bridge/tmp/JavaImportLookupStrategy.java new file mode 100644 index 0000000..d791697 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/JavaImportLookupStrategy.java @@ -0,0 +1,105 @@ +/* +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 getImportedRelationEntities(List importedList) { + ArrayList 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 getImportedTypes(List importedList,Set unsolvedBindings) { + ArrayList 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 getImportedFiles(List importedList) { + return new ArrayList(); + } + + + @Override + public boolean supportGlobalNameLookup() { + return true; + } + +} diff --git a/src/main/java/com/educoder/bridge/tmp/JavaListener.java b/src/main/java/com/educoder/bridge/tmp/JavaListener.java new file mode 100644 index 0000000..326e788 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/JavaListener.java @@ -0,0 +1,337 @@ +/* +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 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 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 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 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 varNames = VariableDeclaratorsContextHelper.getVariables(ctx.variableDeclarators()); + String type = ClassTypeContextHelper.getClassName(ctx.typeType()); + List typeArguments = ClassTypeContextHelper.getTypeArguments(ctx.typeType()); + List 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 typeArguments = ClassTypeContextHelper.getTypeArguments(ctx.typeType()); + List 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 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 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 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 , <> 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())); + } + } +} diff --git a/src/main/java/com/educoder/bridge/tmp/JavaVarResolveTest.java b/src/main/java/com/educoder/bridge/tmp/JavaVarResolveTest.java new file mode 100644 index 0000000..4660844 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/JavaVarResolveTest.java @@ -0,0 +1,100 @@ +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"); + } + +} diff --git a/src/main/java/com/educoder/bridge/tmp/JchService.java b/src/main/java/com/educoder/bridge/tmp/JchService.java new file mode 100644 index 0000000..8657d1d --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/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/Main.java b/src/main/java/com/educoder/bridge/tmp/Main.java new file mode 100644 index 0000000..260ae11 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/Main.java @@ -0,0 +1,197 @@ +/* +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 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 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; + } + +} diff --git a/src/main/java/com/educoder/bridge/tmp/MatrixLevelReducer.java b/src/main/java/com/educoder/bridge/tmp/MatrixLevelReducer.java new file mode 100644 index 0000000..4cb0d5d --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/MatrixLevelReducer.java @@ -0,0 +1,131 @@ +/* +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 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 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() { + @Override + public int compare(String o1, String o2) { + return o1.compareTo(o2); + } + }); + DependencyMatrix ordered = new DependencyMatrix(); + for (int id=0;id 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; + } + +} diff --git a/src/main/java/com/educoder/bridge/tmp/ParserTest.java b/src/main/java/com/educoder/bridge/tmp/ParserTest.java new file mode 100644 index 0000000..4df73d0 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/ParserTest.java @@ -0,0 +1,109 @@ +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 resolveAllBindings() { + Set result = bindingResolver.resolveAllBindings(langProcessor.isEagerExpressionResolve()); + new RelationCounter(entityRepo,langProcessor, bindingResolver).computeRelations(); + return result; + } + + protected Set resolveAllBindings(boolean callAsImpl) { + Set 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 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 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 types = function.getReturnTypes(); + for (Entity type:types) { + if (type.getRawName().uniqName().equals(name)) { + return; + } + } + fail("cannot found return type with rawname " + name); + } + +} diff --git a/src/main/java/com/educoder/bridge/tmp/PomListener.java b/src/main/java/com/educoder/bridge/tmp/PomListener.java new file mode 100644 index 0000000..8bcd2f1 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/PomListener.java @@ -0,0 +1,165 @@ +/* +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 includePaths; + private IBindingResolver IBindingResolver; + private Stack pomCoords= new Stack<>(); + + public PomListener(String fileFullPath, EntityRepo entityRepo, List 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; + } +} diff --git a/src/main/java/com/educoder/bridge/tmp/PreprocessorHandler.java b/src/main/java/com/educoder/bridge/tmp/PreprocessorHandler.java new file mode 100644 index 0000000..decaedf --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/PreprocessorHandler.java @@ -0,0 +1,126 @@ +/* +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 includePaths; + private String inputSrcPath; + private HashSet allFiles = new HashSet<>(); + public PreprocessorHandler(String inputSrcPath, List 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 getDirectIncludedFiles(IASTPreprocessorStatement[] statements, String fileLocation) { + ArrayList includedFullPathNames = new ArrayList<>(); + for (int statementIndex=0;statementIndex 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 getIncludePaths() { + return includePaths; + } +} diff --git a/src/main/java/com/educoder/bridge/tmp/PythonBuiltInType.java b/src/main/java/com/educoder/bridge/tmp/PythonBuiltInType.java new file mode 100644 index 0000000..934c870 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/PythonBuiltInType.java @@ -0,0 +1,96 @@ +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 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 functionCalls) { + for (TypeEntity type:buildInTypes) { + FunctionMatcher functionMatcher = new FunctionMatcher(type.getFunctions()); + if (functionMatcher.containsAll(functionCalls)) { + return true; + } + } + return false; + } + +} diff --git a/src/main/java/com/educoder/bridge/tmp/PythonCodeListener.java b/src/main/java/com/educoder/bridge/tmp/PythonCodeListener.java new file mode 100644 index 0000000..e406a13 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/PythonCodeListener.java @@ -0,0 +1,371 @@ +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 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 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 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 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 =""; + String name = getName(ctx.name()); + if (name!=null) { + functionName = name; + } + + FunctionEntity method = context.foundMethodDeclarator(functionName,ctx.getStart().getLine()); + if (ctx.typedargslist()!=null) { + List 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 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 getParameterList(List def_parameters) { + List 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 getArgList(ArglistContext arglist) { + List 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); + } +} diff --git a/src/main/java/com/educoder/bridge/tmp/PythonImportTest.java b/src/main/java/com/educoder/bridge/tmp/PythonImportTest.java new file mode 100644 index 0000000..6b36c4f --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/PythonImportTest.java @@ -0,0 +1,284 @@ +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")); + } + +} diff --git a/src/main/java/com/educoder/bridge/tmp/PythonLexerBase.java b/src/main/java/com/educoder/bridge/tmp/PythonLexerBase.java new file mode 100644 index 0000000..ca98458 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/PythonLexerBase.java @@ -0,0 +1,186 @@ +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 _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); + } +} + diff --git a/src/main/java/com/educoder/bridge/tmp/PythonParameterTypeDedudceTest.java b/src/main/java/com/educoder/bridge/tmp/PythonParameterTypeDedudceTest.java new file mode 100644 index 0000000..8fcb6fd --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/PythonParameterTypeDedudceTest.java @@ -0,0 +1,118 @@ +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); + } + + +} + diff --git a/src/main/java/com/educoder/bridge/tmp/RelationCounter.java b/src/main/java/com/educoder/bridge/tmp/RelationCounter.java new file mode 100644 index 0000000..c3a163f --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/RelationCounter.java @@ -0,0 +1,246 @@ +/* +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 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 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 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)); + } + } + } + +} diff --git a/src/main/java/com/educoder/bridge/tmp/RubyHandlerContext.java b/src/main/java/com/educoder/bridge/tmp/RubyHandlerContext.java new file mode 100644 index 0000000..2ce057c --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/RubyHandlerContext.java @@ -0,0 +1,105 @@ +/* +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 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); + } + } + } + + + +} diff --git a/src/main/java/com/educoder/bridge/tmp/RubyParserHelper.java b/src/main/java/com/educoder/bridge/tmp/RubyParserHelper.java new file mode 100644 index 0000000..bfb80fb --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/RubyParserHelper.java @@ -0,0 +1,165 @@ +/* +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 getName(AssignableNode ctx) { + List 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); + } +} diff --git a/src/main/java/com/educoder/bridge/tmp/RubyVarTest.java b/src/main/java/com/educoder/bridge/tmp/RubyVarTest.java new file mode 100644 index 0000000..fcd7dcc --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/RubyVarTest.java @@ -0,0 +1,172 @@ +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"); + } +} + diff --git a/src/main/java/com/educoder/bridge/tmp/TypeEntity.java b/src/main/java/com/educoder/bridge/tmp/TypeEntity.java new file mode 100644 index 0000000..6282ef4 --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/TypeEntity.java @@ -0,0 +1,204 @@ +/* +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 inheritedTypes = new ArrayList<>(); + Collection implementedTypes = new ArrayList<>(); + Collection inhertedTypeIdentifiers; + Collection 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 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 getInheritedTypes() { + return inheritedTypes; + } + + public Collection getImplementedTypes() { + return implementedTypes; + } + + public TypeEntity getInheritedType() { + return inheritedType; + } + + @Override + public FunctionEntity lookupFunctionLocally(GenericName functionName) { + Collection searchedTypes = new ArrayList<>(); + return lookupFunctionLocally(functionName,searchedTypes); + } + + private FunctionEntity lookupFunctionLocally(GenericName functionName, Collection 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 searchedTypes = new ArrayList<>(); + return lookupVarLocally(varName,searchedTypes); + } + + private VarEntity lookupVarLocally(GenericName varName, Collection 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 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; + } + + +} diff --git a/src/main/java/com/educoder/bridge/tmp/UnsolvedSymbolDumper.java b/src/main/java/com/educoder/bridge/tmp/UnsolvedSymbolDumper.java new file mode 100644 index 0000000..874369f --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/UnsolvedSymbolDumper.java @@ -0,0 +1,96 @@ +/* +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 unsolved; + private String name; + private String outputDir; + private LeadingNameStripper leadingNameStripper; + + public UnsolvedSymbolDumper(Set 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> grouped = new TreeMap>(); + for (UnsolvedBindings symbol: unsolved) { + String depended = symbol.getRawName(); + String from = leadingNameStripper.stripFilename(symbol.getSourceDisplay()); + Set 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(); + } + } + +} diff --git a/src/main/java/com/educoder/bridge/tmp/VarEntity.java b/src/main/java/com/educoder/bridge/tmp/VarEntity.java new file mode 100644 index 0000000..f81bdbc --- /dev/null +++ b/src/main/java/com/educoder/bridge/tmp/VarEntity.java @@ -0,0 +1,106 @@ +/* +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 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 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 candidateTypes = bindingResolver.calculateCandidateTypes(this,this.functionCalls); + if (candidateTypes.size()>0) { + this.type = new CandidateTypes(candidateTypes, bindingResolver.getRepo().generateId()); + bindingResolver.getRepo().add(this.type); + } + } + } +} diff --git a/src/main/java/com/educoder/bridge/utils/Base64Util.java b/src/main/java/com/educoder/bridge/utils/Base64Util.java new file mode 100644 index 0000000..3ef71ed --- /dev/null +++ b/src/main/java/com/educoder/bridge/utils/Base64Util.java @@ -0,0 +1,52 @@ +package com.educoder.bridge.utils; + + +import org.apache.commons.codec.binary.Base64; + +import java.nio.charset.StandardCharsets; + +/** + * Created by guange on 23/02/2017. + */ +public class Base64Util { + + /** + * base64编码 + * + * @param code + * @return + */ + public static String encode(String code) { + byte[] encode = Base64.encodeBase64URLSafe(code.getBytes(StandardCharsets.UTF_8)); + return new String(encode, StandardCharsets.UTF_8); + } + + public static byte[] encodeBytes(byte[] codes) { + return Base64.encodeBase64(codes); + } + + + /** + * base64解码 + * + * @param code + * @return + */ + public static String decode(String code) { + byte[] decode = Base64.decodeBase64(code); + return new String(decode, StandardCharsets.UTF_8); + } + + /** + * base64再解码,把原本的非URL safe编码转换为URL safe编码 + * + * @param code + * @return + */ + public static String reencode(String code) { + String str = decode(code); + str = str.replace("\n", "\r\n"); + return encode(str); + } + +} diff --git a/src/main/resources/applicationContext.xml b/src/main/resources/applicationContext.xml new file mode 100644 index 0000000..620ed30 --- /dev/null +++ b/src/main/resources/applicationContext.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + 0 + UTF-8 + 0.########## + yyyy-MM-dd HH:mm:ss + true + ignore + + + + + + + + + + + + diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..fe3a44e --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,47 @@ + + + + + + + + + %d{MM-dd HH:mm:ss} [%thread] %-5level %logger{30} %M %L - %msg%n + + + + DEBUG + + + + + + UTF-8 + + %d{MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{30} %M - %msg%n%L + + + ERROR + + + ${log_path}error.%d{MM-dd}.log + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/mvc-dispatcher-servlet.xml b/src/main/webapp/WEB-INF/mvc-dispatcher-servlet.xml new file mode 100644 index 0000000..d81863c --- /dev/null +++ b/src/main/webapp/WEB-INF/mvc-dispatcher-servlet.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + .ftl + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/pages/index.ftl b/src/main/webapp/WEB-INF/pages/index.ftl new file mode 100644 index 0000000..bd2f036 --- /dev/null +++ b/src/main/webapp/WEB-INF/pages/index.ftl @@ -0,0 +1,61 @@ + + + + + + + JWebssh + + + + + + + + + + + + + + +
+

JWebssh

+
+
+ +
+ +
+
+ +
+
+ +
+
+ +
+ +
+
+
+ +
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..e71e27e --- /dev/null +++ b/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,63 @@ + + + + educoder bridge + + + + contextConfigLocation + classpath:applicationContext.xml + + + + + org.springframework.web.context.ContextLoaderListener + + + + + + logbackConfigLocation + classpath:logback.xml + + + + ch.qos.logback.ext.spring.web.LogbackConfigListener + + + + mvc-dispatcher + org.springframework.web.servlet.DispatcherServlet + 1 + + + + mvc-dispatcher + / + + + + encodingFilter + org.springframework.web.filter.CharacterEncodingFilter + + encoding + UTF-8 + + + forceEncoding + true + + + + encodingFilter + /* + + + + + + + diff --git a/src/main/webapp/index.html b/src/main/webapp/index.html new file mode 100644 index 0000000..e8bbf0a --- /dev/null +++ b/src/main/webapp/index.html @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/src/main/webapp/static/css/main.css b/src/main/webapp/static/css/main.css new file mode 100644 index 0000000..d0bb3c4 --- /dev/null +++ b/src/main/webapp/static/css/main.css @@ -0,0 +1,53 @@ +.aside { + text-align: center; + background: #1f8dd6; + height: 100px; + color: #fff; + vertical-align: middle; + line-height: 100px; + font-size: 30px +} + +#main { + margin-top: 20px; +} + +#ratio-group { + float: right; +} + +.pure-item { + margin: 0 auto 10px; + width: 300px; + position: relative; +} + +.pure-radio { + margin-left: 10px; +} + +.pure-item:after { + content: ""; + display: table; + clear: both; +} + +.pure-item label { + float: left; + line-height: 34px; +} + +.pure-item input { + float: right; +} + +.terminal { + float: none; + border: #000 solid 5px; + font-family: "Monaco", "DejaVu Sans Mono", "Liberation Mono", monospace; + font-size: 11px; + color: #f0f0f0; + width: 600px; + background: #000; + box-shadow: rgba(0, 0, 0, 0.8) 2px 2px 20px; +} \ No newline at end of file diff --git a/src/main/webapp/static/css/pure-min.css b/src/main/webapp/static/css/pure-min.css new file mode 100644 index 0000000..f0aa374 --- /dev/null +++ b/src/main/webapp/static/css/pure-min.css @@ -0,0 +1,11 @@ +/*! +Pure v0.6.0 +Copyright 2014 Yahoo! Inc. All rights reserved. +Licensed under the BSD License. +https://github.com/yahoo/pure/blob/master/LICENSE.md +*/ +/*! +normalize.css v^3.0 | MIT License | git.io/normalize +Copyright (c) Nicolas Gallagher and Jonathan Neal +*/ +/*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}.hidden,[hidden]{display:none!important}.pure-img{max-width:100%;height:auto;display:block}.pure-g{letter-spacing:-.31em;*letter-spacing:normal;*word-spacing:-.43em;text-rendering:optimizespeed;font-family:FreeSans,Arimo,"Droid Sans",Helvetica,Arial,sans-serif;display:-webkit-flex;-webkit-flex-flow:row wrap;display:-ms-flexbox;-ms-flex-flow:row wrap;-ms-align-content:flex-start;-webkit-align-content:flex-start;align-content:flex-start}.opera-only :-o-prefocus,.pure-g{word-spacing:-.43em}.pure-u{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-g [class *="pure-u"]{font-family:sans-serif}.pure-u-1,.pure-u-1-1,.pure-u-1-2,.pure-u-1-3,.pure-u-2-3,.pure-u-1-4,.pure-u-3-4,.pure-u-1-5,.pure-u-2-5,.pure-u-3-5,.pure-u-4-5,.pure-u-5-5,.pure-u-1-6,.pure-u-5-6,.pure-u-1-8,.pure-u-3-8,.pure-u-5-8,.pure-u-7-8,.pure-u-1-12,.pure-u-5-12,.pure-u-7-12,.pure-u-11-12,.pure-u-1-24,.pure-u-2-24,.pure-u-3-24,.pure-u-4-24,.pure-u-5-24,.pure-u-6-24,.pure-u-7-24,.pure-u-8-24,.pure-u-9-24,.pure-u-10-24,.pure-u-11-24,.pure-u-12-24,.pure-u-13-24,.pure-u-14-24,.pure-u-15-24,.pure-u-16-24,.pure-u-17-24,.pure-u-18-24,.pure-u-19-24,.pure-u-20-24,.pure-u-21-24,.pure-u-22-24,.pure-u-23-24,.pure-u-24-24{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-1-24{width:4.1667%;*width:4.1357%}.pure-u-1-12,.pure-u-2-24{width:8.3333%;*width:8.3023%}.pure-u-1-8,.pure-u-3-24{width:12.5%;*width:12.469%}.pure-u-1-6,.pure-u-4-24{width:16.6667%;*width:16.6357%}.pure-u-1-5{width:20%;*width:19.969%}.pure-u-5-24{width:20.8333%;*width:20.8023%}.pure-u-1-4,.pure-u-6-24{width:25%;*width:24.969%}.pure-u-7-24{width:29.1667%;*width:29.1357%}.pure-u-1-3,.pure-u-8-24{width:33.3333%;*width:33.3023%}.pure-u-3-8,.pure-u-9-24{width:37.5%;*width:37.469%}.pure-u-2-5{width:40%;*width:39.969%}.pure-u-5-12,.pure-u-10-24{width:41.6667%;*width:41.6357%}.pure-u-11-24{width:45.8333%;*width:45.8023%}.pure-u-1-2,.pure-u-12-24{width:50%;*width:49.969%}.pure-u-13-24{width:54.1667%;*width:54.1357%}.pure-u-7-12,.pure-u-14-24{width:58.3333%;*width:58.3023%}.pure-u-3-5{width:60%;*width:59.969%}.pure-u-5-8,.pure-u-15-24{width:62.5%;*width:62.469%}.pure-u-2-3,.pure-u-16-24{width:66.6667%;*width:66.6357%}.pure-u-17-24{width:70.8333%;*width:70.8023%}.pure-u-3-4,.pure-u-18-24{width:75%;*width:74.969%}.pure-u-19-24{width:79.1667%;*width:79.1357%}.pure-u-4-5{width:80%;*width:79.969%}.pure-u-5-6,.pure-u-20-24{width:83.3333%;*width:83.3023%}.pure-u-7-8,.pure-u-21-24{width:87.5%;*width:87.469%}.pure-u-11-12,.pure-u-22-24{width:91.6667%;*width:91.6357%}.pure-u-23-24{width:95.8333%;*width:95.8023%}.pure-u-1,.pure-u-1-1,.pure-u-5-5,.pure-u-24-24{width:100%}.pure-button{display:inline-block;zoom:1;line-height:normal;white-space:nowrap;vertical-align:middle;text-align:center;cursor:pointer;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button{font-family:inherit;font-size:100%;padding:.5em 1em;color:#444;color:rgba(0,0,0,.8);border:1px solid #999;border:0 rgba(0,0,0,0);background-color:#E6E6E6;text-decoration:none;border-radius:2px}.pure-button-hover,.pure-button:hover,.pure-button:focus{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#1a000000', GradientType=0);background-image:-webkit-gradient(linear,0 0,0 100%,from(transparent),color-stop(40%,rgba(0,0,0,.05)),to(rgba(0,0,0,.1)));background-image:-webkit-linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1));background-image:-moz-linear-gradient(top,rgba(0,0,0,.05) 0,rgba(0,0,0,.1));background-image:-o-linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1));background-image:linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1))}.pure-button:focus{outline:0}.pure-button-active,.pure-button:active{box-shadow:0 0 0 1px rgba(0,0,0,.15) inset,0 0 6px rgba(0,0,0,.2) inset;border-color:#000\9}.pure-button[disabled],.pure-button-disabled,.pure-button-disabled:hover,.pure-button-disabled:focus,.pure-button-disabled:active{border:0;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);filter:alpha(opacity=40);-khtml-opacity:.4;-moz-opacity:.4;opacity:.4;cursor:not-allowed;box-shadow:none}.pure-button-hidden{display:none}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button-primary,.pure-button-selected,a.pure-button-primary,a.pure-button-selected{background-color:#0078e7;color:#fff}.pure-form input[type=text],.pure-form input[type=password],.pure-form input[type=email],.pure-form input[type=url],.pure-form input[type=date],.pure-form input[type=month],.pure-form input[type=time],.pure-form input[type=datetime],.pure-form input[type=datetime-local],.pure-form input[type=week],.pure-form input[type=number],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=color],.pure-form select,.pure-form textarea{padding:.5em .6em;display:inline-block;border:1px solid #ccc;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;vertical-align:middle;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.pure-form input:not([type]){padding:.5em .6em;display:inline-block;border:1px solid #ccc;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.pure-form input[type=color]{padding:.2em .5em}.pure-form input[type=text]:focus,.pure-form input[type=password]:focus,.pure-form input[type=email]:focus,.pure-form input[type=url]:focus,.pure-form input[type=date]:focus,.pure-form input[type=month]:focus,.pure-form input[type=time]:focus,.pure-form input[type=datetime]:focus,.pure-form input[type=datetime-local]:focus,.pure-form input[type=week]:focus,.pure-form input[type=number]:focus,.pure-form input[type=search]:focus,.pure-form input[type=tel]:focus,.pure-form input[type=color]:focus,.pure-form select:focus,.pure-form textarea:focus{outline:0;border-color:#129FEA}.pure-form input:not([type]):focus{outline:0;border-color:#129FEA}.pure-form input[type=file]:focus,.pure-form input[type=radio]:focus,.pure-form input[type=checkbox]:focus{outline:thin solid #129FEA;outline:1px auto #129FEA}.pure-form .pure-checkbox,.pure-form .pure-radio{margin:.5em 0;display:block}.pure-form input[type=text][disabled],.pure-form input[type=password][disabled],.pure-form input[type=email][disabled],.pure-form input[type=url][disabled],.pure-form input[type=date][disabled],.pure-form input[type=month][disabled],.pure-form input[type=time][disabled],.pure-form input[type=datetime][disabled],.pure-form input[type=datetime-local][disabled],.pure-form input[type=week][disabled],.pure-form input[type=number][disabled],.pure-form input[type=search][disabled],.pure-form input[type=tel][disabled],.pure-form input[type=color][disabled],.pure-form select[disabled],.pure-form textarea[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input:not([type])[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input[readonly],.pure-form select[readonly],.pure-form textarea[readonly]{background-color:#eee;color:#777;border-color:#ccc}.pure-form input:focus:invalid,.pure-form textarea:focus:invalid,.pure-form select:focus:invalid{color:#b94a48;border-color:#e9322d}.pure-form input[type=file]:focus:invalid:focus,.pure-form input[type=radio]:focus:invalid:focus,.pure-form input[type=checkbox]:focus:invalid:focus{outline-color:#e9322d}.pure-form select{height:2.25em;border:1px solid #ccc;background-color:#fff}.pure-form select[multiple]{height:auto}.pure-form label{margin:.5em 0 .2em}.pure-form fieldset{margin:0;padding:.35em 0 .75em;border:0}.pure-form legend{display:block;width:100%;padding:.3em 0;margin-bottom:.3em;color:#333;border-bottom:1px solid #e5e5e5}.pure-form-stacked input[type=text],.pure-form-stacked input[type=password],.pure-form-stacked input[type=email],.pure-form-stacked input[type=url],.pure-form-stacked input[type=date],.pure-form-stacked input[type=month],.pure-form-stacked input[type=time],.pure-form-stacked input[type=datetime],.pure-form-stacked input[type=datetime-local],.pure-form-stacked input[type=week],.pure-form-stacked input[type=number],.pure-form-stacked input[type=search],.pure-form-stacked input[type=tel],.pure-form-stacked input[type=color],.pure-form-stacked input[type=file],.pure-form-stacked select,.pure-form-stacked label,.pure-form-stacked textarea{display:block;margin:.25em 0}.pure-form-stacked input:not([type]){display:block;margin:.25em 0}.pure-form-aligned input,.pure-form-aligned textarea,.pure-form-aligned select,.pure-form-aligned .pure-help-inline,.pure-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.pure-form-aligned textarea{vertical-align:top}.pure-form-aligned .pure-control-group{margin-bottom:.5em}.pure-form-aligned .pure-control-group label{text-align:right;display:inline-block;vertical-align:middle;width:10em;margin:0 1em 0 0}.pure-form-aligned .pure-controls{margin:1.5em 0 0 11em}.pure-form input.pure-input-rounded,.pure-form .pure-input-rounded{border-radius:2em;padding:.5em 1em}.pure-form .pure-group fieldset{margin-bottom:10px}.pure-form .pure-group input,.pure-form .pure-group textarea{display:block;padding:10px;margin:0 0 -1px;border-radius:0;position:relative;top:-1px}.pure-form .pure-group input:focus,.pure-form .pure-group textarea:focus{z-index:3}.pure-form .pure-group input:first-child,.pure-form .pure-group textarea:first-child{top:1px;border-radius:4px 4px 0 0;margin:0}.pure-form .pure-group input:first-child:last-child,.pure-form .pure-group textarea:first-child:last-child{top:1px;border-radius:4px;margin:0}.pure-form .pure-group input:last-child,.pure-form .pure-group textarea:last-child{top:-2px;border-radius:0 0 4px 4px;margin:0}.pure-form .pure-group button{margin:.35em 0}.pure-form .pure-input-1{width:100%}.pure-form .pure-input-2-3{width:66%}.pure-form .pure-input-1-2{width:50%}.pure-form .pure-input-1-3{width:33%}.pure-form .pure-input-1-4{width:25%}.pure-form .pure-help-inline,.pure-form-message-inline{display:inline-block;padding-left:.3em;color:#666;vertical-align:middle;font-size:.875em}.pure-form-message{display:block;color:#666;font-size:.875em}@media only screen and (max-width :480px){.pure-form button[type=submit]{margin:.7em 0 0}.pure-form input:not([type]),.pure-form input[type=text],.pure-form input[type=password],.pure-form input[type=email],.pure-form input[type=url],.pure-form input[type=date],.pure-form input[type=month],.pure-form input[type=time],.pure-form input[type=datetime],.pure-form input[type=datetime-local],.pure-form input[type=week],.pure-form input[type=number],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=color],.pure-form label{margin-bottom:.3em;display:block}.pure-group input:not([type]),.pure-group input[type=text],.pure-group input[type=password],.pure-group input[type=email],.pure-group input[type=url],.pure-group input[type=date],.pure-group input[type=month],.pure-group input[type=time],.pure-group input[type=datetime],.pure-group input[type=datetime-local],.pure-group input[type=week],.pure-group input[type=number],.pure-group input[type=search],.pure-group input[type=tel],.pure-group input[type=color]{margin-bottom:0}.pure-form-aligned .pure-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.pure-form-aligned .pure-controls{margin:1.5em 0 0}.pure-form .pure-help-inline,.pure-form-message-inline,.pure-form-message{display:block;font-size:.75em;padding:.2em 0 .8em}}.pure-menu{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.pure-menu-fixed{position:fixed;left:0;top:0;z-index:3}.pure-menu-list,.pure-menu-item{position:relative}.pure-menu-list{list-style:none;margin:0;padding:0}.pure-menu-item{padding:0;margin:0;height:100%}.pure-menu-link,.pure-menu-heading{display:block;text-decoration:none;white-space:nowrap}.pure-menu-horizontal{width:100%;white-space:nowrap}.pure-menu-horizontal .pure-menu-list{display:inline-block}.pure-menu-horizontal .pure-menu-item,.pure-menu-horizontal .pure-menu-heading,.pure-menu-horizontal .pure-menu-separator{display:inline-block;*display:inline;zoom:1;vertical-align:middle}.pure-menu-item .pure-menu-item{display:block}.pure-menu-children{display:none;position:absolute;left:100%;top:0;margin:0;padding:0;z-index:3}.pure-menu-horizontal .pure-menu-children{left:0;top:auto;width:inherit}.pure-menu-allow-hover:hover>.pure-menu-children,.pure-menu-active>.pure-menu-children{display:block;position:absolute}.pure-menu-has-children>.pure-menu-link:after{padding-left:.5em;content:"\25B8";font-size:small}.pure-menu-horizontal .pure-menu-has-children>.pure-menu-link:after{content:"\25BE"}.pure-menu-scrollable{overflow-y:scroll;overflow-x:hidden}.pure-menu-scrollable .pure-menu-list{display:block}.pure-menu-horizontal.pure-menu-scrollable .pure-menu-list{display:inline-block}.pure-menu-horizontal.pure-menu-scrollable{white-space:nowrap;overflow-y:hidden;overflow-x:auto;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;padding:.5em 0}.pure-menu-horizontal.pure-menu-scrollable::-webkit-scrollbar{display:none}.pure-menu-separator{background-color:#ccc;height:1px;margin:.3em 0}.pure-menu-horizontal .pure-menu-separator{width:1px;height:1.3em;margin:0 .3em}.pure-menu-heading{text-transform:uppercase;color:#565d64}.pure-menu-link{color:#777}.pure-menu-children{background-color:#fff}.pure-menu-link,.pure-menu-disabled,.pure-menu-heading{padding:.5em 1em}.pure-menu-disabled{opacity:.5}.pure-menu-disabled .pure-menu-link:hover{background-color:transparent}.pure-menu-active>.pure-menu-link,.pure-menu-link:hover,.pure-menu-link:focus{background-color:#eee}.pure-menu-selected .pure-menu-link,.pure-menu-selected .pure-menu-link:visited{color:#000}.pure-table{border-collapse:collapse;border-spacing:0;empty-cells:show;border:1px solid #cbcbcb}.pure-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.pure-table td,.pure-table th{border-left:1px solid #cbcbcb;border-width:0 0 0 1px;font-size:inherit;margin:0;overflow:visible;padding:.5em 1em}.pure-table td:first-child,.pure-table th:first-child{border-left-width:0}.pure-table thead{background-color:#e0e0e0;color:#000;text-align:left;vertical-align:bottom}.pure-table td{background-color:transparent}.pure-table-odd td{background-color:#f2f2f2}.pure-table-striped tr:nth-child(2n-1) td{background-color:#f2f2f2}.pure-table-bordered td{border-bottom:1px solid #cbcbcb}.pure-table-bordered tbody>tr:last-child>td{border-bottom-width:0}.pure-table-horizontal td,.pure-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #cbcbcb}.pure-table-horizontal tbody>tr:last-child>td{border-bottom-width:0} \ No newline at end of file diff --git a/src/main/webapp/static/css/reset.css b/src/main/webapp/static/css/reset.css new file mode 100644 index 0000000..248aacf --- /dev/null +++ b/src/main/webapp/static/css/reset.css @@ -0,0 +1,44 @@ + +/* ------- This is the CSS Reset ------- */ + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, +abbr, acronym, address, big, cite, code, del, +dfn, em, img, ins, kbd, q, s, samp, small, +strike, strong, sub, sup, tt, var, u, i, center, +dl, dt, dd, ol, ul, li, fieldset, form, label, +legend, table, caption, tbody, tfoot, thead, tr, +th, td, article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, menu, +nav, output, ruby, section, summary, time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} + +/* ------- HTML5 display-role reset for older browsers ------- */ + +article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { + display: block; +} +body { + line-height: 1; +} +ol, ul { + list-style: none; +} +blockquote, q { + quotes: none; +} +blockquote:before, blockquote:after, q:before, q:after { + content: ''; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} + diff --git a/src/main/webapp/static/css/style.css b/src/main/webapp/static/css/style.css new file mode 100644 index 0000000..e2073ba --- /dev/null +++ b/src/main/webapp/static/css/style.css @@ -0,0 +1,187 @@ +/* + * + * Template Name: Fullscreen Login + * Description: Login Template with Fullscreen Background Slideshow + * Author: Anli Zaimi + * Author URI: http://azmind.com + * + */ + + +body { + background: #f8f8f8; + font-family: 'PT Sans', Helvetica, Arial, sans-serif; + text-align: center; + color: #fff; +} + +.page-container { + margin: 120px auto 0 auto; +} + +h1 { + font-size: 30px; + font-weight: 700; + text-shadow: 0 1px 4px rgba(0,0,0,.2); +} + +form { + position: relative; + width: 305px; + margin: 15px auto 0 auto; + text-align: center; +} + +input { + width: 270px; + height: 42px; + margin-top: 25px; + padding: 0 15px; + background: #2d2d2d; /* browsers that don't support rgba */ + background: rgba(45,45,45,.15); + -moz-border-radius: 6px; + -webkit-border-radius: 6px; + border-radius: 6px; + border: 1px solid #3d3d3d; /* browsers that don't support rgba */ + border: 1px solid rgba(255,255,255,.15); + -moz-box-shadow: 0 2px 3px 0 rgba(0,0,0,.1) inset; + -webkit-box-shadow: 0 2px 3px 0 rgba(0,0,0,.1) inset; + box-shadow: 0 2px 3px 0 rgba(0,0,0,.1) inset; + font-family: 'PT Sans', Helvetica, Arial, sans-serif; + font-size: 14px; + color: #fff; + text-shadow: 0 1px 2px rgba(0,0,0,.1); + -o-transition: all .2s; + -moz-transition: all .2s; + -webkit-transition: all .2s; + -ms-transition: all .2s; +} + +input:-moz-placeholder { color: #fff; } +input:-ms-input-placeholder { color: #fff; } +input::-webkit-input-placeholder { color: #fff; } + +input:focus { + outline: none; + -moz-box-shadow: + 0 2px 3px 0 rgba(0,0,0,.1) inset, + 0 2px 7px 0 rgba(0,0,0,.2); + -webkit-box-shadow: + 0 2px 3px 0 rgba(0,0,0,.1) inset, + 0 2px 7px 0 rgba(0,0,0,.2); + box-shadow: + 0 2px 3px 0 rgba(0,0,0,.1) inset, + 0 2px 7px 0 rgba(0,0,0,.2); +} + +button { + cursor: pointer; + width: 300px; + height: 44px; + margin-top: 25px; + padding: 0; + background: #ef4300; + -moz-border-radius: 6px; + -webkit-border-radius: 6px; + border-radius: 6px; + border: 1px solid #ff730e; + -moz-box-shadow: + 0 15px 30px 0 rgba(255,255,255,.25) inset, + 0 2px 7px 0 rgba(0,0,0,.2); + -webkit-box-shadow: + 0 15px 30px 0 rgba(255,255,255,.25) inset, + 0 2px 7px 0 rgba(0,0,0,.2); + box-shadow: + 0 15px 30px 0 rgba(255,255,255,.25) inset, + 0 2px 7px 0 rgba(0,0,0,.2); + font-family: 'PT Sans', Helvetica, Arial, sans-serif; + font-size: 14px; + font-weight: 700; + color: #fff; + text-shadow: 0 1px 2px rgba(0,0,0,.1); + -o-transition: all .2s; + -moz-transition: all .2s; + -webkit-transition: all .2s; + -ms-transition: all .2s; +} + +button:hover { + -moz-box-shadow: + 0 15px 30px 0 rgba(255,255,255,.15) inset, + 0 2px 7px 0 rgba(0,0,0,.2); + -webkit-box-shadow: + 0 15px 30px 0 rgba(255,255,255,.15) inset, + 0 2px 7px 0 rgba(0,0,0,.2); + box-shadow: + 0 15px 30px 0 rgba(255,255,255,.15) inset, + 0 2px 7px 0 rgba(0,0,0,.2); +} + +button:active { + -moz-box-shadow: + 0 15px 30px 0 rgba(255,255,255,.15) inset, + 0 2px 7px 0 rgba(0,0,0,.2); + -webkit-box-shadow: + 0 15px 30px 0 rgba(255,255,255,.15) inset, + 0 2px 7px 0 rgba(0,0,0,.2); + box-shadow: + 0 5px 8px 0 rgba(0,0,0,.1) inset, + 0 1px 4px 0 rgba(0,0,0,.1); + + border: 0px solid #ef4300; +} + +.error { + display: none; + position: absolute; + top: 27px; + right: -55px; + width: 40px; + height: 40px; + background: #2d2d2d; /* browsers that don't support rgba */ + background: rgba(45,45,45,.25); + -moz-border-radius: 8px; + -webkit-border-radius: 8px; + border-radius: 8px; +} + +.error span { + display: inline-block; + margin-left: 2px; + font-size: 40px; + font-weight: 700; + line-height: 40px; + text-shadow: 0 1px 2px rgba(0,0,0,.1); + -o-transform: rotate(45deg); + -moz-transform: rotate(45deg); + -webkit-transform: rotate(45deg); + -ms-transform: rotate(45deg); + +} + +.connect { + width: 305px; + margin: 35px auto 0 auto; + font-size: 18px; + font-weight: 700; + text-shadow: 0 1px 3px rgba(0,0,0,.2); +} + +.connect a { + display: inline-block; + width: 32px; + height: 35px; + margin-top: 15px; + -o-transition: all .2s; + -moz-transition: all .2s; + -webkit-transition: all .2s; + -ms-transition: all .2s; +} + +.connect a.facebook { background: url(../image/facebook.png) center center no-repeat; } +.connect a.twitter { background: url(../image/twitter.png) center center no-repeat; } + +.connect a:hover { background-position: center bottom; } + + + diff --git a/src/main/webapp/static/css/supersized.css b/src/main/webapp/static/css/supersized.css new file mode 100644 index 0000000..a507e4d --- /dev/null +++ b/src/main/webapp/static/css/supersized.css @@ -0,0 +1,34 @@ +/* + + Supersized - Fullscreen Slideshow jQuery Plugin + Version : 3.2.7 + Site : www.buildinternet.com/project/supersized + + Author : Sam Dunn + Company : One Mighty Roar (www.onemightyroar.com) + License : MIT License / GPL License + +*/ + +* { margin:0; padding:0; } +body { background:#111; height:100%; } + img { border:none; } + + #supersized-loader { position:absolute; top:50%; left:50%; z-index:0; width:60px; height:60px; margin:-30px 0 0 -30px; text-indent:-999em; background:url(../image/progress.gif) no-repeat center center;} + + #supersized { display:block; position:fixed; left:0; top:0; overflow:hidden; z-index:-999; height:100%; width:100%; } + #supersized img { width:auto; height:auto; position:relative; display:none; outline:none; border:none; } + #supersized.speed img { -ms-interpolation-mode:nearest-neighbor; image-rendering: -moz-crisp-edges; } /*Speed*/ + #supersized.quality img { -ms-interpolation-mode:bicubic; image-rendering: optimizeQuality; } /*Quality*/ + + #supersized li { display:block; list-style:none; z-index:-30; position:fixed; overflow:hidden; top:0; left:0; width:100%; height:100%; background:#111; } + #supersized a { width:100%; height:100%; display:block; } + #supersized li.prevslide { z-index:-20; } + #supersized li.activeslide { z-index:-10; } + #supersized li.image-loading { background:#111 url(../image/progress.gif) no-repeat center center; width:100%; height:100%; } + #supersized li.image-loading img{ visibility:hidden; } + #supersized li.prevslide img, #supersized li.activeslide img{ display:inline; } + + +#supersized img { max-width: none !important } + diff --git a/src/main/webapp/static/css/tooltip.css b/src/main/webapp/static/css/tooltip.css new file mode 100644 index 0000000..978506f --- /dev/null +++ b/src/main/webapp/static/css/tooltip.css @@ -0,0 +1,25 @@ +.tooltip{ + position: absolute; + max-width: 300px; + top: 3px; + left: 105%; + padding: 8px 10px; + border-radius: 5px; + color: #fff; + background: #000000; + box-shadow: 0 2px 2px 0 #7F7C7C; + white-space: nowrap; +} +.tooltip:after{ + content: ''; + position: absolute; + top: 35%; + right:100%; + margin-left: 10px; + width: 0; + height: 0; + border: 5px solid transparent; + border-right: 7px #000; + border-left-width: 7px; +} + diff --git a/src/main/webapp/static/css/xterm.css b/src/main/webapp/static/css/xterm.css new file mode 100644 index 0000000..e6f3909 --- /dev/null +++ b/src/main/webapp/static/css/xterm.css @@ -0,0 +1,2273 @@ +/** + * xterm.js: xterm, in the browser + * Copyright (c) 2014-2016, SourceLair Private Company (www.sourcelair.com (MIT License) + * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License) + * https://github.com/chjj/term.js + * + * 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. + * + * Originally forked from (with the author's permission): + * Fabrice Bellard's javascript vt100 for jslinux: + * http://bellard.org/jslinux/ + * Copyright (c) 2011 Fabrice Bellard + * The original design remains. The terminal itself + * has been extended to include xterm CSI codes, among + * other features. + */ + +/* + * Default style for xterm.js + */ +::-webkit-scrollbar { width:10px; height:10px; background-color: #F5F5F5; } +::-webkit-scrollbar-track { -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); background-color: #F5F5F5; } +::-webkit-scrollbar-thumb { -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3); background-color: #ccc; } + +.terminal { + background-color: #000; + color: #fff; + font-family: courier-new, courier, monospace; + font-feature-settings: "liga" 0; + position: relative; + user-select: none; + -ms-user-select: none; + -webkit-user-select: none; +} + +.terminal.focus, +.terminal:focus { + outline: none; +} + +.terminal .xterm-helpers { + position: absolute; + top: 0; +} + +.terminal .xterm-helper-textarea { + /* + * HACK: to fix IE's blinking cursor + * Move textarea out of the screen to the far left, so that the cursor is not visible. + */ + position: absolute; + opacity: 0; + left: -9999em; + top: 0; + width: 0; + height: 0; + z-index: -10; + /** Prevent wrapping so the IME appears against the textarea at the correct position */ + white-space: nowrap; + overflow: hidden; + resize: none; +} + +.terminal a { + color: inherit; + text-decoration: none; +} + +.terminal a:hover { + cursor: pointer; + text-decoration: underline; +} + +.terminal a.xterm-invalid-link:hover { + cursor: text; + text-decoration: none; +} + +.terminal.focus:not(.xterm-cursor-style-underline):not(.xterm-cursor-style-bar) .terminal-cursor { + background-color: #fff; + color: #000; +} + +.terminal:not(.focus) .terminal-cursor { + outline: 1px solid #fff; + outline-offset: -1px; + background-color: transparent; +} + +.terminal:not(.xterm-cursor-style-underline):not(.xterm-cursor-style-bar).focus.xterm-cursor-blink-on .terminal-cursor { + background-color: transparent; + color: inherit; +} + +.terminal.xterm-cursor-style-bar .terminal-cursor, +.terminal.xterm-cursor-style-underline .terminal-cursor { + position: relative; +} +.terminal.xterm-cursor-style-bar .terminal-cursor::before, +.terminal.xterm-cursor-style-underline .terminal-cursor::before { + content: ""; + display: block; + position: absolute; + background-color: #fff; +} +.terminal.xterm-cursor-style-bar .terminal-cursor::before { + top: 0; + bottom: 0; + left: 0; + width: 1px; +} +.terminal.xterm-cursor-style-underline .terminal-cursor::before { + bottom: 0; + left: 0; + right: 0; + height: 1px; +} +.terminal.xterm-cursor-style-bar.focus.xterm-cursor-blink.xterm-cursor-blink-on .terminal-cursor::before, +.terminal.xterm-cursor-style-underline.focus.xterm-cursor-blink.xterm-cursor-blink-on .terminal-cursor::before { + background-color: transparent; +} +.terminal.xterm-cursor-style-bar.focus.xterm-cursor-blink .terminal-cursor::before, +.terminal.xterm-cursor-style-underline.focus.xterm-cursor-blink .terminal-cursor::before { + background-color: #fff; +} + +.terminal .composition-view { + background: #000; + color: #FFF; + display: none; + position: absolute; + white-space: nowrap; + z-index: 1; +} + +.terminal .composition-view.active { + display: block; +} + +.terminal .xterm-viewport { + /* On OS X this is required in order for the scroll bar to appear fully opaque */ + background-color: #000; + overflow-y: auto; +} + +.terminal .xterm-wide-char, +.terminal .xterm-normal-char { + display: inline-block; +} + +.terminal .xterm-rows { + position: absolute; + left: 0; + top: 0; +} + +.terminal .xterm-rows > div { + /* Lines containing spans and text nodes ocassionally wrap despite being the same width (#327) */ + white-space: nowrap; +} + +.terminal .xterm-scroll-area { + visibility: hidden; +} + +.terminal .xterm-char-measure-element { + display: inline-block; + visibility: hidden; + position: absolute; + left: -9999em; +} + +.terminal.enable-mouse-events { + /* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */ + cursor: default; +} + +.terminal .xterm-selection { + position: absolute; + top: 0; + left: 0; + z-index: 1; + opacity: 0.3; + pointer-events: none; +} + +.terminal .xterm-selection div { + position: absolute; + background-color: #fff; +} + +/* + * Determine default colors for xterm.js + */ +.terminal .xterm-bold { + font-weight: bold; +} + +.terminal .xterm-underline { + text-decoration: underline; +} + +.terminal .xterm-blink { + text-decoration: blink; +} + +.terminal .xterm-hidden { + visibility: hidden; +} + +.terminal .xterm-color-0 { + color: #2e3436; +} + +.terminal .xterm-bg-color-0 { + background-color: #2e3436; +} + +.terminal .xterm-color-1 { + color: #cc0000; +} + +.terminal .xterm-bg-color-1 { + background-color: #cc0000; +} + +.terminal .xterm-color-2 { + color: #4e9a06; +} + +.terminal .xterm-bg-color-2 { + background-color: #4e9a06; +} + +.terminal .xterm-color-3 { + color: #c4a000; +} + +.terminal .xterm-bg-color-3 { + background-color: #c4a000; +} + +.terminal .xterm-color-4 { + color: #3465a4; +} + +.terminal .xterm-bg-color-4 { + background-color: #3465a4; +} + +.terminal .xterm-color-5 { + color: #75507b; +} + +.terminal .xterm-bg-color-5 { + background-color: #75507b; +} + +.terminal .xterm-color-6 { + color: #06989a; +} + +.terminal .xterm-bg-color-6 { + background-color: #06989a; +} + +.terminal .xterm-color-7 { + color: #d3d7cf; +} + +.terminal .xterm-bg-color-7 { + background-color: #d3d7cf; +} + +.terminal .xterm-color-8 { + color: #555753; +} + +.terminal .xterm-bg-color-8 { + background-color: #555753; +} + +.terminal .xterm-color-9 { + color: #ef2929; +} + +.terminal .xterm-bg-color-9 { + background-color: #ef2929; +} + +.terminal .xterm-color-10 { + color: #8ae234; +} + +.terminal .xterm-bg-color-10 { + background-color: #8ae234; +} + +.terminal .xterm-color-11 { + color: #fce94f; +} + +.terminal .xterm-bg-color-11 { + background-color: #fce94f; +} + +.terminal .xterm-color-12 { + color: #729fcf; +} + +.terminal .xterm-bg-color-12 { + background-color: #729fcf; +} + +.terminal .xterm-color-13 { + color: #ad7fa8; +} + +.terminal .xterm-bg-color-13 { + background-color: #ad7fa8; +} + +.terminal .xterm-color-14 { + color: #34e2e2; +} + +.terminal .xterm-bg-color-14 { + background-color: #34e2e2; +} + +.terminal .xterm-color-15 { + color: #eeeeec; +} + +.terminal .xterm-bg-color-15 { + background-color: #eeeeec; +} + +.terminal .xterm-color-16 { + color: #000000; +} + +.terminal .xterm-bg-color-16 { + background-color: #000000; +} + +.terminal .xterm-color-17 { + color: #00005f; +} + +.terminal .xterm-bg-color-17 { + background-color: #00005f; +} + +.terminal .xterm-color-18 { + color: #000087; +} + +.terminal .xterm-bg-color-18 { + background-color: #000087; +} + +.terminal .xterm-color-19 { + color: #0000af; +} + +.terminal .xterm-bg-color-19 { + background-color: #0000af; +} + +.terminal .xterm-color-20 { + color: #0000d7; +} + +.terminal .xterm-bg-color-20 { + background-color: #0000d7; +} + +.terminal .xterm-color-21 { + color: #0000ff; +} + +.terminal .xterm-bg-color-21 { + background-color: #0000ff; +} + +.terminal .xterm-color-22 { + color: #005f00; +} + +.terminal .xterm-bg-color-22 { + background-color: #005f00; +} + +.terminal .xterm-color-23 { + color: #005f5f; +} + +.terminal .xterm-bg-color-23 { + background-color: #005f5f; +} + +.terminal .xterm-color-24 { + color: #005f87; +} + +.terminal .xterm-bg-color-24 { + background-color: #005f87; +} + +.terminal .xterm-color-25 { + color: #005faf; +} + +.terminal .xterm-bg-color-25 { + background-color: #005faf; +} + +.terminal .xterm-color-26 { + color: #005fd7; +} + +.terminal .xterm-bg-color-26 { + background-color: #005fd7; +} + +.terminal .xterm-color-27 { + color: #005fff; +} + +.terminal .xterm-bg-color-27 { + background-color: #005fff; +} + +.terminal .xterm-color-28 { + color: #008700; +} + +.terminal .xterm-bg-color-28 { + background-color: #008700; +} + +.terminal .xterm-color-29 { + color: #00875f; +} + +.terminal .xterm-bg-color-29 { + background-color: #00875f; +} + +.terminal .xterm-color-30 { + color: #008787; +} + +.terminal .xterm-bg-color-30 { + background-color: #008787; +} + +.terminal .xterm-color-31 { + color: #0087af; +} + +.terminal .xterm-bg-color-31 { + background-color: #0087af; +} + +.terminal .xterm-color-32 { + color: #0087d7; +} + +.terminal .xterm-bg-color-32 { + background-color: #0087d7; +} + +.terminal .xterm-color-33 { + color: #0087ff; +} + +.terminal .xterm-bg-color-33 { + background-color: #0087ff; +} + +.terminal .xterm-color-34 { + color: #00af00; +} + +.terminal .xterm-bg-color-34 { + background-color: #00af00; +} + +.terminal .xterm-color-35 { + color: #00af5f; +} + +.terminal .xterm-bg-color-35 { + background-color: #00af5f; +} + +.terminal .xterm-color-36 { + color: #00af87; +} + +.terminal .xterm-bg-color-36 { + background-color: #00af87; +} + +.terminal .xterm-color-37 { + color: #00afaf; +} + +.terminal .xterm-bg-color-37 { + background-color: #00afaf; +} + +.terminal .xterm-color-38 { + color: #00afd7; +} + +.terminal .xterm-bg-color-38 { + background-color: #00afd7; +} + +.terminal .xterm-color-39 { + color: #00afff; +} + +.terminal .xterm-bg-color-39 { + background-color: #00afff; +} + +.terminal .xterm-color-40 { + color: #00d700; +} + +.terminal .xterm-bg-color-40 { + background-color: #00d700; +} + +.terminal .xterm-color-41 { + color: #00d75f; +} + +.terminal .xterm-bg-color-41 { + background-color: #00d75f; +} + +.terminal .xterm-color-42 { + color: #00d787; +} + +.terminal .xterm-bg-color-42 { + background-color: #00d787; +} + +.terminal .xterm-color-43 { + color: #00d7af; +} + +.terminal .xterm-bg-color-43 { + background-color: #00d7af; +} + +.terminal .xterm-color-44 { + color: #00d7d7; +} + +.terminal .xterm-bg-color-44 { + background-color: #00d7d7; +} + +.terminal .xterm-color-45 { + color: #00d7ff; +} + +.terminal .xterm-bg-color-45 { + background-color: #00d7ff; +} + +.terminal .xterm-color-46 { + color: #00ff00; +} + +.terminal .xterm-bg-color-46 { + background-color: #00ff00; +} + +.terminal .xterm-color-47 { + color: #00ff5f; +} + +.terminal .xterm-bg-color-47 { + background-color: #00ff5f; +} + +.terminal .xterm-color-48 { + color: #00ff87; +} + +.terminal .xterm-bg-color-48 { + background-color: #00ff87; +} + +.terminal .xterm-color-49 { + color: #00ffaf; +} + +.terminal .xterm-bg-color-49 { + background-color: #00ffaf; +} + +.terminal .xterm-color-50 { + color: #00ffd7; +} + +.terminal .xterm-bg-color-50 { + background-color: #00ffd7; +} + +.terminal .xterm-color-51 { + color: #00ffff; +} + +.terminal .xterm-bg-color-51 { + background-color: #00ffff; +} + +.terminal .xterm-color-52 { + color: #5f0000; +} + +.terminal .xterm-bg-color-52 { + background-color: #5f0000; +} + +.terminal .xterm-color-53 { + color: #5f005f; +} + +.terminal .xterm-bg-color-53 { + background-color: #5f005f; +} + +.terminal .xterm-color-54 { + color: #5f0087; +} + +.terminal .xterm-bg-color-54 { + background-color: #5f0087; +} + +.terminal .xterm-color-55 { + color: #5f00af; +} + +.terminal .xterm-bg-color-55 { + background-color: #5f00af; +} + +.terminal .xterm-color-56 { + color: #5f00d7; +} + +.terminal .xterm-bg-color-56 { + background-color: #5f00d7; +} + +.terminal .xterm-color-57 { + color: #5f00ff; +} + +.terminal .xterm-bg-color-57 { + background-color: #5f00ff; +} + +.terminal .xterm-color-58 { + color: #5f5f00; +} + +.terminal .xterm-bg-color-58 { + background-color: #5f5f00; +} + +.terminal .xterm-color-59 { + color: #5f5f5f; +} + +.terminal .xterm-bg-color-59 { + background-color: #5f5f5f; +} + +.terminal .xterm-color-60 { + color: #5f5f87; +} + +.terminal .xterm-bg-color-60 { + background-color: #5f5f87; +} + +.terminal .xterm-color-61 { + color: #5f5faf; +} + +.terminal .xterm-bg-color-61 { + background-color: #5f5faf; +} + +.terminal .xterm-color-62 { + color: #5f5fd7; +} + +.terminal .xterm-bg-color-62 { + background-color: #5f5fd7; +} + +.terminal .xterm-color-63 { + color: #5f5fff; +} + +.terminal .xterm-bg-color-63 { + background-color: #5f5fff; +} + +.terminal .xterm-color-64 { + color: #5f8700; +} + +.terminal .xterm-bg-color-64 { + background-color: #5f8700; +} + +.terminal .xterm-color-65 { + color: #5f875f; +} + +.terminal .xterm-bg-color-65 { + background-color: #5f875f; +} + +.terminal .xterm-color-66 { + color: #5f8787; +} + +.terminal .xterm-bg-color-66 { + background-color: #5f8787; +} + +.terminal .xterm-color-67 { + color: #5f87af; +} + +.terminal .xterm-bg-color-67 { + background-color: #5f87af; +} + +.terminal .xterm-color-68 { + color: #5f87d7; +} + +.terminal .xterm-bg-color-68 { + background-color: #5f87d7; +} + +.terminal .xterm-color-69 { + color: #5f87ff; +} + +.terminal .xterm-bg-color-69 { + background-color: #5f87ff; +} + +.terminal .xterm-color-70 { + color: #5faf00; +} + +.terminal .xterm-bg-color-70 { + background-color: #5faf00; +} + +.terminal .xterm-color-71 { + color: #5faf5f; +} + +.terminal .xterm-bg-color-71 { + background-color: #5faf5f; +} + +.terminal .xterm-color-72 { + color: #5faf87; +} + +.terminal .xterm-bg-color-72 { + background-color: #5faf87; +} + +.terminal .xterm-color-73 { + color: #5fafaf; +} + +.terminal .xterm-bg-color-73 { + background-color: #5fafaf; +} + +.terminal .xterm-color-74 { + color: #5fafd7; +} + +.terminal .xterm-bg-color-74 { + background-color: #5fafd7; +} + +.terminal .xterm-color-75 { + color: #5fafff; +} + +.terminal .xterm-bg-color-75 { + background-color: #5fafff; +} + +.terminal .xterm-color-76 { + color: #5fd700; +} + +.terminal .xterm-bg-color-76 { + background-color: #5fd700; +} + +.terminal .xterm-color-77 { + color: #5fd75f; +} + +.terminal .xterm-bg-color-77 { + background-color: #5fd75f; +} + +.terminal .xterm-color-78 { + color: #5fd787; +} + +.terminal .xterm-bg-color-78 { + background-color: #5fd787; +} + +.terminal .xterm-color-79 { + color: #5fd7af; +} + +.terminal .xterm-bg-color-79 { + background-color: #5fd7af; +} + +.terminal .xterm-color-80 { + color: #5fd7d7; +} + +.terminal .xterm-bg-color-80 { + background-color: #5fd7d7; +} + +.terminal .xterm-color-81 { + color: #5fd7ff; +} + +.terminal .xterm-bg-color-81 { + background-color: #5fd7ff; +} + +.terminal .xterm-color-82 { + color: #5fff00; +} + +.terminal .xterm-bg-color-82 { + background-color: #5fff00; +} + +.terminal .xterm-color-83 { + color: #5fff5f; +} + +.terminal .xterm-bg-color-83 { + background-color: #5fff5f; +} + +.terminal .xterm-color-84 { + color: #5fff87; +} + +.terminal .xterm-bg-color-84 { + background-color: #5fff87; +} + +.terminal .xterm-color-85 { + color: #5fffaf; +} + +.terminal .xterm-bg-color-85 { + background-color: #5fffaf; +} + +.terminal .xterm-color-86 { + color: #5fffd7; +} + +.terminal .xterm-bg-color-86 { + background-color: #5fffd7; +} + +.terminal .xterm-color-87 { + color: #5fffff; +} + +.terminal .xterm-bg-color-87 { + background-color: #5fffff; +} + +.terminal .xterm-color-88 { + color: #870000; +} + +.terminal .xterm-bg-color-88 { + background-color: #870000; +} + +.terminal .xterm-color-89 { + color: #87005f; +} + +.terminal .xterm-bg-color-89 { + background-color: #87005f; +} + +.terminal .xterm-color-90 { + color: #870087; +} + +.terminal .xterm-bg-color-90 { + background-color: #870087; +} + +.terminal .xterm-color-91 { + color: #8700af; +} + +.terminal .xterm-bg-color-91 { + background-color: #8700af; +} + +.terminal .xterm-color-92 { + color: #8700d7; +} + +.terminal .xterm-bg-color-92 { + background-color: #8700d7; +} + +.terminal .xterm-color-93 { + color: #8700ff; +} + +.terminal .xterm-bg-color-93 { + background-color: #8700ff; +} + +.terminal .xterm-color-94 { + color: #875f00; +} + +.terminal .xterm-bg-color-94 { + background-color: #875f00; +} + +.terminal .xterm-color-95 { + color: #875f5f; +} + +.terminal .xterm-bg-color-95 { + background-color: #875f5f; +} + +.terminal .xterm-color-96 { + color: #875f87; +} + +.terminal .xterm-bg-color-96 { + background-color: #875f87; +} + +.terminal .xterm-color-97 { + color: #875faf; +} + +.terminal .xterm-bg-color-97 { + background-color: #875faf; +} + +.terminal .xterm-color-98 { + color: #875fd7; +} + +.terminal .xterm-bg-color-98 { + background-color: #875fd7; +} + +.terminal .xterm-color-99 { + color: #875fff; +} + +.terminal .xterm-bg-color-99 { + background-color: #875fff; +} + +.terminal .xterm-color-100 { + color: #878700; +} + +.terminal .xterm-bg-color-100 { + background-color: #878700; +} + +.terminal .xterm-color-101 { + color: #87875f; +} + +.terminal .xterm-bg-color-101 { + background-color: #87875f; +} + +.terminal .xterm-color-102 { + color: #878787; +} + +.terminal .xterm-bg-color-102 { + background-color: #878787; +} + +.terminal .xterm-color-103 { + color: #8787af; +} + +.terminal .xterm-bg-color-103 { + background-color: #8787af; +} + +.terminal .xterm-color-104 { + color: #8787d7; +} + +.terminal .xterm-bg-color-104 { + background-color: #8787d7; +} + +.terminal .xterm-color-105 { + color: #8787ff; +} + +.terminal .xterm-bg-color-105 { + background-color: #8787ff; +} + +.terminal .xterm-color-106 { + color: #87af00; +} + +.terminal .xterm-bg-color-106 { + background-color: #87af00; +} + +.terminal .xterm-color-107 { + color: #87af5f; +} + +.terminal .xterm-bg-color-107 { + background-color: #87af5f; +} + +.terminal .xterm-color-108 { + color: #87af87; +} + +.terminal .xterm-bg-color-108 { + background-color: #87af87; +} + +.terminal .xterm-color-109 { + color: #87afaf; +} + +.terminal .xterm-bg-color-109 { + background-color: #87afaf; +} + +.terminal .xterm-color-110 { + color: #87afd7; +} + +.terminal .xterm-bg-color-110 { + background-color: #87afd7; +} + +.terminal .xterm-color-111 { + color: #87afff; +} + +.terminal .xterm-bg-color-111 { + background-color: #87afff; +} + +.terminal .xterm-color-112 { + color: #87d700; +} + +.terminal .xterm-bg-color-112 { + background-color: #87d700; +} + +.terminal .xterm-color-113 { + color: #87d75f; +} + +.terminal .xterm-bg-color-113 { + background-color: #87d75f; +} + +.terminal .xterm-color-114 { + color: #87d787; +} + +.terminal .xterm-bg-color-114 { + background-color: #87d787; +} + +.terminal .xterm-color-115 { + color: #87d7af; +} + +.terminal .xterm-bg-color-115 { + background-color: #87d7af; +} + +.terminal .xterm-color-116 { + color: #87d7d7; +} + +.terminal .xterm-bg-color-116 { + background-color: #87d7d7; +} + +.terminal .xterm-color-117 { + color: #87d7ff; +} + +.terminal .xterm-bg-color-117 { + background-color: #87d7ff; +} + +.terminal .xterm-color-118 { + color: #87ff00; +} + +.terminal .xterm-bg-color-118 { + background-color: #87ff00; +} + +.terminal .xterm-color-119 { + color: #87ff5f; +} + +.terminal .xterm-bg-color-119 { + background-color: #87ff5f; +} + +.terminal .xterm-color-120 { + color: #87ff87; +} + +.terminal .xterm-bg-color-120 { + background-color: #87ff87; +} + +.terminal .xterm-color-121 { + color: #87ffaf; +} + +.terminal .xterm-bg-color-121 { + background-color: #87ffaf; +} + +.terminal .xterm-color-122 { + color: #87ffd7; +} + +.terminal .xterm-bg-color-122 { + background-color: #87ffd7; +} + +.terminal .xterm-color-123 { + color: #87ffff; +} + +.terminal .xterm-bg-color-123 { + background-color: #87ffff; +} + +.terminal .xterm-color-124 { + color: #af0000; +} + +.terminal .xterm-bg-color-124 { + background-color: #af0000; +} + +.terminal .xterm-color-125 { + color: #af005f; +} + +.terminal .xterm-bg-color-125 { + background-color: #af005f; +} + +.terminal .xterm-color-126 { + color: #af0087; +} + +.terminal .xterm-bg-color-126 { + background-color: #af0087; +} + +.terminal .xterm-color-127 { + color: #af00af; +} + +.terminal .xterm-bg-color-127 { + background-color: #af00af; +} + +.terminal .xterm-color-128 { + color: #af00d7; +} + +.terminal .xterm-bg-color-128 { + background-color: #af00d7; +} + +.terminal .xterm-color-129 { + color: #af00ff; +} + +.terminal .xterm-bg-color-129 { + background-color: #af00ff; +} + +.terminal .xterm-color-130 { + color: #af5f00; +} + +.terminal .xterm-bg-color-130 { + background-color: #af5f00; +} + +.terminal .xterm-color-131 { + color: #af5f5f; +} + +.terminal .xterm-bg-color-131 { + background-color: #af5f5f; +} + +.terminal .xterm-color-132 { + color: #af5f87; +} + +.terminal .xterm-bg-color-132 { + background-color: #af5f87; +} + +.terminal .xterm-color-133 { + color: #af5faf; +} + +.terminal .xterm-bg-color-133 { + background-color: #af5faf; +} + +.terminal .xterm-color-134 { + color: #af5fd7; +} + +.terminal .xterm-bg-color-134 { + background-color: #af5fd7; +} + +.terminal .xterm-color-135 { + color: #af5fff; +} + +.terminal .xterm-bg-color-135 { + background-color: #af5fff; +} + +.terminal .xterm-color-136 { + color: #af8700; +} + +.terminal .xterm-bg-color-136 { + background-color: #af8700; +} + +.terminal .xterm-color-137 { + color: #af875f; +} + +.terminal .xterm-bg-color-137 { + background-color: #af875f; +} + +.terminal .xterm-color-138 { + color: #af8787; +} + +.terminal .xterm-bg-color-138 { + background-color: #af8787; +} + +.terminal .xterm-color-139 { + color: #af87af; +} + +.terminal .xterm-bg-color-139 { + background-color: #af87af; +} + +.terminal .xterm-color-140 { + color: #af87d7; +} + +.terminal .xterm-bg-color-140 { + background-color: #af87d7; +} + +.terminal .xterm-color-141 { + color: #af87ff; +} + +.terminal .xterm-bg-color-141 { + background-color: #af87ff; +} + +.terminal .xterm-color-142 { + color: #afaf00; +} + +.terminal .xterm-bg-color-142 { + background-color: #afaf00; +} + +.terminal .xterm-color-143 { + color: #afaf5f; +} + +.terminal .xterm-bg-color-143 { + background-color: #afaf5f; +} + +.terminal .xterm-color-144 { + color: #afaf87; +} + +.terminal .xterm-bg-color-144 { + background-color: #afaf87; +} + +.terminal .xterm-color-145 { + color: #afafaf; +} + +.terminal .xterm-bg-color-145 { + background-color: #afafaf; +} + +.terminal .xterm-color-146 { + color: #afafd7; +} + +.terminal .xterm-bg-color-146 { + background-color: #afafd7; +} + +.terminal .xterm-color-147 { + color: #afafff; +} + +.terminal .xterm-bg-color-147 { + background-color: #afafff; +} + +.terminal .xterm-color-148 { + color: #afd700; +} + +.terminal .xterm-bg-color-148 { + background-color: #afd700; +} + +.terminal .xterm-color-149 { + color: #afd75f; +} + +.terminal .xterm-bg-color-149 { + background-color: #afd75f; +} + +.terminal .xterm-color-150 { + color: #afd787; +} + +.terminal .xterm-bg-color-150 { + background-color: #afd787; +} + +.terminal .xterm-color-151 { + color: #afd7af; +} + +.terminal .xterm-bg-color-151 { + background-color: #afd7af; +} + +.terminal .xterm-color-152 { + color: #afd7d7; +} + +.terminal .xterm-bg-color-152 { + background-color: #afd7d7; +} + +.terminal .xterm-color-153 { + color: #afd7ff; +} + +.terminal .xterm-bg-color-153 { + background-color: #afd7ff; +} + +.terminal .xterm-color-154 { + color: #afff00; +} + +.terminal .xterm-bg-color-154 { + background-color: #afff00; +} + +.terminal .xterm-color-155 { + color: #afff5f; +} + +.terminal .xterm-bg-color-155 { + background-color: #afff5f; +} + +.terminal .xterm-color-156 { + color: #afff87; +} + +.terminal .xterm-bg-color-156 { + background-color: #afff87; +} + +.terminal .xterm-color-157 { + color: #afffaf; +} + +.terminal .xterm-bg-color-157 { + background-color: #afffaf; +} + +.terminal .xterm-color-158 { + color: #afffd7; +} + +.terminal .xterm-bg-color-158 { + background-color: #afffd7; +} + +.terminal .xterm-color-159 { + color: #afffff; +} + +.terminal .xterm-bg-color-159 { + background-color: #afffff; +} + +.terminal .xterm-color-160 { + color: #d70000; +} + +.terminal .xterm-bg-color-160 { + background-color: #d70000; +} + +.terminal .xterm-color-161 { + color: #d7005f; +} + +.terminal .xterm-bg-color-161 { + background-color: #d7005f; +} + +.terminal .xterm-color-162 { + color: #d70087; +} + +.terminal .xterm-bg-color-162 { + background-color: #d70087; +} + +.terminal .xterm-color-163 { + color: #d700af; +} + +.terminal .xterm-bg-color-163 { + background-color: #d700af; +} + +.terminal .xterm-color-164 { + color: #d700d7; +} + +.terminal .xterm-bg-color-164 { + background-color: #d700d7; +} + +.terminal .xterm-color-165 { + color: #d700ff; +} + +.terminal .xterm-bg-color-165 { + background-color: #d700ff; +} + +.terminal .xterm-color-166 { + color: #d75f00; +} + +.terminal .xterm-bg-color-166 { + background-color: #d75f00; +} + +.terminal .xterm-color-167 { + color: #d75f5f; +} + +.terminal .xterm-bg-color-167 { + background-color: #d75f5f; +} + +.terminal .xterm-color-168 { + color: #d75f87; +} + +.terminal .xterm-bg-color-168 { + background-color: #d75f87; +} + +.terminal .xterm-color-169 { + color: #d75faf; +} + +.terminal .xterm-bg-color-169 { + background-color: #d75faf; +} + +.terminal .xterm-color-170 { + color: #d75fd7; +} + +.terminal .xterm-bg-color-170 { + background-color: #d75fd7; +} + +.terminal .xterm-color-171 { + color: #d75fff; +} + +.terminal .xterm-bg-color-171 { + background-color: #d75fff; +} + +.terminal .xterm-color-172 { + color: #d78700; +} + +.terminal .xterm-bg-color-172 { + background-color: #d78700; +} + +.terminal .xterm-color-173 { + color: #d7875f; +} + +.terminal .xterm-bg-color-173 { + background-color: #d7875f; +} + +.terminal .xterm-color-174 { + color: #d78787; +} + +.terminal .xterm-bg-color-174 { + background-color: #d78787; +} + +.terminal .xterm-color-175 { + color: #d787af; +} + +.terminal .xterm-bg-color-175 { + background-color: #d787af; +} + +.terminal .xterm-color-176 { + color: #d787d7; +} + +.terminal .xterm-bg-color-176 { + background-color: #d787d7; +} + +.terminal .xterm-color-177 { + color: #d787ff; +} + +.terminal .xterm-bg-color-177 { + background-color: #d787ff; +} + +.terminal .xterm-color-178 { + color: #d7af00; +} + +.terminal .xterm-bg-color-178 { + background-color: #d7af00; +} + +.terminal .xterm-color-179 { + color: #d7af5f; +} + +.terminal .xterm-bg-color-179 { + background-color: #d7af5f; +} + +.terminal .xterm-color-180 { + color: #d7af87; +} + +.terminal .xterm-bg-color-180 { + background-color: #d7af87; +} + +.terminal .xterm-color-181 { + color: #d7afaf; +} + +.terminal .xterm-bg-color-181 { + background-color: #d7afaf; +} + +.terminal .xterm-color-182 { + color: #d7afd7; +} + +.terminal .xterm-bg-color-182 { + background-color: #d7afd7; +} + +.terminal .xterm-color-183 { + color: #d7afff; +} + +.terminal .xterm-bg-color-183 { + background-color: #d7afff; +} + +.terminal .xterm-color-184 { + color: #d7d700; +} + +.terminal .xterm-bg-color-184 { + background-color: #d7d700; +} + +.terminal .xterm-color-185 { + color: #d7d75f; +} + +.terminal .xterm-bg-color-185 { + background-color: #d7d75f; +} + +.terminal .xterm-color-186 { + color: #d7d787; +} + +.terminal .xterm-bg-color-186 { + background-color: #d7d787; +} + +.terminal .xterm-color-187 { + color: #d7d7af; +} + +.terminal .xterm-bg-color-187 { + background-color: #d7d7af; +} + +.terminal .xterm-color-188 { + color: #d7d7d7; +} + +.terminal .xterm-bg-color-188 { + background-color: #d7d7d7; +} + +.terminal .xterm-color-189 { + color: #d7d7ff; +} + +.terminal .xterm-bg-color-189 { + background-color: #d7d7ff; +} + +.terminal .xterm-color-190 { + color: #d7ff00; +} + +.terminal .xterm-bg-color-190 { + background-color: #d7ff00; +} + +.terminal .xterm-color-191 { + color: #d7ff5f; +} + +.terminal .xterm-bg-color-191 { + background-color: #d7ff5f; +} + +.terminal .xterm-color-192 { + color: #d7ff87; +} + +.terminal .xterm-bg-color-192 { + background-color: #d7ff87; +} + +.terminal .xterm-color-193 { + color: #d7ffaf; +} + +.terminal .xterm-bg-color-193 { + background-color: #d7ffaf; +} + +.terminal .xterm-color-194 { + color: #d7ffd7; +} + +.terminal .xterm-bg-color-194 { + background-color: #d7ffd7; +} + +.terminal .xterm-color-195 { + color: #d7ffff; +} + +.terminal .xterm-bg-color-195 { + background-color: #d7ffff; +} + +.terminal .xterm-color-196 { + color: #ff0000; +} + +.terminal .xterm-bg-color-196 { + background-color: #ff0000; +} + +.terminal .xterm-color-197 { + color: #ff005f; +} + +.terminal .xterm-bg-color-197 { + background-color: #ff005f; +} + +.terminal .xterm-color-198 { + color: #ff0087; +} + +.terminal .xterm-bg-color-198 { + background-color: #ff0087; +} + +.terminal .xterm-color-199 { + color: #ff00af; +} + +.terminal .xterm-bg-color-199 { + background-color: #ff00af; +} + +.terminal .xterm-color-200 { + color: #ff00d7; +} + +.terminal .xterm-bg-color-200 { + background-color: #ff00d7; +} + +.terminal .xterm-color-201 { + color: #ff00ff; +} + +.terminal .xterm-bg-color-201 { + background-color: #ff00ff; +} + +.terminal .xterm-color-202 { + color: #ff5f00; +} + +.terminal .xterm-bg-color-202 { + background-color: #ff5f00; +} + +.terminal .xterm-color-203 { + color: #ff5f5f; +} + +.terminal .xterm-bg-color-203 { + background-color: #ff5f5f; +} + +.terminal .xterm-color-204 { + color: #ff5f87; +} + +.terminal .xterm-bg-color-204 { + background-color: #ff5f87; +} + +.terminal .xterm-color-205 { + color: #ff5faf; +} + +.terminal .xterm-bg-color-205 { + background-color: #ff5faf; +} + +.terminal .xterm-color-206 { + color: #ff5fd7; +} + +.terminal .xterm-bg-color-206 { + background-color: #ff5fd7; +} + +.terminal .xterm-color-207 { + color: #ff5fff; +} + +.terminal .xterm-bg-color-207 { + background-color: #ff5fff; +} + +.terminal .xterm-color-208 { + color: #ff8700; +} + +.terminal .xterm-bg-color-208 { + background-color: #ff8700; +} + +.terminal .xterm-color-209 { + color: #ff875f; +} + +.terminal .xterm-bg-color-209 { + background-color: #ff875f; +} + +.terminal .xterm-color-210 { + color: #ff8787; +} + +.terminal .xterm-bg-color-210 { + background-color: #ff8787; +} + +.terminal .xterm-color-211 { + color: #ff87af; +} + +.terminal .xterm-bg-color-211 { + background-color: #ff87af; +} + +.terminal .xterm-color-212 { + color: #ff87d7; +} + +.terminal .xterm-bg-color-212 { + background-color: #ff87d7; +} + +.terminal .xterm-color-213 { + color: #ff87ff; +} + +.terminal .xterm-bg-color-213 { + background-color: #ff87ff; +} + +.terminal .xterm-color-214 { + color: #ffaf00; +} + +.terminal .xterm-bg-color-214 { + background-color: #ffaf00; +} + +.terminal .xterm-color-215 { + color: #ffaf5f; +} + +.terminal .xterm-bg-color-215 { + background-color: #ffaf5f; +} + +.terminal .xterm-color-216 { + color: #ffaf87; +} + +.terminal .xterm-bg-color-216 { + background-color: #ffaf87; +} + +.terminal .xterm-color-217 { + color: #ffafaf; +} + +.terminal .xterm-bg-color-217 { + background-color: #ffafaf; +} + +.terminal .xterm-color-218 { + color: #ffafd7; +} + +.terminal .xterm-bg-color-218 { + background-color: #ffafd7; +} + +.terminal .xterm-color-219 { + color: #ffafff; +} + +.terminal .xterm-bg-color-219 { + background-color: #ffafff; +} + +.terminal .xterm-color-220 { + color: #ffd700; +} + +.terminal .xterm-bg-color-220 { + background-color: #ffd700; +} + +.terminal .xterm-color-221 { + color: #ffd75f; +} + +.terminal .xterm-bg-color-221 { + background-color: #ffd75f; +} + +.terminal .xterm-color-222 { + color: #ffd787; +} + +.terminal .xterm-bg-color-222 { + background-color: #ffd787; +} + +.terminal .xterm-color-223 { + color: #ffd7af; +} + +.terminal .xterm-bg-color-223 { + background-color: #ffd7af; +} + +.terminal .xterm-color-224 { + color: #ffd7d7; +} + +.terminal .xterm-bg-color-224 { + background-color: #ffd7d7; +} + +.terminal .xterm-color-225 { + color: #ffd7ff; +} + +.terminal .xterm-bg-color-225 { + background-color: #ffd7ff; +} + +.terminal .xterm-color-226 { + color: #ffff00; +} + +.terminal .xterm-bg-color-226 { + background-color: #ffff00; +} + +.terminal .xterm-color-227 { + color: #ffff5f; +} + +.terminal .xterm-bg-color-227 { + background-color: #ffff5f; +} + +.terminal .xterm-color-228 { + color: #ffff87; +} + +.terminal .xterm-bg-color-228 { + background-color: #ffff87; +} + +.terminal .xterm-color-229 { + color: #ffffaf; +} + +.terminal .xterm-bg-color-229 { + background-color: #ffffaf; +} + +.terminal .xterm-color-230 { + color: #ffffd7; +} + +.terminal .xterm-bg-color-230 { + background-color: #ffffd7; +} + +.terminal .xterm-color-231 { + color: #ffffff; +} + +.terminal .xterm-bg-color-231 { + background-color: #ffffff; +} + +.terminal .xterm-color-232 { + color: #080808; +} + +.terminal .xterm-bg-color-232 { + background-color: #080808; +} + +.terminal .xterm-color-233 { + color: #121212; +} + +.terminal .xterm-bg-color-233 { + background-color: #121212; +} + +.terminal .xterm-color-234 { + color: #1c1c1c; +} + +.terminal .xterm-bg-color-234 { + background-color: #1c1c1c; +} + +.terminal .xterm-color-235 { + color: #262626; +} + +.terminal .xterm-bg-color-235 { + background-color: #262626; +} + +.terminal .xterm-color-236 { + color: #303030; +} + +.terminal .xterm-bg-color-236 { + background-color: #303030; +} + +.terminal .xterm-color-237 { + color: #3a3a3a; +} + +.terminal .xterm-bg-color-237 { + background-color: #3a3a3a; +} + +.terminal .xterm-color-238 { + color: #444444; +} + +.terminal .xterm-bg-color-238 { + background-color: #444444; +} + +.terminal .xterm-color-239 { + color: #4e4e4e; +} + +.terminal .xterm-bg-color-239 { + background-color: #4e4e4e; +} + +.terminal .xterm-color-240 { + color: #585858; +} + +.terminal .xterm-bg-color-240 { + background-color: #585858; +} + +.terminal .xterm-color-241 { + color: #626262; +} + +.terminal .xterm-bg-color-241 { + background-color: #626262; +} + +.terminal .xterm-color-242 { + color: #6c6c6c; +} + +.terminal .xterm-bg-color-242 { + background-color: #6c6c6c; +} + +.terminal .xterm-color-243 { + color: #767676; +} + +.terminal .xterm-bg-color-243 { + background-color: #767676; +} + +.terminal .xterm-color-244 { + color: #808080; +} + +.terminal .xterm-bg-color-244 { + background-color: #808080; +} + +.terminal .xterm-color-245 { + color: #8a8a8a; +} + +.terminal .xterm-bg-color-245 { + background-color: #8a8a8a; +} + +.terminal .xterm-color-246 { + color: #949494; +} + +.terminal .xterm-bg-color-246 { + background-color: #949494; +} + +.terminal .xterm-color-247 { + color: #9e9e9e; +} + +.terminal .xterm-bg-color-247 { + background-color: #9e9e9e; +} + +.terminal .xterm-color-248 { + color: #a8a8a8; +} + +.terminal .xterm-bg-color-248 { + background-color: #a8a8a8; +} + +.terminal .xterm-color-249 { + color: #b2b2b2; +} + +.terminal .xterm-bg-color-249 { + background-color: #b2b2b2; +} + +.terminal .xterm-color-250 { + color: #bcbcbc; +} + +.terminal .xterm-bg-color-250 { + background-color: #bcbcbc; +} + +.terminal .xterm-color-251 { + color: #c6c6c6; +} + +.terminal .xterm-bg-color-251 { + background-color: #c6c6c6; +} + +.terminal .xterm-color-252 { + color: #d0d0d0; +} + +.terminal .xterm-bg-color-252 { + background-color: #d0d0d0; +} + +.terminal .xterm-color-253 { + color: #dadada; +} + +.terminal .xterm-bg-color-253 { + background-color: #dadada; +} + +.terminal .xterm-color-254 { + color: #e4e4e4; +} + +.terminal .xterm-bg-color-254 { + background-color: #e4e4e4; +} + +.terminal .xterm-color-255 { + color: #eeeeee; +} + +.terminal .xterm-bg-color-255 { + background-color: #eeeeee; +} \ No newline at end of file diff --git a/src/main/webapp/static/image/backgrounds/1.jpg b/src/main/webapp/static/image/backgrounds/1.jpg new file mode 100644 index 0000000..e43067c Binary files /dev/null and b/src/main/webapp/static/image/backgrounds/1.jpg differ diff --git a/src/main/webapp/static/image/backgrounds/2.jpg b/src/main/webapp/static/image/backgrounds/2.jpg new file mode 100644 index 0000000..0a28d75 Binary files /dev/null and b/src/main/webapp/static/image/backgrounds/2.jpg differ diff --git a/src/main/webapp/static/image/backgrounds/3.jpg b/src/main/webapp/static/image/backgrounds/3.jpg new file mode 100644 index 0000000..b344359 Binary files /dev/null and b/src/main/webapp/static/image/backgrounds/3.jpg differ diff --git a/src/main/webapp/static/image/facebook.png b/src/main/webapp/static/image/facebook.png new file mode 100644 index 0000000..0c7e505 Binary files /dev/null and b/src/main/webapp/static/image/facebook.png differ diff --git a/src/main/webapp/static/image/favicon.ico b/src/main/webapp/static/image/favicon.ico new file mode 100644 index 0000000..606e280 Binary files /dev/null and b/src/main/webapp/static/image/favicon.ico differ diff --git a/src/main/webapp/static/image/progress.gif b/src/main/webapp/static/image/progress.gif new file mode 100644 index 0000000..f3e45e0 Binary files /dev/null and b/src/main/webapp/static/image/progress.gif differ diff --git a/src/main/webapp/static/image/twitter.png b/src/main/webapp/static/image/twitter.png new file mode 100644 index 0000000..924228f Binary files /dev/null and b/src/main/webapp/static/image/twitter.png differ diff --git a/src/main/webapp/static/js/base64.js b/src/main/webapp/static/js/base64.js new file mode 100644 index 0000000..c4df1c0 --- /dev/null +++ b/src/main/webapp/static/js/base64.js @@ -0,0 +1,103 @@ +function Base64() { + + // private property + _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + + // public method for encoding + this.encode = function (input) { + var output = ""; + var chr1, chr2, chr3, enc1, enc2, enc3, enc4; + var i = 0; + input = _utf8_encode(input); + while (i < input.length) { + chr1 = input.charCodeAt(i++); + chr2 = input.charCodeAt(i++); + chr3 = input.charCodeAt(i++); + enc1 = chr1 >> 2; + enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); + enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); + enc4 = chr3 & 63; + if (isNaN(chr2)) { + enc3 = enc4 = 64; + } else if (isNaN(chr3)) { + enc4 = 64; + } + output = output + + _keyStr.charAt(enc1) + _keyStr.charAt(enc2) + + _keyStr.charAt(enc3) + _keyStr.charAt(enc4); + } + return output; + } + + // public method for decoding + this.decode = function (input) { + var output = ""; + var chr1, chr2, chr3; + var enc1, enc2, enc3, enc4; + var i = 0; + input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); + while (i < input.length) { + enc1 = _keyStr.indexOf(input.charAt(i++)); + enc2 = _keyStr.indexOf(input.charAt(i++)); + enc3 = _keyStr.indexOf(input.charAt(i++)); + enc4 = _keyStr.indexOf(input.charAt(i++)); + chr1 = (enc1 << 2) | (enc2 >> 4); + chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); + chr3 = ((enc3 & 3) << 6) | enc4; + output = output + String.fromCharCode(chr1); + if (enc3 != 64) { + output = output + String.fromCharCode(chr2); + } + if (enc4 != 64) { + output = output + String.fromCharCode(chr3); + } + } + output = _utf8_decode(output); + return output; + } + + // private method for UTF-8 encoding + _utf8_encode = function (string) { + string = string.replace(/\r\n/g,"\n"); + var utftext = ""; + for (var n = 0; n < string.length; n++) { + var c = string.charCodeAt(n); + if (c < 128) { + utftext += String.fromCharCode(c); + } else if((c > 127) && (c < 2048)) { + utftext += String.fromCharCode((c >> 6) | 192); + utftext += String.fromCharCode((c & 63) | 128); + } else { + utftext += String.fromCharCode((c >> 12) | 224); + utftext += String.fromCharCode(((c >> 6) & 63) | 128); + utftext += String.fromCharCode((c & 63) | 128); + } + + } + return utftext; + } + + // private method for UTF-8 decoding + _utf8_decode = function (utftext) { + var string = ""; + var i = 0; + var c = c1 = c2 = 0; + while ( i < utftext.length ) { + c = utftext.charCodeAt(i); + if (c < 128) { + string += String.fromCharCode(c); + i++; + } else if((c > 191) && (c < 224)) { + c2 = utftext.charCodeAt(i+1); + string += String.fromCharCode(((c & 31) << 6) | (c2 & 63)); + i += 2; + } else { + c2 = utftext.charCodeAt(i+1); + c3 = utftext.charCodeAt(i+2); + string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); + i += 3; + } + } + return string; + } +} \ No newline at end of file diff --git a/src/main/webapp/static/js/formvalid.js b/src/main/webapp/static/js/formvalid.js new file mode 100644 index 0000000..4106442 --- /dev/null +++ b/src/main/webapp/static/js/formvalid.js @@ -0,0 +1,234 @@ +/* + Jquery + janchie 2010.1 + 1.02版 + */ + +var validResult = {}; +var errorMsg = {}; + +(function ($) { + $.fn.extend({ + valid: function () { + if (!$(this).is("form")) return; + + var items = $.isArray(arguments[0]) ? arguments[0] : [], + isBindSubmit = typeof arguments[1] === "boolean" ? arguments[1] : true, + isAlert = typeof arguments[2] === "boolean" ? arguments[2] : false, + + rule = { + "eng": /^[A-Za-z]+$/, + "chn": /^[\u0391-\uFFE5]+$/, + "mail": /\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/, + "url": /^http[s]?:\/\/[A-Za-z0-9]+\.[A-Za-z0-9]+[\/=\?%\-&_~`@[\]\':+!]*([^<>\"\"])*$/, + "currency": /^\d+(\.\d+)?$/, + "number": /^\d+$/, + "int": /^[0-9]{1,30}$/, + "double": /^[-\+]?\d+(\.\d+)?$/, + "username": /^[a-zA-Z]{1}([a-zA-Z0-9]|[._]){3,19}$/, + "password": /^[\w\W]{6,20}$/, + "safe": />|<|,|\[|\]|\{|\}|\?|\/|\+|=|\||\'|\\|\"|:|;|\~|\!|\@|\#|\*|\$|\%|\^|\&|\(|\)|`/i, + "dbc": /[a-zA-Z0-9!@#¥%^&*()_+{}[]|:"';.,/?<>`~ ]/, + "qq": /[1-9][0-9]{4,}/, + "date": /^((((1[6-9]|[2-9]\d)\d{2})-(0?[13578]|1[02])-(0?[1-9]|[12]\d|3[01]))|(((1[6-9]|[2-9]\d)\d{2})-(0?[13456789]|1[012])-(0?[1-9]|[12]\d|30))|(((1[6-9]|[2-9]\d)\d{2})-0?2-(0?[1-9]|1\d|2[0-8]))|(((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-0?2-29-))$/, + "year": /^(19|20)[0-9]{2}$/, + "month": /^(0?[1-9]|1[0-2])$/, + "day": /^((0?[1-9])|((1|2)[0-9])|30|31)$/, + "hour": /^((0?[1-9])|((1|2)[0-3]))$/, + "minute": /^((0?[1-9])|((1|5)[0-9]))$/, + "second": /^((0?[1-9])|((1|5)[0-9]))$/, + "mobile": /^((\(\d{2,3}\))|(\d{3}\-))?13\d{9}$/, + "phone": /^[+]{0,1}(\d){1,3}[ ]?([-]?((\d)|[ ]){1,12})+$/, + "zipcode": /^[1-9]\d{5}$/, + "IDcard": /^((1[1-5])|(2[1-3])|(3[1-7])|(4[1-6])|(5[0-4])|(6[1-5])|71|(8[12])|91)\d{4}((19\d{2}(0[13-9]|1[012])(0[1-9]|[12]\d|30))|(19\d{2}(0[13578]|1[02])31)|(19\d{2}02(0[1-9]|1\d|2[0-8]))|(19([13579][26]|[2468][048]|0[48])0229))\d{3}(\d|X|x)?$/, + "ip": /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/, + "file": /^[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/, + "image": /.+\.(jpg|gif|png|bmp)$/i, + "word": /.+\.(doc|rtf|pdf)$/i, + + "port": function (port) { + return (!isNaN(port) && port > 0 && port < 65536) ? true : false; + }, + "eq": function (arg1, arg2) { + return arg1 == arg2 ? true : false; + }, + "gt": function (arg1, arg2) { + return arg1 > arg2 ? true : false; + }, + "gte": function (arg1, arg2) { + return arg1 >= arg2 ? true : false; + }, + "lt": function (arg1, arg2) { + return arg1 < arg2 ? true : false; + }, + "lte": function (arg1, arg2) { + return arg1 <= arg2 ? true : false; + } + + }, + + msgSuffix = { + "eng": "only english welcomed", + "chn": "only chinese welcomed", + "mail": "invalid email format", + "url": "invalid url format", + "currency": "invalid number format", + "number": "only number welcomed", + "int": "only integer welcomed", + "double": "only float welcomed", + "username": "invalid username format,4-20 characters", + "password": "warning, you'd better use 6-20 characters", + "safe": "forbidden special characters", + "dbc": "forbidden full width characters", + "qq": "invalid qq format", + "date": "invalid date format", + "year": "invalid year format", + "month": "invalid month format", + "day": "invalid day format", + "hour": "invalid hour format", + "minute": "invalid minute format", + "second": "invalid second format", + "mobile": "invalid mobile format", + "phone": "invalid phone format", + "zipcode": "invalid zipcode format", + "IDcard": "invalid identity format", + "ip": "invalid ip format", + "port": "invalid port format", + "file": "invalid file format", + "image": "invalid image format", + "word": "invalid word file format", + "eq": "not equal", + "gt": "no greater than", + "gte": "no greater than or equal", + "lt": "no smaller than", + "lte": "no smaller than or equal" + }, + + msg = "", formObj = $(this), checkRet = true, isAll, + tipname = function (namestr) { + return "tip_" + namestr.replace(/([a-zA-Z0-9])/g, "-$1"); + }, + + typeTest = function () { + var result = true, args = arguments; + if (rule.hasOwnProperty(args[0])) { + var t = rule[args[0]], v = args[1]; + result = args.length > 2 ? t.apply(arguments, [].slice.call(args, 1)) : ($.isFunction(t) ? t(v) : t.test(v)); + } + return result; + }, + + showError = function (fieldObj, filedName, warnInfo) { + checkRet = false; + var tipObj = $("#" + tipname(filedName)); + if (tipObj.length > 0) tipObj.remove(); + var tipPosition = fieldObj.next().length > 0 ? fieldObj.nextAll().eq(this.length - 1) : fieldObj.eq(this.length - 1); + //tipPosition.after(" " + warnInfo + " "); + validResult[filedName] = false; + errorMsg[filedName] = warnInfo; + if (isAlert && isAll) msg = warnInfo; + }, + + showRight = function (fieldObj, filedName) { + var tipObj = $("#" + tipname(filedName)); + if (tipObj.length > 0) tipObj.remove(); + var tipPosition = fieldObj.next().length > 0 ? fieldObj.nextAll().eq(this.length - 1) : fieldObj.eq(this.length - 1); + //tipPosition.after("correct"); + validResult[filedName] = true; + }, + + findTo = function (objName) { + var find; + $.each(items, function () { + if (this.name == objName && this.simple) { + find = this.simple; + return false; + } + }); + if (!find) find = $("[name='" + objName + "']")[0].name; + return find; + }, + + fieldCheck = function (item) { + var i = item, field = $("[name='" + i.name + "']", formObj[0]); + if (!field[0]) return; + + var warnMsg, fv = $.trim(field.val()), isRq = typeof i.require === "boolean" ? i.require : true; + + if (isRq && ((field.is(":radio") || field.is(":checkbox")) && !field.is(":checked"))) { + warnMsg = i.message || "choice needed"; + showError(field, i.name, warnMsg); + + } else if (isRq && fv == "") { + warnMsg = i.message || ( field.is("select") ? "choice needed" : "not none" ); + showError(field, i.name, warnMsg); + + } else if (fv != "") { + if (i.min || i.max) { + var len = fv.length, min = i.min || 0, max = i.max; + warnMsg = i.message || (max ? "range" + min + "~" + max + "" : "min length" + min); + + if ((max && (len > max || len < min)) || (!max && len < min)) { + showError(field, i.name, warnMsg); + return; + } + } + if (i.type) { + var matchVal = i.to ? $.trim($("[name='" + i.to + "']").val()) : i.value; + var matchRet = matchVal ? typeTest(i.type, fv, matchVal) : typeTest(i.type, fv); + + warnMsg = i.message || msgSuffix[i.type]; + if (matchVal) warnMsg += (i.to ? findTo(i.to) + "value" : i.value); + + if (!matchRet) showError(field, i.name, warnMsg); + else showRight(field, i.name); + + } else { + showRight(field, i.name); + } + + } else if (isRq) { + showRight(field, i.name); + } + + }, + + validate = function () { + $.each(items, function () { + isAll = true; + fieldCheck(this); + }); + + if (isAlert && msg != "") { + alert(msg); + msg = ""; + } + return checkRet; + }; + + $.each(items, function () { + var field = $("[name='" + this.name + "']", formObj[0]); + if (field.is(":hidden")) return; + + var obj = this, toCheck = function () { + isAll = false; + fieldCheck(obj); + }; + if (field.is(":file") || field.is("select")) { + field.change(toCheck); + } else { + field.blur(toCheck); + } + }); + + if (isBindSubmit) { + $(this).submit(validate); + } else { + return validate(); + } + + } + + }); + +})(jQuery); diff --git a/src/main/webapp/static/js/jquerymin.js b/src/main/webapp/static/js/jquerymin.js new file mode 100644 index 0000000..8e16b0b --- /dev/null +++ b/src/main/webapp/static/js/jquerymin.js @@ -0,0 +1,5 @@ +/*! jQuery v2.1.2 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l=a.document,m="2.1.2",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return!n.isArray(a)&&a-parseFloat(a)+1>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=l.createElement("script"),b.text=a,l.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:k}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=hb(),z=hb(),A=hb(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+N+"))|)"+L+"*\\]",P=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+O+")*)|.*)\\)|)",Q=new RegExp(L+"+","g"),R=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),S=new RegExp("^"+L+"*,"+L+"*"),T=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),U=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),V=new RegExp(P),W=new RegExp("^"+N+"$"),X={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+O),PSEUDO:new RegExp("^"+P),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},eb=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(fb){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function gb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],k=b.nodeType,"string"!=typeof a||!a||1!==k&&9!==k&&11!==k)return d;if(!e&&p){if(11!==k&&(f=_.exec(a)))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return H.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName)return H.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=1!==k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+rb(o[l]);w=ab.test(a)&&pb(b.parentNode)||b,x=o.join(",")}if(x)try{return H.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function hb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ib(a){return a[u]=!0,a}function jb(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function kb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function lb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function nb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function ob(a){return ib(function(b){return b=+b,ib(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function pb(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=gb.support={},f=gb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=gb.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=g.documentElement,e=g.defaultView,e&&e!==e.top&&(e.addEventListener?e.addEventListener("unload",eb,!1):e.attachEvent&&e.attachEvent("onunload",eb)),p=!f(g),c.attributes=jb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=jb(function(a){return a.appendChild(g.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(g.getElementsByClassName),c.getById=jb(function(a){return o.appendChild(a).id=u,!g.getElementsByName||!g.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(g.querySelectorAll))&&(jb(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),jb(function(a){var b=g.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&jb(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",P)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===g||a.ownerDocument===v&&t(v,a)?-1:b===g||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,h=[a],i=[b];if(!e||!f)return a===g?-1:b===g?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return lb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?lb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},g):n},gb.matches=function(a,b){return gb(a,null,null,b)},gb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return gb(b,n,null,[a]).length>0},gb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},gb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},gb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},gb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=gb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=gb.selectors={cacheLength:50,createPseudo:ib,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||gb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&gb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=gb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(Q," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||gb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ib(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ib(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?ib(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ib(function(a){return function(b){return gb(a,b).length>0}}),contains:ib(function(a){return a=a.replace(cb,db),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ib(function(a){return W.test(a||"")||gb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:ob(function(){return[0]}),last:ob(function(a,b){return[b-1]}),eq:ob(function(a,b,c){return[0>c?c+b:c]}),even:ob(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:ob(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:ob(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:ob(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function sb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function tb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ub(a,b,c){for(var d=0,e=b.length;e>d;d++)gb(a,b[d],c);return c}function vb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function wb(a,b,c,d,e,f){return d&&!d[u]&&(d=wb(d)),e&&!e[u]&&(e=wb(e,f)),ib(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ub(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:vb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=vb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=vb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function xb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=sb(function(a){return a===b},h,!0),l=sb(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[sb(tb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return wb(i>1&&tb(m),i>1&&rb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&xb(a.slice(i,e)),f>e&&xb(a=a.slice(e)),f>e&&rb(a))}m.push(c)}return tb(m)}function yb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=F.call(i));s=vb(s)}H.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&gb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?ib(f):f}return h=gb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=xb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,yb(e,d)),f.selector=a}return f},i=gb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&pb(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&rb(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&pb(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=jb(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),jb(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||kb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&jb(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||kb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),jb(function(a){return null==a.getAttribute("disabled")})||kb(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),gb}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return g.call(b,a)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:l,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=l.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=l,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};A.prototype=n.fn,y=n(l);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(n(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(C[a]||n.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return n.each(a.match(E)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&n.each(arguments,function(a,b){var c;while((c=n.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(H.resolveWith(l,[n]),n.fn.triggerHandler&&(n(l).triggerHandler("ready"),n(l).off("ready"))))}});function I(){l.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),n.ready()}n.ready.promise=function(b){return H||(H=n.Deferred(),"complete"===l.readyState?setTimeout(n.ready):(l.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},n.ready.promise();var J=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};n.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=n.expando+K.uid++}K.uid=1,K.accepts=n.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,n.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(n.isEmptyObject(f))n.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!n.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){return M.access(a,b,c) +},removeData:function(a,b){M.remove(a,b)},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=n.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||n.isArray(c)?d=L.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:n.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthx",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";k.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|pointer|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return l.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof n!==U&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,m,o,p=[d||l],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||l,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+n.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},e||!o.trigger||o.trigger.apply(d,c)!==!1)){if(!e&&!o.noBubble&&!n.isWindow(d)){for(i=o.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||l)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:o.bindType||q,m=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),m&&m.apply(g,c),m=k&&g[k],m&&m.apply&&n.acceptData(g)&&(b.result=m.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==!1||!n.acceptData(d)||k&&n.isFunction(d[q])&&!n.isWindow(d)&&(h=d[k],h&&(d[k]=null),n.event.triggered=q,d[q](),n.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>=0:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]*)\/>/gi,bb=/<([\w:]+)/,cb=/<|&#?\w+;/,db=/<(?:script|style|link)/i,eb=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/^$|\/(?:java|ecma)script/i,gb=/^true\/(.*)/,hb=/^\s*\s*$/g,ib={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ib.optgroup=ib.option,ib.tbody=ib.tfoot=ib.colgroup=ib.caption=ib.thead,ib.th=ib.td;function jb(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function kb(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function lb(a){var b=gb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function mb(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function nb(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=n.extend({},h),M.set(b,i))}}function ob(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function pb(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}n.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=ob(h),f=ob(a),d=0,e=f.length;e>d;d++)pb(f[d],g[d]);if(b)if(c)for(f=f||ob(a),g=g||ob(h),d=0,e=f.length;e>d;d++)nb(f[d],g[d]);else nb(a,h);return g=ob(h,"script"),g.length>0&&mb(g,!i&&ob(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,o=a.length;o>m;m++)if(e=a[m],e||0===e)if("object"===n.type(e))n.merge(l,e.nodeType?[e]:e);else if(cb.test(e)){f=f||k.appendChild(b.createElement("div")),g=(bb.exec(e)||["",""])[1].toLowerCase(),h=ib[g]||ib._default,f.innerHTML=h[1]+e.replace(ab,"<$1>")+h[2],j=h[0];while(j--)f=f.lastChild;n.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===n.inArray(e,d))&&(i=n.contains(e.ownerDocument,e),f=ob(k.appendChild(e),"script"),i&&mb(f),c)){j=0;while(e=f[j++])fb.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f=n.event.special,g=0;void 0!==(c=a[g]);g++){if(n.acceptData(c)&&(e=c[L.expando],e&&(b=L.cache[e]))){if(b.events)for(d in b.events)f[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);L.cache[e]&&delete L.cache[e]}delete M.cache[c[M.expando]]}}}),n.fn.extend({text:function(a){return J(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(ob(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&mb(ob(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(ob(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!db.test(a)&&!ib[(bb.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ab,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(ob(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(ob(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,m=this,o=l-1,p=a[0],q=n.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&eb.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(c=n.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=n.map(ob(c,"script"),kb),g=f.length;l>j;j++)h=c,j!==o&&(h=n.clone(h,!0,!0),g&&n.merge(f,ob(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,n.map(f,lb),j=0;g>j;j++)h=f[j],fb.test(h.type||"")&&!L.access(h,"globalEval")&&n.contains(i,h)&&(h.src?n._evalUrl&&n._evalUrl(h.src):n.globalEval(h.textContent.replace(hb,"")))}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),n(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qb,rb={};function sb(b,c){var d,e=n(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:n.css(e[0],"display");return e.detach(),f}function tb(a){var b=l,c=rb[a];return c||(c=sb(a,b),"none"!==c&&c||(qb=(qb||n("