]> git.uio.no Git - ifi-stolz-refaktor.git/blobdiff - thesis/master-thesis-erlenkr.tex
Thesis: writing
[ifi-stolz-refaktor.git] / thesis / master-thesis-erlenkr.tex
index 92e2fa0f68c7292f06a6dab60d8c482494519a33..ce277af26d9eb3e9c3129ff56e2928b95513931d 100644 (file)
@@ -1197,7 +1197,7 @@ sequence. This problem is not trivial to handle in Eclipse.
 \See{hacking_undo_history}
 
 \section{Wishful Thinking}
-
+\todoin{???}
 
 \chapter{Composite Refactorings in Eclipse}
 
@@ -1299,12 +1299,20 @@ For finding the best suitable target the analyzer is using a
 collects all the possible candidates for the refactoring. All the non-candidates 
 is found by an 
 \typewithref{no.uio.ifi.refaktor.analyze.collectors}{UnfixesCollector} that 
-collects all the targets that will give some kind of error if used. The safe 
-prefixes is found by subtracting from the set of candidate prefixes the prefixes 
-that is enclosing any of the unfixes.\todo{Consolidate with section about 
-``Computing safe prefixes''}
-
-\todoin{Continue here\ldots Clean up sections/subsections.}
+collects all the targets that will give some kind of error if used. All prefixes 
+(and unfixes) are represented by a 
+\typewithref{no.uio.ifi.refaktor.extractors}{Prefix}, and they are collected 
+into sets of prefixes. The safe prefixes is found by subtracting from the set of 
+candidate prefixes the prefixes that is enclosing any of the unfixes. A prefix 
+is enclosing an unfix if the unfix is in the set of its sub-prefixes.  As an 
+example, \texttt{``a.b''} is enclosing \texttt{``a''}, as is \texttt{``a''}. The 
+safe prefixes is unified in a \type{PrefixSet}. If a prefix has only one 
+occurrence, and is a simple expression, it is considered unsuitable as a move 
+target. This occurs in statements such as \texttt{``a.foo()''}. For such 
+statements it bares no meaning to extract and move them. It only generates an 
+extra method and the calling of it. 
+
+\todoin{Clean up sections/subsections.}
 
 \subsubsection{The \type{ExtractAndMoveMethodExecutor}}
 If the analysis finds a possible target for the composite refactoring, it is 
@@ -1315,8 +1323,8 @@ It is composed of the two executors known as
 and 
 \typewithref{no.uio.ifi.refaktor.change.executors}{MoveMethodRefactoringExecutor}.  
 The \type{ExtractAndMoveMethodExecutor} is responsible for gluing the two 
-together by feeding the \type{MoveMethodRefactoringExecutor} with the resources 
-needed after executing the extract method refactoring.  
+together by feeding the \type{MoveMethod\-RefactoringExecutor} with the 
+resources needed after executing the extract method refactoring.  
 \See{postExtractExecution}
 
 \subsubsection{The \type{ExtractMethodRefactoringExecutor}}
@@ -1366,16 +1374,7 @@ is provided by the parameter information object.
 \subsection{Finding the IMethod}\label{postExtractExecution}
 \todoin{Rename section. Write.}
 
-\subsection{The ExtractAndMoveMethodPrefixesExtractor Class}
-This extractor extracts properties needed for building the Extract and Move 
-Method refactoring. It searches through the given selection to find safe 
-prefixes, and those prefixes form a base that can be used to compute possible 
-targets for the move part of the refactoring.  It finds both the candidates, in 
-the form of prefixes, and the non-candidates, called unfixes. All prefixes (and 
-unfixes) are represented by a 
-\typewithref{no.uio.ifi.refaktor.extractors}{Prefix}, and they are collected 
-into prefix sets.\typeref{no.uio.ifi.refaktor.extractors.PrefixSet}. 
-
+\subsection{Property collectors}
 The prefixes and unfixes are found by property 
 collectors\typeref{no.uio.ifi.refaktor.extractors.collectors.PropertyCollector}.  
 A property collector follows the visitor pattern\citing{designPatterns} and is 
@@ -1386,33 +1385,144 @@ document object model. The tree consists of nodes of type
 
 \subsubsection{The PrefixesCollector}
 The \typewithref{no.uio.ifi.refaktor.extractors.collectors}{PrefixesCollector} 
