From 9218c22696918b09a1cf0f0348b2efb594116a13 Mon Sep 17 00:00:00 2001 From: Sevhena Walker <83547364+Sevhena@users.noreply.github.com> Date: Sun, 10 Nov 2024 22:31:25 -0500 Subject: [PATCH 01/85] [DEV PLAN] Update POC Plan (#242) Co-authored-by: mya Co-authored-by: Ayushi Amin Co-authored-by: tbrar06 Co-authored-by: Nivetha Kuruparan --- docs/DevelopmentPlan/DevelopmentPlan.tex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/DevelopmentPlan/DevelopmentPlan.tex b/docs/DevelopmentPlan/DevelopmentPlan.tex index 4cd317b2..c1097b4e 100644 --- a/docs/DevelopmentPlan/DevelopmentPlan.tex +++ b/docs/DevelopmentPlan/DevelopmentPlan.tex @@ -171,15 +171,15 @@ \section{Proof of Concept Demonstration Plan} \begin{enumerate} \item Determine the code smells we want to address for energy saving. \begin{itemize} - \item These are items like but not limited to: Large Class (LC), Long Parameter List (LPL), Long Method (LM), Long Message Chain (LMC), Long Scope Chaining (LSC), Long Base Class List (LBCL), Useless Exception Handling (UEH), Long Lambda Function (LLF), Complex List Comprehension (CLC), Long Element Chain (LEC), and Long Ternary Conditional Expression (LTCE). + \item List Comprehension in an \texttt{any} or \texttt{all} statement, Member Ignoring Method, Long Paramter List, Unused Imports, Long Message Chain, Unused Class Attributes and Variables \end{itemize} \item Determine the detectability of a specific code smell \begin{itemize} - \item Many of these code smells are detectable using linters like Pylint, Flake8 and bandit. Hence the detection technology already exists if we choose to use it, and or the tools have been made before if we intend to remake them, proving they are possible to construct. + \item These code smells are detectable using Pylint or manual AST parsing. \end{itemize} \item Determine the appropriate refactorings for a particular detected smell that results in decreased energy consumption. \begin{itemize} - \item There are many tools such as Pyjoule that we can use to measure the energy consumed by a piece of code. This step will involve various phases of trial and error as it is not a 1-1 trivial solution. There could be various refactorings possible for a given situation that all result in different energy consumption levels. We want our tool to choose the most optimal refactoring possible. For our POC this can exist as an algorithm. For our final project we can attempt to implement a neural network to choose between refactorings. There are also prebuilt free to use libraries we can implement to perform simple refactorings. + \item We will use codecarbon to measure the emissions of a python code file. This step will involve various phases of trial and error as it is not a 1-1 trivial solution. There could be various refactorings possible for a given situation that all result in different energy consumption levels. We want our tool to choose the most optimal refactoring possible. For our POC this can exist as an algorithm. For our final project we can attempt to implement a neural network to choose between refactorings. There are also prebuilt free to use libraries we can implement to perform simple refactorings. \end{itemize} \item Once we determine preset algorithms mapping detected smells to their appropriate refactorings, we want to then make those changes in the code, measure the energy consumption and test it against the original code ensuring it is less. \item The code must then ensure that the original code functionallity is preserved. If it is not a different refactoring is required. From f8dece879e028e70adabff7fafcab47948afe4b0 Mon Sep 17 00:00:00 2001 From: Sevhena Walker <83547364+Sevhena@users.noreply.github.com> Date: Mon, 2 Dec 2024 20:19:13 -0500 Subject: [PATCH 02/85] closes #140 : Enhanced customer description in stakeholders section --- docs/SRS/SRS.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/SRS/SRS.tex b/docs/SRS/SRS.tex index fd9bac3c..42f2291c 100644 --- a/docs/SRS/SRS.tex +++ b/docs/SRS/SRS.tex @@ -92,7 +92,7 @@ \section{Stakeholders} \subsection{Client} The client of this project is \textbf{Dr. Istvan David} from McMaster's Department of Computing and Software. As the project supervisor, his role is to guide the development team with his technical and domain expertise. As the client, he sets the product's requirements and will be involved throughout its development. \subsection{Customer} -The customers of this product are all the \textbf{software developers} that use it to improve the energy efficiency of their codebase. As members of corporations or independent workers, they will be the primary users of the product and, therefore, will offer critical feedback on its effectiveness. Suggestions for improvement and/or additional features may come from this stakeholder. +The customers of this product are \textbf{software developers}. Specifically, they are the developers that work in teams for small to large corporations, or freelancers looking to improve their services. They will be the primary users of the product and, therefore, will offer critical feedback on its effectiveness such as suggestions for improvement and/or additional features. Any feedback received from this stakeholder will be given top priority for consideration as the goal for this tool is to be an integral part of a software developer's workflow. \subsection{Other Stakeholders} \subsubsection*{\textcolor{Maroon}{Project Managers}} From 6efd1c06f863f14e53349689b4601c842dfe05fd Mon Sep 17 00:00:00 2001 From: Sevhena Walker <83547364+Sevhena@users.noreply.github.com> Date: Mon, 2 Dec 2024 20:21:04 -0500 Subject: [PATCH 03/85] closes #157: Added Adaptability requirements --- docs/SRS/SRS.tex | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/docs/SRS/SRS.tex b/docs/SRS/SRS.tex index 42f2291c..ee031d02 100644 --- a/docs/SRS/SRS.tex +++ b/docs/SRS/SRS.tex @@ -972,7 +972,48 @@ \subsection{Supportability Requirements} \end{enumerate} \subsection{Adaptability Requirements} -Not applicable in this project currently +\begin{enumerate}[label=MS-AD \arabic*., wide=0pt, leftmargin=*] + \item \emph{The system must be compatible with the latest stable version of python (v3.13).}\\ + {\bf Rationale:} This allows the library to use the most up-to-date features, performance improvements, and security patches. Furthermore, it will ensure that users can integrate the library into modern projects without compatibility issues, reduces the risk of vulnerabilities.\\ + {\bf Fit Criteria:} The system passes all test cases when run in python 3.13.\\ + {\bf Priority:} High + + \item \emph{The system should offer backward compatibility with Python 3.10 and higher.}\\ + {\bf Rationale:} Offering backwards compatibility makes the library more accessible to users who may need to use the library in legacy codebases that can't easily be upgraded. Based on Python's versioning schedule, version 3.10 will not be considered end-of-life until nearly 2 years after the scheduled end of the development of this system.\\ + {\bf Fit Criteria:} All features of the system must work on Python 3.10 and higher versions, with minimal degradation in performance or functionality\\ + {\bf Priority:} Low + + \item \emph{The system must be able to detect and handle Python version-specific features and syntax.}\\ + {\bf Rationale:} Depending on the Python version of the source code, the refactorings should be made accordingly to not introduce compatibility errors.\\ + {\bf Fit Criteria:} The input source code should pass the given test cases.\\ + {\bf Priority:} High + + \item \emph{The energy measurement module must be adaptable to cloud-based systems.}\\ + {\bf Rationale:} Many modern applications are hosted and run in cloud environments so, it is essential for the energy measurement module to operate effectively in cloud-based systems. This ensures that developers can accurately measure the energy consumption of their cloud-hosted applications.\\ + {\bf Fit Criteria:} The energy consumption module returns usable statistics related to the energy consumption of the cloud-application.\\ + {\bf Priority:} Medium + + \item \emph{The system must be deployable in both cloud-based environments and on-premise infrastructures to meet different user needs.}\\ + {\bf Rationale:} Whether the system is being used locally or in the cloud, developers still need access to the features offered by the system. Some developers might not even host their applications, and, even if they do, they might want to conduct local testing. \\ + {\bf Fit Criteria:} The system should be fully functional in both cloud and local environments, with minimal configuration changes.\\ + {\bf Priority:} Medium + + \item \emph{The system must support major operating systems, including Windows, macOS, and Linux.}\\ + {\bf Rationale:} Developers may not all use the same operating system (OS), it's actually unlikely (even impossible) that they do. Allowing users to use the library on their preferred OS will only increase the adoption of the system.\\ + {\bf Fit Criteria:} The system must pass all tests on Windows 10+, macOS 13+ (Ventura and later), and Linux distributions such as Ubuntu 22.04.5+ without requiring different codebases or significant modifications.\\ + {\bf Priority:} Low + + \item \emph{The system must provide seamless functionality across different versions of the same operating system.}\\ + {\bf Rationale:} Users do not adopt the latest version of an OS at the same rate and some programs are to complex or fragile to upgrade to newer systems.\\ + {\bf Fit Criteria:} The system runs without errors or crashes across multiple versions of Windows, macOS, and Linux, with no compatibility issues in handling file systems, dependencies, or libraries.\\ + {\bf Priority:} Low + + \item \emph{The system must offer consistent performance (e.g., refactoring speed, energy consumption measurements) regardless of the underlying operating system.}\\ + {\bf Rationale:} Having the system be OS dependent would invalidate the point of being compatible with multiple OSes and conflict with requirement MS-AD 6.\\ + {\bf Fit Criteria:} Performance metrics, such as time taken for refactoring and energy measurements, must not vary by more than 5\% across different operating systems during testing.\\ + {\bf Priority:} Low + +\end{enumerate} \section{Security Requirements} \subsection{Access Requirements} From 243a79c51a7e3986013e874fd86e5c7ee746aaac Mon Sep 17 00:00:00 2001 From: Sevhena Walker <83547364+Sevhena@users.noreply.github.com> Date: Wed, 1 Jan 2025 15:55:30 -0500 Subject: [PATCH 04/85] Add references to tables and figure (#271) As per the feedback received on avenue, changes were made to the SRS tex file to ensure that tables and figrues were properly referenced with captions and working links. Preambles to the related sections and subsections were also added to allow such referencing since some subsections only contained a diagram/table. The revision table was updated to reflect these changes. closes #271 --- docs/SRS/SRS.tex | 120 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 88 insertions(+), 32 deletions(-) diff --git a/docs/SRS/SRS.tex b/docs/SRS/SRS.tex index ee031d02..548bba1e 100644 --- a/docs/SRS/SRS.tex +++ b/docs/SRS/SRS.tex @@ -24,6 +24,7 @@ filecolor=magenta, % color of file links urlcolor=cyan % color of external links } +\usepackage{float} \newcommand{\lips}{\textit{Insert your content here.}} @@ -57,6 +58,7 @@ \section*{Revision History} \toprule {\textbf{Date}} & {\textbf{Version}} & {\textbf{Notes}}\\ \midrule October 11th, 2024 & 0 & Created initial revision of SRS\\ +January 1st, 2025 & 0.1 & Fixed link references to tables and figures and added preambles to those sections\\ \bottomrule \end{tabularx} @@ -391,6 +393,8 @@ \subsection{Assumptions} It is assumed for this system that users will be seeking to refactor Python code and will make use of Visual Studio Code. \section{The Scope of the Work} +This section defines the boundaries and objectives of the work, focusing on the tasks and components required to develop and deliver the refactoring library. It provides a clear view of how the system operates within its context and breaks the work into logical partitions to facilitate development and implementation. + \subsection{The Current Situation} The current software development landscape often prioritizes functionality and performance over energy efficiency. Many existing Python codebases are not optimized for energy consumption, leading to unnecessary power usage and increased carbon footprint. The following aspects characterize the current situation: @@ -412,25 +416,39 @@ \subsection{The Current Situation} \end{enumerate} \subsection{The Context of the Work} +The purpose of this subsection is to illustrate the flow of inputs, outputs, and interactions between the refactoring library and its external systems, such as developers, energy measurement tools, and machine learning frameworks. \hyperref[img:work-context]{Figure 1} highlights the connections between the system's components and external elements, ensuring a comprehensive understanding of its operational environment. -\includegraphics[scale=0.5]{../Images/WorkContextModel.png} +\begin{figure}[H] + \centering + \includegraphics[scale=0.5]{../Images/WorkContextModel.png} + \caption{Work Context Diagram} + \label{img:work-context} +\end{figure} +\newpage \subsection{Work Partitioning} - -\setlength\extrarowheight{5mm} -\begin{tabularx}{\textwidth}{|c|X|l|p{1.5in}|} - \toprule \textbf{Event \#} & \textbf{Event Name} & \textbf{Input} & \textbf{Output(s)} \\ - \midrule - 1 & Users submit Python code & Python Code & Refactored Code \\ - 2 & Energy Analysis of code & Python Code & Total Energy Consumed \\ - 3 & RI Model produces refactoring & Python Code & Correct Refactoring \\ - 4 & Testing and Validation of refactored code & Refactored Code & Test Results \\ - 5 & Reporting Performance metrics of new code & Refactored Code & Performance Reports \\ - 6 & Viewing Energy consumption reports & Refactored Code & Energy Consumption Statistics \\ - \bottomrule -\end{tabularx} +In this subsection, the work needed to complete this system is divided into distinct activities, such as identifying code smells, applying refactorings, and measuring energy efficiency. As seen in \hyperref[tab:work-part]{Table 1}, each partition outlines its purpose, dependencies, and deliverables to provide a structured overview of the project's tasks. + +\begin{table}[H] + \centering + \setlength\extrarowheight{5mm} + \begin{tabularx}{\textwidth}{|c|X|l|p{1.5in}|} + \toprule \textbf{Event \#} & \textbf{Event Name} & \textbf{Input} & \textbf{Output(s)} \\ + \midrule + 1 & Users submit Python code & Python Code & Refactored Code\\ + 2 & Energy Analysis of code & Python Code & Total Energy Consumed \\ + 3 & RI Model produces refactoring & Python Code & Correct Refactoring \\ + 4 & Testing and Validation of refactored code & Refactored Code & Test Results \\ + 5 & Reporting Performance metrics of new code & Refactored Code & Performance Reports \\ + 6 & Viewing Energy consumption reports & Refactored Code & Energy Consumption Statistics \\ + \bottomrule + \end{tabularx} + \caption{Work Partitioning of System} + \label{tab:work-part} +\end{table} \subsection{Specifying a Business Use Case (BUC)} +Each event listed in \hyperref[tab:work-part]{Table 1} is expanded into an individual business use case which describes how the system handles specific scenarios. \begin{enumerate}[label={\bf BUC \arabic*:}, wide=0pt, font=\itshape] \item {\bf Code Submission} \\[2mm] @@ -520,14 +538,33 @@ \subsection{Specifying a Business Use Case (BUC)} \end{enumerate} \section{Business Data Model and Data Dictionary} + +This section describes the structure and organization of the data that flows through the refactoring library. It explains how the system's components interact with data entities, ensuring a consistent and well-defined understanding of the information processed by the system. + \subsection{Business Data Model} -\includegraphics[width=\textwidth]{../Images/business-data-model.png} +The following diagram (\hyperref[img:bdata-model]{Figure 2}) illustrates the relationships between key components of the system as well as their interactions with external components. + +\begin{figure}[H] + \centering + \includegraphics[width=\textwidth]{../Images/business-data-model.png} + \caption{Business Data Model of System} + \label{img:bdata-model} +\end{figure} + \subsection{Data Dictionary} +\hyperref[tab:data-dict]{Table 2} shown below defines each component in the system, including its attributes, type, and purpose. It ensures clarity and consistency in data handling and serves as a reference for development and testing. % \renewcommand{\arraystretch}{1} -\begin{longtable}{|p{3.5cm}|p{9cm}|p{2cm}|} - \toprule \textbf{Name} & \textbf{Content} & \textbf{Type} \\ +\begin{longtable}[H]{|p{3.5cm}|p{9cm}|p{2cm}|} + \toprule + \textbf{Name} & \textbf{Content} & \textbf{Type} \\ \midrule + \endhead + \bottomrule + \caption{Data Dictionary for the System} + \label{tab:data-dict} + \endlastfoot + EcoOptimizer & CentralCtrl + RefactoringCtrl + TestingCtrl + Reinforcement Learning Model & package \\ \hline GitHub Actions & External tool for automated customizable workflows & External Service Provider \\ \hline VS Code extension & A plugin containing the EcoOptimizer package delivered through Visual Studio Code Marketplace & External Service Provider \\ \hline @@ -547,30 +584,49 @@ \subsection{Data Dictionary} getSmells() & returns all the smells detected in the source code & method \\ \hline refactor(smell) & refactors the source code based on the given code smell & method \\ \hline checkFunctionality() & checks that the original functionality of the code is maintained & method \\ - \bottomrule \end{longtable} \section{The Scope of the Product} +This section outlines the boundaries and functionality of the refactoring library, detailing what the system will and will not deliver. It focuses on the internal components of the library, their interactions, and how they collectively address the project's objectives. + \subsection{Product Boundary} -\includegraphics[width=0.8\textwidth]{../Images/UseCaseDiagram.png} +This subsection includes a diagram (\hyperref[img:prod-bound]{Figure 3}) showing the system's boundary, identifying its internal components and their interactions. It clarifies what falls within the scope of the product and what lies outside its responsibility. + +\begin{figure}[H] + \centering + \includegraphics[width=0.8\textwidth]{../Images/UseCaseDiagram.png} + \caption{Product Boundary Diagram of System} + \label{img:prod-bound} +\end{figure} + \subsection{Product Use Case Table} +The following \hyperref[tab:puc]{table} summarizes the primary use cases of the refactoring library, such as identifying code smells, measuring energy consumption, and applying refactorings. Each use case briefly describes the interaction between the user and the system. \setlength\extrarowheight{2mm} -\begin{tabularx}{\textwidth}{|c| - >{\raggedright\arraybackslash}X|p{1.2in}| - >{\raggedright\arraybackslash}X|} - \toprule \textbf{PUC \#} & \textbf{PUC Name} & \textbf{Actor/s} & \textbf{Input \& Output(s)} \\ - \midrule - 1 & Receive Code for Refactoring & User & Original Python Code (in) \\ - 2 & Analyze Energy Consumption of Original Code & Energy Consumption Tool & Original Code (in), Energy Consumption Report (out) \\ - 3 & Refactor Code & Reinforcement Learning Model & Code Segment (in), Previous Energy Saving Patterns (out) \\ - 4 & Test Refactored Code Functionality & Testing Service & Refactored Code (in), Test Results (out) \\ - 5 & Generate Performance Metrics of Refactored Code & Energy Consumption Tool & Refactored Code (in), Energy Consumption Report (out) \\ - 6 & Show Results & User & Refactored Code, Performance Metrics (out) \\ - \bottomrule -\end{tabularx} + +\begin{table}[H] + \centering + \begin{tabularx}{\textwidth}{|c| + >{\raggedright\arraybackslash}X| + >{\raggedright\arraybackslash}p{1.2in}| + >{\raggedright\arraybackslash}X|} + \toprule \textbf{PUC \#} & \textbf{PUC Name} & \textbf{Actor/s} & \textbf{Input \& Output(s)} \\ + \midrule + 1 & Receive Code for Refactoring & User & Original Python Code (in) \\ + 2 & Analyze Energy Consumption of Original Code & Energy Consumption Tool & Original Code (in), Energy Consumption Report (out) \\ + 3 & Refactor Code & Reinforcement Learning Model & Code Segment (in), Previous Energy Saving Patterns (out) \\ + 4 & Test Refactored Code Functionality & Testing Service & Refactored Code (in), Test Results (out) \\ + 5 & Generate Performance Metrics of Refactored Code & Energy Consumption Tool & Refactored Code (in), Energy Consumption Report (out) \\ + 6 & Show Results & User & Refactored Code, Performance Metrics (out) \\ + \bottomrule + \end{tabularx} + \caption{Product Use Case Table of System} + \label{tab:puc} +\end{table} \subsection{Individual Product Use Cases (PUC's)} +This subsection expands on the use cases listed in \hyperref[tab:puc]{Table 3}, providing a detailed description of each. It explains how the system components work together to fulfill each use case, emphasizing expected functionality and outcomes for users. + \setlength{\parindent}{0pt} \begin{enumerate}[label={\bf PUC \arabic*:}, wide=0pt, font=\itshape] \item {\bf Receive Code for Refactoring} \\[2mm] From e2ce110bace175bdd92da6357d56cb7acad0145e Mon Sep 17 00:00:00 2001 From: Sevhena Walker <83547364+Sevhena@users.noreply.github.com> Date: Wed, 1 Jan 2025 17:35:53 -0500 Subject: [PATCH 05/85] Move up glossary in document (#270) In accordance to the TA's feedback, moved the glossary section up in the document to rigth below the Purpose of the Project (Section 1). closes #270 --- docs/SRS/SRS.tex | 148 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 146 insertions(+), 2 deletions(-) diff --git a/docs/SRS/SRS.tex b/docs/SRS/SRS.tex index 548bba1e..600370b3 100644 --- a/docs/SRS/SRS.tex +++ b/docs/SRS/SRS.tex @@ -58,7 +58,7 @@ \section*{Revision History} \toprule {\textbf{Date}} & {\textbf{Version}} & {\textbf{Notes}}\\ \midrule October 11th, 2024 & 0 & Created initial revision of SRS\\ -January 1st, 2025 & 0.1 & Fixed link references to tables and figures and added preambles to those sections\\ +January 1st, 2025 & 0.1 & Fixed link references to tables and figures and added preambles to those sections, move glossary section\\ \bottomrule \end{tabularx} @@ -86,6 +86,151 @@ \subsection{Goals of the Project} ability to make informed choices about whether to apply refactorings will also be evaluated through user feedback. +\section{Naming Conventions and Terminology} +\subsection{Glossary of All Terms, Including Acronyms, Used by Stakeholders +involved in the Project} + +% --- TERMS PRESENT IN THE STAKEHOLDER SECTION --- +\paragraph*{supervisor} +A member of faculty from McMaster University responsible for overseeing a project being worked on by students taking the SFWRENG 4G06 Capstone course. + +\paragraph*{large-scale applications} +Applications that manage high volumes of data, users, or transactions, typically requiring scalable architectures. + +\paragraph*{cloud-hosted applications} +Software applications deployed and run on remote cloud servers, accessible over the internet. + +\paragraph*{environmental footprint} +The total impact an activity or product has on the environment, measured by metrics like carbon emissions and resource consumption. + +\paragraph*{refactoring} +The process of restructuring existing code without changing its external behaviour to improve readability, performance, or maintainability. + +\paragraph*{mobile environment} +A software environment specifically designed for mobile devices, such as smartphones or tablets, which have limited resources. + +\paragraph*{embedded environment} +A software environment where applications run on specialized hardware with constrained resources, often without traditional operating systems. + +\paragraph*{SaaS} +Software as a Service (SaaS) refers to cloud-based software applications delivered to users via the internet on a subscription basis. + +\paragraph*{backend} +The part of a software system that handles server-side logic, database interactions, and application functionality not directly visible to users. + +\paragraph*{software developer} +A professional who designs, writes, and maintains software applications or systems. + +\paragraph*{data analyst} +A professional who processes and analyzes large sets of data to help organizations make informed decisions. + +\paragraph*{tech company} +A company focused on technology products and services, including software, hardware, and IT services. + +\paragraph*{freelance} +Self-employed individuals who offer specialized services, such as software development, without long-term commitments to any employer. + +\paragraph*{usability testing} +A method of evaluating how easy and user-friendly a software application or product is by observing real users interacting with it. + +% --- TERMS PRESENT IN THE OPERATIONAL AND ENVIRONMENTAL REQUIREMENTS SECTION --- +\paragraph*{Python Code} +Refers to the original Python code given by the end user to refactor. + +\paragraph*{Refactored Code} +Refers to the Python code that had refactorings made to it. + +\paragraph*{library} +A collection of pre-written code that developers can reuse in their projects to add specific functionalities. + +\paragraph*{Git} +\label{term:git} +A distributed version control system that allows multiple developers to track changes in source code, collaborate, and manage project history efficiently. + +\paragraph*{GitHub} +\label{term:GitH} +A web-based platform used for version control and collaboration on code through \hyperref[term:git]{Git} repositories. + +\paragraph*{Actions} +A \hyperref[term:GitH]{GitHub} feature that automates tasks such as testing, deployment, and continuous integration via custom workflows. + +\paragraph*{workflow} +A sequence of automated steps or actions that define a process, often for continuous integration, deployment, or testing. + +\paragraph*{Visual Studio Code} +\label{term:VSC} +A free, open-source code editor developed by Microsoft, known for its versatility and wide range of extensions. + +\paragraph*{VS Code} +An abbreviation of \hyperref[term:VSC]{Visual Studio Code} + +\paragraph*{Visual Studio Code (VS Code) marketplace} +An online platform where users can discover, install, and manage extensions that enhance the functionality of \hyperref[term:VSC]{Visual Studio Code}. + +\paragraph*{JSON} +\label{term:JSON} +\hyperref[term:JS]{JavaScript} Object Notation, a lightweight data format used to store and exchange information between systems. + +\paragraph*{XML} +\label{term:XML} +Extensible Markup Language, a data format used to encode documents in a way that is both human-readable and machine-readable. + +\paragraph*{package manager} +A tool that automates the process of installing, updating, and managing software packages or libraries in a project. + +\paragraph*{PIP} +A package manager for \hyperref[term:python]{Python} that simplifies the installation and management of Python libraries. + +% --- TERMS PRESENT IN WAITING ROOM SECTION --- +\paragraph*{IDE} +Integrated Development Environment, a software application providing tools like a code editor, debugger, and compiler to facilitate development. + +\paragraph*{progress indicators} +Visual or textual cues, such as loading bars or percentages, that inform users about the status of ongoing processes. + +\paragraph*{plugin} +A software component that adds specific features or functionalities to an existing software system. + +\paragraph*{configuration file} +A file used to define settings or preferences for a software application, often stored in a human-readable format like \hyperref[term:JSON]{JSON} or \hyperref[term:XML]{XML}. + +\paragraph*{dashboard} +A user interface that provides an overview of key information and metrics, typically presented in graphs, charts, and tables. + +\paragraph*{sync} +The process of ensuring that data is consistent across multiple systems or devices by automatically updating changes in real-time. + +\paragraph*{programming language} +\label{term:progl} +A formal language used to write software programs by providing instructions that a computer can execute. + +\paragraph*{Python} +\label{term:python} +A \hyperref[term:progl]{programming language} known for its simplicity and versatility, widely used in web development, data science, and automation. + +\paragraph*{Java} +A \hyperref[term:progl]{programming language} known for its portability and scalability, commonly used for enterprise-level applications. + +\paragraph*{C/C++} +A \hyperref[term:progl]{programming language} family used for system programming, game development, and applications requiring high performance. + +\paragraph*{C\#} +A \hyperref[term:progl]{programming language} developed by Microsoft, primarily used for developing applications on the .NET platform. + +\paragraph*{JavaScript} +\label{term:JS} +A \hyperref[term:progl]{programming language} used primarily for adding interactivity to web pages and building dynamic web applications. + +\paragraph*{TypeScript} +A \hyperref[term:progl]{programming language} that builds on JavaScript by adding static typing, improving code reliability and scalability. + +\paragraph*{Go} +A \hyperref[term:progl]{programming language} created by Google, designed for simplicity and efficiency in building scalable applications. + +\paragraph*{Rust} +A \hyperref[term:progl]{programming language} focused on safety, performance, and concurrency, often used in system programming. + + \section{Stakeholders} The stakeholders involved in this project include all individuals and groups that have a direct or indirect interest in the development, implementation, and usage of the refactoring library for energy efficiency. These stakeholders influence project decisions and will be impacted by their outcomes. Understanding their roles and expectations is crucial for ensuring that the library meets the needs of its users and aligns with broader organizational goals.\\ @@ -374,7 +519,6 @@ \subsection{Glossary of All Terms, Including Acronyms, Used by Stakeholders A \hyperref[term:progl]{programming language} focused on safety, performance, and concurrency, often used in system programming. - \section{Relevant Facts And Assumptions} \subsection{Relevant Facts} Not applicable to this system. From 7af0bfe5b06e405014a11ff2e370444bc8af6073 Mon Sep 17 00:00:00 2001 From: Sevhena Walker <83547364+Sevhena@users.noreply.github.com> Date: Thu, 2 Jan 2025 18:29:24 -0500 Subject: [PATCH 06/85] fix duplicate glossary (#270) Forgot to delete the original glossary when addressing feedback --- docs/SRS/SRS.tex | 145 ----------------------------------------------- 1 file changed, 145 deletions(-) diff --git a/docs/SRS/SRS.tex b/docs/SRS/SRS.tex index 600370b3..a2435859 100644 --- a/docs/SRS/SRS.tex +++ b/docs/SRS/SRS.tex @@ -374,151 +374,6 @@ \subsection{Enterprise Constraints} {\bf Priority:} High \end{enumerate} -\section{Naming Conventions and Terminology} -\subsection{Glossary of All Terms, Including Acronyms, Used by Stakeholders -involved in the Project} - -% --- TERMS PRESENT IN THE STAKEHOLDER SECTION --- -\paragraph*{supervisor} -A member of faculty from McMaster University responsible for overseeing a project being worked on by students taking the SFWRENG 4G06 Capstone course. - -\paragraph*{large-scale applications} -Applications that manage high volumes of data, users, or transactions, typically requiring scalable architectures. - -\paragraph*{cloud-hosted applications} -Software applications deployed and run on remote cloud servers, accessible over the internet. - -\paragraph*{environmental footprint} -The total impact an activity or product has on the environment, measured by metrics like carbon emissions and resource consumption. - -\paragraph*{refactoring} -The process of restructuring existing code without changing its external behaviour to improve readability, performance, or maintainability. - -\paragraph*{mobile environment} -A software environment specifically designed for mobile devices, such as smartphones or tablets, which have limited resources. - -\paragraph*{embedded environment} -A software environment where applications run on specialized hardware with constrained resources, often without traditional operating systems. - -\paragraph*{SaaS} -Software as a Service (SaaS) refers to cloud-based software applications delivered to users via the internet on a subscription basis. - -\paragraph*{backend} -The part of a software system that handles server-side logic, database interactions, and application functionality not directly visible to users. - -\paragraph*{software developer} -A professional who designs, writes, and maintains software applications or systems. - -\paragraph*{data analyst} -A professional who processes and analyzes large sets of data to help organizations make informed decisions. - -\paragraph*{tech company} -A company focused on technology products and services, including software, hardware, and IT services. - -\paragraph*{freelance} -Self-employed individuals who offer specialized services, such as software development, without long-term commitments to any employer. - -\paragraph*{usability testing} -A method of evaluating how easy and user-friendly a software application or product is by observing real users interacting with it. - -% --- TERMS PRESENT IN THE OPERATIONAL AND ENVIRONMENTAL REQUIREMENTS SECTION --- -\paragraph*{Python Code} -Refers to the original Python code given by the end user to refactor. - -\paragraph*{Refactored Code} -Refers to the Python code that had refactorings made to it. - -\paragraph*{library} -A collection of pre-written code that developers can reuse in their projects to add specific functionalities. - -\paragraph*{Git} -\label{term:git} -A distributed version control system that allows multiple developers to track changes in source code, collaborate, and manage project history efficiently. - -\paragraph*{GitHub} -\label{term:GitH} -A web-based platform used for version control and collaboration on code through \hyperref[term:git]{Git} repositories. - -\paragraph*{Actions} -A \hyperref[term:GitH]{GitHub} feature that automates tasks such as testing, deployment, and continuous integration via custom workflows. - -\paragraph*{workflow} -A sequence of automated steps or actions that define a process, often for continuous integration, deployment, or testing. - -\paragraph*{Visual Studio Code} -\label{term:VSC} -A free, open-source code editor developed by Microsoft, known for its versatility and wide range of extensions. - -\paragraph*{VS Code} -An abbreviation of \hyperref[term:VSC]{Visual Studio Code} - -\paragraph*{Visual Studio Code (VS Code) marketplace} -An online platform where users can discover, install, and manage extensions that enhance the functionality of \hyperref[term:VSC]{Visual Studio Code}. - -\paragraph*{JSON} -\label{term:JSON} -\hyperref[term:JS]{JavaScript} Object Notation, a lightweight data format used to store and exchange information between systems. - -\paragraph*{XML} -\label{term:XML} -Extensible Markup Language, a data format used to encode documents in a way that is both human-readable and machine-readable. - -\paragraph*{package manager} -A tool that automates the process of installing, updating, and managing software packages or libraries in a project. - -\paragraph*{PIP} -A package manager for \hyperref[term:python]{Python} that simplifies the installation and management of Python libraries. - -% --- TERMS PRESENT IN WAITING ROOM SECTION --- -\paragraph*{IDE} -Integrated Development Environment, a software application providing tools like a code editor, debugger, and compiler to facilitate development. - -\paragraph*{progress indicators} -Visual or textual cues, such as loading bars or percentages, that inform users about the status of ongoing processes. - -\paragraph*{plugin} -A software component that adds specific features or functionalities to an existing software system. - -\paragraph*{configuration file} -A file used to define settings or preferences for a software application, often stored in a human-readable format like \hyperref[term:JSON]{JSON} or \hyperref[term:XML]{XML}. - -\paragraph*{dashboard} -A user interface that provides an overview of key information and metrics, typically presented in graphs, charts, and tables. - -\paragraph*{sync} -The process of ensuring that data is consistent across multiple systems or devices by automatically updating changes in real-time. - -\paragraph*{programming language} -\label{term:progl} -A formal language used to write software programs by providing instructions that a computer can execute. - -\paragraph*{Python} -\label{term:python} -A \hyperref[term:progl]{programming language} known for its simplicity and versatility, widely used in web development, data science, and automation. - -\paragraph*{Java} -A \hyperref[term:progl]{programming language} known for its portability and scalability, commonly used for enterprise-level applications. - -\paragraph*{C/C++} -A \hyperref[term:progl]{programming language} family used for system programming, game development, and applications requiring high performance. - -\paragraph*{C\#} -A \hyperref[term:progl]{programming language} developed by Microsoft, primarily used for developing applications on the .NET platform. - -\paragraph*{JavaScript} -\label{term:JS} -A \hyperref[term:progl]{programming language} used primarily for adding interactivity to web pages and building dynamic web applications. - -\paragraph*{TypeScript} -A \hyperref[term:progl]{programming language} that builds on JavaScript by adding static typing, improving code reliability and scalability. - -\paragraph*{Go} -A \hyperref[term:progl]{programming language} created by Google, designed for simplicity and efficiency in building scalable applications. - -\paragraph*{Rust} -A \hyperref[term:progl]{programming language} focused on safety, performance, and concurrency, often used in system programming. - - \section{Relevant Facts And Assumptions} \subsection{Relevant Facts} Not applicable to this system. From 529da98bef82a85fae95f471ef0ebd6b22681776 Mon Sep 17 00:00:00 2001 From: Nivetha Kuruparan Date: Sun, 5 Jan 2025 00:29:13 -0500 Subject: [PATCH 07/85] Fixed Ambiguous Meaning on FR-8 (#137) --- docs/SRS/SRS.tex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/SRS/SRS.tex b/docs/SRS/SRS.tex index a2435859..5065235d 100644 --- a/docs/SRS/SRS.tex +++ b/docs/SRS/SRS.tex @@ -730,9 +730,9 @@ \subsection{Functional Requirements} {\bf Rationale:} There may be multiple ways to refactor code, but the most energy-efficient one should be chosen.\\ {\bf Fit Criterion:} The algorithm evaluates multiple refactoring options and selects the one that results in the lowest energy consumption for the given code smell.\\ {\bf Priority:} Medium - \item \emph{The tool must be compatible with various Python versions and common libraries.}\\[2mm] - {\bf Rationale:} The tool should be flexible enough to be used across different Python environments.\\ - {\bf Fit Criterion:} The tool operates correctly with the latest two major versions of Python (e.g., Python 3.8 and 3.9) and commonly used libraries.\\ + \item \emph{The tool must require Python version 3.10 to run but must be capable of analyzing and refactoring Python code written for versions 3.8 and newer.}\\[2mm] + {\bf Rationale:} The tool leverages features available in Python 3.10 for its operation while ensuring compatibility with analyzing codebases written in Python 3.8 and 3.9, which are the most widely adopted recent major versions in use.\\ + {\bf Fit Criterion:} The tool operates correctly in a Python 3.10 environment and successfully analyzes and refactors code written for Python versions 3.8, 3.9, and newer.\\ {\bf Priority:} Medium \item \emph{The tool must generate comprehensive reports on detected smells, refactorings applied, energy consumption measurements, and testing results.}\\[2mm] {\bf Rationale:} Developers need clear reports to understand the impact of the refactorings and to track changes effectively.\\ From f52035d91b2ec1fb3fcebbdd3eb4f25ba739a64e Mon Sep 17 00:00:00 2001 From: Nivetha Kuruparan Date: Sun, 5 Jan 2025 00:34:12 -0500 Subject: [PATCH 08/85] Fixed Lowest Energy Consumption definition (#138) --- docs/SRS/SRS.tex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/SRS/SRS.tex b/docs/SRS/SRS.tex index 5065235d..8c94d765 100644 --- a/docs/SRS/SRS.tex +++ b/docs/SRS/SRS.tex @@ -726,9 +726,9 @@ \subsection{Functional Requirements} {\bf Rationale:} Refactored code must remain functional and error-free to ensure maintainability and usability.\\ {\bf Fit Criterion:} The output code is syntactically correct and adheres to Python standards, validated by an automatic linter.\\ {\bf Priority:} High - \item \emph{The tool must implement an algorithm to choose the most optimal refactoring based on measured energy consumption.}\\[2mm] - {\bf Rationale:} There may be multiple ways to refactor code, but the most energy-efficient one should be chosen.\\ - {\bf Fit Criterion:} The algorithm evaluates multiple refactoring options and selects the one that results in the lowest energy consumption for the given code smell.\\ + \item \emph{The tool must implement an algorithm to choose the most optimal refactoring based on energy consumption, measured using CodeCarbon.}\\[2mm] + {\bf Rationale:} There may be multiple ways to refactor code, but the most energy-efficient one should be chosen to minimize power usage. Energy consumption will be measured in terms of power usage (e.g., kilowatt-hours) by leveraging the CodeCarbon library.\\ + {\bf Fit Criterion:} The algorithm evaluates multiple refactoring options and selects the one that results in the lowest measured energy consumption, as reported by CodeCarbon, for the given code smell.\\ {\bf Priority:} Medium \item \emph{The tool must require Python version 3.10 to run but must be capable of analyzing and refactoring Python code written for versions 3.8 and newer.}\\[2mm] {\bf Rationale:} The tool leverages features available in Python 3.10 for its operation while ensuring compatibility with analyzing codebases written in Python 3.8 and 3.9, which are the most widely adopted recent major versions in use.\\ From 49b262c4927486931de7eab59d24b1c79bf81615 Mon Sep 17 00:00:00 2001 From: Nivetha Kuruparan Date: Sun, 5 Jan 2025 00:39:32 -0500 Subject: [PATCH 09/85] Fixed Ideas for Solution (Energy Dashboard) (#152) --- docs/SRS/SRS.tex | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/docs/SRS/SRS.tex b/docs/SRS/SRS.tex index 8c94d765..a0dc8b34 100644 --- a/docs/SRS/SRS.tex +++ b/docs/SRS/SRS.tex @@ -1483,11 +1483,30 @@ \section{Ideas for Solution} \item \textbf{Integration with Existing Tools via Pre-Commit Hooks:} Integrate the refactoring tool with popular tools like PyLint or Black by setting up pre-commit hooks to run the refactoring library before committing. \item \textbf{Energy Usage Dashboard Using JavaScript and Flask:} - Build a simple dashboard that displays energy consumption metrics for code refactorings over time. + Build a simple dashboard to track and display energy consumption metrics for code refactorings over time. + \begin{itemize} + \item \textbf{Data Sources:} The dashboard will utilize data provided by the CodeCarbon library, including: + \begin{itemize} + \item \textit{Energy Usage (kWh):} Measured by CodeCarbon for each refactoring session. + \item \textit{Refactoring Metadata:} Information such as the type of code smell addressed, refactored lines of code, and energy savings. + \item \textit{Time-Based Logs:} Timestamped entries to track trends over time. + \end{itemize} + \item \textbf{Insights Provided:} The dashboard will display: + \begin{itemize} + \item Total energy consumption for all refactoring processes. + \item Energy savings percentage for individual refactorings. + \item Trends in energy consumption over time. + \item Comparative metrics across projects or refactoring types. + \end{itemize} + \item \textbf{Implementation Details:} + \begin{itemize} + \item \textit{Backend:} Flask to handle API requests and process CodeCarbon data. + \item \textit{Frontend:} JavaScript (e.g., Chart.js or D3.js) to create interactive graphs. + \item \textit{Data Storage:} SQLite to store historical metrics for trend analysis. + \end{itemize} + \end{itemize} \end{itemize} - - \newpage{} \section*{Appendix --- Reflection} @@ -1663,7 +1682,7 @@ \subsubsection*{Nivetha Reflection} ~\newpage \bibliographystyle {plainnat} -\bibliography{../../refs/References} +% \bibliography{../../refs/References} \end{document} From 93999f9b8e7655b87b24ed5424c118e81dbcbdd1 Mon Sep 17 00:00:00 2001 From: Nivetha Kuruparan Date: Sun, 5 Jan 2025 00:43:18 -0500 Subject: [PATCH 10/85] Uncomment references --- docs/SRS/SRS.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/SRS/SRS.tex b/docs/SRS/SRS.tex index a0dc8b34..a9101b15 100644 --- a/docs/SRS/SRS.tex +++ b/docs/SRS/SRS.tex @@ -1682,7 +1682,7 @@ \subsubsection*{Nivetha Reflection} ~\newpage \bibliographystyle {plainnat} -% \bibliography{../../refs/References} +\bibliography{../../refs/References} \end{document} From ea369f7fb30bfb865c2d0a24f7cc03d7dd5753d7 Mon Sep 17 00:00:00 2001 From: Sevhena Walker <83547364+Sevhena@users.noreply.github.com> Date: Mon, 6 Jan 2025 13:58:18 -0500 Subject: [PATCH 11/85] Fixes #269: Added symbolic constants for srs Created table of symbolic constants at the begining of the document and used them in place of their hard values throughout the document. --- docs/SRS/SRS.tex | 92 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 64 insertions(+), 28 deletions(-) diff --git a/docs/SRS/SRS.tex b/docs/SRS/SRS.tex index a9101b15..54cdd708 100644 --- a/docs/SRS/SRS.tex +++ b/docs/SRS/SRS.tex @@ -58,13 +58,49 @@ \section*{Revision History} \toprule {\textbf{Date}} & {\textbf{Version}} & {\textbf{Notes}}\\ \midrule October 11th, 2024 & 0 & Created initial revision of SRS\\ -January 1st, 2025 & 0.1 & Fixed link references to tables and figures and added preambles to those sections, move glossary section\\ +January 6th, 2025 & 0.1 & Fixed link references to tables and figures and added preambles to those sections, move glossary section, added symbolic constants\\ \bottomrule \end{tabularx} ~\\ ~\newpage + +\section*{Symbolic Constants} +\begin{table}[H] + \centering + \begin{tabular}{|l|c|} + \toprule \textbf{Name} & \textbf{Value} \\ + \midrule + ENERGY\_SAVE & 5\% \\ + SMELL\_COVERAGE & 80\% \\ + TEST\_FUNCTION\_THRESH & 100\% \\ + REFACTOR\_EFFICACY\_THRESH & 95\% \\ + REFACTOR\_REVERT\_LIMIT & 5 commits \\ + CRITICAL\_ENERGY\_SAVE\_THRESH & 10\% \\ + MIN\_USER\_CONFIDENCE & 70\% \\ + MAX\_TASK\_CLICKS & 3 clicks \\ + MIN\_USER\_EOU & 80\% \\ + SMALL\_FILE\_TIME & 5 sec \\ + LARGE\_FILE\_TIME & 30 sec \\ + REFACTOR\_TIME & 10 sec \\ + DETECTION\_ACC & 90\% \\ + LARGE\_CODE\_BASE\_TIME & 2 min \\ + NEW\_REFACTOR\_TIME & 7 days \\ + COMPREHENSION\_TIME & 2 days \\ + ROLLBACK\_TIME & 1h \\ + MIN\_CODE\_COVERAGE & 80\% \\ + OS\_PERF\_DIFF\_LIMIT & 5\% \\ + \bottomrule + \end{tabular} + \caption{Table of Symbolic Constants} + \label{tab:syms} +\end{table} + +~\\ + +~\newpage + \pagenumbering{arabic} \section{Purpose of the Project} @@ -331,7 +367,7 @@ \subsection{Solution Constraints} {\bf Priority:} High \item \emph{The refactored code must result in measurable energy savings.}\\[2mm] {\bf Rationale:} The project's primary objective is to improve the code's energy efficiency. Refactorings should lead to a noticeable reduction in energy consumption.\\ - {\bf Fit Criterion:} The system must show at least a 5\% reduction in energy consumption, as measured by tools like \texttt{PyJoules}, for most of the refactored code.\\ + {\bf Fit Criterion:} The system must show at least a ENERGY\_SAVE reduction in energy consumption, as measured by tools like \texttt{PyJoules}, for most of the refactored code.\\ {\bf Priority:} High \item \emph{The refactored code must be provided to the user upon completion of the refactoring process.}\\[2mm] {\bf Rationale:} Developers need access to the refactored code to utilize it in their projects immediately after the refactoring process.\\ @@ -426,7 +462,7 @@ \subsection{The Context of the Work} \newpage \subsection{Work Partitioning} -In this subsection, the work needed to complete this system is divided into distinct activities, such as identifying code smells, applying refactorings, and measuring energy efficiency. As seen in \hyperref[tab:work-part]{Table 1}, each partition outlines its purpose, dependencies, and deliverables to provide a structured overview of the project's tasks. +In this subsection, the work needed to complete this system is divided into distinct activities, such as identifying code smells, applying refactorings, and measuring energy efficiency. As seen in \hyperref[tab:work-part]{Table 2}, each partition outlines its purpose, dependencies, and deliverables to provide a structured overview of the project's tasks. \begin{table}[H] \centering @@ -447,7 +483,7 @@ \subsection{Work Partitioning} \end{table} \subsection{Specifying a Business Use Case (BUC)} -Each event listed in \hyperref[tab:work-part]{Table 1} is expanded into an individual business use case which describes how the system handles specific scenarios. +Each event listed in \hyperref[tab:work-part]{Table 2} is expanded into an individual business use case which describes how the system handles specific scenarios. \begin{enumerate}[label={\bf BUC \arabic*:}, wide=0pt, font=\itshape] \item {\bf Code Submission} \\[2mm] @@ -551,7 +587,7 @@ \subsection{Business Data Model} \end{figure} \subsection{Data Dictionary} -\hyperref[tab:data-dict]{Table 2} shown below defines each component in the system, including its attributes, type, and purpose. It ensures clarity and consistency in data handling and serves as a reference for development and testing. +\hyperref[tab:data-dict]{Table 3} shown below defines each component in the system, including its attributes, type, and purpose. It ensures clarity and consistency in data handling and serves as a reference for development and testing. % \renewcommand{\arraystretch}{1} \begin{longtable}[H]{|p{3.5cm}|p{9cm}|p{2cm}|} @@ -624,7 +660,7 @@ \subsection{Product Use Case Table} \end{table} \subsection{Individual Product Use Cases (PUC's)} -This subsection expands on the use cases listed in \hyperref[tab:puc]{Table 3}, providing a detailed description of each. It explains how the system components work together to fulfill each use case, emphasizing expected functionality and outcomes for users. +This subsection expands on the use cases listed in \hyperref[tab:puc]{Table 4}, providing a detailed description of each. It explains how the system components work together to fulfill each use case, emphasizing expected functionality and outcomes for users. \setlength{\parindent}{0pt} \begin{enumerate}[label={\bf PUC \arabic*:}, wide=0pt, font=\itshape] @@ -708,11 +744,11 @@ \subsection{Functional Requirements} {\bf Priority:} High \item \emph{The system must identify specific code smells that can be targeted for energy saving.}\\[2mm] {\bf Rationale:} Energy inefficiencies are often related to well-known code smells, so identifying them is the first step in improving efficiency.\\ - {\bf Fit Criterion:} The tool should detect and report at least 80\% of the following code smells: Large Class (LC), Long Parameter List (LPL), Long Method (LM), Long Message Chain (LMC), Long Scope Chaining (LSC), Long Base Class List (LBCL), Useless Exception Handling (UEH), Long Lambda Function (LLF), Complex List Comprehension (CLC), Long Element Chain (LEC), Long Ternary Conditional Expression (LTCE).\\ + {\bf Fit Criterion:} The tool should be meet the SMELL\_COVERAGE for the detection and reporting of the following smells: Large Class (LC), Long Parameter List (LPL), Long Method (LM), Long Message Chain (LMC), Long Scope Chaining (LSC), Long Base Class List (LBCL), Useless Exception Handling (UEH), Long Lambda Function (LLF), Complex List Comprehension (CLC), Long Element Chain (LEC), Long Ternary Conditional Expression (LTCE).\\ {\bf Priority:} High \item \emph{The system shall maintain the original functionality of the Python code after refactoring.}\\[2mm] {\bf Rationale:} Ensuring that the refactored code preserves the original behaviour is critical to avoid regressions or unexpected issues in the software.\\ - {\bf Fit Criterion:} The system runs the original test suite against the refactored code and passes 100\% of the tests.\\ + {\bf Fit Criterion:} The system runs the original test suite against the refactored code and the amount of test to pass should meet the TEST\_FUNCTION\_THRESH.\\ {\bf Priority:} High \item \emph{The system must allow users to input their original test suite as a required argument.}\\[2mm] {\bf Rationale:} Verifying that the refactored code preserves functionality requires the use of the original test suite.\\ @@ -748,11 +784,11 @@ \subsection{Functional Requirements} {\bf Priority:} Medium \item \emph{The system shall integrate with GitHub and provide an automated refactoring process that is triggered when code is pushed to a repository.}\\[2mm] {\bf Rationale:} Automated refactoring integrated into CI/CD pipelines ensures that energy-efficient code is maintained across all stages of development, reducing the burden on developers.\\ - {\bf Fit Criterion:} The refactoring process must be triggered automatically on GitHub commits, with at least 95\% of refactorings improving energy efficiency without introducing any functional errors.\\ + {\bf Fit Criterion:} The refactoring process must be triggered automatically on GitHub commits, with the number of refactorings improving energy efficiency without introducing any functional errors meeting the REFACTOR\_EFFICACY\_THRESH.\\ {\bf Priority:} Medium \item \emph{The system shall allow developers to undo any refactorings applied, restoring the code to its previous state.}\\[2mm] {\bf Rationale:} Developers may want to revert changes if they do not align with specific project goals or introduce performance bottlenecks unrelated to energy consumption.\\ - {\bf Fit Criterion:} The system must provide an option to revert any refactoring applied within the last 5 commits, restoring both code and energy consumption metrics to their original state.\\ + {\bf Fit Criterion:} The system must provide an option to revert any refactoring commits applied within the REFACTOR\_REVERT\_LIMIT, restoring both code and energy consumption metrics to their original state.\\ {\bf Priority:} Medium \end{enumerate} @@ -778,22 +814,22 @@ \subsection{Appearance Requirements} {\bf Priority:} Low \item \emph{The GitHub Action shall highlight significant energy savings with visual alerts in pull requests (PRs).}\\[2mm] {\bf Rationale:} Visual alerts in PRs inform developers of the energy savings achieved, encouraging the adoption of energy-efficient practices.\\ - {\bf Fit Criterion:} The GitHub Action must display a success icon or green label in the PR summary if energy savings exceed a predefined threshold (e.g., 10\%).\\ + {\bf Fit Criterion:} The GitHub Action must display a success icon or green label in the PR summary if energy savings exceed the CRITICAL\_ENERGY\_SAVE\_THRESH.\\ {\bf Priority:} Low \end{enumerate} \subsection{Style Requirements} \begin{enumerate}[label=LFR-ST \arabic*., wide=0pt, leftmargin=*] \item \emph{The tool shall convey a professional and authoritative appearance to instill confidence in developers.}\\[2mm] {\bf Rationale:} A professional appearance helps build trust and encourages developers to use the tool confidently for energy-efficient refactoring.\\ - {\bf Fit Criterion:} After their first encounter with the tool, at least 60\% of representative developers should feel that it is a trustworthy and reliable solution for energy-efficient refactoring.\\ + {\bf Fit Criterion:} After their first encounter with the tool, the amount of representative developers that feel that it is a trustworthy and reliable solution for energy-efficient refactoring should be above the MIN\_USER\_CONFIDENCE.\\ {\bf Priority:} High \item \emph{The IDE plugin interface shall promote a calm and focused atmosphere, enhancing the developer's ability to concentrate on code improvements.}\\[2mm] {\bf Rationale:} A calm environment reduces distractions and improves productivity, allowing developers to focus on their work effectively.\\ - {\bf Fit Criterion:} Developers should report feeling less distracted and more productive while using the tool, with 70\% indicating a positive change in their coding environment.\\ + {\bf Fit Criterion:} Developers should report feeling less distracted and more productive while using the tool, with the amount of developers indicating a positive change in their coding environment meeting the MIN\_USER\_CONFIDENCE.\\ {\bf Priority:} Medium \item \emph{The tool design shall be visually appealing and modern, aligning with contemporary software development tools.}\\[2mm] {\bf Rationale:} A modern design improves user experience and satisfaction, making the tool more enjoyable to use.\\ - {\bf Fit Criterion:} At least 75\% of users should express satisfaction with the tool's visual design and layout after their initial interaction.\\ + {\bf Fit Criterion:} The number of users that express satisfaction with the tool's visual design and layout after their initial interaction should meet the MIN\_USER\_CONFIDENCE.\\ {\bf Priority:} Medium \end{enumerate} @@ -802,11 +838,11 @@ \subsection{Ease of Use Requirements} \begin{enumerate}[label=UHR-EOU \arabic*., wide=0pt, leftmargin=*] \item \emph{The tool shall have an intuitive user interface that simplifies navigation and functionality.}\\[2mm] {\bf Rationale:} A simple, intuitive interface allows users to access the tool's key features quickly, improving usability and reducing the learning curve.\\ - {\bf Fit Criterion:} Users should be able to complete key tasks (e.g., parsing code, configuring settings) within three clicks or less.\\ + {\bf Fit Criterion:} Users should be able to complete key tasks (e.g., parsing code, configuring settings) MAX\_TASK\_CLICKS limit.\\ {\bf Priority:} High \item \emph{The tool shall provide clear and concise prompts for user input.}\\[2mm] {\bf Rationale:} Clear instructions help users understand what inputs are required, minimizing confusion and errors during the process.\\ - {\bf Fit Criterion:} At least 90\% of test users should report that prompts are straightforward and guide them effectively through the process.\\ + {\bf Fit Criterion:} The amount of test users that report that prompts are straightforward and guide them effectively through the process should meet the MIN\_USER\_EOU.\\ {\bf Priority:} High \end{enumerate} @@ -826,7 +862,7 @@ \subsection{Learning Requirements} \begin{enumerate}[label=UHR-LRN \arabic*., wide=0pt, leftmargin=*] \item \emph{The tool shall provide context-sensitive help that offers assistance based on the current user actions.}\\[2mm] {\bf Rationale:} Context-sensitive help ensures that users can receive timely and relevant assistance, reducing confusion and improving usability.\\ - {\bf Fit Criterion:} Help resources should be accessible within 1-3 clicks.\\ + {\bf Fit Criterion:} Help resources should be accessible within MAX\_TASK\_CLICKS limit.\\ {\bf Priority:} High \item \emph{The tool shall have an available YouTube video demonstrating installation.}\\[2mm] {\bf Rationale:} Video tutorials provide visual learning resources that can make the installation process more accessible to users.\\ @@ -838,7 +874,7 @@ \subsection{Understandability and Politeness Requirements} \begin{enumerate}[label=UHR-UPL \arabic*., wide=0pt, leftmargin=*] \item \emph{The tool shall communicate errors and issues politely and constructively.}\\[2mm] {\bf Rationale:} Polite and constructive error messages reduce frustration and enhance the user experience, making the tool more approachable.\\ - {\bf Fit Criterion:} User feedback should reflect that at least 80\% of users perceive error messages as helpful and courteous, rather than frustrating or vague.\\ + {\bf Fit Criterion:} User feedback should reflect that at least the MIN\_USER\_EOU of users perceive error messages as helpful and courteous, rather than frustrating or vague.\\ {\bf Priority:} Medium \end{enumerate} @@ -850,7 +886,7 @@ \subsection{Accessibility Requirements} {\bf Priority:} Low \item \emph{The tool shall offer audio cues for important actions and alerts to assist users with use and navigation.}\\[2mm] {\bf Rationale:} Audio cues help users with visual impairments or cognitive difficulties to stay informed about important events or actions.\\ - {\bf Fit Criterion:} At least 70\% of users should report that the audio cues enhance their understanding of important notifications or actions.\\ + {\bf Fit Criterion:} The MIN\_USER\_EOU of users should report that the audio cues enhance their understanding of important notifications or actions.\\ {\bf Priority:} Low \end{enumerate} @@ -859,11 +895,11 @@ \subsection{Speed and Latency Requirements} \begin{enumerate}[label=PR-SL \arabic*., wide=0pt, leftmargin=*] \item \emph{The tool shall analyze and detect code smells in the input code within a reasonable time frame.}\\[2mm] {\bf Rationale:} Fast analysis ensures that developers do not experience significant delays while reviewing code.\\ - {\bf Fit Criterion:} The tool should complete the analysis for files up to 1,000 lines of code in under 5 seconds, and for files up to 10,000 lines in under 30 seconds.\\ + {\bf Fit Criterion:} The tool should complete the analysis for files up to 1,000 lines of code in under SMALL\_FILE\_TIME, and for files up to 10,000 lines in under LARGE\_FILE\_TIME.\\ {\bf Priority:} High \item \emph{The refactoring process shall be executed efficiently without noticeable delays.}\\[2mm] {\bf Rationale:} Fast refactoring ensures a smooth workflow for developers, preventing frustration during development.\\ - {\bf Fit Criterion:} The tool should refactor the code and generate output in under 10 seconds for small to medium-sized files (up to 5,000 lines).\\ + {\bf Fit Criterion:} The tool should refactor the code and generate output in under REFACTOR\_TIME for small to medium-sized files (up to 5,000 lines).\\ {\bf Priority:} Medium \end{enumerate} \subsection{Safety-Critical Requirements} @@ -881,7 +917,7 @@ \subsection{Precision or Accuracy Requirements} {\bf Priority:} High \item \emph{The tool shall reliably identify code smells with minimal false positives and negatives.}\\[2mm] {\bf Rationale:} High detection accuracy ensures that developers are not misled by incorrect or missed suggestions.\\ - {\bf Fit Criterion:} Detection accuracy should exceed 90\% when validated against a set of known cases.\\ + {\bf Fit Criterion:} Detection accuracy should exceed DETECTION\_ACC when validated against a set of known cases.\\ {\bf Priority:} Medium \item \emph{The tool shall produce valid refactored Python code as output or indicate that no possible refactorings were found.}\\[2mm] {\bf Rationale:} Ensuring that the tool produces valid output is essential for maintaining code quality.\\ @@ -905,7 +941,7 @@ \subsection{Capacity Requirements} \begin{enumerate}[label=PR-CR \arabic*., wide=0pt, leftmargin=*] \item \emph{The tool shall efficiently manage large codebases.}\\[2mm] {\bf Rationale:} Efficient handling of large projects ensures that the tool remains usable for teams working with extensive codebases.\\ - {\bf Fit Criterion:} The tool must process projects with up to 100,000 lines of code within 2 minutes, maintaining performance standards.\\ + {\bf Fit Criterion:} The tool must process projects with up to 100,000 lines of code within LARGE\_CODE\_BASE\_TIME, maintaining performance standards.\\ {\bf Priority:} High \end{enumerate} @@ -992,22 +1028,22 @@ \subsection{Maintenance Requirements} \begin{enumerate}[label=MS-MNT \arabic*., wide=0pt, leftmargin=*] \item \emph{The tool must allow new refactoring techniques to be added within one week of identification.}\\ {\bf Rationale:} Rapid integration of new techniques ensures the tool remains up-to-date with evolving best practices in energy-efficient coding.\\ - {\bf Fit Criteria:} Developers can integrate new refactoring methods into the tool, and they are fully operational within seven days.\\ + {\bf Fit Criteria:} Developers can integrate new refactoring methods into the tool, and they are fully operational within NEW\_REFACTOR\_TIME.\\ {\bf Priority:} Medium \item \emph{The tool must be maintainable by developers who are not the original creators.}\\ {\bf Rationale:} Ensuring that new developers can easily understand and modify the system reduces dependency on original developers and facilitates long-term maintenance.\\ - {\bf Fit Criteria:} Comprehensive documentation is available, including setup guides and code comments, allowing new developers to understand and modify the system within two days.\\ + {\bf Fit Criteria:} Comprehensive documentation is available, including setup guides and code comments, allowing new developers to understand and modify the system within COMPREHENSION\_TIME.\\ {\bf Priority:} High \item \emph{The tool must allow for easy rollback of updates in case of errors.}\\ {\bf Rationale:} Quick rollback capabilities minimize downtime and user disruption in case an update introduces issues.\\ - {\bf Fit Criteria:} Any update can be reverted with minimal effort, ensuring the system returns to a stable state within one hour.\\ + {\bf Fit Criteria:} Any update can be reverted with minimal effort, ensuring the system returns to a stable state within ROLLBACK\_TIME.\\ {\bf Priority:} Medium \item \emph{The tool must provide automated testing for all refactoring functions.}\\ {\bf Rationale:} Automated testing ensures that changes do not introduce new bugs, maintaining the reliability and stability of the tool.\\ - {\bf Fit Criteria:} All refactoring methods have associated unit tests that run automatically with each code change, ensuring 80\% code coverage.\\ + {\bf Fit Criteria:} All refactoring methods have associated unit tests that run automatically with each code change, ensuring code coverage meets MIN\_CODE\_COVERAGE.\\ {\bf Priority:} High \item \emph{Each version of the library must maintain compatibility with the current releases of external libraries during its development phase.}\\ @@ -1065,7 +1101,7 @@ \subsection{Adaptability Requirements} \item \emph{The system must offer consistent performance (e.g., refactoring speed, energy consumption measurements) regardless of the underlying operating system.}\\ {\bf Rationale:} Having the system be OS dependent would invalidate the point of being compatible with multiple OSes and conflict with requirement MS-AD 6.\\ - {\bf Fit Criteria:} Performance metrics, such as time taken for refactoring and energy measurements, must not vary by more than 5\% across different operating systems during testing.\\ + {\bf Fit Criteria:} Performance metrics, such as time taken for refactoring and energy measurements, must not vary by more than OS\_PERF\_DIFF\_LIMIT across different operating systems during testing.\\ {\bf Priority:} Low \end{enumerate} From 5d50ebf13a6e1bc0cb9a18650cf3e43d145ffc8e Mon Sep 17 00:00:00 2001 From: Ayushi Amin <66652121+Ayushi1972@users.noreply.github.com> Date: Thu, 16 Jan 2025 16:59:22 -0500 Subject: [PATCH 12/85] Added #307: MIS of Long Element Chain (#309) --- docs/Design/SoftArchitecture/MG.tex | 19 +++++- docs/Design/SoftDetailedDes/MIS.tex | 97 +++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 2 deletions(-) diff --git a/docs/Design/SoftArchitecture/MG.tex b/docs/Design/SoftArchitecture/MG.tex index 86f8d76f..5a61c01e 100644 --- a/docs/Design/SoftArchitecture/MG.tex +++ b/docs/Design/SoftArchitecture/MG.tex @@ -192,7 +192,7 @@ \section{Module Hierarchy} \label{SecMH} \begin{description} \item [\refstepcounter{mnum} \mthemnum \label{mHH}:] Hardware-Hiding Module -\item ... +\item [\refstepcounter{mnum} \mthemnum \label{mLEC}:] LongElementChainRefactorer Module \end{description} @@ -209,7 +209,7 @@ \section{Module Hierarchy} \label{SecMH} \multirow{7}{0.3\textwidth}{Behaviour-Hiding Module} & ?\\ & ?\\ & ?\\ -& ?\\ +& LongElementChainRefactorer Module\\ & ?\\ & ?\\ & ?\\ @@ -278,6 +278,21 @@ \subsection{Behaviour-Hiding Module} \item[Implemented By:] -- \end{description} +\subsubsection{Long Element Chain Module (\mref{mLEC})} + +% [Record, Library, Abstract Object, or Abstract Data Type] + +\begin{description} + \item[Secrets:] How to parse a given code file to its AST representation, traverse the + AST tree to identify dictionary assignments, analyze the structure of nested dictionaries, + and flatten them. Additionally, it identifies all access calls associated with these dictionaries + in the source code and determines how to update them to reflect the new flattened structure. + \item[Services:] Detects nested dictionaries in the source code using AST parsing, simplifies their + structure by flattening them, and updates all associated access calls throughout the file. This improves + code readability, reduces complexity, and ensures correctness while maintaining the program's intended behavior. + \item[Implemented By:] EcoOptimizer +\end{description} + \subsubsection{Input Format Module (\mref{mInput})} \begin{description} diff --git a/docs/Design/SoftDetailedDes/MIS.tex b/docs/Design/SoftDetailedDes/MIS.tex index b09df2c1..665e8524 100644 --- a/docs/Design/SoftDetailedDes/MIS.tex +++ b/docs/Design/SoftDetailedDes/MIS.tex @@ -227,8 +227,105 @@ \subsubsection{Local Functions} explicitly. Even if they are implemented, they are not exported; they only have local scope.} + +\section{MIS of LongElementChainRefactorer} + +\subsection{Module} + +LongElementChainRefactorer is a module that refactors long element chains, specifically focusing on flattening nested dictionaries to improve readability, maintainability, and energy efficiency. The module uses a recursive flattening strategy while caching previously seen patterns for optimization. + +\subsection{Uses} + +\begin{itemize} + \item Uses \texttt{Smell} interface for data access + \item Inherits from \texttt{BaseRefactorer} +\end{itemize} + +\subsection{Syntax} + +\subsubsection{Exported Constants} +None + +\subsubsection{Exported Access Programs} + +\begin{center} +\begin{tabular}{|p{3cm}|p{5cm}|p{2cm}|p{3cm}|} +\hline +\textbf{Name} & \textbf{In} & \textbf{Out} & \textbf{Exceptions} \\ +\hline +\texttt{\_\_init\_\_} & \texttt{output\_dir: Path} & None & None \\ +\hline +\texttt{refactor} & \texttt{file\_path: Path, pylint\_smell: Smell, initial\_emissions: float} & None & Logging exceptions \\ +\hline +\end{tabular} +\end{center} + +\subsection{Semantics} + +\subsubsection{State Variables} + +\begin{itemize} + \item \textbf{\_reference\_map}: Maps element chain references to their line numbers and corresponding values. +\end{itemize} + +\subsubsection{Environment Variables} + +\begin{itemize} + \item \textbf{File system}: Used to read, write, and store temporary and refactored files. + \item \textbf{Logger}: Logs information during the refactoring process. +\end{itemize} + +\subsubsection{Assumptions} + +\begin{itemize} + \item Input files are valid Python scripts. + \item Smells identified by \textbf{pylint\_smell} include valid line numbers. + \item Refactored code must pass the provided test suite. +\end{itemize} + +\subsubsection{Access Routine Semantics} + +\paragraph{\texttt{\_\_init\_\_(output\_dir: Path)}} +\begin{itemize} +\item \textbf{Transition}: Initializes the refactorer with the specified output directory and sets up internal caching structures. +\item \textbf{Output}: None. +\item \textbf{Exception}: None. +\end{itemize} + +\paragraph{\texttt{refactor(file\_path: Path, pylint\_smell: Smell, initial\_emissions: float)}} +\begin{itemize} + \item \textbf{Transition}: + \begin{itemize} + \item Reads the file at \texttt{file\_path}. + \item Identifies nested dictionary chains for flattening. + \item Refactors the identified chain by flattening the dictionary and replacing its occurrences. + \item Writes the refactored code to a temporary file. +\end{itemize} + \item \textbf{Output}: None. Refactored file is saved if improvements are validated. + \item \textbf{Exception}: Logs exceptions during file operations or refactoring. +\end{itemize} + +\subsubsection{Local Functions} +\begin{itemize} + \item \textbf{\_flatten\_dict(d: dict[str, Any], parent\_key: str = "")} \\ + Recursively flattens a nested dictionary by combining keys with underscores. + + \item \textbf{\_extract\_dict\_literal(node: ast.AST)} \\ + Converts an Abstract Syntax Tree (AST) dictionary literal into a Python dictionary. + + \item \textbf{\_find\_dict\_assignments(tree: ast.AST, name: str)} \\ + Extracts dictionary assignments given the name of the dictionary from the AST and returns them as a dictionary. + + \item \textbf{\_collect\_dict\_references(tree: ast.AST)} \\ + Identifies and stores all dictionary access patterns in the `\_reference\_map`. + + \item \textbf{\_generate\_flattened\_access(base\_var: str, access\_chain: list[str])} \\ + Generates a flattened dictionary key string by combining elements of an access chain with underscores. +\end{itemize} + \newpage + \bibliographystyle {plainnat} \bibliography {../../../refs/References} From b74aefb325d3b4da3b3b1db91030c48734aa577b Mon Sep 17 00:00:00 2001 From: Nivetha Kuruparan <167944429+nivethakuruparan@users.noreply.github.com> Date: Thu, 16 Jan 2025 22:00:07 -0500 Subject: [PATCH 13/85] [DESIGN] Added MIS and MG for PylintAnalyzer, RepeatedCalls Refactorer and UseAGenerator Refactor (#317) --- docs/Design/SoftArchitecture/MG.tex | 34 +++- docs/Design/SoftDetailedDes/MIS.tex | 296 ++++++++++++++++++++++++++++ 2 files changed, 327 insertions(+), 3 deletions(-) diff --git a/docs/Design/SoftArchitecture/MG.tex b/docs/Design/SoftArchitecture/MG.tex index 5a61c01e..659e4fc0 100644 --- a/docs/Design/SoftArchitecture/MG.tex +++ b/docs/Design/SoftArchitecture/MG.tex @@ -192,6 +192,8 @@ \section{Module Hierarchy} \label{SecMH} \begin{description} \item [\refstepcounter{mnum} \mthemnum \label{mHH}:] Hardware-Hiding Module +\item [\refstepcounter{mnum} \mthemnum \label{mUGENR}:] UseAGeneratorRefactorer Module +\item [\refstepcounter{mnum} \mthemnum \label{mCRC}:] CacheRepeatedCallsRefactorer Module \item [\refstepcounter{mnum} \mthemnum \label{mLEC}:] LongElementChainRefactorer Module \end{description} @@ -206,8 +208,8 @@ \section{Module Hierarchy} \label{SecMH} {Hardware-Hiding Module} & ~ \\ \midrule -\multirow{7}{0.3\textwidth}{Behaviour-Hiding Module} & ?\\ -& ?\\ +\multirow{7}{0.3\textwidth}{Behaviour-Hiding Module} & CacheRepeatedCallsRefactorer Module\\ +& UseAGeneratorRefactorer Module\\ & ?\\ & LongElementChainRefactorer Module\\ & ?\\ @@ -304,6 +306,20 @@ \subsubsection{Input Format Module (\mref{mInput})} [Information to include for leaf modules in the decomposition by secrets tree.] \end{description} +\subsubsection{UseAGeneratorRefactorer Module (\mref{mUGENR})} +\begin{description} + \item[Secrets:] How to parse a given code file to its AST representation, how to traverse the AST tree, how to modify specific nodes in the AST tree, how to convert the modified AST tree back to source code and write it to an output file. + \item[Services:] Refactors the \textit{List Comprehension Instead of a Generator} smell in a provided code file to improve energy efficiency. + \item[Implemented By:] EcoOptimizer +\end{description} + +\subsubsection{CacheRepeatedCallsRefactorer Module (\mref{mCRC})} +\begin{description} + \item[Secrets:] How to parse a given code file to its AST representation, how to traverse the AST tree, how to modify specific nodes in the AST tree, how to convert the modified AST tree back to source code and write it to an output file. + \item[Services:] Refactors the \textit{Repeated Function Calls} smell in a provided code file to improve energy efficiency and performance. + \item[Implemented By:] EcoOptimizer +\end{description} + \subsubsection{Etc.} @@ -320,7 +336,19 @@ \subsection{Software Decision Module} \item[Implemented By:] -- \end{description} -\subsubsection{Etc.} +\subsubsection{Pylint Analyzer Module} + +\begin{description} +\item[Secrets:] The internal design and execution of static code analysis using Pylint and AST parsing, including custom detection and structuring of smells. These details are hidden from external modules. +\item[Services:] The module provides the following services: + \begin{itemize} + \item Executes Pylint analysis on Python source code files. + \item Performs AST-based custom checks for specific code smells. + \item Filters and structures the analysis results into a standardized format for further processing. + \end{itemize} +\item[Implemented By:] \texttt{EcoOptimizer} +\end{description} + \section{Traceability Matrix} \label{SecTM} diff --git a/docs/Design/SoftDetailedDes/MIS.tex b/docs/Design/SoftDetailedDes/MIS.tex index 665e8524..d600bee1 100644 --- a/docs/Design/SoftDetailedDes/MIS.tex +++ b/docs/Design/SoftDetailedDes/MIS.tex @@ -325,6 +325,302 @@ \subsubsection{Local Functions} \newpage +\section{MIS of Pylint Analyzer} \label{mis:PylintAnalyzer} + +\texttt{PylintAnalyzer} + +\subsection{Module} + +The \texttt{PylintAnalyzer} module performs static code analysis on Python files using Pylint, with additional custom checks for detecting specific code smells. It outputs detected smells in a structured format for further processing. + +\subsection{Uses} +\begin{itemize} + \item Uses Python's \texttt{pylint} library for code analysis + \item Uses \texttt{ast} module for parsing and analyzing abstract syntax trees + \item Uses \texttt{astor} library for converting AST nodes back to source code + \item Integrates with custom checkers, including \texttt{StringConcatInLoopChecker} + \item Accesses configuration settings from \texttt{analyzers\_config} +\end{itemize} + +\subsection{Syntax} +\noindent +\textbf{Exported Constants}: None + +\noindent +\textbf{Exported Access Programs}:\\ +{\footnotesize +\begin{tabularx}{\linewidth}{| + l| + >{\raggedright\arraybackslash}X| + l| + l|} + \toprule Name & In & Out & Exceptions \\ + \midrule + \texttt{\_\_init\_\_} & \texttt{file\_path: Path, source\_code: ast.Module} & None & None \\ + \hline + \texttt{build\_pylint\_options} & None & \texttt{list[str]} & None \\ + \hline + \texttt{analyze} & None & None & \texttt{JSONDecodeError}, \texttt{Exception} \\ + \hline + \texttt{configure\_smells} & None & None & None \\ + \hline + \texttt{filter\_for\_one\_code\_smell} & \texttt{pylint\_results: list[Smell], code: str} & \texttt{list[Smell]} & None \\ + \hline + \texttt{detect\_long\_message\_chain} & \texttt{threshold: int = 3} & \texttt{list[Smell]} & None \\ + \hline + \texttt{detect\_long\_lambda\_expression} & \texttt{threshold\_length: int = 100, threshold\_count: int = 3} & \texttt{list[Smell]} & None \\ + \hline + \texttt{detect\_long\_element\_chain} & \texttt{threshold: int = 3} & \texttt{list[Smell]} & None \\ + \hline + \texttt{detect\_repeated\_calls} & \texttt{threshold: int = 2} & \texttt{list[Smell]} & None \\ + \bottomrule +\end{tabularx} +} + +\subsection{Semantics} + +\subsubsection*{State Variables} +\begin{itemize} + \item \texttt{file\_path: Path}: The path to the Python file being analyzed. + \item \texttt{source\_code: ast.Module}: The parsed abstract syntax tree of the source file. + \item \texttt{smells\_data: list[dict]}: A list of detected code smells, represented as dictionaries. +\end{itemize} + +\subsubsection*{Environment Variables} +None + +\subsubsection*{Assumptions} +\begin{itemize} + \item The input file is valid Python code and can be parsed into an AST. + \item Configuration settings, such as extra Pylint options and custom smell definitions, are valid. +\end{itemize} + +\subsubsection*{Access Routine Semantics} + +\paragraph{\texttt{\_\_init\_\_(self, file\_path: Path, source\_code: ast.Module)}} +\begin{itemize} + \item \textbf{transition}: Initializes the analyzer with the provided file path and AST of the source code. + \item \textbf{output}: None. + \item \textbf{exception:} None. +\end{itemize} + +\paragraph{\texttt{build\_pylint\_options(self)}} +\begin{itemize} + \item \textbf{transition}: Constructs the list of Pylint options based on the file path and configuration settings. + \item \textbf{output}: Returns a list of strings representing Pylint options. + \item \textbf{exception:} None. +\end{itemize} + +\paragraph{\texttt{analyze(self)}} +\begin{itemize} + \item \textbf{transition}: Executes Pylint analysis and custom checks, populating \texttt{smells\_data} with detected smells. + \item \textbf{output}: None. + \item \textbf{exception:} Raises \texttt{JSONDecodeError} if Pylint's output cannot be parsed. Raises \texttt{Exception} for other runtime errors. +\end{itemize} + +\paragraph{\texttt{configure\_smells(self)}} +\begin{itemize} + \item \textbf{transition}: Filters \texttt{smells\_data} to include only configured smells. + \item \textbf{output}: None. + \item \textbf{exception:} None. +\end{itemize} + +\paragraph{\texttt{filter\_for\_one\_code\_smell(self, pylint\_results: list[Smell], code: str)}} +\begin{itemize} + \item \textbf{transition}: Filters the given Pylint results for a specific code smell identified by \texttt{code}. + \item \textbf{output}: Returns a list of smells matching the specified code. + \item \textbf{exception:} None. +\end{itemize} + +\paragraph{\texttt{detect\_long\_message\_chain(self, threshold: int = 3)}} +\begin{itemize} + \item \textbf{transition}: Identifies method chains exceeding the specified \texttt{threshold}. + \item \textbf{output}: Returns a list of smells for long method chains. + \item \textbf{exception:} None. +\end{itemize} + +\paragraph{\texttt{detect\_long\_lambda\_expression(self, threshold\_length: int = 100, threshold\_count: int = 3)}} +\begin{itemize} + \item \textbf{transition}: Detects lambda expressions exceeding length or expression count thresholds. + \item \textbf{output}: Returns a list of smells for long lambda expressions. + \item \textbf{exception:} None. +\end{itemize} + +\paragraph{\texttt{detect\_long\_element\_chain(self, threshold: int = 3)}} +\begin{itemize} + \item \textbf{transition}: Detects dictionary access chains exceeding the specified \texttt{threshold}. + \item \textbf{output}: Returns a list of smells for long dictionary chains. + \item \textbf{exception:} None. +\end{itemize} + +\paragraph{\texttt{detect\_repeated\_calls(self, threshold: int = 2)}} +\begin{itemize} + \item \textbf{transition}: Identifies repeated function calls exceeding the \texttt{threshold}. + \item \textbf{output}: Returns a list of smells for repeated function calls. + \item \textbf{exception:} None. +\end{itemize} + +\subsubsection*{Local Functions} +\begin{itemize} + \item \texttt{parse\_line(file\_path: Path, line: int)}: Parses a specific line of code into an AST node. + \item \texttt{get\_lambda\_code(lambda\_node: ast.Lambda)}: Returns the string representation of a lambda expression. +\end{itemize} + + +\newpage + +\section{MIS of Use A Generator Refactorer} \label{mis:UseGen} + +\texttt{UseAGeneratorRefactorer} + +\subsection{Module} + +The \texttt{UseAGeneratorRefactorer} module identifies and refactors +unnecessary list comprehensions in Python code by converting them to generator expressions. This refactoring improves energy efficiency while maintaining the original functionality. + +\subsection{Uses} +\begin{itemize} + \item Uses \texttt{Smell} interface for data access + \item Inherits from \texttt{BaseRefactorer} + \item Uses Python's \texttt{ast} module for parsing and manipulating abstract syntax trees +\end{itemize} + +\subsection{Syntax} +\noindent +\textbf{Exported Constants}: None + +\noindent +\textbf{Exported Access Programs}:\\ +\begin{tabularx}{\linewidth}{| + l| + >{\raggedright\arraybackslash}X| + l| + l|} + \toprule Name & In & Out & Exceptions \\ + \midrule + \texttt{\_\_init\_\_} & \texttt{output\_dir: Path} & None & None \\ + \hline + \texttt{refactor} & \texttt{file\_path: Path, pylint\_smell: Smell, initial\_emissions: float} & None & \texttt{IOError}, \texttt{TypeError} \\ + \hline + \texttt{\_replace\_node} & \texttt{tree: ast.Module, old\_node: ast.ListComp, new\_node: ast.GeneratorExp} & None & None \\ + \bottomrule +\end{tabularx} + +\subsection{Semantics} + +\subsubsection*{State Variables} +\begin{itemize} + \item \texttt{temp\_dir: Path}: Directory path for storing refactored files. + \item \texttt{output\_dir: Path}: Directory path for saving final refactored code. +\end{itemize} + +\subsubsection*{Environment Variables} +None + +\subsubsection*{Assumptions} +\begin{itemize} + \item The input file contains valid Python syntax. + \item \texttt{pylint\_smell} provides a valid line number for the detected code smell. +\end{itemize} + +\subsubsection*{Access Routine Semantics} + +\paragraph{\texttt{\_\_init\_\_(self, output\_dir: Path)}} +\begin{itemize} + \item \textbf{transition}: Initializes the \texttt{temp\_dir} variable within \texttt{output\_dir}. + \item \textbf{output}: None. + \item \textbf{exception:} None. +\end{itemize} + +\paragraph{\texttt{refactor(self, file\_path: Path, pylint\_smell: Smell, initial\_emissions: float)}} +\begin{itemize} + \item \textbf{transition}: Parses \texttt{file\_path}, identifies unnecessary list comprehensions, modifies the code to use generator expressions, and validates refactoring. + \item \textbf{output}: None. + \item \textbf{exception}: Raises \texttt{IOError} if input file cannot be read. Raises \texttt{TypeError} if source file cannot be parsed into an AST. +\end{itemize} + +\paragraph{\texttt{\_replace\_node(self, tree: ast.Module, old\_node: ast.ListComp, new\_node: ast.GeneratorExp)}} +\begin{itemize} + \item \textbf{transition}: Replaces an \texttt{old\_node} in the AST with a \texttt{new\_node}. + \item \textbf{output}: None. + \item \textbf{exception}: None. +\end{itemize} + +\subsubsection*{Local Functions} +Functions for internal AST parsing, node manipulation, and validation are defined within the class but are not exported. + +\newpage + +\section{MIS of Cache Repeated Calls Refactorer} \label{mis:CacheCalls} + +\texttt{CacheRepeatedCallsRefactorer} + +\subsection{Module} + +The \texttt{CacheRepeatedCallsRefactorer} module identifies repeated function calls in Python code and refactors them by caching the result of the first call to a temporary variable. This refactoring improves performance and energy efficiency while preserving the original functionality. + +\subsection{Uses} +\begin{itemize} + \item Uses \texttt{Smell} interface for data access + \item Inherits from \texttt{BaseRefactorer} + \item Uses Python's \texttt{ast} module for parsing and manipulating abstract syntax trees +\end{itemize} + +\subsection{Syntax} +\noindent +\textbf{Exported Constants}: None + +\noindent +\textbf{Exported Access Programs}:\\ +\begin{tabularx}{\linewidth}{|l|>{\raggedright\arraybackslash}X|l|l|} + \toprule Name & In & Out & Exceptions \\ + \midrule + \texttt{\_\_init\_\_} & \texttt{output\_dir: Path} & None & None \\ + \hline + \texttt{refactor} & \texttt{file\_path: Path, pylint\_smell: Smell, initial\_emissions: float} & None & \texttt{IOError}, \texttt{TypeError} \\ + \bottomrule +\end{tabularx} + +\subsection{Semantics} + +\subsubsection*{State Variables} +\begin{itemize} + \item \texttt{cached\_var\_name: str}: Name of the temporary variable used for caching. + \item \texttt{target\_line: int}: Line number where refactoring is applied. +\end{itemize} + +\subsubsection*{Environment Variables} +None + +\subsubsection*{Assumptions} +\begin{itemize} + \item The input file contains valid Python syntax. + \item \texttt{pylint\_smell} provides valid occurrences of repeated calls with line numbers and call strings. +\end{itemize} + +\subsubsection*{Access Routine Semantics} + +\paragraph{\texttt{\_\_init\_\_(self, output\_dir: Path)}} +\begin{itemize} + \item \textbf{transition}: Initializes the \texttt{temp\_dir} variable within \texttt{output\_dir}. + \item \textbf{output}: None. + \item \textbf{exception:} None. +\end{itemize} + +\paragraph{\texttt{refactor(self, file\_path: Path, pylint\_smell: Smell, initial\_emissions: float)}} +\begin{itemize} + \item \textbf{transition}: Parses \texttt{file\_path}, identifies repeated function calls, inserts a cached variable for the first call, updates subsequent calls to use the cached variable, and validates refactoring. + \item \textbf{output}: None. + \item \textbf{exception}: Raises \texttt{IOError} if input file cannot be read. Raises \texttt{TypeError} if source file cannot be parsed into an AST. +\end{itemize} + +\subsubsection*{Local Functions} +\begin{itemize} + \item \texttt{\_get\_indentation(lines, line\_number)}: Determines the indentation of a specific line. + \item \texttt{\_replace\_call\_in\_line(line, call\_string, cached\_var\_name)}: Replaces repeated calls with the cached variable. + \item \texttt{\_find\_valid\_parent(tree)}: Identifies the valid parent node containing all occurrences of the repeated call. + \item \texttt{\_find\_insert\_line(parent\_node)}: Determines the line to insert the cached variable. +\end{itemize} \bibliographystyle {plainnat} \bibliography {../../../refs/References} From 4c31b670effbb34d674c8971e68a6faab8583520 Mon Sep 17 00:00:00 2001 From: Nivetha Kuruparan <167944429+nivethakuruparan@users.noreply.github.com> Date: Fri, 17 Jan 2025 11:06:42 -0500 Subject: [PATCH 14/85] [DESIGN] Added MIS Introduction (#322) --- docs/Design/SoftDetailedDes/MIS.tex | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/Design/SoftDetailedDes/MIS.tex b/docs/Design/SoftDetailedDes/MIS.tex index d600bee1..62d17da9 100644 --- a/docs/Design/SoftDetailedDes/MIS.tex +++ b/docs/Design/SoftDetailedDes/MIS.tex @@ -76,12 +76,11 @@ \section{Symbols, Abbreviations and Acronyms} \section{Introduction} -The following document details the Module Interface Specifications for -\wss{Fill in your project name and description} +The following document details the Module Interface Specifications (MIS) for the Source Code Optimizer project. The Source Code Optimizer is a software tool designed to analyze, refactor, and optimize Python source code to improve energy efficiency, maintainability, and performance. This tool incorporates a combination of static code analysis using Pylint, abstract syntax tree (AST) parsing, and custom refactoring techniques to detect and address various code smells in Python programs. -Complementary documents include the System Requirement Specifications -and Module Guide. The full documentation and implementation can be -found at \url{...}. \wss{provide the url for your repo} +The application allows developers to identify inefficient coding patterns, refactor them into optimized alternatives, and validate the results through built-in testing mechanisms. Key features include support for custom smell detection, energy profiling, and modular refactorers tailored to specific code smells, such as long method chains or inefficient list comprehensions. By automating parts of the optimization process, the Source Code Optimizer helps developers have the option of choosing to reduce emissions and produce more efficient software. + +Complementary documents include the System Requirement Specifications (SRS) and Module Guide (MG). The full documentation and implementation can be found at: \url{https://github.com/ssm-lab/capstone--source-code-optimizer} \section{Notation} From 12dbfcf310db72541116ad7197b45917d789ba60 Mon Sep 17 00:00:00 2001 From: Ayushi Amin <66652121+Ayushi1972@users.noreply.github.com> Date: Fri, 17 Jan 2025 11:17:46 -0500 Subject: [PATCH 15/85] Added #291: MG for Anticipated and Unlikely Changes (#318) --- docs/Design/SoftArchitecture/MG.tex | 62 ++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 9 deletions(-) diff --git a/docs/Design/SoftArchitecture/MG.tex b/docs/Design/SoftArchitecture/MG.tex index 659e4fc0..28833639 100644 --- a/docs/Design/SoftArchitecture/MG.tex +++ b/docs/Design/SoftArchitecture/MG.tex @@ -157,12 +157,56 @@ \subsection{Anticipated Changes} \label{SecAchange} change. \begin{description} -\item[\refstepcounter{acnum} \actheacnum \label{acHardware}:] The specific - hardware on which the software is running. -\item[\refstepcounter{acnum} \actheacnum \label{acInput}:] The format of the - initial input data. -\item ... -\end{description} + \item[\refstepcounter{acnum} \actheacnum \label{acUserInterface}:] The user interface of the plugin. Enhancements may be required to improve usability or accommodate new features. Specific anticipated changes include: + \begin{itemize} + \item \textbf{Refactoring Suggestions Display}: Updates to how refactoring suggestions are presented, such as side-by-side views of original and refactored code. + \item \textbf{Theme Support}: Adding compatibility with various VS Code themes, including light and dark modes. + \item \textbf{Visual Indicators}: Implementing color-coded indicators to highlight the impact of energy savings for each refactoring suggestion. + \item \textbf{Interactive Elements}: Introducing interactive components like tooltips or progress indicators to guide users during the refactoring process. + \item \textbf{Customization Options}: Allowing users to configure UI elements, such as adjusting the sensitivity of code smell detection or selecting preferred refactoring styles. + \end{itemize} + + \item[\refstepcounter{acnum} \actheacnum \label{acVSCodePlugin}:] The VS Code plugin's + functionality. Future versions may expand to support more complex refactorings + or additional code smells that users can address with minimal setup. Changes + may involve adding more customizable user settings. + + \item[\refstepcounter{acnum} \actheacnum \label{acRefactorers}:] The refactorers responsible + for detecting and fixing specific code smells. As more code smells are identified + and refactoring techniques are developed, new modules may be added or existing + ones may evolve. For example: + \begin{itemize} + \item \textbf{Base Refactorer} \label{acBaseRefactorer}: Updates to the base refactorer module to + support new refactoring patterns or improved algorithms. + \item \textbf{Complex List Comprehension} \label{acComplexListComprehension}: Adding or modifying + the logic for simplifying complex list comprehensions. + \item \textbf{Long Element Chain} \label{acLongElementChain}: Refining the logic to handle longer + chains of elements and optimize their readability and performance. + \item \textbf{Long Lambda Function} \label{acLongLambdaFunction}: Improvements to better handle + long lambda functions, making them more efficient and readable. + \item \textbf{Long Message Chain} \label{acLongMessageChain}: Extending the module's ability + to identify and refactor long message chains. + \item \textbf{Member Ignoring Method} \label{acMemberIgnoringMethod}: Enhancements to the + module for detecting methods that ignore members, optimizing the code structure. + \item \textbf{Repeated Calls} \label{acRepeatedCalls}: Optimizing detection and handling + of repeated function calls to improve performance. + \item \textbf{String Concatenation in Loop} \label{acStringConcatenationInLoop}: Adjusting + the refactorer's logic to improve handling of string concatenation within loops. + \item \textbf{Long Parameter List} \label{acLongParameterList}: Future extensions to handle + complex parameter lists in a more structured manner, perhaps allowing for simplifications. + \end{itemize} + + \item[\refstepcounter{acnum} \actheacnum \label{acSmell}:] The core logic + for identifying specific code smells. As the system evolves, new code smells may be added to the system’s detection capabilities, necessitating changes to this module. + + \item[\refstepcounter{acnum} \actheacnum \label{acAnalyzer}:] The analyzers used to + gather metrics and assess code quality. + + \item[\refstepcounter{acnum} \actheacnum \label{acTesting}:] The testing module + responsible for ensuring the correct functionality of the refactorers. As new + features and code smells are added, this module may need updates to test these + changes thoroughly. +\end{description} \wss{Anticipated changes relate to changes that would be made in requirements, design or implementation choices. They are not related to changes that are made @@ -178,9 +222,9 @@ \subsection{Unlikely Changes} \label{SecUchange} decisions will be changed. \begin{description} -\item[\refstepcounter{ucnum} \uctheucnum \label{ucIO}:] Input/Output devices - (Input: File and/or Keyboard, Output: File, Memory, and/or Screen). -\item ... + \item[\refstepcounter{ucnum} \uctheucnum \label{ucPlatform}:] Transitioning from VS Code to another IDE. The plugin is tightly integrated with VS Code's API, making such a change complex. + \item[\refstepcounter{ucnum} \uctheucnum \label{ucCoreLogic}:] Fundamental changes to the core logic of code smell detection. The current architecture is designed around widely accepted principles of software quality. + \item[\refstepcounter{ucnum} \uctheucnum \label{ucPluginType}:] Changing from a plugin-based architecture to a standalone application. This would require rethinking the entire deployment and user interaction model. \end{description} \section{Module Hierarchy} \label{SecMH} From 8015888a0c2f2c9a3393c6213af7186c67948a68 Mon Sep 17 00:00:00 2001 From: Sevhena Walker <83547364+Sevhena@users.noreply.github.com> Date: Fri, 17 Jan 2025 11:19:30 -0500 Subject: [PATCH 16/85] Made additions to the MG and MIS (#316) --- docs/Design/SoftArchitecture/MG.tex | 107 ++++--- docs/Design/SoftDetailedDes/MIS.tex | 426 +++++++++++++++++++++++++- docs/Images/use_hierarchy_modules.png | Bin 0 -> 66310 bytes 3 files changed, 478 insertions(+), 55 deletions(-) create mode 100644 docs/Images/use_hierarchy_modules.png diff --git a/docs/Design/SoftArchitecture/MG.tex b/docs/Design/SoftArchitecture/MG.tex index 28833639..9a529efe 100644 --- a/docs/Design/SoftArchitecture/MG.tex +++ b/docs/Design/SoftArchitecture/MG.tex @@ -235,10 +235,15 @@ \section{Module Hierarchy} \label{SecMH} actually be implemented. \begin{description} -\item [\refstepcounter{mnum} \mthemnum \label{mHH}:] Hardware-Hiding Module +\item [\refstepcounter{mnum} \mthemnum \label{mSmell}:] Smell Module +\item [\refstepcounter{mnum} \mthemnum \label{mBR}:] BaseRefactorer Module +\item [\refstepcounter{mnum} \mthemnum \label{mMIMR}:] MakeStaticRefactorer Module +\item [\refstepcounter{mnum} \mthemnum \label{mSCLR}:] UseListAccumulationRefactorer Module \item [\refstepcounter{mnum} \mthemnum \label{mUGENR}:] UseAGeneratorRefactorer Module \item [\refstepcounter{mnum} \mthemnum \label{mCRC}:] CacheRepeatedCallsRefactorer Module \item [\refstepcounter{mnum} \mthemnum \label{mLEC}:] LongElementChainRefactorer Module +\item [\refstepcounter{mnum} \mthemnum \label{mPyA}:] Pylint Analyzer Module +\item [\refstepcounter{mnum} \mthemnum \label{mTest}:] Testing Functionality Module \end{description} @@ -249,10 +254,15 @@ \section{Module Hierarchy} \label{SecMH} \textbf{Level 1} & \textbf{Level 2}\\ \midrule -{Hardware-Hiding Module} & ~ \\ +{Hardware-Hiding Module} & None \\ \midrule -\multirow{7}{0.3\textwidth}{Behaviour-Hiding Module} & CacheRepeatedCallsRefactorer Module\\ +\multirow{7}{0.3\textwidth}{Behaviour-Hiding Module} & Smell Module\\ +& BaseRefactorer Module\\ +& CacheRepeatedCallsRefactorer Module\\ +& MakeStaticRefactorer Module\\ +& UseListAccumulationRefactorer Module\\ +& ?\\ & UseAGeneratorRefactorer Module\\ & ?\\ & LongElementChainRefactorer Module\\ @@ -262,9 +272,9 @@ \section{Module Hierarchy} \label{SecMH} & ?\\ \midrule -\multirow{3}{0.3\textwidth}{Software Decision Module} & {?}\\ -& ?\\ -& ?\\ +\multirow{3}{0.3\textwidth}{Software Decision Module} & Pylint Analyzer Module\\ +& Testing Functionality Module\\ +& Measurements Module\\ \bottomrule \end{tabular} @@ -301,53 +311,48 @@ \section{Module Decomposition} \label{SecMD} (\emph{--}) is shown, this means that the module is not a leaf and will not have to be implemented. -\subsection{Hardware Hiding Modules (\mref{mHH})} +\subsection{Hardware Hiding Modules} -\begin{description} -\item[Secrets:]The data structure and algorithm used to implement the virtual - hardware. -\item[Services:]Serves as a virtual hardware used by the rest of the - system. This module provides the interface between the hardware and the - software. So, the system can use it to display outputs or to accept inputs. -\item[Implemented By:] OS -\end{description} +This system has no hardware components. \subsection{Behaviour-Hiding Module} +\subsubsection{Smell Module (\mref{mSmell})} + \begin{description} -\item[Secrets:]The contents of the required behaviours. -\item[Services:]Includes programs that provide externally visible behaviour of - the system as specified in the software requirements specification (SRS) - documents. This module serves as a communication layer between the - hardware-hiding module and the software decision module. The programs in this - module will need to change if there are changes in the SRS. -\item[Implemented By:] -- +\item[Secrets:] Data structure of a code smell. +\item[Services:] Provides an interface for other modules to access information of a smell object. +\item[Implemented By:] EcoOptimizer +\item[Type of Module:] Abstract Data Type \end{description} -\subsubsection{Long Element Chain Module (\mref{mLEC})} +\subsubsection{Base Refactorer Module (\mref{mBR})} % [Record, Library, Abstract Object, or Abstract Data Type] \begin{description} - \item[Secrets:] How to parse a given code file to its AST representation, traverse the - AST tree to identify dictionary assignments, analyze the structure of nested dictionaries, - and flatten them. Additionally, it identifies all access calls associated with these dictionaries - in the source code and determines how to update them to reflect the new flattened structure. - \item[Services:] Detects nested dictionaries in the source code using AST parsing, simplifies their - structure by flattening them, and updates all associated access calls throughout the file. This improves - code readability, reduces complexity, and ensures correctness while maintaining the program's intended behavior. + \item[Secrets:] None + \item[Services:] Offers an interface for other refactoring modules to implement. \item[Implemented By:] EcoOptimizer \end{description} -\subsubsection{Input Format Module (\mref{mInput})} +\subsubsection{MakeStaticRefactorer Module (\mref{mMIMR})} + +% [Record, Library, Abstract Object, or Abstract Data Type] +\begin{description} +\item[Secrets:] How to parse a given code file to its AST representation, how to traverse the AST tree, how to modify specific nodes in the AST tree, how to convert the modified AST tree back to source code and write it to an output file. +\item[Services:] Refactors the \textit{\textbf{Member Ignoring Method (MIM)}} smell in a provided code file to improve energy efficiency. +\item[Implemented By:] EcoOptimizer +\end{description} + +\subsubsection{UseListAccumulationRefactorer Module (\mref{mSCLR})} + +% [Record, Library, Abstract Object, or Abstract Data Type] \begin{description} -\item[Secrets:]The format and structure of the input data. -\item[Services:]Converts the input data into the data structure used by the - input parameters module. -\item[Implemented By:] [Your Program Name Here] -\item[Type of Module:] [Record, Library, Abstract Object, or Abstract Data Type] - [Information to include for leaf modules in the decomposition by secrets tree.] +\item[Secrets:] How to parse a given code file into its AST representation, how to traverse the AST tree, how to find the initializing variable of the string concatenation, how to find the scope of the concatenation, how to modify the given code file in plain text and write it back to an output file. +\item[Services:] Refactors the \textbf{\textit{String Concatenation Inside Loop (SCL)}} smell in a provided code file to improve energy efficiency. +\item[Implemented By:] EcoOptimizer \end{description} \subsubsection{UseAGeneratorRefactorer Module (\mref{mUGENR})} @@ -364,8 +369,20 @@ \subsubsection{CacheRepeatedCallsRefactorer Module (\mref{mCRC})} \item[Implemented By:] EcoOptimizer \end{description} -\subsubsection{Etc.} +\subsubsection{Long Element Chain Module (\mref{mLEC})} +% [Record, Library, Abstract Object, or Abstract Data Type] + +\begin{description} + \item[Secrets:] How to parse a given code file to its AST representation, traverse the + AST tree to identify dictionary assignments, analyze the structure of nested dictionaries, + and flatten them. Additionally, it identifies all access calls associated with these dictionaries + in the source code and determines how to update them to reflect the new flattened structure. + \item[Services:] Detects nested dictionaries in the source code using AST parsing, simplifies their + structure by flattening them, and updates all associated access calls throughout the file. This improves + code readability, reduces complexity, and ensures correctness while maintaining the program's intended behavior. + \item[Implemented By:] EcoOptimizer +\end{description} \subsection{Software Decision Module} @@ -380,7 +397,7 @@ \subsection{Software Decision Module} \item[Implemented By:] -- \end{description} -\subsubsection{Pylint Analyzer Module} +\subsubsection{Pylint Analyzer Module (\mref{mPyA})} \begin{description} \item[Secrets:] The internal design and execution of static code analysis using Pylint and AST parsing, including custom detection and structuring of smells. These details are hidden from external modules. @@ -393,6 +410,16 @@ \subsubsection{Pylint Analyzer Module} \item[Implemented By:] \texttt{EcoOptimizer} \end{description} +\subsubsection{Testing Functionality Module (\mref{mTest})} + +% [Record, Library, Abstract Object, or Abstract Data Type] + +\begin{description} + \item[Secrets:] Runs testing suites in a subprocess. + \item[Services:] Checks whether the functionality of a given source code has changed. + \item[Implemented By:] EcoOptimizer +\end{description} + \section{Traceability Matrix} \label{SecTM} @@ -472,7 +499,7 @@ \section{Use Hierarchy Between Modules} \label{SecUse} \begin{figure}[H] \centering -%\includegraphics[width=0.7\textwidth]{UsesHierarchy.png} +\includegraphics[width=\textwidth]{../../Images/use_hierarchy_modules.png} \caption{Use hierarchy among modules} \label{FigUH} \end{figure} diff --git a/docs/Design/SoftDetailedDes/MIS.tex b/docs/Design/SoftDetailedDes/MIS.tex index 62d17da9..2b0e9cd5 100644 --- a/docs/Design/SoftDetailedDes/MIS.tex +++ b/docs/Design/SoftDetailedDes/MIS.tex @@ -226,6 +226,334 @@ \subsubsection{Local Functions} explicitly. Even if they are implemented, they are not exported; they only have local scope.} +\newpage + +\section{MIS of Base Refactorer} \label{mis:baseR} + +\texttt{BaseRefactorer} + +\subsection{Module} + +The interface that all refactorers of this system will inherit from. + +\subsection{Uses} + +None + +\subsection{Syntax} +\noindent +\textbf{Exported Constants}: None + +\noindent +\textbf{Exported Access Programs}: + +\begin{tabularx}{\linewidth}{|l|>{\raggedright\arraybackslash}X|l|l|} + \toprule Name & In & Out & Exceptions \\\hline + \midrule + \texttt{\_\_init\_\_} & \texttt{output\_dir: Path} & None & None \\\hline + \texttt{refactor} & \texttt{file\_path: Path, pylint\_smell: dict, initial\_emissions: float} & None & None \\ + \hline + \bottomrule +\end{tabularx} + +\subsection{Semantics} + +\subsubsection{State Variables} +\begin{itemize} + \item \texttt{temp\_dir: Path}: Directory path for storing refactored files. +\end{itemize} + +\subsubsection{Environment Variables} +None + +\subsubsection{Assumptions} +\begin{itemize} + \item \texttt{output\_dir} exists or can be created, and write permissions are available. +\end{itemize} + +\subsubsection{Access Routine Semantics} + +\paragraph{\texttt{\_\_init\_\_(self, output\_dir: Path)}} +\begin{itemize} + \item \textbf{transition}: Initializes the \texttt{temp\_dir} variable within \texttt{output\_dir}. + \item \textbf{output}: None. + \item \textbf{exception:} None. +\end{itemize} + +\paragraph{\texttt{refactor(self, file\_path: Path, pylint\_smell: dict, initial\_emissions: float)}} +\begin{itemize} + \item \textbf{transition}: Abstract method. No transition defined. + \item \textbf{output}: None. + \item \textbf{exception:} None. +\end{itemize} + +\subsubsection{Local Functions} +None. + +\newpage + +\section{MIS of Smell Data Type} \label{mis:smell} +\texttt{Smell} + +\subsection{Module} +Contains data related to a code smell. + +\subsection{Uses} +None + +\subsection{Syntax} +\noindent +\textbf{Exported Constants}: None + +\noindent +\textbf{Exported Access Programs}: None + +\subsection{Semantics} + +\subsubsection{State Variables} +\begin{itemize} + \item \texttt{absolutePath: str}: Absolute path to the source file containing the smell. + \item \texttt{column: int}: Starting column in the source file where the smell is detected. + \item \texttt{confidence: str}: Confidence level for the smell detection. + \item \texttt{endColumn: int | None}: Ending column for the smell location, if applicable. + \item \texttt{endLine: int | None}: Ending line number for the smell location, if applicable. + \item \texttt{occurences: dict}: Contains positional data related to where the smell is located in a code file. + \item \texttt{message: str}: Descriptive message explaining the smell. + \item \texttt{messageId: str}: Unique identifier for the specific message or warning. + \item \texttt{module: str}: Module or component name containing the smell. + \item \texttt{obj: str}: Specific object associated with the smell. + \item \texttt{path: str}: Relative path to the source file from the project root. + \item \texttt{symbol: str}: Symbol or code construct involved in the smell. + \item \texttt{type: str}: Type or category of the smell. +\end{itemize} + +\subsubsection{Environment Variables} +None + +\subsubsection{Assumptions} +\begin{itemize} + \item All values provided to the fields of \texttt{Smell} conform to the expected data types and constraints. +\end{itemize} + +\subsubsection{Access Routine Semantics} + +\paragraph{\texttt{Smell()}} +\begin{itemize} + \item \textbf{transition}: Creates a dictionary-like structure with the defined attributes representing a code smell. + \item \textbf{output}: Returns a \texttt{Smell} instance. +\end{itemize} + +\subsubsection{Local Functions} +None. + + +\newpage + +\section{MIS of Use List Accumulation Refactorer} \label{mis:ListAccum} + +\texttt{UseListAccumulationRefactorer} + +\subsection{Module} + +The \texttt{UseListAccumulationRefactorer} module identifies and refactors +string concatenations in loops in Python code to improve the performance and energy efficiency of the software. It specifically handles these concatenations by, instead, adding the string for each iteration to a list that is then converted to a string using Python's \texttt{join()} function, ensuring proper refactoring while maintaining the original functionality. + +\subsection{Uses} +\begin{itemize} + \item Uses \texttt{Smell} interface for data access + \item Inherits from \texttt{BaseRefactorer} + \item Inherits from Python's \texttt{ast} module's \texttt{NodeTransformer} +\end{itemize} + +\subsection{Syntax} +\noindent +\textbf{Exported Constants}: None + +\noindent +\textbf{Exported Access Programs}: + +\begin{tabularx}{\linewidth}{| + l| + >{\raggedright\arraybackslash}X| + l| + l|} + \toprule Name & In & Out & Exceptions \\ + \midrule + \texttt{\_\_init\_\_} & \texttt{output\_dir: Path} & None & None \\ + \hline + \texttt{refactor} & \texttt{file\_path: Path, pylint\_smell: Smell, initial\_emissions: Real} & None & \texttt{TypeError}, \texttt{IOError} \\ + \hline + \texttt{visit} & \texttt{node: nodes.NodeNG} & None & None \\ + \hline + \texttt{find\_last\_assignment} & \texttt{scope: nodes.NodeNG} & None & \texttt{TypeError} \\ + \hline + \texttt{find\_scope} & None & None & \texttt{TypeError} \\ + \hline + \texttt{add\_node\_to\_body} & \texttt{code\_file: str} & \texttt{str} & \texttt{TypeError} \\ + \bottomrule +\end{tabularx} + +\subsection{Semantics} + +\subsubsection{State Variables} +\begin{itemize} + \item \texttt{target\_line: int}: Line number where refactoring is applied. + \item \texttt{target\_node: ASTnode}: Node representing the concatenation variable. + \item \texttt{assign\_var: str}: Name of the variable the \texttt{target\_node} represents. + \item \texttt{last\_assign\_node: ASTnode}: Last initialization/assignment of the \texttt{assign\_var} prior to the start of the loop. + \item \texttt{concat\_node: ASTnode}: Node where concatenation occurs. + \item \texttt{scope\_node: ASTnode}: Scope where refactoring is inserted. + \item \texttt{outer\_loop: ASTnode}: Outermost loop before the start of the concatenation. +\end{itemize} + +\subsubsection{Environment Variables} +None + +\subsubsection{Assumptions} +\begin{itemize} + \item The input file contains valid Python syntax. + \item \texttt{pylint\_smell} provides a valid line number for the detected code smell. +\end{itemize} + +\subsubsection{Access Routine Semantics} + +\paragraph{\texttt{\_\_init\_\_(self, output\_dir: Path)}} +\begin{itemize} + \item \textbf{transition}: Initializes the refactorer with \texttt{output\_dir} and sets default state variables. + \item \textbf{output}: None. + \item \textbf{exception}: None +\end{itemize} + +\paragraph{\texttt{refactor(self, file\_path: Path, pylint\_smell: Smell, initial\_emissions: float)}} +\begin{itemize} + \item \textbf{transition}: Parses \texttt{file\_path}, identifies string concatenations in loops, modifies code for list accumulation, and writes refactored code to a file. + \item \textbf{output}: None. + \item \textbf{exception}: Raises \texttt{IOError} if input file cannot be read. Raises \texttt{TypeError} if source file cannot be parsed into an AST. +\end{itemize} + +\paragraph{\texttt{find\_last\_assignment(self, scope: nodes.NodeNG)}} +\begin{itemize} + \item \textbf{transition}: Identifies the last assignment of \texttt{assign\_var} within the given \texttt{scope}. + \item \textbf{output}: None. + \item \textbf{exception}: Raises \texttt{TypeError} if given scope is null. +\end{itemize} + +\paragraph{\texttt{find\_scope(self)}} +\begin{itemize} + \item \textbf{transition}: Finds the scope for refactoring based on AST node ancestry. + \item \textbf{output}: None. + \item \textbf{exception}: Raises \texttt{TypeError} if \texttt{concat\_node} is not set. +\end{itemize} + +\paragraph{\texttt{add\_node\_to\_body(self, code\_file: str)}} +\begin{itemize} + \item \textbf{transition}: Inserts list accumulation and join statements into \texttt{code\_file}. + \item \textbf{output}: Returns the modified source code as a string. + \item \textbf{exception}: Raises \texttt{TypeError} if \texttt{target\_node} or \texttt{outer\_loop} is not set. +\end{itemize} + +\subsubsection{Local Functions} +Functions for internal AST parsing, node manipulation, and validation are defined within the class but are not exported. + +\newpage + +\section{MIS of Make Method Static Refactorer} \label{mis:MakeStatic} + +\texttt{MakeStaticRefactorer} + +\subsection{Module} + +The \texttt{MakeStaticRefactorer} module identifies and refactors +class methods that don't make use of their instance attributes to improve the readability, performance and energy efficiency of the software. It specifically handles these methods by turning them into static functions and ensuring any calls to this method use the proper calling syntax. This ensures proper refactoring while maintaining the original functionality. + +\subsection{Uses} +\begin{itemize} + \item Uses \texttt{Smell} interface for data access + \item Inherits from \texttt{BaseRefactorer} + \item Inherits from Python's \texttt{ast} module's \texttt{NodeTransformer} +\end{itemize} + +\subsection{Syntax} +\noindent +\textbf{Exported Constants}: None + +\noindent +\textbf{Exported Access Programs}: + +\begin{tabularx}{\linewidth}{|l|>{\raggedright\arraybackslash}X|l|l|} + \toprule Name & In & Out & Exceptions \\ + \midrule + \texttt{\_\_init\_\_} & \texttt{output\_dir: Path} & None & None \\ + \hline + \texttt{refactor} & \texttt{file\_path: Path, pylint\_smell: Smell, initial\_emissions: $\mathbb{R}$} & None & \texttt{TypeError}, \texttt{IOError} \\ + \hline + \texttt{visit\_FunctionDef} & \texttt{node: FunctionDef} & \texttt{FunctionDef} & None \\ + \hline + \texttt{visit\_ClassDef} & \texttt{node: ClassDef} & \texttt{ClassDef} & None \\ + \hline + \texttt{visit\_Call} & \texttt{node: Call} & \texttt{Call} & None \\ + \bottomrule +\end{tabularx} + +\subsection{Semantics} + +\subsubsection{State Variables} +\begin{itemize} + \item \texttt{target\_line: int}: Line number where refactoring is applied. + \item \texttt{mim\_method\_class: str}: Class name containing the method to refactor. + \item \texttt{mim\_method: str}: Method name to refactor. +\end{itemize} + +\subsubsection{Environment Variables} +None + +\subsubsection{Assumptions} +\begin{itemize} + \item The input file contains valid Python syntax. + \item \texttt{pylint\_smell} provides a valid line number for the detected code smell. +\end{itemize} + +\subsubsection{Access Routine Semantics} + +\paragraph{\texttt{\_\_init\_\_(self, output\_dir: Path)}} +\begin{itemize} + \item \textbf{transition}: Initializes the refactorer with \texttt{output\_dir} and sets default state variables. + \item \textbf{output}: None. + \item \textbf{exception}: None. +\end{itemize} + +\paragraph{\texttt{refactor(self, file\_path: Path, pylint\_smell: Smell, initial\_emissions: float)}} +\begin{itemize} + \item \textbf{transition}: Parses \texttt{file\_path}, identifies the target function, modifies it to be static, and validates refactoring. + \item \textbf{output}: None. + \item \textbf{exception}: Raises \texttt{IOError} if input file cannot be read. Raises \texttt{TypeError} if source file cannot be parsed into an AST. +\end{itemize} + +\paragraph{\texttt{visit\_FunctionDef(self, node: ast.FunctionDef)}} +\begin{itemize} + \item \textbf{transition}: Adds the \texttt{staticmethod} decorator to the target method and removes the \texttt{self} parameter if present. + \item \textbf{output}: Returns the modified \texttt{FunctionDef} node. + \item \textbf{exception}: None +\end{itemize} + +\paragraph{\texttt{visit\_ClassDef(self, node: ast.ClassDef)}} +\begin{itemize} + \item \textbf{transition}: Identifies the class containing the target method. + \item \textbf{output}: Returns the modified \texttt{ClassDef} node. + \item \textbf{exception}: None. +\end{itemize} + +\paragraph{\texttt{visit\_Call(self, node: ast.Call)}} +\begin{itemize} + \item \textbf{transition}: Updates method call references to use the class name instead of \texttt{self}. + \item \textbf{output}: Returns the modified \texttt{Call} node. + \item \textbf{exception}: None. +\end{itemize} + +\subsubsection{Local Functions} +Functions for internal AST parsing, node transformation, and validation are defined within the class but are not exported. + +\newpage \section{MIS of LongElementChainRefactorer} @@ -378,23 +706,23 @@ \subsection{Syntax} \subsection{Semantics} -\subsubsection*{State Variables} +\subsubsection{State Variables} \begin{itemize} \item \texttt{file\_path: Path}: The path to the Python file being analyzed. \item \texttt{source\_code: ast.Module}: The parsed abstract syntax tree of the source file. \item \texttt{smells\_data: list[dict]}: A list of detected code smells, represented as dictionaries. \end{itemize} -\subsubsection*{Environment Variables} +\subsubsection{Environment Variables} None -\subsubsection*{Assumptions} +\subsubsection{Assumptions} \begin{itemize} \item The input file is valid Python code and can be parsed into an AST. \item Configuration settings, such as extra Pylint options and custom smell definitions, are valid. \end{itemize} -\subsubsection*{Access Routine Semantics} +\subsubsection{Access Routine Semantics} \paragraph{\texttt{\_\_init\_\_(self, file\_path: Path, source\_code: ast.Module)}} \begin{itemize} @@ -459,13 +787,81 @@ \subsubsection*{Access Routine Semantics} \item \textbf{exception:} None. \end{itemize} -\subsubsection*{Local Functions} +\subsubsection{Local Functions} \begin{itemize} \item \texttt{parse\_line(file\_path: Path, line: int)}: Parses a specific line of code into an AST node. \item \texttt{get\_lambda\_code(lambda\_node: ast.Lambda)}: Returns the string representation of a lambda expression. \end{itemize} +\newpage + +\section{MIS of Testing Functionality} + +\texttt{TestRunner} + +\subsection{Module} + +Responsible for validating that any refactorings made to the source code do not modify it's original functionality. + +\subsection{Uses} +\begin{itemize} + \item Uses Python's subprocess library +\end{itemize} + +\subsection{Syntax} +\noindent +\textbf{Exported Constants}: None + +\noindent +\textbf{Exported Access Programs}: + +\begin{tabularx}{\linewidth}{|l|>{\raggedright\arraybackslash}X|l|l|} +\hline +Name & In & Out & Exceptions \\ +\hline +\texttt{\_\_init\_\_} & \texttt{run\_command: str, project\_path: Path} & None & None \\ +\hline +\texttt{retained\_functionality} & None & \texttt{bool} & \texttt{CalledProcessError} \\ +\hline +\end{tabularx} + +\subsection{Semantics} + +\subsubsection{State Variables} +\begin{itemize} + \item \texttt{project\_path: Path}: Path to the source code directory. + \item \texttt{run\_command: str}: Command used to run the tests. +\end{itemize} + +\subsubsection{Environment Variables} +None + +\subsubsection{Assumptions} +\begin{itemize} + \item The provided \texttt{run\_command} is a valid shell command. + \item \texttt{project\_path} is a valid path working source code directory. +\end{itemize} + +\subsubsection{Access Routine Semantics} + +\paragraph{\texttt{\_\_init\_\_(self, run\_command: str, project\_path: Path)}} +\begin{itemize} + \item \textbf{transition}: Initializes the test runner with the given \texttt{run\_command} and \texttt{project\_path}. + \item \textbf{output}: None. + \item \textbf{exception}: None. +\end{itemize} + +\paragraph{\texttt{retained\_functionality(self)}} +\begin{itemize} + \item \textbf{transition}: Runs the specified test command in the given project path. Logs success or failure, including standard output and error streams. + \item \textbf{output}: Returns \texttt{True} if the tests passed; otherwise, returns \texttt{False}. + \item \textbf{exception}: Raises a \texttt{CalledProcessError} if an eror occurs while running the tests in a subprocess. +\end{itemize} + +\subsubsection{Local Functions} +None. + \newpage \section{MIS of Use A Generator Refactorer} \label{mis:UseGen} @@ -507,22 +903,22 @@ \subsection{Syntax} \subsection{Semantics} -\subsubsection*{State Variables} +\subsubsection{State Variables} \begin{itemize} \item \texttt{temp\_dir: Path}: Directory path for storing refactored files. \item \texttt{output\_dir: Path}: Directory path for saving final refactored code. \end{itemize} -\subsubsection*{Environment Variables} +\subsubsection{Environment Variables} None -\subsubsection*{Assumptions} +\subsubsection{Assumptions} \begin{itemize} \item The input file contains valid Python syntax. \item \texttt{pylint\_smell} provides a valid line number for the detected code smell. \end{itemize} -\subsubsection*{Access Routine Semantics} +\subsubsection{Access Routine Semantics} \paragraph{\texttt{\_\_init\_\_(self, output\_dir: Path)}} \begin{itemize} @@ -545,7 +941,7 @@ \subsubsection*{Access Routine Semantics} \item \textbf{exception}: None. \end{itemize} -\subsubsection*{Local Functions} +\subsubsection{Local Functions} Functions for internal AST parsing, node manipulation, and validation are defined within the class but are not exported. \newpage @@ -582,22 +978,22 @@ \subsection{Syntax} \subsection{Semantics} -\subsubsection*{State Variables} +\subsubsection{State Variables} \begin{itemize} \item \texttt{cached\_var\_name: str}: Name of the temporary variable used for caching. \item \texttt{target\_line: int}: Line number where refactoring is applied. \end{itemize} -\subsubsection*{Environment Variables} +\subsubsection{Environment Variables} None -\subsubsection*{Assumptions} +\subsubsection{Assumptions} \begin{itemize} \item The input file contains valid Python syntax. \item \texttt{pylint\_smell} provides valid occurrences of repeated calls with line numbers and call strings. \end{itemize} -\subsubsection*{Access Routine Semantics} +\subsubsection{Access Routine Semantics} \paragraph{\texttt{\_\_init\_\_(self, output\_dir: Path)}} \begin{itemize} @@ -613,7 +1009,7 @@ \subsubsection*{Access Routine Semantics} \item \textbf{exception}: Raises \texttt{IOError} if input file cannot be read. Raises \texttt{TypeError} if source file cannot be parsed into an AST. \end{itemize} -\subsubsection*{Local Functions} +\subsubsection{Local Functions} \begin{itemize} \item \texttt{\_get\_indentation(lines, line\_number)}: Determines the indentation of a specific line. \item \texttt{\_replace\_call\_in\_line(line, call\_string, cached\_var\_name)}: Replaces repeated calls with the cached variable. diff --git a/docs/Images/use_hierarchy_modules.png b/docs/Images/use_hierarchy_modules.png new file mode 100644 index 0000000000000000000000000000000000000000..af6c57ffbcb1625c0464a46864f06009b9e8ef2a GIT binary patch literal 66310 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 literal 0 HcmV?d00001 From 0ee33d7775fcf289de9231de062485b35c119487 Mon Sep 17 00:00:00 2001 From: Ayushi Amin <66652121+Ayushi1972@users.noreply.github.com> Date: Fri, 17 Jan 2025 11:25:06 -0500 Subject: [PATCH 17/85] Added #308: MIS for Measurements (#310) --- docs/Design/SoftArchitecture/MG.tex | 16 +++++ docs/Design/SoftDetailedDes/MIS.tex | 104 ++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) diff --git a/docs/Design/SoftArchitecture/MG.tex b/docs/Design/SoftArchitecture/MG.tex index 9a529efe..6273bfd8 100644 --- a/docs/Design/SoftArchitecture/MG.tex +++ b/docs/Design/SoftArchitecture/MG.tex @@ -235,6 +235,8 @@ \section{Module Hierarchy} \label{SecMH} actually be implemented. \begin{description} +\item [\refstepcounter{mnum} \mthemnum \label{mHH}:] Hardware-Hiding Module +\item [\refstepcounter{mnum} \mthemnum \label{mM}:] Measurements Module \item [\refstepcounter{mnum} \mthemnum \label{mSmell}:] Smell Module \item [\refstepcounter{mnum} \mthemnum \label{mBR}:] BaseRefactorer Module \item [\refstepcounter{mnum} \mthemnum \label{mMIMR}:] MakeStaticRefactorer Module @@ -272,6 +274,9 @@ \section{Module Hierarchy} \label{SecMH} & ?\\ \midrule +\multirow{3}{0.3\textwidth}{Software Decision Module} & {?}\\ +& Measurements Module\\ +& ?\\ \multirow{3}{0.3\textwidth}{Software Decision Module} & Pylint Analyzer Module\\ & Testing Functionality Module\\ & Measurements Module\\ @@ -397,6 +402,17 @@ \subsection{Software Decision Module} \item[Implemented By:] -- \end{description} +\subsection{Measurements Module} + +\begin{description} +\item[Secrets:] How to measure energy consumption and carbon emissions of a given Python program using the CodeCarbon library, including managing temporary directories for storing output, executing the program, and processing the emissions data from a CSV file. +\item[Services:] Provides functionality for measuring the energy consumption and carbon emissions of a provided code file. This module handles execution, tracking, and data extraction, ensuring that the emissions data is available for further analysis. +\item[Implemented By:] CodeCarbonEnergyMeter +\end{description} + +\subsubsection{Etc.} +\subsubsection{Pylint Analyzer Module} + \subsubsection{Pylint Analyzer Module (\mref{mPyA})} \begin{description} diff --git a/docs/Design/SoftDetailedDes/MIS.tex b/docs/Design/SoftDetailedDes/MIS.tex index 2b0e9cd5..11ba80fa 100644 --- a/docs/Design/SoftDetailedDes/MIS.tex +++ b/docs/Design/SoftDetailedDes/MIS.tex @@ -649,6 +649,110 @@ \subsubsection{Local Functions} \item \textbf{\_generate\_flattened\_access(base\_var: str, access\_chain: list[str])} \\ Generates a flattened dictionary key string by combining elements of an access chain with underscores. \end{itemize} + + + +\section{MIS of Measurements Module} + +\subsection{Module} + +The MeasurementsModule is a module designed to measure and track the carbon emissions generated by executing Python scripts. By leveraging the CodeCarbon library, it allows developers to assess the environmental impact of their code execution. The module runs a specified Python file, tracks the associated carbon emissions during the execution, and logs the results for further analysis. It provides functionality for measuring, logging, and extracting emissions data in a structured manner to help improve energy efficiency in software development. + +\subsection{Uses} + +\begin{itemize} + \item Uses \texttt{CodeCarbon} library for track energy consumption + \item Uses \texttt{TemporaryDirectory} to store temporary files + \item Inherits from \texttt{BaseEnergyMeter} +\end{itemize} + +\subsection{Syntax} + +\subsubsection{Exported Constants} +None + +\subsubsection{Exported Access Programs} + +\begin{center} +\begin{tabular}{|p{3cm}|p{5cm}|p{2cm}|p{3cm}|} +\hline +\textbf{Name} & \textbf{In} & \textbf{Out} & \textbf{Exceptions} \\ +\hline +\texttt{\_\_init\_\_} & \texttt{output\_dir: Path} & None & None \\ +\hline +\texttt{measure\_energy} & \texttt{None} & None & CalledProcessError and FileReading exceptions \\ +\hline +\end{tabular} +\end{center} + +\subsection{Semantics} + +\subsubsection{State Variables} + +\begin{itemize} + \item \textbf{Emissions\_data}: Stores the emissions data extracted from the CSV file generated by CodeCarbon. It is populated after the energy measurement process completes successfully. The value is either a dictionary containing the last row of emissions data or \texttt{None} if no data was extracted due to an error. + +\end{itemize} + +\subsubsection{Environment Variables} + +\begin{itemize} + \item \textbf{TEMP}: Sets the temporary directory location for Windows systems. Used during the CodeCarbon energy measurement process. + \item \textbf{TMPDIR}: Sets the temporary directory location for Unix-based systems. Used during the CodeCarbon energy measurement process. + \item \textbf{Logger}: A logging mechanism that logs various events during the energy measurement process, including errors, completion of measurements, and other key actions. +\end{itemize} + +\subsubsection{Assumptions} + +\begin{itemize} + \item The file at \texttt{file\_path} is a valid Python script. + \item The CodeCarbon tool is properly installed and configured. + \item The \texttt{EmissionsTracker} can successfully execute the Python script specified by \texttt{file\_path}. + \item The emissions data is captured in a CSV format and can be extracted correctly. + \item The temporary directories are correctly set up and accessible during execution. +\end{itemize} + +\subsubsection{Access Routine Semantics} +\paragraph{\texttt{\_\_init\_\_(file\_path: Path)}} +\begin{itemize} + \item \textbf{Transition}: Initializes the \texttt{CodeCarbonEnergyMeter} with the specified file path and logger. It sets up the necessary internal state for energy measurement and prepares the environment. + \item \textbf{Output}: None. + \item \textbf{Exception}: None. +\end{itemize} + +\paragraph{\texttt{measure\_energy()}} +\begin{itemize} + \item \textbf{Transition}: + \begin{itemize} + \item Logs the start of the energy measurement process. + \item Creates a temporary directory to store custom data. + \item Initializes the \texttt{EmissionsTracker} from CodeCarbon. + \item Runs the script specified by \texttt{file\_path} and captures the output. + \item Stops the tracker after execution and stores the emissions data. + \item If available, it extracts the emissions data from the generated CSV file. + \end{itemize} + \item \textbf{Output}: + \begin{itemize} + \item Logs the results of the energy measurement process. + \item Stores the emissions data in \texttt{self.emissions\_data}. + \end{itemize} + \item \textbf{Exception}: + \begin{itemize} + \item Logs an error if the file cannot be executed or if the emissions file is not created. + \item If the emissions data cannot be extracted from the CSV file, logs the issue. + \end{itemize} + \end{itemize} + +\subsubsection{Local Functions} +\paragraph{\texttt{\_extract\_emissions\_csv(csv\_file\_path: Path)}} + + Extracts emissions data from a CSV file generated by CodeCarbon. + \begin{itemize} + \item \textbf{Input}: \texttt{csv\_file\_path} - The path to the CSV file containing emissions data. + \item \textbf{Output}: Returns the last row of emissions data as a dictionary, or \texttt{None} if an error occurs. + \end{itemize} + + \newpage From 39baf531b058bd8ff45c36fe6a3ca42916297726 Mon Sep 17 00:00:00 2001 From: Mya <55725523+mmyaaaaa@users.noreply.github.com> Date: Fri, 17 Jan 2025 11:26:16 -0500 Subject: [PATCH 18/85] [DESIGN] Added Timeline Co-authored-by: mya Co-authored-by: Sevhena Walker <83547364+Sevhena@users.noreply.github.com> Co-authored-by: Ayushi Amin <66652121+Ayushi1972@users.noreply.github.com> --- docs/Design/SoftArchitecture/MG.tex | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/docs/Design/SoftArchitecture/MG.tex b/docs/Design/SoftArchitecture/MG.tex index 6273bfd8..1de47efb 100644 --- a/docs/Design/SoftArchitecture/MG.tex +++ b/docs/Design/SoftArchitecture/MG.tex @@ -533,9 +533,30 @@ \section{Design of Communication Protocols} \section{Timeline} -\wss{Schedule of tasks and who is responsible} +All code and corresponding documentation was aimed to be completed before Jan 6th our Demo date for our supervisor. -\wss{You can point to GitHub if this information is included there} +\begin{table}[h!] + \centering + \caption{Timeline} + \begin{tabular}{|l|l|l|} + \hline + \textbf{Module Name} & \textbf{Team Member} & \textbf{Due Date} \\ \hline + Base Refactorer & Sevhena Walker & Jan 6, 2025 \\ \hline + Complex List Comprehension & Nivetha Kuruparan & Jan 6, 2025 \\ \hline + Long Element Chain & Ayushi Amin & Jan 6, 2025 \\ \hline + Long Lambda Function & Mya Hussain & Jan 6, 2025 \\ \hline + Long Message Chain & Mya Hussain & Jan 6, 2025 \\ \hline + Member Ignoring Method & Sevhena Walker & Jan 6, 2025 \\ \hline + Repeated Calls & Nivetha Kuruparan & Jan 6, 2025 \\ \hline + String Concatenation in Loop & Team Member 8 & Jan 6, 2025 \\ \hline + Long Parameter List & Tanveer Brar & Jan 6, 2025 \\ \hline + Smell & All & Jan 31, 2025 \\ \hline + Analyzers & All & Jan 31, 2025 \\ \hline + Measurements & All & Jan 31, 2025 \\ \hline + Testing Functionality & All & Jan 31, 2025 \\ \hline + \end{tabular} + \end{table} + \bibliographystyle {plainnat} \bibliography{../../../refs/References} From b06e346a35290b35ef99f23042f78b906be306ec Mon Sep 17 00:00:00 2001 From: Tanveer Brar <92374772+tbrar06@users.noreply.github.com> Date: Fri, 17 Jan 2025 12:20:42 -0500 Subject: [PATCH 19/85] [DESIGN] Added #311: MIS for LongParameterListRefactorer (#313) --- docs/Design/SoftArchitecture/MG.tex | 16 ++++- docs/Design/SoftDetailedDes/MIS.tex | 94 +++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 2 deletions(-) diff --git a/docs/Design/SoftArchitecture/MG.tex b/docs/Design/SoftArchitecture/MG.tex index 1de47efb..3d6cacd4 100644 --- a/docs/Design/SoftArchitecture/MG.tex +++ b/docs/Design/SoftArchitecture/MG.tex @@ -244,6 +244,7 @@ \section{Module Hierarchy} \label{SecMH} \item [\refstepcounter{mnum} \mthemnum \label{mUGENR}:] UseAGeneratorRefactorer Module \item [\refstepcounter{mnum} \mthemnum \label{mCRC}:] CacheRepeatedCallsRefactorer Module \item [\refstepcounter{mnum} \mthemnum \label{mLEC}:] LongElementChainRefactorer Module +\item [\refstepcounter{mnum} \mthemnum \label{mLPL}:] LongParameterListRefactorer Module \item [\refstepcounter{mnum} \mthemnum \label{mPyA}:] Pylint Analyzer Module \item [\refstepcounter{mnum} \mthemnum \label{mTest}:] Testing Functionality Module \end{description} @@ -268,7 +269,7 @@ \section{Module Hierarchy} \label{SecMH} & UseAGeneratorRefactorer Module\\ & ?\\ & LongElementChainRefactorer Module\\ -& ?\\ +& LongParameterListRefactorer Module\\ & ?\\ & ?\\ & ?\\ @@ -389,6 +390,17 @@ \subsubsection{Long Element Chain Module (\mref{mLEC})} \item[Implemented By:] EcoOptimizer \end{description} +\subsubsection{Long Parameter List Module (\mref{mLPL})} + +% [Record, Library, Abstract Object, or Abstract Data Type] + +\begin{description} + \item[Secrets:] How to parse a given code file to its AST representation, traverse the AST tree to identify functions or methods with long parameter lists, and encapsulate related parameters into objects or structures. Additionally, it identifies all function or method calls associated with these functions and updates their arguments to align with the refactored signature. + \item[Services:] Detects long parameter lists in functions or methods using AST parsing, simplifies their structure by grouping related parameters into objects or structures, and updates all associated function or method calls throughout the file. This improves code readability, reduces complexity, and ensures correctness while maintaining the program’s intended behavior. + \item[Implemented By:] EcoOptimizer +\end{description} + + \subsection{Software Decision Module} \begin{description} @@ -548,7 +560,7 @@ \section{Timeline} Long Message Chain & Mya Hussain & Jan 6, 2025 \\ \hline Member Ignoring Method & Sevhena Walker & Jan 6, 2025 \\ \hline Repeated Calls & Nivetha Kuruparan & Jan 6, 2025 \\ \hline - String Concatenation in Loop & Team Member 8 & Jan 6, 2025 \\ \hline + String Concatenation in Loop & Sevhena Walker & Jan 6, 2025 \\ \hline Long Parameter List & Tanveer Brar & Jan 6, 2025 \\ \hline Smell & All & Jan 31, 2025 \\ \hline Analyzers & All & Jan 31, 2025 \\ \hline diff --git a/docs/Design/SoftDetailedDes/MIS.tex b/docs/Design/SoftDetailedDes/MIS.tex index 11ba80fa..f449536e 100644 --- a/docs/Design/SoftDetailedDes/MIS.tex +++ b/docs/Design/SoftDetailedDes/MIS.tex @@ -155,6 +155,100 @@ \section{Module Decomposition} \newpage ~\newpage +\section{MIS of LongParameterListRefactorer} \label{Module} \wss{Use labels for + cross-referencing} + +\wss{You can reference SRS labels, such as R\ref{R_Inputs}.} + +\wss{It is also possible to use \LaTeX for hypperlinks to external documents.} + +\subsection{Module} + +LongParameterListRefactorer is a module that identifies and refactors functions or methods with long parameter lists(detected beyond configured threshold) in Python code. The refactoring aims to improve code readability, maintainability, and energy efficiency by encapsulating related parameters into objects and removing unused ones. + +\subsection{Uses} + +\begin{itemize} + \item Uses \texttt{Smell} interface for data access + \item Inherits from \texttt{BaseRefactorer} + \item Inherits from Python's \texttt{ast} module's \texttt{NodeTransformer} +\end{itemize} + +\subsection{Syntax} + +\subsubsection{Exported Constants} + +None + +\subsubsection{Exported Access Programs} + +\begin{center} +\begin{tabular}{|p{3cm}|p{5cm}|p{2cm}|p{3cm}|} +\hline +\textbf{Name} & \textbf{In} & \textbf{Out} & \textbf{Exceptions} \\ +\hline +\texttt{\_\_init\_\_} & \texttt{output\_dir: Path} & None & None \\ +\hline +\texttt{refactor} & \texttt{file\_path: Path, pylint\_smell: Smell, initial\_emissions: float} & None & Logging exceptions \\ +\hline +\end{tabular} +\end{center} + +\subsection{Semantics} + +\subsubsection{State Variables} + +None + +\subsubsection{Environment Variables} + +\begin{itemize} +\item \textbf{File system}: Used for reading, writing, and storing temporary and refactored files. +\item \textbf{Logger}: Logs details of the refactoring process. +\end{itemize} + +\subsubsection{Assumptions} + +\begin{itemize} + \item Input files are valid Python scripts. + \item Smells identified by \texttt{pylint\_smell} include valid line numbers. + \item Refactored code must pass the provided test suite. +\end{itemize} + +\subsubsection{Access Routine Semantics} + +\paragraph{\texttt{init(output\_dir: Path)}} +\begin{itemize} +\item \textbf{Transition}: Initializes the refactorer with the specified output directory. +\item \textbf{Output}: None. +\item \textbf{Exception}: None. +\end{itemize} + +\paragraph{\texttt{refactor(file\_path: Path, pylint\_smell: Smell, initial\_emissions: float)}} +\begin{itemize} +\item \textbf{Transition}: +\begin{enumerate} +\item Reads the file at \texttt{file\_path} and locates the target function using \texttt{pylint\_smell}. +\item Analyzes function body to remove unused parameters. Updates the function signature and references in the code accordingly. +\item If number of used parameters also exceeds the maximum configured limit, encapsulates related parameters into classes. Updates the function signature and references in the code accordingly. +\item Writes the refactored code to a temporary file. +\end{enumerate} +\item \textbf{Output}: None.Refactored file is saved if improvements are validated. +\item \textbf{Exception}: Logs exceptions during file operations or the refactoring process. +\end{itemize} + +\subsubsection{Local Functions} + +\begin{enumerate} +\item \texttt{get\_used\_parameters(function\_node: ast.FunctionDef, params: list[str]) -> set[str]}: Identifies parameters used within the function body. +\item \texttt{get\_parameters\_with\_default\_value(default\_values: list[ast.Constant], params: list[str]) -> dict}: Maps parameter names to their default values. +\item \texttt{classify\_parameters(params: list[str]) -> dict}: Classifies parameters into \texttt{data} and \texttt{config} groups based on naming conventions. +\item \texttt{create\_parameter\_object\_class(param\_names: list[str], default\_value\_params: dict, class\_name: str) -> str}: Generates class definitions for encapsulating parameters. +\item \texttt{update\_function\_signature(function\_node: ast.FunctionDef, params: dict) -> ast.FunctionDef}: Updates function signatures to use encapsulated parameter objects. +\item \texttt{update\_parameter\_usages(function\_node: ast.FunctionDef, params: dict) -> ast.FunctionDef}: Replaces parameter usages within the function body with attributes of encapsulated objects. +\item \texttt{update\_function\_calls(tree: ast.Module, function\_node: ast.FunctionDef, params: dict) -> ast.Module}: Updates all calls to the refactored function. +\end{enumerate} + \section{MIS of \wss{Module Name}} \label{Module} \wss{Use labels for cross-referencing} From 687d1bebc159e85d50ec257291f49a461d2772e4 Mon Sep 17 00:00:00 2001 From: Mya <55725523+mmyaaaaa@users.noreply.github.com> Date: Fri, 17 Jan 2025 12:38:59 -0500 Subject: [PATCH 20/85] Added modules long lambda functions and long message chain to MIS (#306) Co-authored-by: mya Co-authored-by: Ayushi Amin <66652121+Ayushi1972@users.noreply.github.com> Co-authored-by: Sevhena Walker <83547364+Sevhena@users.noreply.github.com> --- docs/Design/SoftArchitecture/MG.tex | 29 ++++ docs/Design/SoftDetailedDes/MIS.tex | 196 ++++++++++++++++++++++++++++ 2 files changed, 225 insertions(+) diff --git a/docs/Design/SoftArchitecture/MG.tex b/docs/Design/SoftArchitecture/MG.tex index 3d6cacd4..f8a01734 100644 --- a/docs/Design/SoftArchitecture/MG.tex +++ b/docs/Design/SoftArchitecture/MG.tex @@ -236,6 +236,8 @@ \section{Module Hierarchy} \label{SecMH} \begin{description} \item [\refstepcounter{mnum} \mthemnum \label{mHH}:] Hardware-Hiding Module +\item [\refstepcounter{mnum} \mthemnum \label{mLMC}:] LongMessageChainRefactorer Module +\item [\refstepcounter{mnum} \mthemnum \label{mLLF}:] LongLambdaFunctionRefactorer Module \item [\refstepcounter{mnum} \mthemnum \label{mM}:] Measurements Module \item [\refstepcounter{mnum} \mthemnum \label{mSmell}:] Smell Module \item [\refstepcounter{mnum} \mthemnum \label{mBR}:] BaseRefactorer Module @@ -403,6 +405,33 @@ \subsubsection{Long Parameter List Module (\mref{mLPL})} \subsection{Software Decision Module} +\subsubsection{Long Message Chain Refactorer (\mref{mLMC})} + + +\begin{description} + \item[Secrets:] Understanding the syntax and structure of Python code to identify/classify long message chains, including both f-strings and non-f-string chains. This involves parsing the target file, extracting method calls from identified long chains, and systematically breaking them into separate statements while preserving the original functionality and indentation. Additionally, it ensures unmatched brackets are corrected during refactoring. + + \item[Services:] Detects long message chains in Python source code and refactors them by splitting the chain into intermediate variables and a final result. This improves code readability and maintainability while retaining the original program behavior. + + \item[Implemented By:] EcoOptimizer + \item[Type of Module:] Library: a reusable component that provides functionality for refactoring long message chains in Python code. + +\end{description} + +\subsubsection{Long Lambda Function Refactorer (\mref{mLLF})} + + +\begin{description} + \item[Secrets:] Understanding the syntax and structure of Python code to identify long lambda functions. This includes parsing the target file to locate lambda expressions, extracting their arguments and bodies, and converting them into standard Python function definitions. The module ensures proper handling of nested structures (e.g., parentheses, brackets, and braces) within the lambda body, and truncates overly complex expressions at the first top-level comma for readability. + + \item[Services:] Detects components of long lambda functions in Python source code and refactors them by converting the lambda expression into a standalone function with a unique name. This improves code readability, debugging, and maintainability. The module inserts the newly defined function in the appropriate scope, updates the original lambda usage with a function call, and validates the refactored code by maintaining its functionality and measuring energy efficiency improvements. + + \item[Implemented By:] EcoOptimizer + + \item[Type of Module:] Library: a reusable component that provides functionality for refactoring long lambda functions in Python code. +\end{description} + + \begin{description} \item[Secrets:] The design decision based on mathematical theorems, physical facts, or programming considerations. The secrets of this module are diff --git a/docs/Design/SoftDetailedDes/MIS.tex b/docs/Design/SoftDetailedDes/MIS.tex index f449536e..bd5752b1 100644 --- a/docs/Design/SoftDetailedDes/MIS.tex +++ b/docs/Design/SoftDetailedDes/MIS.tex @@ -153,8 +153,204 @@ \section{Module Decomposition} \end{table} \newpage + ~\newpage +\section{MIS of LongMessageChainRefactorer} + +\subsection{Module} + +LongMessageChainRefactorer is a module that identifies and refactors +long message chains in Python code to improve readability, maintainability, +and performance. It specifically handles long chains by breaking them into +separate statements, ensuring proper refactoring while maintaining the +original functionality. + +\subsection{Uses} + +\begin{itemize} + \item Uses \texttt{Smell} interface for data access + \item Inherits from \texttt{BaseRefactorer} +\end{itemize} + +\subsection{Syntax} + +\subsubsection{Exported Constants} +None + +\subsubsection{Exported Access Programs} + +\begin{center} +\begin{tabular}{|p{4cm}|p{5cm}|p{4cm}|p{3cm}|} +\hline +\textbf{Name} & \textbf{In} & \textbf{Out} & \textbf{Exceptions} \\ +\hline +\texttt{\_\_init\_\_} & \texttt{output\_dir: Path} & LongMessageChainRefactorer & None \\ +\hline +\texttt{remove\_unmatched\_brackets} & \texttt{input\_string: str} & \texttt{str} & None \\ +\hline +\texttt{refactor} & \texttt{file\_path: Path, pylint\_smell: Smell, initial\_emissions: float} & None & Logging exceptions \\ +\hline +\end{tabular} +\end{center} + + +\subsection{Semantics} + +\subsubsection{State Variables} + +\begin{itemize} + \item \textbf{temp\_dir}: Temporary directory for intermediate refactored files. +\end{itemize} + +\subsubsection{Environment Variables} + +\begin{itemize} + \item \textbf{File system}: Used to read, write, and store temporary and refactored files. + + \item \textbf{Logger}: Logs information during refactoring. + +\end{itemize} + +\subsubsection{Assumptions} + +\begin{itemize} + \item Input files are valid Python scripts. + \item Smells identified by \textbf{pylint\_smell} include valid line numbers. + \item Refactored code must pass the provided test suite. +\end{itemize} +\subsubsection{Access Routine Semantics} + +\paragraph{\texttt{\_\_init\_\_(output\_dir: Path)}} +\begin{itemize} +\item \textbf{Transition}: Initializes the refactorer with the specified output directory. +\item \textbf{Output}: LongMessageChainRefactorer. +\item \textbf{Exception}: None. +\end{itemize} + +\paragraph{\texttt{remove\_unmatched\_brackets(input\_string: str)}} +\begin{itemize} +\item \textbf{Transition}: Removes unmatched parentheses from the input string. +\item \textbf{Output}: Returns the string with unmatched parentheses removed. +\item \textbf{Exception}: None. +\end{itemize} + +\paragraph{\texttt{refactor(file\_path: Path, pylint\_smell: Smell, initial\_emissions: float)}} +\begin{itemize} + \item \textbf{Transition}: + \begin{itemize} + \item Reads the file at \texttt{file\_path}. + \item Identifies the line with a long message chain. + \item Refactors the chain by breaking it into separate statements. + \item Writes the refactored code to a temporary file. + \item Evaluates the refactored code’s energy efficiency and functionality. + \end{itemize} + \item \textbf{Output}: None. Refactored file is saved if improvements are validated. + \item \textbf{Exception}: Logs exceptions during file operations or refactoring process. +\end{itemize} + +\subsubsection{Local Functions} +None + +~\newpage + +\section{MIS of LongLambdaFunctionRefactorer} + +\subsection{Module} +LongLambdaFunctionRefactorer is a module that refactors +long lambda functions in Python code by converting them into normal functions. +This improves code readability, maintainability, and performance, while reducing potential energy consumption. + +\subsection{Uses} +\begin{itemize} + \item Uses \texttt{Smell} interface for data access + \item Inherits from \texttt{BaseRefactorer} +\end{itemize} + +\subsection{Syntax} + +\subsubsection{Exported Constants} +None + +\subsubsection{Exported Access Programs} + +\begin{center} +\begin{tabular}{|p{4cm}|p{5cm}|p{4cm}|p{3cm}|} +\hline +\textbf{Name} & \textbf{In} & \textbf{Out} & \textbf{Exceptions} \\ +\hline +\texttt{\_\_init\_\_} & \texttt{output\_dir: Path} & LongLambdaFunctionRefactorer & None \\ +\hline +\texttt{truncate\_at\_top\_level\_comma} & \texttt{body: str} & \texttt{str} & None \\ +\hline +\texttt{refactor} & \texttt{file\_path: Path, pylint\_smell: Smell, initial\_emissions: float} & None & Logging exceptions \\ +\hline +\end{tabular} +\end{center} + +\subsection{Semantics} + +\subsubsection{State Variables} + +\begin{itemize} + \item \textbf{temp\_dir}: Temporary directory for intermediate refactored files. +\end{itemize} + +\subsubsection{Environment Variables} + +\begin{itemize} + \item \textbf{File system}: Used to read, write, and store temporary and refactored files. + + \item \textbf{Logger}: Logs information during refactoring. +\end{itemize} + +\subsubsection{Assumptions} + +\begin{itemize} + \item Input files are valid Python scripts. + \item Smells identified by \textbf{pylint\_smell} include valid line numbers. + \item Refactored code must pass the provided test suite. +\end{itemize} + +\subsubsection{Access Routine Semantics} + +\paragraph{\texttt{\_\_init\_\_(output\_dir: Path)}} +\begin{itemize} +\item \textbf{Transition}: Initializes the refactorer with the specified output directory. +\item \textbf{Output}: LongLambdaFunctionRefactorer. +\item \textbf{Exception}: None. +\end{itemize} + +\paragraph{\texttt{truncate\_at\_top\_level\_comma(body: str)}} +\begin{itemize} +\item \textbf{Transition}: Truncates the lambda body at the first top-level comma, ignoring commas within nested parentheses, brackets, or braces. +\item \textbf{Output}: Returns the truncated lambda body as a string. +\item \textbf{Exception}: None. +\end{itemize} + +\paragraph{\texttt{refactor(file\_path: Path, pylint\_smell: Smell, initial\_emissions: float)}} +\begin{itemize} + \item \textbf{Transition}: + \begin{itemize} + \item Reads the file at \texttt{file\_path}. + \item Identifies the line with a long lambda function. + \item Refactors the lambda into a normal function. + \item Writes the refactored code to a temporary file. + \end{itemize} + \item \textbf{Output}: None. Refactored file is saved if improvements are validated. + \item \textbf{Exception}: Logs exceptions during file operations or the refactoring process. +\end{itemize} + +\subsubsection{Local Functions} +None + +~\newpage + + + + + + \section{MIS of LongParameterListRefactorer} \label{Module} \wss{Use labels for cross-referencing} From 42e898fed77d6a2b8e4c818393eff86283de0e3d Mon Sep 17 00:00:00 2001 From: Tanveer Brar <92374772+tbrar06@users.noreply.github.com> Date: Fri, 17 Jan 2025 16:07:37 -0500 Subject: [PATCH 21/85] [DESIGN] MIS for User Interfaces Closes #295 (#324) --- docs/Design/SoftArchitecture/MG.tex | 97 +++++++- docs/Design/SoftDetailedDes/MIS.tex | 374 ++++++++++++++++++++++++++++ 2 files changed, 458 insertions(+), 13 deletions(-) diff --git a/docs/Design/SoftArchitecture/MG.tex b/docs/Design/SoftArchitecture/MG.tex index f8a01734..cb3ef7ea 100644 --- a/docs/Design/SoftArchitecture/MG.tex +++ b/docs/Design/SoftArchitecture/MG.tex @@ -249,6 +249,13 @@ \section{Module Hierarchy} \label{SecMH} \item [\refstepcounter{mnum} \mthemnum \label{mLPL}:] LongParameterListRefactorer Module \item [\refstepcounter{mnum} \mthemnum \label{mPyA}:] Pylint Analyzer Module \item [\refstepcounter{mnum} \mthemnum \label{mTest}:] Testing Functionality Module +\item [\refstepcounter{mnum} \mthemnum \label{mExe}:] Plugin Initiator Module +\item [\refstepcounter{mnum} \mthemnum \label{mBac}:] Backend Communicator Module +\item [\refstepcounter{mnum} \mthemnum \label{mDet}:] Smell Detector Module +\item [\refstepcounter{mnum} \mthemnum \label{mRef}:] Smell Refactorer Module +\item [\refstepcounter{mnum} \mthemnum \label{mHig}:] File Highlighter Module +\item [\refstepcounter{mnum} \mthemnum \label{mHov}:] Hover Manager Module +\item [\refstepcounter{mnum} \mthemnum \label{mMan}:] Refactor Manager Module \end{description} @@ -267,22 +274,21 @@ \section{Module Hierarchy} \label{SecMH} & CacheRepeatedCallsRefactorer Module\\ & MakeStaticRefactorer Module\\ & UseListAccumulationRefactorer Module\\ -& ?\\ & UseAGeneratorRefactorer Module\\ -& ?\\ & LongElementChainRefactorer Module\\ & LongParameterListRefactorer Module\\ -& ?\\ -& ?\\ -& ?\\ +& PluginInitiator Module\\ +& BackendCommunicator Module\\ +& SmellDetector Module\\ +& FileHighlighter Module\\ +& HoverManager Module\\ \midrule -\multirow{3}{0.3\textwidth}{Software Decision Module} & {?}\\ -& Measurements Module\\ -& ?\\ \multirow{3}{0.3\textwidth}{Software Decision Module} & Pylint Analyzer Module\\ & Testing Functionality Module\\ & Measurements Module\\ +& SmellRefactorer Module\\ +& RefactorManager Module\\ \bottomrule \end{tabular} @@ -402,6 +408,55 @@ \subsubsection{Long Parameter List Module (\mref{mLPL})} \item[Implemented By:] EcoOptimizer \end{description} +\subsubsection{Plugin Initiator Module (\mref{mExe})} + +% [Record, Library, Abstract Object, or Abstract Data Type] + +\begin{description} + \item[Secrets:] How to initialize the plugin, set up the environment for interaction, and handle configurations for plugin commands. + \item[Services:] Initializes and manages the plugin's setup, enabling its functionality without exposing the underlying initialization logic. + \item[Implemented By:] EcoOptimizer +\end{description} + +\subsubsection{Backend Communicator (\mref{mBac})} + +% [Record, Library, Abstract Object, or Abstract Data Type] + +\begin{description} + \item[Secrets:] How to establish communication between the plugin and Source Code Optimizer, handle requests, and process responses. + \item[Services:] Provides an interface for sending requests to and receiving responses from Source Code Optimizer. Abstracts the communication details from modules within the plugin. + \item[Implemented By:] EcoOptimizer +\end{description} + +\subsubsection{Smell Detector (\mref{mDet})} + +% [Record, Library, Abstract Object, or Abstract Data Type] + +\begin{description} + \item[Secrets:] How to analyze Python code in active VS Code editor by accessing Source Code Optimizer endpoint. + \item[Services:] Detects code smells in Python scripts using Source Code Optimizer and provides structured data for further processing based on received output. + \item[Implemented By:] EcoOptimizer +\end{description} + +\subsubsection{File Highlighter Module (\mref{mHig})} + +% [Record, Library, Abstract Object, or Abstract Data Type] + +\begin{description} + \item[Secrets:] How to identify code regions requiring attention and how to highlight those regions in the file. + \item[Services:] Highlights areas in files that contain code smells and can be refactored, assisting developers in identifying problem areas quickly. + \item[Implemented By:] EcoOptimizer +\end{description} + +\subsubsection{Hover Manager Module (\mref{mHov})} + +% [Record, Library, Abstract Object, or Abstract Data Type] + +\begin{description} + \item[Secrets:] How to detect hover events, retrieve relevant information dynamically, and present tooltips based on hovered elements. + \item[Services:] Manages hover interactions and displays contextual information for elements within the user interface. + \item[Implemented By:] EcoOptimizer +\end{description} \subsection{Software Decision Module} @@ -440,10 +495,10 @@ \subsubsection{Long Lambda Function Refactorer (\mref{mLLF})} do not provide direct interaction with the user. % Changes in these modules are more likely to be motivated by a desire to % improve performance than by externally imposed changes. -\item[Implemented By:] -- +\item[Implemented By:] EcoOptimizer \end{description} -\subsection{Measurements Module} +\subsubsection{Measurements Module (\mref{mM})} \begin{description} \item[Secrets:] How to measure energy consumption and carbon emissions of a given Python program using the CodeCarbon library, including managing temporary directories for storing output, executing the program, and processing the emissions data from a CSV file. @@ -451,9 +506,6 @@ \subsection{Measurements Module} \item[Implemented By:] CodeCarbonEnergyMeter \end{description} -\subsubsection{Etc.} -\subsubsection{Pylint Analyzer Module} - \subsubsection{Pylint Analyzer Module (\mref{mPyA})} \begin{description} @@ -477,6 +529,25 @@ \subsubsection{Testing Functionality Module (\mref{mTest})} \item[Implemented By:] EcoOptimizer \end{description} +\subsubsection{Smell Refactorer Module (\mref{mRef})} + +% [Record, Library, Abstract Object, or Abstract Data Type] + +\begin{description} + \item[Secrets:] How to utilize Source Code Optimizer endpoint for refactoring specific code smells, and how to sanitize received output. + \item[Services:] Refactors code smells in Python scripts using Source Code Optimizer and determines if received output is valid format. + \item[Implemented By:] EcoOptimizer +\end{description} + +\subsubsection{Refactor Manager Module (\mref{mMan})} + +% [Record, Library, Abstract Object, or Abstract Data Type] + +\begin{description} + \item[Secrets:] How to manage the sequence of refactorings, coordinate the application of refactoring techniques, validate results after each step and revert at any stage. + \item[Services:] Decides if refactored result of Python code should be updated in the code editor window. Determines if refactoring should be reverted if needed by user. + \item[Implemented By:] EcoOptimizer +\end{description} \section{Traceability Matrix} \label{SecTM} diff --git a/docs/Design/SoftDetailedDes/MIS.tex b/docs/Design/SoftDetailedDes/MIS.tex index bd5752b1..4ff452be 100644 --- a/docs/Design/SoftDetailedDes/MIS.tex +++ b/docs/Design/SoftDetailedDes/MIS.tex @@ -1411,6 +1411,380 @@ \subsubsection{Local Functions} \item \texttt{\_find\_insert\_line(parent\_node)}: Determines the line to insert the cached variable. \end{itemize} +\section{MIS of Plugin Initiator} + +\subsection{Module} +\texttt{Plugin Initiator} is a module that initializes the VS Code plugin and registers commands for VS Code Plugin. + +\subsection{Uses} +\begin{itemize} + \item \texttt{Smell Detector} to register the command for detecting code smells. + \item \texttt{Smell Refactorer} to register the command for refactoring user's selected code smell. +\end{itemize} + +\subsection{Syntax} + +\textbf{Exported Constants:} None\\ +\noindent \textbf{Exported Access Programs:} +None + + +\subsection{Semantics} + +\subsubsection{State Variables} +None + +\subsubsection{Environment Variables} +\begin{itemize} + \item \textbf{VS CODE API}: Used to register commands. +\end{itemize} + +\subsubsection{Assumptions} +\begin{itemize} +\item The plugin is correctly loaded in VS Code. +\item Source Code Optimizer executable is reachable and operational. +\end{itemize} + +\subsubsection{Access Routine Semantics} +\texttt{activate()} +\begin{itemize} +\item \textbf{Transition}: Activates the plugin and registers commands. +\item \textbf{Output}: None. +\item \textbf{Exception}: None. +\end{itemize} + +\subsubsection{Local Functions} +None + +\section{MIS of Backend Communicator} + +\subsection{Module} +\texttt{BackendCommunicator} handles all communication between the plugin and the backend service. It sends requests for analysis or refactoring and receives results. + +\subsection{Uses} +Source Code Optimizer executable for energy measurement, smell detection and refactoring of applications. + +\subsection{Syntax} + +\textbf{Exported Constants:} None + +\noindent \textbf{Exported Access Programs:}\\ +\begin{tabularx}{\linewidth}{|l|>{\raggedright\arraybackslash}X|l|l|} + \toprule Name & In & Out & Exceptions \\ + \midrule + \texttt{sendRequest} & \texttt{requestType: string, data: any} & Promise & Communication Error \\ + \bottomrule +\end{tabularx} + + +\subsection{Semantics} + +\subsubsection{State Variables} +None + +\subsubsection{Environment Variables} +\begin{itemize} +\item \textbf{NETWORK}: Used for communicating with Source Code Optimizer. +\item \textbf{LOGGER}: Logs any communication errors. +\end{itemize} + +\subsubsection{Assumptions} +\begin{itemize} +\item Source Code Optimizer executable is reachable and operational. +\item Python file with no syntax errors is present in the VS Code editor. +\end{itemize} + +\subsubsection{Access Routine Semantics} +\texttt{sendRequest(requestType: string, data: any)} +\begin{itemize} +\item \textbf{Transition}: Sends the provided request to Source Code Optimizer and receives a response. +\item \textbf{Output}: A promise that resolves with Source Code Optimizer's response. +\item \textbf{Exception}: Logs any errors encountered during communication. +\end{itemize} + +\subsubsection{Local Functions} +None + +\section{MIS of Smell Detector} + +\subsection{Module} +\texttt{Smell Detector} analyzes the active file for code smells and interacts with Source Code Optimizer for detection. + +\subsection{Uses} +\begin{itemize} +\item \texttt{Backend Communicator} for communicating with Source Code Optimizer for smell detection. +\item \texttt{File Highlighter} for highlighting detected smells in the editor. +\end{itemize} + +\subsection{Syntax} + +\textbf{Exported Constants:} None + +\textbf{Exported Access Programs:}\\ +\begin{tabularx}{\linewidth}{|l|>{\raggedright\arraybackslash}X|l|l|} + \toprule Name & In & Out & Exceptions \\ + \midrule + \texttt{detect} & None & None & Active file not found \\ + \bottomrule +\end{tabularx} + +\subsection{Semantics} + +\subsubsection{State Variables} +None + +\subsubsection{Environment Variables} +\begin{itemize} +\item \textbf{EDITOR}: Used to access the active file. +\end{itemize} + +\subsubsection{Assumptions} +\begin{itemize} +\item There is an active Python file with no syntax error in the editor. +\item Source Code Optimizer correctly identifies smells. +\end{itemize} + +\subsubsection{Access Routine Semantics} +\texttt{detect()} +\begin{itemize} +\item \textbf{Transition}: Reads the active file, sends it to Source Code Optimizer for analysis, and highlights detected smells in the editor. +\item \textbf{Output}: None. +\item \textbf{Exception}: Throws an error if no active file is found. +\end{itemize} + +\subsubsection{Local Functions} +None + +\section{MIS of Smell Refactorer} + +\subsection{Module} +\texttt{Smell Refactorer} applies a refactoring to a detected smell. + +\subsection{Uses} +\begin{itemize} +\item \texttt{Backend Communicator} for sending the smell data to Source Code Optimizer for refactoring. +\item \texttt{Refactor Manager} for managing refactoring workflows. +\end{itemize} + +\subsection{Syntax} + +\textbf{Exported Constants:} None + +\textbf{Exported Access Programs:}\\ +\begin{tabularx}{\linewidth}{|l|>{\raggedright\arraybackslash}X|l|l|} + \toprule Name & In & Out & Exceptions \\ + \midrule + \texttt{refactor} & {smell: Smell} & None & Invalid input \\ + \bottomrule +\end{tabularx} + +\subsection{Semantics} + +\subsubsection{State Variables} +None + +\subsubsection{Environment Variables} +\begin{itemize} +\item \textbf{EDITOR}: Used to apply refactored changes. +\end{itemize} + +\subsubsection{Assumptions} +\begin{itemize} +\item The smell data is valid and correctly identifies a refactorable issue. +\end{itemize} + +\subsubsection{Access Routine Semantics} +\texttt{refactor(smell: Smell)} +\begin{itemize} +\item \textbf{Transition}: Sends the smell data to the backend for refactoring and applies the changes in the editor. +\item \textbf{Output}: None. +\item \textbf{Exception}: Logs errors for invalid inputs or failed refactoring. +\end{itemize} + +\subsubsection{Local Functions} +None + +\section{MIS of File Highlighter} + +\subsection{Module} +\texttt{File Highlighter} is a module that manages highlighting of code regions in the VS Code editor. + +\subsection{Uses} +\begin{itemize} +\item \texttt{Smell Detector} for marking detected smells in the editor. +\end{itemize} + +\subsection{Syntax} + +\textbf{Exported Constants:} None + +\noindent \textbf{Exported Access Programs:}\\ +\begin{tabularx}{\linewidth}{|l|>{\raggedright\arraybackslash}X|l|l|} + \toprule Name & In & Out & Exceptions \\ + \midrule + \texttt{highlight} & \texttt{range: range[]} & None & None \\ \hline + \texttt{clear} & \texttt{None} & None & None \\ + \bottomrule +\end{tabularx} + +\subsection{Semantics} + +\subsubsection{State Variables} +\begin{itemize} +\item \texttt{highlightedRanges}: Stores the currently highlighted regions in the editor. +\end{itemize} + +\subsubsection{Environment Variables} +\begin{itemize} +\item \textbf{EDITOR}: Used to apply and clear highlights. +\end{itemize} + +\subsubsection{Assumptions} +\begin{itemize} +\item The VS Code editor is active and accessible. +\item Python file with no syntax errors is currently open in the editor. +\end{itemize} + +\subsubsection{Access Routine Semantics} +\texttt{highlight(ranges: Range[])} +\begin{itemize} +\item \textbf{Transition}: Adds highlights to the specified ranges in the editor. +\item \textbf{Output}: None. +\item \textbf{Exception}: None. +\end{itemize} + +\texttt{clear()} +\begin{itemize} +\item \textbf{Transition}: Removes all highlights from the editor. +\item \textbf{Output}: None. +\item \textbf{Exception}: None. +\end{itemize} + +\subsubsection{Local Functions} +None + +\section{MIS of Hover Manager} + +\subsection{Module} +\texttt{Hover Manager} manages hover effects to display contextual information. + +\subsection{Uses} +\begin{itemize} +\item \texttt{File Highlighter} for providing contextual information about highlighted smells. +\end{itemize} + +\subsection{Syntax} + +\textbf{Exported Constants:} None + +\textbf{Exported Access Programs:}\\ +\begin{tabularx}{\linewidth}{|l|>{\raggedright\arraybackslash}X|l|l|} + \toprule Name & In & Out & Exceptions \\ + \midrule + \texttt{showHover} & \texttt{position: Position} & None & None \\ \hline + \texttt{clearHover} & \texttt{None} & None & None \\ + \bottomrule +\end{tabularx} + +\subsection{Semantics} + +\subsubsection{State Variables} +\begin{itemize} +\item \texttt{currentHover}: Stores the currently displayed hover information. +\end{itemize} + +\subsubsection{Environment Variables} +\begin{itemize} +\item \textbf{EDITOR}: Used to display hover effects. +\end{itemize} + +\subsubsection{Assumptions} +None + +\subsubsection{Access Routine Semantics} +\texttt{showHover(position: Position)} +\begin{itemize} +\item \textbf{Transition}: Displays hover information at the specified position. +\item \textbf{Output}: None. +\item \textbf{Exception}: None. +\end{itemize} + +\texttt{clearHover()} +\begin{itemize} +\item \textbf{Transition}: Clears any active hover information. +\item \textbf{Output}: None. +\item \textbf{Exception}: None. +\end{itemize} + +\subsubsection{Local Functions} +None + +\section{MIS of Refactor Manager} + +\subsection{Module} +\texttt{Refactor Manager} manages the process of applying refactorings to detected smells. + +\subsection{Uses} +\begin{itemize} +\item \texttt{Smell Refactorer} for sending smell data to the backend for refactoring. +\end{itemize} + +\subsection{Syntax} + +\textbf{Exported Constants:} None + +\textbf{Exported Access Programs:}\\ +\begin{tabularx}{\linewidth}{|l|>{\raggedright\arraybackslash}X|l|l|} + \toprule Name & In & Out & Exceptions \\ + \midrule + \texttt{applyRefactor} & \texttt{refactor: Refactor} & None & Validation error \\ \hline + \texttt{previewRefactor} & \texttt{refactor: Refactor} & None & None \\ \hline + \texttt{undoRefactor} & None & None & None \\ + \bottomrule +\end{tabularx} + +\subsection{Semantics} + +\subsubsection{State Variables} +\begin{itemize} +\item \texttt{appliedRefactors}: Stores a history of applied refactors. +\end{itemize} + +\subsubsection{Environment Variables} +\begin{itemize} +\item \textbf{EDITOR}: Used to apply and preview refactors. +\end{itemize} + +\subsubsection{Assumptions} +\begin{itemize} +\item The refactoring data is valid and corresponds to detected smells. +\end{itemize} + +\subsubsection{Access Routine Semantics} +\texttt{applyRefactor(refactor: Refactor)} +\begin{itemize} +\item \textbf{Transition}: Applies the provided refactor to the active editor. +\item \textbf{Output}: None. +\item \textbf{Exception}: Logs validation errors if the refactor cannot be applied. +\end{itemize} + +\texttt{previewRefactor(refactor: Refactor)} +\begin{itemize} +\item \textbf{Transition}: Displays a preview of the refactor in the editor. +\item \textbf{Output}: None. +\item \textbf{Exception}: None. +\end{itemize} + +\texttt{undoRefactor()} +\begin{itemize} +\item \textbf{Transition}: Reverts the most recently applied refactor. +\item \textbf{Output}: None. +\item \textbf{Exception}: None. +\end{itemize} + +\subsubsection{Local Functions} +None + \bibliographystyle {plainnat} \bibliography {../../../refs/References} From 849c474e6c61dbc79200043aa9686fbeaba90222 Mon Sep 17 00:00:00 2001 From: Tanveer Brar <92374772+tbrar06@users.noreply.github.com> Date: Fri, 17 Jan 2025 16:54:43 -0500 Subject: [PATCH 22/85] [DESIGN] MIS for Traceability Matrix(Anticipated Changes) + User Interface (#325) --- docs/Design/SoftArchitecture/MG.tex | 64 ++++++++++++++++++--------- docs/Images/VSPlugin.png | Bin 0 -> 176068 bytes docs/Images/VSPluginCommands.png | Bin 0 -> 35596 bytes docs/Images/VSPluginDetectMode.png | Bin 0 -> 654454 bytes docs/Images/VSPluginRefactorMode.png | Bin 0 -> 650663 bytes 5 files changed, 43 insertions(+), 21 deletions(-) create mode 100644 docs/Images/VSPlugin.png create mode 100644 docs/Images/VSPluginCommands.png create mode 100644 docs/Images/VSPluginDetectMode.png create mode 100644 docs/Images/VSPluginRefactorMode.png diff --git a/docs/Design/SoftArchitecture/MG.tex b/docs/Design/SoftArchitecture/MG.tex index cb3ef7ea..674f6976 100644 --- a/docs/Design/SoftArchitecture/MG.tex +++ b/docs/Design/SoftArchitecture/MG.tex @@ -580,27 +580,21 @@ \section{Traceability Matrix} \label{SecTM} \end{table} \begin{table}[H] -\centering -\begin{tabular}{p{0.2\textwidth} p{0.6\textwidth}} -\toprule -\textbf{AC} & \textbf{Modules}\\ -\midrule -\acref{acHardware} & \mref{mHH}\\ -\acref{acInput} & \mref{mInput}\\ -\acref{acParams} & \mref{mParams}\\ -\acref{acVerify} & \mref{mVerify}\\ -\acref{acOutput} & \mref{mOutput}\\ -\acref{acVerifyOut} & \mref{mVerifyOut}\\ -\acref{acODEs} & \mref{mODEs}\\ -\acref{acEnergy} & \mref{mEnergy}\\ -\acref{acControl} & \mref{mControl}\\ -\acref{acSeqDS} & \mref{mSeqDS}\\ -\acref{acSolver} & \mref{mSolver}\\ -\acref{acPlot} & \mref{mPlot}\\ -\bottomrule -\end{tabular} -\caption{Trace Between Anticipated Changes and Modules} -\label{TblACT} + \centering + \begin{tabular}{p{0.2\textwidth} p{0.6\textwidth}} + \toprule + \textbf{AC} & \textbf{Modules}\\ + \midrule + \acref{acUserInterface} & \mref{mExe}, \mref{mHig} , \mref{mHov}, \mref{mMan} \\ \hline + \acref{acVSCodePlugin} & \mref{mExe} , \mref{mRef}, \mref{mMan} \\ \hline + \acref{acRefactorers} & \mref{mBR}, \mref{mMIMR}, \mref{mSCLR}, \mref{mUGENR}, \mref{mCRC}, \mref{mLEC}, \mref{mLPL} \\ \hline + \acref{acSmell} & \mref{mDet}, \mref{mPyA} \\ \hline + \acref{acAnalyzer} & \mref{mM}, \mref{mPyA}, \mref{mDet} \\ \hline + \acref{acTesting} & \mref{mTest} \\ + \bottomrule + \end{tabular} + \caption{Trace Between Anticipated Changes and Modules} + \label{TblACT} \end{table} \section{Use Hierarchy Between Modules} \label{SecUse} @@ -636,6 +630,34 @@ \section{Use Hierarchy Between Modules} \label{SecUse} \section{User Interfaces} +\begin{figure}[H] + \centering + \includegraphics[width=\textwidth]{../../Images/VSPlugin.png} + \caption{VS Code Plugin Setup} + \label{FigUH} + \end{figure} + + \begin{figure}[H] + \centering + \includegraphics[width=\textwidth]{../../Images/VSPluginCommands.png} + \caption{VS Code Plugin Commands} + \label{FigUH} + \end{figure} + + \begin{figure}[H] + \centering + \includegraphics[width=0.7\textwidth]{../../Images/VSPluginDetectMode.png} + \caption{VS Code Code Analysis Interaction} + \label{FigUH} + \end{figure} + + \begin{figure}[H] + \centering + \includegraphics[width=0.7\textwidth]{../../Images/VSPluginRefactorMode.png} + \caption{VS Code Code Refactoring Interaction(in progress for selected line)} + \label{FigUH} + \end{figure} + \wss{Design of user interface for software and hardware. Attach an appendix if needed. Drawings, Sketches, Figma} diff --git a/docs/Images/VSPlugin.png b/docs/Images/VSPlugin.png new file mode 100644 index 0000000000000000000000000000000000000000..69f1dd0c24b5c8afd2fd3a139c2f430dc311d66d GIT binary patch literal 176068 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

Cu`Q(2bW?AHN+2Qu7gb6#4^&E{4-n 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

$=m&q0iC;_CKDExwgtry z$2*HgzHw1~6k`u#{VNu3o1X=Iki}kkz9)C6aEqF6?h{oNCX=5U289!~ACqS8Jdc-7 z4N&ZXX%#xGxc$ekW+OU0E}?{+Yu*=hdN?fnnF61PRVLAQ8UEaMD&Z?JHb+`0bV}|q zn4zPbdz9S&Fd4DdiCmcSFeVL5bzsyLdJ(uCfpHa4!rOT40OGJnY)1B3b_eKQpQFbU z&Hf>`srF9^AnaIJy6&&=ADf^I?|iB>Ep8vx&F#i=_#7Ayz%fDP5Xw%l+Q&vkm#nJT zUt%R|AG(_$sv{nZn`_|_zo;qU$$M0Yo#GF70xYoM6IU~zs0q*We(^pByP=B|?Qc

bWD_z+` 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