-is of type \type{PropertyCollector}. It visits expression 
+finds prefixes that makes up tha basis for calculating move targets for the 
+Extract and Move Method refactoring. It visits expression 
 statements\typeref{org.eclipse.jdt.core.dom.ExpressionStatement} and creates 
 prefixes from its expressions in the case of method invocations. The prefixes 
 found is registered with a prefix set, together with all its sub-prefixes.
 \todo{Rewrite in the case of changes to the way prefixes are found}
 
-\subsubsection{The UnfixesCollector}
+\subsubsection{The UnfixesCollector}\label{unfixes}
 The \typewithref{no.uio.ifi.refaktor.extractors.collectors}{UnfixesCollector} 
-finds unfixes within the selection. An unfix is a name that is assigned to 
-within the selection. The reason that this cannot be allowed, is that the result 
-would be an assignment to the \type{this} keyword, which is not valid in Java.
-
-\subsubsection{Computing Safe Prefixes}
-A safe prefix is a prefix that does not enclose an unfix. A prefix is enclosing 
-an unfix if the unfix is in the set of its sub-prefixes. As an example, 
-\texttt{``a.b''} is enclosing \texttt{``a''}, as is \texttt{``a''}. The safe 
-prefixes is unified in a \type{PrefixSet} and can be fetched calling the 
-\method{getSafePrefixes} method of the 
-\type{ExtractAndMoveMethodPrefixesExtractor}.
+finds unfixes within a selection. That is prefixes that cannot be used as a 
+basis for finding a move target in a refactoring.
+
+An unfix can be a name that is assigned to within a selection. The reason that 
+this cannot be allowed, is that the result would be an assignment to the 
+\type{this} keyword, which is not valid in Java \see{eclipse_bug_420726}.
+
+Prefixes that originates from variable declarations within the same selection 
+are also considered unfixes. This is because when a method is moved, it needs to 
+be called through a variable. If this variable is also within the method that is 
+to be moved, this obviously cannot be done.
+
+Also considered as unfixes are variable references that are of types that is not 
+suitable for moving a methods to. This can be either because it is not 
+physically possible to move the method to the desired class or that it will 
+cause compilation errors by doing so.
+
+If the type binding for a name is not resolved it is considered and unfix. The 
+same applies to types that is only found in compiled code, so they have no 
+underlying source that is accessible to us. (E.g. the \type{java.lang.String} 
+class.)
+
+Interfaces types are not suitable as targets. This is simply because interfaces 
+in java cannot contain methods with bodies. (This thesis does not deal with 
+features of Java versions later than Java 7. Java 8 has interfaces with default 
+implementations of methods.) Neither are local types allowed. This accounts for 
+both local and anonymous classes. Anonymous classes are effectively the same as 
+interface types with respect to unfixes. Local classes could in theory be used 
+as targets, but this is not possible due to limitations of the implementation of 
+the Extract and Move Method refactoring. The problem is that the refactoring is 
+done in two steps, so the intermediate state between the two refactorings would 
+not be legal Java code. In the case of local classes, the problem is that, in 
+the intermediate step, a selection referencing a local class would need to take 
+the local class as a parameter if it were to be extracted to a new method. This 
+new method would need to live in the scope of the declaring class of the 
+originating method. The local class would then not be in the scope of the 
+extracted method, thus bringing the source code into an illegal state. One could 
+imagine that the method was extracted and moved in one operation, without an 
+intermediate state. Then it would make sense to include variables with types of 
+local classes in the set of legal targets, since the local classes would then be 
+in the scopes of the method calls. If this makes any difference for software 
+metrics that measure coupling would be a different discussion.
+
+\begin{listing}
+\begin{multicols}{2}
+\begin{minted}[]{java}
+// Before
+void declaresLocalClass() {
+  class LocalClass {
+    void foo() {}
+    void bar() {}
+  }
+
+  LocalClass inst =
+    new LocalClass();
+  inst.foo();
+  inst.bar();
+}
+\end{minted}
+
+\columnbreak
+
+\begin{minted}[]{java}
+// After Extract Method
+void declaresLocalClass() {
+  class LocalClass {
+    void foo() {}
+    void bar() {}
+  }
+
+  LocalClass inst =
+    new LocalClass();
+  fooBar(inst);
+}
+
+// Intermediate step
+void fooBar(LocalClass inst) {
+  inst.foo();
+  inst.bar();
+}
+\end{minted}
+\end{multicols}
+\caption{When Extract and Move Method tries to use a variable with a local type 
+as the move target, an intermediate step is taken that is not allowed. Here: 
+\type{LocalClass} is not in the scope of \method{fooBar} in its intermediate 
+location.}
+\label{lst:extractMethod_LocalClass}
+\end{listing}
+
+The last class of names that are considered unfixes is names used in null tests.  
+These are tests that reads like this: if \texttt{<name>} equals \var{null} then 
+do something. If allowing variables used in those kinds of expressions as 
+targets for moving methods, we would end up with code containing boolean 
+expressions like \texttt{this == null}, which would not be meaningful, since 
+\var{this} would never be \var{null}.
 
 \subsection{The Prefix Class}
-\todo{?}
+This class exists mainly for holding data about a prefix, such as the expression 
+that the prefix represents and the occurrence count of the prefix within a 
+selection. In addition to this, it has some functionality such as calculating 
+its sub-prefixes and intersecting it with another prefix. The definition of the 
+intersection between two prefixes is a prefix representing the longest common 
+expression between the two.
+
 \subsection{The PrefixSet Class}
+A prefix set holds elements of type \type{Prefix}. It is implemented with the 
+help of a \typewithref{java.util}{HashMap} and contains some typical set 
+operations, but it does not implement the \typewithref{java.util}{Set} 
+interface, since the prefix set does not need all of the functionality a 
+\type{Set} requires to be implemented. In addition It needs some other 
+functionality not found in the \type{Set} interface. So due to the relatively 
+limited use of prefix sets, and that it almost always needs to be referenced as 
+such, and not a \type{Set<Prefix>}, it remains as an ad hoc solution to a 
+concrete problem.
+
+There are two ways adding prefixes to a \type{PrefixSet}. The first is through 
+its \method{add} method. This works like one would expect from a set. It adds 
+the prefix to the set if it does not already contain the prefix. The other way 
+is to \emph{register} the prefix with the set. When registering a prefix, if the 
+set does not contain the prefix, it is just added. If the set contains the 
+prefix, its count gets incremented. This is how the occurrence count is handled.
+
+The prefix set also computes the set of prefixes that is not enclosing any 
+prefixes of another set. This is kind of a set difference operation only for 
+enclosing prefixes.
 
 \subsection{Hacking the Refactoring Undo 
 History}\label{hacking_undo_history}
-\todo{Where to put this section?}
+\todoin{Where to put this section?}
 
 As an attempt to make multiple subsequent changes to the workspace appear as a 
 single action (i.e. make the undo changes appear as such), I tried to alter 
@@ -1486,14 +1596,15 @@ are also return statements in the selection.
 local/anonymous classes. (The referenced variables need to be final and so 
 on\ldots)}
 
-\chapter{Eclipse Bugs}
+\chapter{Eclipse Bugs Found}
 \todoin{Add other things and change headline?}
 
 \section{Eclipse bug 420726: Code is broken when moving a method that is 
-assigning to the parameter that is also the move destination}
+assigning to the parameter that is also the move 
+destination}\label{eclipse_bug_420726}
 This bug\footnote{\url{https://bugs.eclipse.org/bugs/show\_bug.cgi?id=420726}}  
 was found when analyzing what kinds of names that was to be considered as 
-\emph{unfixes}.\todo{refer to unfixes}
+\emph{unfixes} \see{unfixes}.
 
 \subsection{The bug}
 The bug emerges when trying to move a method from one class to another, and when 
@@ -1550,6 +1661,25 @@ warnings), is in the \method{createInlinedMethodInvocation}. When the declaring
 class of the method to move is anonymous, the \var{this} expression in the 
 parameter list is not qualified with the declaring class' (empty) name.
 
+\section{Eclipse bug 429954: Extracting statement with reference to local type 
+breaks code}\label{eclipse_bug_429954}
+The bug\footnote{\url{https://bugs.eclipse.org/bugs/show\_bug.cgi?id=429954}} 
+was discovered when doing some changes to the way unfixes is computed.
+
+\subsection{The bug}
+The problem is that Eclipse is allowing selections that references variables of 
+local types to be extracted. When this happens the code is broken, since the 
+extracted method must take a parameter of a local type that is not in the 
+methods scope. The problem is illustrated in 
+\myref{lst:extractMethod_LocalClass}, but there in another setting.
+
+\subsection{Actions taken}
+There are no actions directly springing out of this bug, since the Extract 
+Method refactoring cannot be meant to be this way. This is handled on the 
+analysis stage of our Extract and Move Method refactoring. So names representing 
+variables of local types is considered unfixes \see{unfixes}.
+\todoin{write more when fixing this in legal statements checker}
+
 \chapter{Related Work}
 
 \section{The compositional paradigm of refactoring}