From 7a2e5c263f493228776e0a22202cdea9ce859212 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 8 Dec 2016 01:27:26 -0200 Subject: [PATCH 001/154] Fixing IOUtil.findAllFiles() acessing a loc's extension in the wrong way. - An extension is a field of a Location. --- src/io/IOUtil.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/io/IOUtil.rsc b/src/io/IOUtil.rsc index 1196ba1..f8eb26c 100644 --- a/src/io/IOUtil.rsc +++ b/src/io/IOUtil.rsc @@ -9,7 +9,7 @@ list[loc] findAllFiles(loc location, str ext) { res = []; list[loc] allFiles; - if((isDirectory(location)) || (extension(location) == "jar") || (extension(location) == "zip")) { + if((isDirectory(location)) || (location.extension == "jar") || (location.extension == "zip")) { allFiles = location.ls; } else { From 8925e843964921c0bc5ba43fbf4c84b22421a9c5 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 8 Dec 2016 01:28:54 -0200 Subject: [PATCH 002/154] Method to find all '.java' files in a location. - Previously there was only a method for 'class'. --- src/lang/java/m3/M3Util.rsc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lang/java/m3/M3Util.rsc b/src/lang/java/m3/M3Util.rsc index 036ed17..fd56a2d 100644 --- a/src/lang/java/m3/M3Util.rsc +++ b/src/lang/java/m3/M3Util.rsc @@ -18,6 +18,10 @@ list[loc] listAllClassFiles(loc location) { return findAllFiles(location, "class"); } +list[loc] listAllJavaFiles(loc location) { + return findAllFiles(location, "java"); +} + /* * computes a list of class names from a classpath, * that is, a list of Jar files. From 0394726e1f171be2ff0ad9fb8054c2d6c0a3cf37 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 8 Dec 2016 01:30:29 -0200 Subject: [PATCH 003/154] Finding all classes that is a direct subclass of Exception. - Still needs to find indirect subclasses of Exception. --- src/ExceptionFinder.rsc | 46 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/ExceptionFinder.rsc diff --git a/src/ExceptionFinder.rsc b/src/ExceptionFinder.rsc new file mode 100644 index 0000000..bbf9c9d --- /dev/null +++ b/src/ExceptionFinder.rsc @@ -0,0 +1,46 @@ +module ExceptionFinder + +import IO; +import lang::java::m3::M3Util; +import lang::java::\syntax::Java18; +import ParseTree; + +set[str] findCheckedExceptions(list[loc] locs) { + set[str] classesToBeVerified = {}; + set[str] checkedExceptionClasses = {"Exception"}; + for(int i <- [0 .. size(locs) - 1]) { + location = locs[i]; + content = readFile(location); + + try { + unit = parse(#CompilationUnit, content); + + bool unitHasSuperClass = false; + str superClassName = ""; + visit(unit) { + case(Superclass) `extends `: { + unitHasSuperClass = true; + superClassName = unparse(id); + } + } + + if (superClassName in checkedExceptionClasses) { + className = retrieveClassNameFromUnit(unit); + checkedExceptionClasses = checkedExceptionClasses + className; + } + } catch: + continue; + + + } + return checkedExceptionClasses; +} + +str retrieveClassNameFromUnit(unit) { + visit(unit) { + case(NormalClassDeclaration) ` class `: + return unparse(id); + } + // Not the best solution. quick workaround + throw "Could not find class name"; +} \ No newline at end of file From 9d75a7f227bed23191428c6eff2197653da15107 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 8 Dec 2016 02:10:21 -0200 Subject: [PATCH 004/154] First implementation on finding indirect subclasses of Exception. --- src/ExceptionFinder.rsc | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/ExceptionFinder.rsc b/src/ExceptionFinder.rsc index bbf9c9d..d6654b8 100644 --- a/src/ExceptionFinder.rsc +++ b/src/ExceptionFinder.rsc @@ -4,9 +4,10 @@ import IO; import lang::java::m3::M3Util; import lang::java::\syntax::Java18; import ParseTree; +import Map; set[str] findCheckedExceptions(list[loc] locs) { - set[str] classesToBeVerified = {}; + map[str, set[str]] superClassesBySubClasses = (); set[str] checkedExceptionClasses = {"Exception"}; for(int i <- [0 .. size(locs) - 1]) { location = locs[i]; @@ -24,10 +25,25 @@ set[str] findCheckedExceptions(list[loc] locs) { } } - if (superClassName in checkedExceptionClasses) { - className = retrieveClassNameFromUnit(unit); - checkedExceptionClasses = checkedExceptionClasses + className; + if (unitHasSuperClass) { + subClassName = retrieveClassNameFromUnit(unit); + if (superClassName in checkedExceptionClasses) { + checkedExceptionClasses += subClassName; + + if (subClassName in superClassesBySubClasses) { + checkedExceptionClasses += superClassesBySubClasses[subClassName]; + delete(superClassesBySubClasses, subClassName); + } + + } else { + if (superClassName in superClassesBySubClasses) { + superClassesBySubClasses[superClassName] += {subClassName}; + } else { + superClassesBySubClasses[superClassName] = {subClassName}; + } + } } + } catch: continue; From 185aaed79f6c4655a4949ae8e2f060145d95386e Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 8 Dec 2016 02:24:15 -0200 Subject: [PATCH 005/154] Starting refactors. Retrieving superClass data in a method. - Instance fields to facilitate definition of new methods. - Using a tuple to return two values. -- Tuple also has the benefit of nice names. --- src/ExceptionFinder.rsc | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/src/ExceptionFinder.rsc b/src/ExceptionFinder.rsc index d6654b8..36941b2 100644 --- a/src/ExceptionFinder.rsc +++ b/src/ExceptionFinder.rsc @@ -6,28 +6,22 @@ import lang::java::\syntax::Java18; import ParseTree; import Map; +private map[str, set[str]] superClassesBySubClasses = (); +private set[str] checkedExceptionClasses = {"Exception"}; + set[str] findCheckedExceptions(list[loc] locs) { - map[str, set[str]] superClassesBySubClasses = (); - set[str] checkedExceptionClasses = {"Exception"}; for(int i <- [0 .. size(locs) - 1]) { location = locs[i]; content = readFile(location); try { unit = parse(#CompilationUnit, content); + + superClass = retrieveSuperClass(unit); - bool unitHasSuperClass = false; - str superClassName = ""; - visit(unit) { - case(Superclass) `extends `: { - unitHasSuperClass = true; - superClassName = unparse(id); - } - } - - if (unitHasSuperClass) { + if (superClass.present) { subClassName = retrieveClassNameFromUnit(unit); - if (superClassName in checkedExceptionClasses) { + if (superClass.name in checkedExceptionClasses) { checkedExceptionClasses += subClassName; if (subClassName in superClassesBySubClasses) { @@ -36,10 +30,10 @@ set[str] findCheckedExceptions(list[loc] locs) { } } else { - if (superClassName in superClassesBySubClasses) { - superClassesBySubClasses[superClassName] += {subClassName}; + if (superClass.name in superClassesBySubClasses) { + superClassesBySubClasses[superClass.name] += {subClassName}; } else { - superClassesBySubClasses[superClassName] = {subClassName}; + superClassesBySubClasses[superClass.name] = {subClassName}; } } } @@ -52,7 +46,19 @@ set[str] findCheckedExceptions(list[loc] locs) { return checkedExceptionClasses; } -str retrieveClassNameFromUnit(unit) { +private tuple[bool present, str name] retrieveSuperClass(unit) { + tuple[bool present, str name] SuperClass = ; + visit(unit) { + case(Superclass) `extends `: { + SuperClass.present = true; + SuperClass.name = unparse(id); + } + } + return SuperClass; +} + + +private str retrieveClassNameFromUnit(unit) { visit(unit) { case(NormalClassDeclaration) ` class `: return unparse(id); From 5da145841fa1dd6d13ffcbaf870f1cd821cd2266 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 8 Dec 2016 02:24:15 -0200 Subject: [PATCH 006/154] Adding comments to help understanding and future refactors. --- src/ExceptionFinder.rsc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ExceptionFinder.rsc b/src/ExceptionFinder.rsc index 36941b2..e6b9b4e 100644 --- a/src/ExceptionFinder.rsc +++ b/src/ExceptionFinder.rsc @@ -21,15 +21,19 @@ set[str] findCheckedExceptions(list[loc] locs) { if (superClass.present) { subClassName = retrieveClassNameFromUnit(unit); + + // If class extends Exception or class that is a subclass of Exception if (superClass.name in checkedExceptionClasses) { checkedExceptionClasses += subClassName; + if (subClassName in superClassesBySubClasses) { + // All subClasses of class extends Exception indirectly checkedExceptionClasses += superClassesBySubClasses[subClassName]; delete(superClassesBySubClasses, subClassName); } - } else { + } else { // Class has a superClass that we don't know yet if it's a sub class of Exception if (superClass.name in superClassesBySubClasses) { superClassesBySubClasses[superClass.name] += {subClassName}; } else { From c2db7856583bc2f2ed774921077933a30e2805a7 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Tue, 14 Mar 2017 23:49:29 -0300 Subject: [PATCH 007/154] Deeper Inheritance Hierarchy and some tests to verify correctness. --- src/ExceptionFinderTest.rsc | 44 +++++++++++++++++++++++++++++++++ testes/exception-hierarchy.zip | Bin 0 -> 13321 bytes 2 files changed, 44 insertions(+) create mode 100644 src/ExceptionFinderTest.rsc create mode 100644 testes/exception-hierarchy.zip diff --git a/src/ExceptionFinderTest.rsc b/src/ExceptionFinderTest.rsc new file mode 100644 index 0000000..7466201 --- /dev/null +++ b/src/ExceptionFinderTest.rsc @@ -0,0 +1,44 @@ +module ExceptionFinderTest + +import lang::java::m3::M3Util; +import IO; +import ExceptionFinder; + +private loc zipFile = |jar:///D:/exception-hierarchy.zip!|; +private list[loc] javaClassesLocations = listAllJavaFiles(zipFile); + +private set[str] checkedExceptions = findCheckedExceptions(javaClassesLocations); + +public test bool shouldReturnExceptionClass() { + return "Exception" in checkedExceptions; +} + +public test bool shouldReturnLevelTwoHierarchyClasses() { + return "AException" in checkedExceptions && "BException" in checkedExceptions && + "CException" in checkedExceptions && "ZException" in checkedExceptions; +} + +public test bool shouldReturnLevelThreeHierarchyClasses() { + return "DException" in checkedExceptions && "FException" in checkedExceptions && + "IException" in checkedExceptions; +} + +public test bool shouldReturnLevelFourHierarchyClasses() { + return "LException" in checkedExceptions && "EException" in checkedExceptions && + "JException" in checkedExceptions && "HException" in checkedExceptions; +} + +public test bool shouldReturnLevelFiveHierarchyClasses() { + return "GException" in checkedExceptions && "KException" in checkedExceptions; +} + +public test bool shouldReturnLevelSixHierarchyClasses() { + return "MException" in checkedExceptions; +} + +public test bool shouldNotReturnUncheckedExceptions() { + return "RuntimeException" notin checkedExceptions && + "UncheckedLevelFourRuntimeException" notin checkedExceptions && + "UncheckedLevelThreeRuntimeException" notin checkedExceptions && + "UncheckedLevelTwoRuntimeException" notin checkedExceptions; +} \ No newline at end of file diff --git a/testes/exception-hierarchy.zip b/testes/exception-hierarchy.zip new file mode 100644 index 0000000000000000000000000000000000000000..303af0b740becdff738aa8ffb3b1a7d55c61d426 GIT binary patch literal 13321 zcmd5?c{o(<8y?vP6N6+aq3kiEMJbYP>|5D>+9W1B6H_Ql)@-G0B}-Zel@uY7EG7He zg0f|)^z~_xl=#i5Pjk*0zR%&GPFL5ZtLr-V{obDQKKFCKudyCI!!i^ajYbKkxay)n zk09k|f|m`EM0Rj<)pj7dTf5uXd*g97&ek3tBx|z0Z?qm;g&a1xiFN8k%)Q;EW6jd5 zd6r#IdvdMHHmjvb$~$c8SdV02_rXxNj>LTbt*>8)J(W`DA5l9&(5}!Xm_14u%uLDk zyZJ;vWT^4U3%8pYAC72ur(P~yow&}9G19e9{ZW~Y^=pE_ZaUT*jwf5+#xYLjZ=zDYc!&6b zO=1e)4Z`b8U>|;0xgT*FchVptNKvim z?NN&!oX2ZPqoo5~)nae*x*iLEN*ZTY*3FU&Ij5SbCGVN5Ykq9&s`b1<$fX2X?4X@`i4WQ-%sW=B-W(Xd#~-dV-f811=o4zVxXtb zL6h))&8M=ubS75y0;5mc7&=ARiofg_TAK58Y9&$DR${lu)#|hFP;8%?bsjz0LHN$z zES`sXCcL4rwK?_6ZG7HM%?p4;bz=vj?^6UYUjnWdAJ_-8b#{pkIJn}8GvAR1-o~D2 z<3zN@@B001{raMO4a*HHjIqh->G4aRzV6_2eO&JOA@qaV=XO&0=ia|QJbzHxd44CR z>|uB?z0duHt^)9fcmbFrI!0bwgb|U+l{&b>0}_% z^)FI74VZL_V{XrsnV6Wkndpu%iEA=Vv_}lI2gcM-mK^vo5Y;~Lu6@}L4PRc1bCQbm zY&gOx5+MrXyeZK;QS3+*re5H@breRXaY8C<52hZItc1CaagM@FDkpkp`K900$s&k^ z>ukx2!l)@v)P!%b4ksiEE1RB97hRKg?u=^7iR0I<^Ya%4e$tDKF?qRO_1jm@okuOh ziQ$+CjLKEH39o z(_ianrtIX*=$iObjrA1O6dZtv_Ol<1cH1F7?jUAy! zAAU=DWgPPA!-cmM_w5As8Zg-H=ZfWEF~53G`1wtT`c*RRNtqQQU(e`x6@UMq`zDJz zdG1x0O|Olq5i@$rE~VV8PrzzSUwO-2Vp&|b(MbQpaE~G0&G9Byaa>g#Y0k3hdAR|_`Empq;V;#ZV*4(#u+n|ltslR2l+MRAgqu~L z=hwC-={1q`-ly_ zk)xBY$Yg>9H-{fei16IJWyZ3dcs0y>{Meoed+fK8&6DPxN?nq92l9qOblYFGS&sE_ z9mOBLYL=as{!Jd;{rF(PO77&Ou5-PH9~qfR&F|A#qOqErUcLDu-*+G@CeJ{nEy8dh`^_7Riod zQ0!q|e{bwN(U&Lnr~6p4p)aJB#6eWOgmoHl?qb*j**^CABW+ug53evK-am zm*<}*!#(l*%l%(ah}q0f`otqdXHB=m?mG{=k{w)#zhCkz9Z4}VFse|& z`l{<);|Uq%P?$KB%gen{0LNgslv(wC-Fh91x`eoduZ2oyNTbZ7moaUtdGP{vv70~b z>+Y(5cfa5Q>V5Oa9c#!Fdq1t;oV7P3GLQ^J4n;T3O~bro@ba zo=Zv92MJzbQ{Io(i10<`c-z-b@{+s!I8d31>ipLI6a^C@)2l5^W3xqRY-;aLB+ex=C4%}#+u)9@)PVufIIu0#8A8q@~IeITgwMp|DRV5BIl++xHO?>&RTH^Rx zvie3ez2B1(TvT3CQT|rqkNUc=hkC?H2Avaz>f2hEAAI<#R4Le~NV)1q|I|^I@|0T{ zd|V|{6Un{NFJjhsDY#w?Ki;epHK=oU7fIP9GK!_N$|1hN%vE|y@pELmGkSB4e_4^3 z21ic4d{2_2^)#w!Ft$@VS@o0_kEoOuTWCf9dHRM(&y}S*Z7QOC?dlv7fj5K#+S@w2 zbIelQ0EsWsHC*YX2zdTqB{o@{#GY<*34F`2QV#3;>C#)GnYIF;=VjX#@ z7T;L^THrIP`XOov&{qTLmsyLiO&vo?Uy#yWdQC2u+)#nVARo8j_NzWo-tKV(lATXc;(nGLf6BG+EQ zm<>=Q^n!>C&r7$=F0zNa&41*jj@C!4*J|rG8tNOFY2VN`l$EThZ(93QuTk5e(a_-5 z&|v?dw4_08jlQ{dqmB&DJj^{rYKb&nr$JB3TqVpjDDK%ucen)k2jwsI zAON0EDk35Z$tVAvYKvYz4OtR7M2g-~au%|7ggxdO6e>V*Qpv&-L8N3siQodr9-@*Z zX`s!5+J8%{S*#vFpfCkG0+lU1i9^a3l*BE7?O_mGRS4TvwW{lB*}@|*q-;SE*aFyk zg4hxuY%2>Z#c0{WqbHro<+KLn$5vOGf z&lZreg=7o=#r8Jsb_=RoXm9W{43wtbZsEf`QnH|7egR}XsAWrnmhGd$h&ozn;X@5l zwxA&zIonYZh^;!L5PVcj*lF3qhgW25A;ar`u`Qr21kjcMErbHy;X>L%c)qCp3o6c1V%#W&tK+KM~^AQ&d1Z-7h@w`9nT1(LMncWmW5d!fP@cC$t8FZd&n|(f7 z_~L?Xm!)Sg&8+S-y#cVga^u~p(HCzE*!s;ZE#u3Q?Us~f1^?^Pc2fTL_hd{Rujjk8 zS>}>OEG%xAd1hH;`Ua_=j`hLmOv;xPd~w%4+|S>bGrL@w1%WBz^{;iaex^He1!lwy`?^m3`lSw6V1=-UtlC)00AGn zLy^)Mks*P`5gH_5cmSVOLy@|ekRgFa2^u88_=C@Pp-5OXG9=I#K!XIBcJP@f6iJf> z84}3C(;xw7tl)D*D3T8=G9-}wra=PCGWhTfigcR|84}1k(;xvx7kpp^MH96K?0l| zICh63J>*1!1o3$^NPy!7N7YcIX)a_)@K7JT?*Wzy9M}T3gZjuXn-3BqgGIAe!1#dk zOduGhK8ZYwVKBQ5nw0`L?E`!z^_g70C Date: Wed, 15 Mar 2017 02:05:53 -0300 Subject: [PATCH 008/154] Testing a recursive like solution. Still not working as expected. --- src/ExceptionFinder.rsc | 35 ++++++++++++++++++++++++++++++----- src/ExceptionFinderTest.rsc | 3 ++- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/ExceptionFinder.rsc b/src/ExceptionFinder.rsc index e6b9b4e..b96a661 100644 --- a/src/ExceptionFinder.rsc +++ b/src/ExceptionFinder.rsc @@ -4,13 +4,14 @@ import IO; import lang::java::m3::M3Util; import lang::java::\syntax::Java18; import ParseTree; +import Set; import Map; private map[str, set[str]] superClassesBySubClasses = (); private set[str] checkedExceptionClasses = {"Exception"}; set[str] findCheckedExceptions(list[loc] locs) { - for(int i <- [0 .. size(locs) - 1]) { + for(int i <- [0 .. size(locs)]) { location = locs[i]; content = readFile(location); @@ -22,18 +23,24 @@ set[str] findCheckedExceptions(list[loc] locs) { if (superClass.present) { subClassName = retrieveClassNameFromUnit(unit); + //println("Current class (subClass): " + subClassName); + //println("Super class: " + superClass.name); + //println("checkedExceptionClasses: " + toString(checkedExceptionClasses)); + //println("superClassesBySubClasses: " + toString(superClassesBySubClasses)); + //println(); + // If class extends Exception or class that is a subclass of Exception if (superClass.name in checkedExceptionClasses) { checkedExceptionClasses += subClassName; - if (subClassName in superClassesBySubClasses) { - // All subClasses of class extends Exception indirectly - checkedExceptionClasses += superClassesBySubClasses[subClassName]; - delete(superClassesBySubClasses, subClassName); + addAllSubClassesOf(subClassName); } } else { // Class has a superClass that we don't know yet if it's a sub class of Exception + + // TODO: check if superClass is already a sub class mapped to another superclass + if (superClass.name in superClassesBySubClasses) { superClassesBySubClasses[superClass.name] += {subClassName}; } else { @@ -47,6 +54,7 @@ set[str] findCheckedExceptions(list[loc] locs) { } + println(checkedExceptionClasses); return checkedExceptionClasses; } @@ -69,4 +77,21 @@ private str retrieveClassNameFromUnit(unit) { } // Not the best solution. quick workaround throw "Could not find class name"; +} + +private void addAllSubClassesOf(str subClassName) { + directSubClasses = superClassesBySubClasses[subClassName]; + checkedExceptionClasses += directSubClasses; + superClassesBySubClasses = delete(superClassesBySubClasses, subClassName); + + //println(); + println("subClassName: " + subClassName); + //println("directSubClasses: " + toString(directSubClasses)); + //println(); + + list[str] directSubClassesList = toList(directSubClasses); + println("directSubClasses: " + toString(directSubClassesList)); + for(int i <- [0 .. size(directSubClassesList)]) { + addAllSubClassesOf(directSubClassesList[i]); + } } \ No newline at end of file diff --git a/src/ExceptionFinderTest.rsc b/src/ExceptionFinderTest.rsc index 7466201..d619e8a 100644 --- a/src/ExceptionFinderTest.rsc +++ b/src/ExceptionFinderTest.rsc @@ -29,7 +29,8 @@ public test bool shouldReturnLevelFourHierarchyClasses() { } public test bool shouldReturnLevelFiveHierarchyClasses() { - return "GException" in checkedExceptions && "KException" in checkedExceptions; + return "GException" in checkedExceptions && "KException" in checkedExceptions && + "NException" in checkedExceptions; } public test bool shouldReturnLevelSixHierarchyClasses() { From 5e3cec9beef6d01264c8ada6bb416515aaba5d4e Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 15 Mar 2017 12:24:48 -0300 Subject: [PATCH 009/154] Finally working. - An error was silently finishing the loop. -- We had to check if the key was present in the map. --- src/ExceptionFinder.rsc | 52 ++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/src/ExceptionFinder.rsc b/src/ExceptionFinder.rsc index b96a661..6fb87d4 100644 --- a/src/ExceptionFinder.rsc +++ b/src/ExceptionFinder.rsc @@ -34,6 +34,7 @@ set[str] findCheckedExceptions(list[loc] locs) { checkedExceptionClasses += subClassName; if (subClassName in superClassesBySubClasses) { + println(); addAllSubClassesOf(subClassName); } @@ -79,19 +80,44 @@ private str retrieveClassNameFromUnit(unit) { throw "Could not find class name"; } -private void addAllSubClassesOf(str subClassName) { - directSubClasses = superClassesBySubClasses[subClassName]; - checkedExceptionClasses += directSubClasses; - superClassesBySubClasses = delete(superClassesBySubClasses, subClassName); +private void addAllSubClassesOf(str className) { + set[str] allSubClasses = {}; + allSubClasses += superClassesBySubClasses[className]; + println("className: " + className); + println("allSubClasses (pre-while): " + toString(allSubClasses)); + println("checkedExceptionClasses (pre-while): " + toString(checkedExceptionClasses)); + while(!isEmpty(allSubClasses)) { + println(); + currentClass = getOneFrom(allSubClasses); + println("currentClass: " + currentClass); + checkedExceptionClasses += currentClass; + println("checkedExceptionClasses: " + toString(checkedExceptionClasses)); + allSubClasses -= currentClass; + println("allSubClasses (removing current): " + toString(allSubClasses)); + + if (currentClass in superClassesBySubClasses) { + directSubClasses = superClassesBySubClasses[currentClass]; + println("directSubClasses: " + toString(directSubClasses)); + allSubClasses += directSubClasses; + println("allSubClasses (adding direct sub: " + toString(allSubClasses)); + } + + superClassesBySubClasses = delete(superClassesBySubClasses, currentClass); + } - //println(); - println("subClassName: " + subClassName); - //println("directSubClasses: " + toString(directSubClasses)); - //println(); - list[str] directSubClassesList = toList(directSubClasses); - println("directSubClasses: " + toString(directSubClassesList)); - for(int i <- [0 .. size(directSubClassesList)]) { - addAllSubClassesOf(directSubClassesList[i]); - } + ////println(); + //println("subClassName: " + subClassName); + ////println("directSubClasses: " + toString(directSubClasses)); + ////println(); + // + //list[str] directSubClassesList = toList(directSubClasses); + //println("directSubClasses: " + toString(directSubClassesList)); + //for(int i <- [0 .. size(directSubClassesList)]) { + // addAllSubClassesOf(directSubClassesList[i]); + //} +} + +private set[str] retrieveDirectSubClasses(str className) { + return superClassesBySubClasses[className]; } \ No newline at end of file From e32af3807ab08cacbf68ea18794869f97b4b882d Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 15 Mar 2017 12:27:50 -0300 Subject: [PATCH 010/154] Iterative version of checking exception hierarchy. - Removing unecessary comments and debug prints. --- src/ExceptionFinder.rsc | 42 ++++++----------------------------------- 1 file changed, 6 insertions(+), 36 deletions(-) diff --git a/src/ExceptionFinder.rsc b/src/ExceptionFinder.rsc index 6fb87d4..c7fbcd5 100644 --- a/src/ExceptionFinder.rsc +++ b/src/ExceptionFinder.rsc @@ -22,26 +22,16 @@ set[str] findCheckedExceptions(list[loc] locs) { if (superClass.present) { subClassName = retrieveClassNameFromUnit(unit); - - //println("Current class (subClass): " + subClassName); - //println("Super class: " + superClass.name); - //println("checkedExceptionClasses: " + toString(checkedExceptionClasses)); - //println("superClassesBySubClasses: " + toString(superClassesBySubClasses)); - //println(); - + // If class extends Exception or class that is a subclass of Exception if (superClass.name in checkedExceptionClasses) { checkedExceptionClasses += subClassName; if (subClassName in superClassesBySubClasses) { - println(); addAllSubClassesOf(subClassName); } - } else { // Class has a superClass that we don't know yet if it's a sub class of Exception - - // TODO: check if superClass is already a sub class mapped to another superclass - + } else { // Class has a superClass that we don't know yet if it's a sub class of Exception if (superClass.name in superClassesBySubClasses) { superClassesBySubClasses[superClass.name] += {subClassName}; } else { @@ -55,7 +45,6 @@ set[str] findCheckedExceptions(list[loc] locs) { } - println(checkedExceptionClasses); return checkedExceptionClasses; } @@ -82,40 +71,21 @@ private str retrieveClassNameFromUnit(unit) { private void addAllSubClassesOf(str className) { set[str] allSubClasses = {}; - allSubClasses += superClassesBySubClasses[className]; - println("className: " + className); - println("allSubClasses (pre-while): " + toString(allSubClasses)); - println("checkedExceptionClasses (pre-while): " + toString(checkedExceptionClasses)); + allSubClasses += retrieveDirectSubClasses(className); while(!isEmpty(allSubClasses)) { - println(); currentClass = getOneFrom(allSubClasses); - println("currentClass: " + currentClass); + checkedExceptionClasses += currentClass; - println("checkedExceptionClasses: " + toString(checkedExceptionClasses)); + allSubClasses -= currentClass; - println("allSubClasses (removing current): " + toString(allSubClasses)); if (currentClass in superClassesBySubClasses) { - directSubClasses = superClassesBySubClasses[currentClass]; - println("directSubClasses: " + toString(directSubClasses)); + directSubClasses = retrieveDirectSubClasses(currentClass); allSubClasses += directSubClasses; - println("allSubClasses (adding direct sub: " + toString(allSubClasses)); } superClassesBySubClasses = delete(superClassesBySubClasses, currentClass); } - - - ////println(); - //println("subClassName: " + subClassName); - ////println("directSubClasses: " + toString(directSubClasses)); - ////println(); - // - //list[str] directSubClassesList = toList(directSubClasses); - //println("directSubClasses: " + toString(directSubClassesList)); - //for(int i <- [0 .. size(directSubClassesList)]) { - // addAllSubClassesOf(directSubClassesList[i]); - //} } private set[str] retrieveDirectSubClasses(str className) { From 54c14ac5b231d70b07616e13e433a073317812b8 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 15 Mar 2017 12:27:50 -0300 Subject: [PATCH 011/154] Refactoring. - Extracting key membership logic in own method. - Changing old 'for's to a more for-each syntax like. --- src/ExceptionFinder.rsc | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/src/ExceptionFinder.rsc b/src/ExceptionFinder.rsc index c7fbcd5..dc7911d 100644 --- a/src/ExceptionFinder.rsc +++ b/src/ExceptionFinder.rsc @@ -10,9 +10,8 @@ import Map; private map[str, set[str]] superClassesBySubClasses = (); private set[str] checkedExceptionClasses = {"Exception"}; -set[str] findCheckedExceptions(list[loc] locs) { - for(int i <- [0 .. size(locs)]) { - location = locs[i]; +set[str] findCheckedExceptions(list[loc] locations) { + for(location <- locations) { content = readFile(location); try { @@ -70,24 +69,17 @@ private str retrieveClassNameFromUnit(unit) { } private void addAllSubClassesOf(str className) { - set[str] allSubClasses = {}; - allSubClasses += retrieveDirectSubClasses(className); - while(!isEmpty(allSubClasses)) { - currentClass = getOneFrom(allSubClasses); + directSubClasses = getAllDirectSubClassesOf(className); + checkedExceptionClasses += directSubClasses; + superClassesBySubClasses = delete(superClassesBySubClasses, className); - checkedExceptionClasses += currentClass; - - allSubClasses -= currentClass; - - if (currentClass in superClassesBySubClasses) { - directSubClasses = retrieveDirectSubClasses(currentClass); - allSubClasses += directSubClasses; - } - - superClassesBySubClasses = delete(superClassesBySubClasses, currentClass); - } + for (str className <- directSubClasses) + addAllSubClassesOf(className); } -private set[str] retrieveDirectSubClasses(str className) { - return superClassesBySubClasses[className]; +private set[str] getAllDirectSubClassesOf(str className) { + directSubClasses = {}; + if (className in superClassesBySubClasses) + directSubClasses = superClassesBySubClasses[className]; + return directSubClasses; } \ No newline at end of file From cf4d969604f34114168a8b4825aec48778eba31f Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 15 Mar 2017 12:27:50 -0300 Subject: [PATCH 012/154] Removing unecessary parathensis --- src/io/IOUtil.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/io/IOUtil.rsc b/src/io/IOUtil.rsc index f8eb26c..175ba6a 100644 --- a/src/io/IOUtil.rsc +++ b/src/io/IOUtil.rsc @@ -9,7 +9,7 @@ list[loc] findAllFiles(loc location, str ext) { res = []; list[loc] allFiles; - if((isDirectory(location)) || (location.extension == "jar") || (location.extension == "zip")) { + if(isDirectory(location) || (location.extension == "jar") || (location.extension == "zip")) { allFiles = location.ls; } else { From d370ca59eb8aca3ad1751ad875c1a11beec1e42d Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 15 Mar 2017 12:27:50 -0300 Subject: [PATCH 013/154] Updating zip with classes being used for tests. --- testes/exception-hierarchy.zip | Bin 13321 -> 14015 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/testes/exception-hierarchy.zip b/testes/exception-hierarchy.zip index 303af0b740becdff738aa8ffb3b1a7d55c61d426..494ad321797cf286eddec1838b85ad20c8eb22fe 100644 GIT binary patch delta 788 zcmeCo*q^&WosW4pZ~o-{+_v?8t`*6t1tppJd3wn?iN(dOetYu{CGglx-fwn+?JKL+ zwrL9^Z#cvTSi9;deAAbo_Jhkez(ZjD(Uv0zm_Gz?sEf=9$bI?7dj3*tneu7|SrgkU z9P9U7+jGKqmX5P+s_kRX6^9O9cm0}h-`F)=_~6@_N1n`QdHuH5XT$H8EwvF9^*IL` zy*ZR7e^~IN*HU_A#krR08dtOI!e(mzoS*SLc(cluMfE|Yoc|1Tjn3X*_J=!fdB6PD zpbW=F3v?z;<7k?>wvBSKO+} zoTcG;)>|{|gCj?1^OftLiWq@LuybVTW**#JD7T%96BvkIU<)S8tBX!{)6@f-Fi}l< zvWBJ{W6f25l{-b7DZI&E!a9vB~Ro1Si|;$T1m8 zfQ8;DivWf6nWjljZj{oQ%%f|`WG@9|>P;>MGT%U$6V$jT@75ET{8Lwsan|HUJ^jh+ zrT8cB*W;O-q$kJZAp=&wLC=!u8-zK56QbTkUyf;sELe7@3`E0Rpiqz;Sm+NoL=~HX z920{)ScpfHd$NKY3&>~=P%wc4Z8D>t7}GkiJfq*_je1g(^MM*-6ecGc>H)*al8I9h z%q)@= hU>LbDm8-(JZT55>GvZaJ5=(H4p zwKoI~(G(61(NIHEU@h&AErwn1_1@(>zjHn~d`}ydwfjV0t*8`L6crWwQHCqUfkG&Z zQp8>R2`8-B)+k1_j^V-qv*TN%WI;jQqC?Xs$(bs~cEo{Q=0r`WIf+j=Zuz=+ku3XBj_Rl;Z1^-(Y$YkN25@UI zRDue=3_BVeJxJ8F$ka@Vl9ixHHHK}drWkSe3;CCtAayxTh2(zOpk#A^yQ}69Zj2xlI Ef1+WVRR910 From bbb1bc07b2833460e4a9c2364c93ec5a8e9fae27 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 15 Mar 2017 12:27:50 -0300 Subject: [PATCH 014/154] Extracting methods with more meaningful names. --- src/ExceptionFinder.rsc | 78 ++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/src/ExceptionFinder.rsc b/src/ExceptionFinder.rsc index dc7911d..b26f558 100644 --- a/src/ExceptionFinder.rsc +++ b/src/ExceptionFinder.rsc @@ -10,55 +10,41 @@ import Map; private map[str, set[str]] superClassesBySubClasses = (); private set[str] checkedExceptionClasses = {"Exception"}; -set[str] findCheckedExceptions(list[loc] locations) { - for(location <- locations) { - content = readFile(location); - - try { - unit = parse(#CompilationUnit, content); - - superClass = retrieveSuperClass(unit); - - if (superClass.present) { - subClassName = retrieveClassNameFromUnit(unit); +set[str] findCheckedExceptions(list[loc] javaFilesLocations) { + for(javaFileLocation <- javaFilesLocations) { + javaFileContent = readFile(javaFileLocation); + tryToNavigateClassesFindingSubClassesOfException(javaFileContent); + } + return checkedExceptionClasses; +} - // If class extends Exception or class that is a subclass of Exception - if (superClass.name in checkedExceptionClasses) { - checkedExceptionClasses += subClassName; - - if (subClassName in superClassesBySubClasses) { - addAllSubClassesOf(subClassName); - } - - } else { // Class has a superClass that we don't know yet if it's a sub class of Exception - if (superClass.name in superClassesBySubClasses) { - superClassesBySubClasses[superClass.name] += {subClassName}; - } else { - superClassesBySubClasses[superClass.name] = {subClassName}; - } - } - } - +private void tryToNavigateClassesFindingSubClassesOfException(str javaFileContent) { + try { + compilationUnit = parse(#CompilationUnit, javaFileContent); + handleIfClassHasASuperClass(compilationUnit); } catch: continue; - - +} + +private void handleIfClassHasASuperClass(unit) { + superClass = retrieveSuperClass(unit); + if (superClass.present) { + className = retrieveClassNameFromUnit(unit); + handleIfClassIsAnException(className, superClass.name); } - return checkedExceptionClasses; } private tuple[bool present, str name] retrieveSuperClass(unit) { - tuple[bool present, str name] SuperClass = ; + tuple[bool present, str name] superClass = ; visit(unit) { case(Superclass) `extends `: { - SuperClass.present = true; - SuperClass.name = unparse(id); + superClass.present = true; + superClass.name = unparse(id); } } - return SuperClass; + return superClass; } - private str retrieveClassNameFromUnit(unit) { visit(unit) { case(NormalClassDeclaration) ` class `: @@ -68,6 +54,26 @@ private str retrieveClassNameFromUnit(unit) { throw "Could not find class name"; } +private void handleIfClassIsAnException(str className, str superClassName) { + if (superClassName in checkedExceptionClasses) + addClassAndItsSubClassesAsExceptions(className); + else + addClassAsASubClassOfItsSuperClass(className, superClassName); +} + +private void addClassAndItsSubClassesAsExceptions(str className) { + checkedExceptionClasses += className; + if (className in superClassesBySubClasses) + addAllSubClassesOf(className); +} + +private void addClassAsASubClassOfItsSuperClass(str className, str superClassName) { + if (superClassName in superClassesBySubClasses) + superClassesBySubClasses[superClassName] += {className}; + else + superClassesBySubClasses[superClassName] = {className}; +} + private void addAllSubClassesOf(str className) { directSubClasses = getAllDirectSubClassesOf(className); checkedExceptionClasses += directSubClasses; From a0320825720695193c4f399623df0251df8a0282 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 15 Mar 2017 16:00:39 -0300 Subject: [PATCH 015/154] Git ignore --- bin/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 bin/.gitignore diff --git a/bin/.gitignore b/bin/.gitignore new file mode 100644 index 0000000..c8bcf3e --- /dev/null +++ b/bin/.gitignore @@ -0,0 +1 @@ +/ExceptionFinder.rsc From 816549a297e3808d80a156136e1ca34a3f86af71 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 15 Mar 2017 12:27:50 -0300 Subject: [PATCH 016/154] Capturing classes with more than one class modifier. - Forgot a '*', meaning that more than one class modifier would not pattern match. --- src/ExceptionFinder.rsc | 4 ++-- src/ExceptionFinderTest.rsc | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ExceptionFinder.rsc b/src/ExceptionFinder.rsc index b26f558..6b4697b 100644 --- a/src/ExceptionFinder.rsc +++ b/src/ExceptionFinder.rsc @@ -47,7 +47,7 @@ private tuple[bool present, str name] retrieveSuperClass(unit) { private str retrieveClassNameFromUnit(unit) { visit(unit) { - case(NormalClassDeclaration) ` class `: + case(NormalClassDeclaration) ` class `: return unparse(id); } // Not the best solution. quick workaround @@ -57,7 +57,7 @@ private str retrieveClassNameFromUnit(unit) { private void handleIfClassIsAnException(str className, str superClassName) { if (superClassName in checkedExceptionClasses) addClassAndItsSubClassesAsExceptions(className); - else + else addClassAsASubClassOfItsSuperClass(className, superClassName); } diff --git a/src/ExceptionFinderTest.rsc b/src/ExceptionFinderTest.rsc index d619e8a..e703673 100644 --- a/src/ExceptionFinderTest.rsc +++ b/src/ExceptionFinderTest.rsc @@ -42,4 +42,8 @@ public test bool shouldNotReturnUncheckedExceptions() { "UncheckedLevelFourRuntimeException" notin checkedExceptions && "UncheckedLevelThreeRuntimeException" notin checkedExceptions && "UncheckedLevelTwoRuntimeException" notin checkedExceptions; +} + +public test bool shouldReturnAbstractCheckedException() { + return "AbstractCheckedException" in checkedExceptions; } \ No newline at end of file From cd58a6a098698cd90d1f1fbc220bfbfdf177f6fe Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Fri, 17 Mar 2017 01:26:47 -0300 Subject: [PATCH 017/154] Initializing classes found when method is called. - Initializing at module level didn't reset the state on future calls. --- src/ExceptionFinder.rsc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/ExceptionFinder.rsc b/src/ExceptionFinder.rsc index 6b4697b..a8a2b5a 100644 --- a/src/ExceptionFinder.rsc +++ b/src/ExceptionFinder.rsc @@ -7,10 +7,11 @@ import ParseTree; import Set; import Map; -private map[str, set[str]] superClassesBySubClasses = (); -private set[str] checkedExceptionClasses = {"Exception"}; +private map[str, set[str]] superClassesBySubClasses; +private set[str] checkedExceptionClasses; set[str] findCheckedExceptions(list[loc] javaFilesLocations) { + initializeClassesFound(); for(javaFileLocation <- javaFilesLocations) { javaFileContent = readFile(javaFileLocation); tryToNavigateClassesFindingSubClassesOfException(javaFileContent); @@ -18,6 +19,11 @@ set[str] findCheckedExceptions(list[loc] javaFilesLocations) { return checkedExceptionClasses; } +private void initializeClassesFound() { + superClassesBySubClasses = (); + checkedExceptionClasses = {"Exception"}; +} + private void tryToNavigateClassesFindingSubClassesOfException(str javaFileContent) { try { compilationUnit = parse(#CompilationUnit, javaFileContent); From 5386e472f93ed01d050640fda839eba77a09ce74 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Fri, 17 Mar 2017 01:44:43 -0300 Subject: [PATCH 018/154] Map has to be instantiated with '()'. - Don't know why, but errors occur when don't. --- src/ExceptionFinder.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ExceptionFinder.rsc b/src/ExceptionFinder.rsc index a8a2b5a..aeb60c8 100644 --- a/src/ExceptionFinder.rsc +++ b/src/ExceptionFinder.rsc @@ -7,8 +7,8 @@ import ParseTree; import Set; import Map; -private map[str, set[str]] superClassesBySubClasses; -private set[str] checkedExceptionClasses; +private map[str, set[str]] superClassesBySubClasses = (); +private set[str] checkedExceptionClasses = {"Exception"}; set[str] findCheckedExceptions(list[loc] javaFilesLocations) { initializeClassesFound(); From f398ddfade21c8145571600bc907e4aa31c04ead Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Fri, 17 Mar 2017 12:27:32 -0300 Subject: [PATCH 019/154] Making sure that findCheckedExceptions() is called before every test. - Assuring test are independent/isolated. - Slower runtime but still fast due to small example case. - I didn't find a DRY way to do it like JUnit's @Before -- Tests don't run in declaration order. We can't declare a function first and expect it to work. - It only ran once at test startup, much like @BeforeClass. --- bin/.gitignore | 1 + src/ExceptionFinderTest.rsc | 18 ++++++++++++++++-- testes/exception-hierarchy.zip | Bin 14015 -> 22625 bytes 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/bin/.gitignore b/bin/.gitignore index c8bcf3e..63402fa 100644 --- a/bin/.gitignore +++ b/bin/.gitignore @@ -1 +1,2 @@ /ExceptionFinder.rsc +/ExceptionFinderTest.rsc diff --git a/src/ExceptionFinderTest.rsc b/src/ExceptionFinderTest.rsc index e703673..bd07cc2 100644 --- a/src/ExceptionFinderTest.rsc +++ b/src/ExceptionFinderTest.rsc @@ -7,37 +7,42 @@ import ExceptionFinder; private loc zipFile = |jar:///D:/exception-hierarchy.zip!|; private list[loc] javaClassesLocations = listAllJavaFiles(zipFile); -private set[str] checkedExceptions = findCheckedExceptions(javaClassesLocations); - public test bool shouldReturnExceptionClass() { + set[str] checkedExceptions = findCheckedExceptions(javaClassesLocations); return "Exception" in checkedExceptions; } public test bool shouldReturnLevelTwoHierarchyClasses() { + set[str] checkedExceptions = findCheckedExceptions(javaClassesLocations); return "AException" in checkedExceptions && "BException" in checkedExceptions && "CException" in checkedExceptions && "ZException" in checkedExceptions; } public test bool shouldReturnLevelThreeHierarchyClasses() { + set[str] checkedExceptions = findCheckedExceptions(javaClassesLocations); return "DException" in checkedExceptions && "FException" in checkedExceptions && "IException" in checkedExceptions; } public test bool shouldReturnLevelFourHierarchyClasses() { + set[str] checkedExceptions = findCheckedExceptions(javaClassesLocations); return "LException" in checkedExceptions && "EException" in checkedExceptions && "JException" in checkedExceptions && "HException" in checkedExceptions; } public test bool shouldReturnLevelFiveHierarchyClasses() { + set[str] checkedExceptions = findCheckedExceptions(javaClassesLocations); return "GException" in checkedExceptions && "KException" in checkedExceptions && "NException" in checkedExceptions; } public test bool shouldReturnLevelSixHierarchyClasses() { + set[str] checkedExceptions = findCheckedExceptions(javaClassesLocations); return "MException" in checkedExceptions; } public test bool shouldNotReturnUncheckedExceptions() { + set[str] checkedExceptions = findCheckedExceptions(javaClassesLocations); return "RuntimeException" notin checkedExceptions && "UncheckedLevelFourRuntimeException" notin checkedExceptions && "UncheckedLevelThreeRuntimeException" notin checkedExceptions && @@ -45,5 +50,14 @@ public test bool shouldNotReturnUncheckedExceptions() { } public test bool shouldReturnAbstractCheckedException() { + set[str] checkedExceptions = findCheckedExceptions(javaClassesLocations); return "AbstractCheckedException" in checkedExceptions; +} + +public test bool shouldReturnStaticInnerCheckedExceptions() { + set[str] checkedExceptions = findCheckedExceptions(javaClassesLocations); + return "ExceptionClassWithOnlyZeroArgCtor" in checkedExceptions && + "CustomServiceLocatorException3" in checkedExceptions && + "CustomServiceLocatorException2" in checkedExceptions && + "DeepNestedStaticException" in checkedExceptions; } \ No newline at end of file diff --git a/testes/exception-hierarchy.zip b/testes/exception-hierarchy.zip index 494ad321797cf286eddec1838b85ad20c8eb22fe..7c25e56e78c0b99600eb029da8a5d0e44662f8ed 100644 GIT binary patch delta 8598 zcmb_h2{_c<_h*oiWb9kUnq(RKzAt6X8nT3mA!4k_KGBq{sc&QrMQ>!^%RXsZ$oe8m z*;{1aL;f?vEBZZo-rw)}e?6Z0-h0pYo^wCv+;h)4x50h5n7CMhgoHlWvrL&pni&5A zbkZmQjUrS)1L^E;dx~sz_x(LTEpX(>VL*la{cd0UF)ARHLJ)`tH}3WooumaaDJFK? zZ^gE0HV*%y`9Zm|J1#=?iw9VO3h+MqZD&jgNTc4^eHRvj;O6B8j?iH6ePx|A65E2S z(JKK(+?0SJ-3(zsjech!mzNiqJwXk0z?gwJDFz^&nH>1Y@Pk0~p3$E0b(u2r1!5Z9 ze7Zz?9#sHN!HV+my@>GEfcqePMAR<$_yrKr%co~7uC6CQ5tJiNygA3G2C4~_ZifF){1NQn<=EYi@Neww@HR0exDnET)YhPTSfOmAGj1$8S+ z&;U&f8qpGOo8|fC7f!d@GrK4@%3;wMR@zUI3V;r9N@kl-n+<&Z9|uCbViRv3=(2$-B;K%;9B4hA)~f> z!F}_rfNhjIe9m5P<}2&KtLf8s+?G57XcbpUHjFQnMlo*4CN++|ZAneOS6hoxRw9wb zq(mGWK9?e9!T#te(hq3H+;mBGyJF(*_+iwQTOIl;o+YCbqbtg3iB!JNopl%kQ2qY zD({APY=q5HdX&*+rw7EQm~jr2prEv5qmJf(&v#Tf>q3v**|Kkle8(lE5!Ge-Pf(mn$icLm zJ_Plsg8tuBB)(roWtD>!=9jG3hfhHiFOpGmbDz~bc^EU2le6MW?Q4e-@=@7cq?t{_rG)0S)#jSR{)6$N%(ftj$*|IVY}W)1I`I()dD(f>~9n=Rk6EW``-A0yJms^ zU3XRg(^E=8Rrn>WmvJ(L##8$n{(~HptD950#H{LXOg9u@kO?a z@HG;=PV{b_fJ)-Fj5y@~Pbm^RN-@Om8~U`qX}>9}0{4PCitvbUO;CE8Jlm)X@HvyO zO6N7$`uXlSMx$DQp(c)@TeN^#IcK0~*os*4iqrg$}J#b z`X+{@@B2}2ho0c(CG~7Y9}gd=<{?G*vRfD1V#mr?mee1o9X|P8E^F{i zJq6E`>uJj?ShRg6G9X4gPYQjLV!SY7GBSQcKEtrO9uCCNrPxZdNeBmTQ5^E)J2K3> zmNBQymEwbPcvlWtg~vl~oh>vCJy~nz5U>>HOy}Bi4lSLv5Y2>H{)8+hSqWLyn7;A2 zn)&H;>-e3P;h%Ko(DTNayl5|CTdqckl!bdpeDRH?3pzLDrK37ei*;*0Nt$nwVXygd z6t4nLbh9NlP6a=I_guO}NA@^;gWnzgK1ZgBKzJG;e0&j(roM1r7l&OZwylcceK2jm&${4`DJ3 zAA_fYgX`-^WSdT3J%k#5?8{;ig6PNgo#KKQ=Eo0GPQ1QaFzWl|uEdXd%Z29TQt%K> z<=VZ0bI$o3vax2t3l^HQ?fUQ!a#>HSRJi>&#m6CM%6ZC%=;R|$`iq7f^SS&NR*o)E zC)Z5bBq4c@qthq31U)+TX-n}q`nk82OTBoR&fr?*^Pr_{aA&PEW2V+So8pM#3Qsye zPUj2D+WKvDN6;^%$gRkW&IR7i3^VE|dSNX@dHNICh{d-J*I4%aNb1RDSa0V~5FTv7 zLFG9T9MF~j3HBbW%@4$S7hA$9V&UR@(GcktV1@AZQ1f=yz?~rf*ng8Q{@mzB*7%(- za3^agqyE-Z=YKnjGdjHZn_BLW@OcfHQocK9qC*o;G+pBu(uyoI&Ss*~A9`CW6Of#Y zTDjFHLlkt5x|8!en}v32l&<;f+}^ar2Ny~MHj-M%|B6}0RCvF*4$DAhOKJI~$UA6| zqMOo_qO<7(Q#P2vQzSVF3cQk4l`qkpQdQ#Wbm`2(6bCrw zK+v^u3fP5K+XVr5Qc(W!;6CN=i$FRe9M9rxe&_i94@=j1Sdlwoxi~~V5H0gU&lnPZ zFY#m5YgLPpL#6M38M@A5{57R&T&Po*-riocLQQ1xj=F;@?H=-VkESK6a+KVGSLiN- zcks%{yRo$Pch62*TuS#My5(7(o0*_J>rvi0o!Frymrhr!lk9_rVVIRx(Q0{ADuwr% zY~KF;AU=v$Si-E;Ea%cs!9ZlL@G$r0%fvqPMXSQRn3>Ci4)0*q!6uhZ-F$C#742CJ z2f-I#9#L<2;R%+bU*ZvyvosQgNF!xC6oQ`jJ|Sh-3=id5esOj6gxZGRLPPfuQOyWl zq$4T@qPxzu3<)K8bdFw4sdXHb^#_9Oe4vHz4~TS-z6ft8xB~)j>Nw!N;RYT^4G(uu zHy1e4_YA`KqKD&-$;T6-%o|&|DM?nBCSNdp;j%qK@1ewaUH5Md()LMtKI@S}H|$7R zz$|evzZc4sl*EL88orgBF`SyQwh_2RNoxZKq-=pG=dg)o4Q;*Ep~JRy6K;B@5zM30W0sW1k36%DAs%)lNfF&_ zkBkEY?wA|=gVNj(zm9s_>Uk))eSz1cJ!#osM^_{^1 zzIY(u{}He6bKn1A#<9B&+cNd^de)HTStII+5uCq;fFOTl-5_y{9`VtmUZr-J?z=d-5@e9TFV8`+ykkf*7 zojO@lm*&$7WLMC$ZRbX3C3TZONZ$&a~!D@*Lsm@sSg3=d}QghBf}4$P1P z!BjiYdiQ|26CcJJ?qomsOm2f|sRgh#adlPZf*x~3 zf_QtsL&-!J4TjCVyyp0#VS6Il-dx2iM)?NCAuxqYA(e`o?O`Ni-s2?E*OMk@dOcqf zx1z$VUG!vMZQKBhz7@~4?LtT`!3k?tc+|GuGov;DjV zXc$zZ%C{V7`+N4rW9-BcqCLxxTTK}AZuSMVi2`K6Fv^y}@2}RSyN_cHvU^Tv8hl9` zH^U~kcKZj(K53?XaJK(WiYTk0G(#^8{L{cr|AF~mF)yDXhQEhIKoWyM#Bd{cnQC;$ z77s6}-KXWy^k<~%R5P5*AFj5%3R@lHQ!G?Et*oxux_YMk{0w2|mUaxtKEpv{wF3>) zZU(-uZt<^eZ3mlwcCgV~TrkC)=3y-}SlRm%98NA0Xhg~s1@3Y%hA=ATi$FBaRpm$W zy3F+}E)xGRdQrqQ7@ja8{t2DjI%ZwakVu5|5`xeay8Cw{1?o`CUjZ>i^Dc>}{+-HW z1H!sF5>Fh9kwP83i_YF$-MT5RPtut{E)7xeqpK79X|B(^S`<{ zvdXcPyy%+qm0v%Quh*ZSd#NxH;jM5*S0#}_hV}0PnN)8ya?>DFOSb>^DcN~5+++&9n)KAZ*U^njJ@qq~-IvACvLC}07oXWK>&S~WP75ZS z=kmNr;zb;;-wrgn{}$Gr94$7!9bXp0HsnfO+B%oI+(B+6%AIu0Hd`yp=%&B6oqf$w z7u{COwAE~n;wq8yU0*u%>BsR(-#z@6Q~Ud82nP+xBM>{Lz>iJZ5Y<&0dk^vTxw;jq z+N$L8$<*_OvYoo}?$cz?&~xU~jyA8vqwRXF&ErJhyptM3Pk!NZ>AYg#A9F{e;qT$GMXV;Xv=4{}gNW`U#iILF z)GSg&d^?I(h;Q7d<47L`Wi=dc*Xejq0CbkC zf^8ZH=*)qDN*=U_ccPuUb{@29^e@`oPx8>a>-AV|opmv`&O4Q99*b?xDCO?^0gw7>~yqd?dC46+zCy` z?x3%y_?gx9xd?1&OS7MP)vKr{|FWwOt^}cbltY4X6`q(Aq4;{EZ$Ws;HeyrnVYC8V zNS!Z5M(trj#gunuy?1J>d(FNE7)F=IEQ*DO+FtHCX zDLf&)K;sj!Bx(|A=`<~#A)ayE6h$a-RlM}qr@+-w>c{{Ql4E7XESX1G{;5Pt#Cq)W zgDOA?3oGlN>$iX!J0t3q$ZKt3Zv!C%;mV2ek#Pb3GjCq&n``R}z)tGw!;H1tbcA5$ zo@noM2@{~q)YL}sjwz+C_`(9ciJ-2@f=Ltugu92+)HUGgws;+L5hggpx5xeeDv=gB zcW0a|B zX=|o#-kN@N=7Q^)ScW>Z|a2 zp&uvV(_l6*$om5NHm`sx$c|^d*_jV3e*}TivEe>~VFe;B51ii1d5@N;$i54gnO0SFC~CEN?8qs* zv>e$id!n*mz%)d1PFnsnJC$GJ4<+eWF2r}<&eA)^FNv!exX(ZDM`5QT7>km>Np^Rx zY+4Am=dH$$NY=iDKI)BepC|`C*Rx0;E4bxMWqLF{@s{Z;Ps6(CJ!KA& z&orZJ=(Cl<#W+z?&qRNWGuA21FL;#D1TPXz7RGSYn*H_qUIAvD9Usbk zepw_?fpdZSrPw4QGXd3`j1Q>w= zetiPv2LCptkc^!=fimpm_CUu;X99t|z&3$h&E1;>f(C(Yf}?`l1pb2C1kY%K6bJ;H zg4+c8LfZtDJHMR5+wCY}6k+Bgu&adMTd+{V?a1C60961gg1=cIJ!pq{!Pq!)7X-R{ z>(Zt;>;Lt9Vg;JWST63_rTenBe{*|aq(=;*C;Al&?G{{dequkf2gm+*W;;>R@67g= z7WXr=fd22yc4CL$ne8pD8T`T!_x6JW&y4?1F#cY<1pZOX-nx`$xQlUi@bK)+AEH{n#>D48wC^`U6P7I!qLFO%w>@76LL(Pyz#D5WrUi3K9~-l?h-# zBr7%WQS1mXi0kU#?wTRnraCPO1x1Jxs0R5dfecX?NJ@gx+!U1qjc&iHvTuJMCI$uF zmc)%ZgH)slL}}3N5mRv}XllD_Mt~B?7l(mTr3n;=CFDRlG6cy|sHuQZ2^eU3yD2C{ zMG$mF0t(8OB~WZ}(GUc+mxO{$u0ipEUa*InrK?U--F5Wx5Vg#Zx zTu-FJb`LW^Ev*T1RQ#vaew-Ok!-)?REA~WcD*G^2P{Pr(9CWI6h_Q0wW4d4GI}s5+ jru+5$Aj~2D2R#u2J0m@^L--G5aeoTTL_`o(eCz)J5~-i} delta 788 zcmXYsOH5Ni7=?Rhc-+#K-j?zducC+`SPPX$Da1Z_)OrO9MHZ4^jO4B?L>De3ijhP& z7?R@(0bS@qP{edWB2kF0j0w=4f)Zg#XxK?(FmXD!GmANMzWM)u&h~<^d~?A~G47C} zmuQ86x@rkq7CXLrt$1V3!fM(!-ITHVy(vi8V+!f(&tPGysFdupFJkr%HE~3d{#52%!l*~ z@6!xVgMrPdfYI`qZp=iYF^f|`ze_@g&4DSG0i8Mf^alf88v~1tQgkdgEYKU%k?3aL zH7@Y3xExZZ0p>s~Rs@F)r)t z%vcT^G0`KFdCl5lwEsAxRhTrJ_!q8+WuhS<9W?YfUO42Gtys?@WJYv>VDYq{76{0+li}j{7j`V#pxpOLoYHaBlI<`);eO1!w II?9r_|A1L0V*mgE From 84e382ee344ee1dc8ec5cc4f9a97e482b206abb3 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Fri, 17 Mar 2017 12:27:32 -0300 Subject: [PATCH 020/154] Big refactor and now finding inner classes too! - Considering that we might have several class definitions in one unit(.java file) -- Before we were returning after the first class definition, ignoring following definitions. --- This also produced unwanted behavior to capture a superClassName when multiple classes were defined within the same unit - Finding classes with super classes in only one visit. -- 'Superclass' is actually part of 'NormalClassDeclaration' syntax - Introducing an AlgebraicDataType to handle class' and superClass' names -- Replacing the tuple used previously --- src/ExceptionFinder.rsc | 63 +++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 40 deletions(-) diff --git a/src/ExceptionFinder.rsc b/src/ExceptionFinder.rsc index aeb60c8..0160921 100644 --- a/src/ExceptionFinder.rsc +++ b/src/ExceptionFinder.rsc @@ -10,11 +10,14 @@ import Map; private map[str, set[str]] superClassesBySubClasses = (); private set[str] checkedExceptionClasses = {"Exception"}; +private data ClassAndSuperClass = classAndSuperClass(str className, str superClassName); + set[str] findCheckedExceptions(list[loc] javaFilesLocations) { initializeClassesFound(); for(javaFileLocation <- javaFilesLocations) { javaFileContent = readFile(javaFileLocation); - tryToNavigateClassesFindingSubClassesOfException(javaFileContent); + visitJavaFilesLookingForClassesWithSubClasses(javaFileContent); + } return checkedExceptionClasses; } @@ -24,47 +27,27 @@ private void initializeClassesFound() { checkedExceptionClasses = {"Exception"}; } -private void tryToNavigateClassesFindingSubClassesOfException(str javaFileContent) { - try { - compilationUnit = parse(#CompilationUnit, javaFileContent); - handleIfClassHasASuperClass(compilationUnit); - } catch: - continue; -} - -private void handleIfClassHasASuperClass(unit) { - superClass = retrieveSuperClass(unit); - if (superClass.present) { - className = retrieveClassNameFromUnit(unit); - handleIfClassIsAnException(className, superClass.name); - } -} - -private tuple[bool present, str name] retrieveSuperClass(unit) { - tuple[bool present, str name] superClass = ; - visit(unit) { - case(Superclass) `extends `: { - superClass.present = true; - superClass.name = unparse(id); - } - } - return superClass; +private void visitJavaFilesLookingForClassesWithSubClasses(str javaFileContent) { + compilationUnit = parse(#CompilationUnit, javaFileContent); + classesAndSuperClasses = retrieveClassesAndSuperClassesFromCompilationUnit(compilationUnit); + for(classAndSuperClass <- classesAndSuperClasses) + handleIfClassIsAnException(classAndSuperClass); } -private str retrieveClassNameFromUnit(unit) { - visit(unit) { - case(NormalClassDeclaration) ` class `: - return unparse(id); +private list[ClassAndSuperClass] retrieveClassesAndSuperClassesFromCompilationUnit(compilationUnit) { + list[ClassAndSuperClass] classesAndSuperClasses = []; + visit(compilationUnit) { + case(NormalClassDeclaration) ` class extends `: + classesAndSuperClasses += classAndSuperClass(unparse(className), unparse(superClassName)); } - // Not the best solution. quick workaround - throw "Could not find class name"; + return classesAndSuperClasses; } -private void handleIfClassIsAnException(str className, str superClassName) { - if (superClassName in checkedExceptionClasses) - addClassAndItsSubClassesAsExceptions(className); +private void handleIfClassIsAnException(ClassAndSuperClass cas) { + if (cas.superClassName in checkedExceptionClasses) + addClassAndItsSubClassesAsExceptions(cas.className); else - addClassAsASubClassOfItsSuperClass(className, superClassName); + addClassAsASubClassOfItsSuperClass(cas); } private void addClassAndItsSubClassesAsExceptions(str className) { @@ -73,11 +56,11 @@ private void addClassAndItsSubClassesAsExceptions(str className) { addAllSubClassesOf(className); } -private void addClassAsASubClassOfItsSuperClass(str className, str superClassName) { - if (superClassName in superClassesBySubClasses) - superClassesBySubClasses[superClassName] += {className}; +private void addClassAsASubClassOfItsSuperClass(ClassAndSuperClass cas) { + if (cas.superClassName in superClassesBySubClasses) + superClassesBySubClasses[cas.superClassName] += {cas.className}; else - superClassesBySubClasses[superClassName] = {className}; + superClassesBySubClasses[cas.superClassName] = {cas.className}; } private void addAllSubClassesOf(str className) { From dcb31ed57379e49cc822d0d33213847c20185e66 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Fri, 17 Mar 2017 12:27:32 -0300 Subject: [PATCH 021/154] Catching and storing locations that could not be parsed. - Our syntax isn't 100%, so there are multiple classes that can't be parsed --- src/ExceptionFinder.rsc | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/ExceptionFinder.rsc b/src/ExceptionFinder.rsc index 0160921..7a30cfb 100644 --- a/src/ExceptionFinder.rsc +++ b/src/ExceptionFinder.rsc @@ -9,25 +9,34 @@ import Map; private map[str, set[str]] superClassesBySubClasses = (); private set[str] checkedExceptionClasses = {"Exception"}; +private list[loc] fileLocationsThatCouldNotBeParsed = []; private data ClassAndSuperClass = classAndSuperClass(str className, str superClassName); set[str] findCheckedExceptions(list[loc] javaFilesLocations) { initializeClassesFound(); - for(javaFileLocation <- javaFilesLocations) { - javaFileContent = readFile(javaFileLocation); - visitJavaFilesLookingForClassesWithSubClasses(javaFileContent); - - } + for(javaFileLocation <- javaFilesLocations) + tryToVisitFileLookingForClassesWithSubClasses(javaFileLocation); + + printJavaFileLocationsThatCouldNotBeParsed(); return checkedExceptionClasses; } private void initializeClassesFound() { superClassesBySubClasses = (); checkedExceptionClasses = {"Exception"}; + fileLocationsThatCouldNotBeParsed = []; +} + +private void tryToVisitFileLookingForClassesWithSubClasses(loc javaFileLocation) { + javaFileContent = readFile(javaFileLocation); + try + visitFileLookingForClassesWithSubClasses(javaFileContent); + catch: + fileLocationsThatCouldNotBeParsed += javaFileLocation; } -private void visitJavaFilesLookingForClassesWithSubClasses(str javaFileContent) { +private void visitFileLookingForClassesWithSubClasses(str javaFileContent) { compilationUnit = parse(#CompilationUnit, javaFileContent); classesAndSuperClasses = retrieveClassesAndSuperClassesFromCompilationUnit(compilationUnit); for(classAndSuperClass <- classesAndSuperClasses) @@ -77,4 +86,9 @@ private set[str] getAllDirectSubClassesOf(str className) { if (className in superClassesBySubClasses) directSubClasses = superClassesBySubClasses[className]; return directSubClasses; +} + +private void printJavaFileLocationsThatCouldNotBeParsed() { + println("Java File Locations that could not be parsed: "); + println(fileLocationsThatCouldNotBeParsed); } \ No newline at end of file From 5bf86b3cbc21835627366db10459ed4cbaaba0e6 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Fri, 17 Mar 2017 12:27:32 -0300 Subject: [PATCH 022/154] Printing total count of files not parsed, and conditionally printing names --- src/ExceptionFinder.rsc | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/ExceptionFinder.rsc b/src/ExceptionFinder.rsc index 7a30cfb..150b5b8 100644 --- a/src/ExceptionFinder.rsc +++ b/src/ExceptionFinder.rsc @@ -6,6 +6,7 @@ import lang::java::\syntax::Java18; import ParseTree; import Set; import Map; +import util::Math; private map[str, set[str]] superClassesBySubClasses = (); private set[str] checkedExceptionClasses = {"Exception"}; @@ -13,12 +14,14 @@ private list[loc] fileLocationsThatCouldNotBeParsed = []; private data ClassAndSuperClass = classAndSuperClass(str className, str superClassName); +private bool printAllFileNamesThatCouldNotBeParsed = false; + set[str] findCheckedExceptions(list[loc] javaFilesLocations) { initializeClassesFound(); for(javaFileLocation <- javaFilesLocations) tryToVisitFileLookingForClassesWithSubClasses(javaFileLocation); - printJavaFileLocationsThatCouldNotBeParsed(); + printJavaFilesThatCouldNotBeParsed(); return checkedExceptionClasses; } @@ -88,7 +91,15 @@ private set[str] getAllDirectSubClassesOf(str className) { return directSubClasses; } -private void printJavaFileLocationsThatCouldNotBeParsed() { - println("Java File Locations that could not be parsed: "); - println(fileLocationsThatCouldNotBeParsed); +private void printJavaFilesThatCouldNotBeParsed() { + str filesNotParsedCount = toString(size(fileLocationsThatCouldNotBeParsed)); + println(filesNotParsedCount + " Java File Locations that could not be parsed. "); + + if (printAllFileNamesThatCouldNotBeParsed) { + for(fileLoc <- fileLocationsThatCouldNotBeParsed) + print(fileLoc.file + ", "); + println(); + } + + println(); } \ No newline at end of file From 098aa40cb8286121cf1b4681ff4b1eea3b2a3a08 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 19 Mar 2017 22:09:56 -0300 Subject: [PATCH 023/154] Initial impl - Finding throw statements and breaks inside for stataments. --- src/ForLoop.rsc | 52 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 src/ForLoop.rsc diff --git a/src/ForLoop.rsc b/src/ForLoop.rsc new file mode 100644 index 0000000..cc01c88 --- /dev/null +++ b/src/ForLoop.rsc @@ -0,0 +1,52 @@ +module ForLoop + +import IO; +import lang::java::\syntax::Java18; +import ParseTree; + +public void findForLoops(list[loc] locs) { + for(fileLoc <- locs) { + javaFileContent = readFile(fileLoc); + try { + unit = parse(#CompilationUnit, javaFileContent); + lookForForStatements(unit); + } catch: + continue; + } +} + +private void lookForForStatements(CompilationUnit unit) { + visit(unit) { + case (BasicForStatement) `for ( ; ; ) `: + lookForBreakingPreConditions(stmt); + case (EnhancedForStatement) `for ( : ) `: + lookForBreakingPreConditions(stmt); + case (BasicForStatementNoShortIf) `for ( ; ; ) `: + println("TODO"); + case (EnhancedForStatementNoShortIf) `for ( : ) `: + println("TODO"); + } +} + + +// syntax BreakStatement = "break" Identifier? ";" ; +// syntax ThrowStatement = "throw" Expression ";" ; +// syntax Expression = LambdaExpression | AssignmentExpression ; +// syntax AssignmentExpression = ConditionalExpression | Assignment ; +// syntax Assignment = LeftHandSide AssignmentOperator Expression ; +// syntax LeftHandSide = ExpressionName | FieldAccess | ArrayAccess ; +// syntax ExpressionName = Identifier | AmbiguousName "." Identifier ; +// syntax AmbiguousName = Identifier | AmbiguousName "." Identifier ; +// syntax Identifier = id: [$ A-Z _ a-z] !<< ID \ IDKeywords !>> [$ 0-9 A-Z _ a-z]; +// syntax UnqualifiedClassInstanceCreationExpression = "new" TypeArguments? ClassOrInterfaceTypeToInstantiate "(" ArgumentList? ")" + +private void lookForBreakingPreConditions(Statement stmt) { + visit(stmt) { + case (ThrowStatement) `throw new ( );`: { + println(className); + } + case (BreakStatement) `break ;`: { + println("break"); + } + } +} \ No newline at end of file From 0cc3d43353c06325110a6b885515f7fe960066a9 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 19 Mar 2017 22:59:25 -0300 Subject: [PATCH 024/154] Finding more than one return statement inside a for statement. --- src/ForLoop.rsc | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/src/ForLoop.rsc b/src/ForLoop.rsc index cc01c88..825fe1c 100644 --- a/src/ForLoop.rsc +++ b/src/ForLoop.rsc @@ -3,8 +3,15 @@ module ForLoop import IO; import lang::java::\syntax::Java18; import ParseTree; +import ExceptionFinder; +import util::Math; -public void findForLoops(list[loc] locs) { +// TODO maybe return set[Identifier] +// avoids unparse() +private set[str] checkedExceptionClasses; + +public void findForLoops(list[loc] locs, set[str] checkedExceptions) { + checkedExceptionClasses = checkedExceptions; for(fileLoc <- locs) { javaFileContent = readFile(fileLoc); try { @@ -18,9 +25,9 @@ public void findForLoops(list[loc] locs) { private void lookForForStatements(CompilationUnit unit) { visit(unit) { case (BasicForStatement) `for ( ; ; ) `: - lookForBreakingPreConditions(stmt); + isLoopEligibleForRefactor(stmt); case (EnhancedForStatement) `for ( : ) `: - lookForBreakingPreConditions(stmt); + isLoopEligibleForRefactor(stmt); case (BasicForStatementNoShortIf) `for ( ; ; ) `: println("TODO"); case (EnhancedForStatementNoShortIf) `for ( : ) `: @@ -40,13 +47,30 @@ private void lookForForStatements(CompilationUnit unit) { // syntax Identifier = id: [$ A-Z _ a-z] !<< ID \ IDKeywords !>> [$ 0-9 A-Z _ a-z]; // syntax UnqualifiedClassInstanceCreationExpression = "new" TypeArguments? ClassOrInterfaceTypeToInstantiate "(" ArgumentList? ")" -private void lookForBreakingPreConditions(Statement stmt) { +// TODO extract module and test it +private bool isLoopEligibleForRefactor(Statement stmt) { + returnCount = 0; visit(stmt) { case (ThrowStatement) `throw new ( );`: { - println(className); + classNameStr = unparse(className); + if (classNameStr in checkedExceptionClasses) { + println("found checked exception (" + classNameStr + ") thrown inside a for statement."); + return false; + } } case (BreakStatement) `break ;`: { - println("break"); + println("found break statement inside a for statement."); + return false; + } + case (ReturnStatement) `return ;`: { + returnCount += 1; } } + if (returnCount > 1) { + println("returnCount: " + toString(returnCount)); + println(stmt); + println(); + return false; + } + return true; } \ No newline at end of file From 5429595274cab6915e2528e0ebf808e20724812d Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 19 Mar 2017 22:59:25 -0300 Subject: [PATCH 025/154] Looking for continue statements inside for statements. --- src/ForLoop.rsc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/ForLoop.rsc b/src/ForLoop.rsc index 825fe1c..39181dd 100644 --- a/src/ForLoop.rsc +++ b/src/ForLoop.rsc @@ -65,11 +65,16 @@ private bool isLoopEligibleForRefactor(Statement stmt) { case (ReturnStatement) `return ;`: { returnCount += 1; } + // LambdaFicator restructures code to eliminate 'continue' + // if we don't do this, we should not allow 'continue' + case (ContinueStatement) `continue ;`: { + println("found continue statement inside a for statement."); + return false; + } } if (returnCount > 1) { - println("returnCount: " + toString(returnCount)); - println(stmt); - println(); + println("more than one (" + toString(returnCount) + " total) return statements inside a for statement."); + // println(stmt); return false; } return true; From 91794ccff42372c333fe85b0fcd559733234586c Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Mon, 20 Mar 2017 11:05:05 -0300 Subject: [PATCH 026/154] Comment for no labeled 'continue' allowed. --- src/ForLoop.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ForLoop.rsc b/src/ForLoop.rsc index 39181dd..7396d80 100644 --- a/src/ForLoop.rsc +++ b/src/ForLoop.rsc @@ -67,6 +67,7 @@ private bool isLoopEligibleForRefactor(Statement stmt) { } // LambdaFicator restructures code to eliminate 'continue' // if we don't do this, we should not allow 'continue' + // Even if we do it, no labeled 'continue' are allowed case (ContinueStatement) `continue ;`: { println("found continue statement inside a for statement."); return false; From 0b776ea4162ee3fdfacc51a7dbd850f5edfa69d8 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Tue, 21 Mar 2017 21:01:33 -0300 Subject: [PATCH 027/154] module ParseTreeVisualization - Making possible to visualize any Syntax Tree. --- src/ParseTreeVisualization.rsc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ParseTreeVisualization.rsc b/src/ParseTreeVisualization.rsc index ca2d2ab..aed4578 100644 --- a/src/ParseTreeVisualization.rsc +++ b/src/ParseTreeVisualization.rsc @@ -6,7 +6,7 @@ import vis::Figure; import vis::ParseTree; import vis::Render; +void visualize(Tree t) { + render(visParsetree(t)); +} -void visualize(CompilationUnit unit) { - render(visParsetree(unit)); -} \ No newline at end of file From 3f9891066b9505449f6a00993cc02e3043909b84 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 22 Mar 2017 00:20:52 -0300 Subject: [PATCH 028/154] Experimenting with a module for finding local variables in a MethodBody --- src/ForLoop.rsc | 43 ++++++++---------- src/LocalVariablesFinder.rsc | 32 ++++++++++++++ src/LocalVariablesFinderTest.rsc | 33 ++++++++++++++ src/LocalVariablesFinderTestResources.rsc | 11 +++++ .../EnhancedForLoopFinalVarDecl | 44 +++++++++++++++++++ 5 files changed, 138 insertions(+), 25 deletions(-) create mode 100644 src/LocalVariablesFinder.rsc create mode 100644 src/LocalVariablesFinderTest.rsc create mode 100644 src/LocalVariablesFinderTestResources.rsc create mode 100644 testes/localVariables/EnhancedForLoopFinalVarDecl diff --git a/src/ForLoop.rsc b/src/ForLoop.rsc index 7396d80..77071da 100644 --- a/src/ForLoop.rsc +++ b/src/ForLoop.rsc @@ -3,11 +3,9 @@ module ForLoop import IO; import lang::java::\syntax::Java18; import ParseTree; -import ExceptionFinder; import util::Math; +import LocalVariablesFinder; -// TODO maybe return set[Identifier] -// avoids unparse() private set[str] checkedExceptionClasses; public void findForLoops(list[loc] locs, set[str] checkedExceptions) { @@ -24,29 +22,24 @@ public void findForLoops(list[loc] locs, set[str] checkedExceptions) { private void lookForForStatements(CompilationUnit unit) { visit(unit) { - case (BasicForStatement) `for ( ; ; ) `: - isLoopEligibleForRefactor(stmt); + case (MethodDeclaration) ` `: { + bool findEffectiveFinalLocalVars = doesMethodHaveAnEligibleForLoop(methodBody); + if (findEffectiveFinalLocalVars) + findLocalVariables(methodBody); + } + } +} + +private bool doesMethodHaveAnEligibleForLoop(MethodBody methodBody) { + visit(methodBody) { case (EnhancedForStatement) `for ( : ) `: - isLoopEligibleForRefactor(stmt); - case (BasicForStatementNoShortIf) `for ( ; ; ) `: - println("TODO"); + return isLoopEligibleForRefactor(stmt); case (EnhancedForStatementNoShortIf) `for ( : ) `: println("TODO"); } + return false; } - -// syntax BreakStatement = "break" Identifier? ";" ; -// syntax ThrowStatement = "throw" Expression ";" ; -// syntax Expression = LambdaExpression | AssignmentExpression ; -// syntax AssignmentExpression = ConditionalExpression | Assignment ; -// syntax Assignment = LeftHandSide AssignmentOperator Expression ; -// syntax LeftHandSide = ExpressionName | FieldAccess | ArrayAccess ; -// syntax ExpressionName = Identifier | AmbiguousName "." Identifier ; -// syntax AmbiguousName = Identifier | AmbiguousName "." Identifier ; -// syntax Identifier = id: [$ A-Z _ a-z] !<< ID \ IDKeywords !>> [$ 0-9 A-Z _ a-z]; -// syntax UnqualifiedClassInstanceCreationExpression = "new" TypeArguments? ClassOrInterfaceTypeToInstantiate "(" ArgumentList? ")" - // TODO extract module and test it private bool isLoopEligibleForRefactor(Statement stmt) { returnCount = 0; @@ -54,12 +47,12 @@ private bool isLoopEligibleForRefactor(Statement stmt) { case (ThrowStatement) `throw new ( );`: { classNameStr = unparse(className); if (classNameStr in checkedExceptionClasses) { - println("found checked exception (" + classNameStr + ") thrown inside a for statement."); + //println("found checked exception (" + classNameStr + ") thrown inside a for statement."); return false; } } case (BreakStatement) `break ;`: { - println("found break statement inside a for statement."); + //println("found break statement inside a for statement."); return false; } case (ReturnStatement) `return ;`: { @@ -69,14 +62,14 @@ private bool isLoopEligibleForRefactor(Statement stmt) { // if we don't do this, we should not allow 'continue' // Even if we do it, no labeled 'continue' are allowed case (ContinueStatement) `continue ;`: { - println("found continue statement inside a for statement."); + //println("found continue statement inside a for statement."); return false; } } if (returnCount > 1) { - println("more than one (" + toString(returnCount) + " total) return statements inside a for statement."); + //println("more than one (" + toString(returnCount) + " total) return statements inside a for statement."); // println(stmt); return false; } return true; -} \ No newline at end of file +} diff --git a/src/LocalVariablesFinder.rsc b/src/LocalVariablesFinder.rsc new file mode 100644 index 0000000..41faaa4 --- /dev/null +++ b/src/LocalVariablesFinder.rsc @@ -0,0 +1,32 @@ +module LocalVariablesFinder + +import Set; +import lang::java::\syntax::Java18; +import String; +import ParseTree; +import IO; + +// syntax LocalVariableDeclarationStatement = LocalVariableDeclaration ";"+ ; +// syntax LocalVariableDeclaration = VariableModifier* UnannType VariableDeclaratorList ; +// syntax VariableDeclaratorList = variableDeclaratorList: {VariableDeclarator ","}+ ; +// syntax VariableDeclarator = variableDeclarator: VariableDeclaratorId ("=" VariableInitializer)? ; + +public tuple[set[str] finals, set[str] nonFinals] findLocalVariables(MethodBody methodBody) { + set[str] finals = {}; + set[str] nonFinals = {}; + visit(methodBody) { + case (EnhancedForStatement) `for ( final : ) `: + finals += trim(unparse(varId)); + case (LocalVariableDeclaration) `final `: { + visit(vdl) { + case (VariableDeclaratorId) ` `: + finals += trim(unparse(varId)); + } + } + // finding all variables declared, including ones in loop declaration + case VariableDeclaratorId varId: nonFinals += trim(unparse(varId)); + } + // nonFinals must not have finals + nonFinals -= finals; + return ; +} \ No newline at end of file diff --git a/src/LocalVariablesFinderTest.rsc b/src/LocalVariablesFinderTest.rsc new file mode 100644 index 0000000..9d8b2e9 --- /dev/null +++ b/src/LocalVariablesFinderTest.rsc @@ -0,0 +1,33 @@ +module LocalVariablesFinderTest + +import IO; +import LocalVariablesFinderTestResources; +import LocalVariablesFinder; +import Set; + +public test bool shouldHaveTheEnhancedDeclaredVarAsFinal() { + methodBody = enhancedForLoopFinalVarDecl(); + vars = findLocalVariables(methodBody); + return "listenable" in vars.finals; +} + +public test bool shouldHaveAllFinalVarsInTheEnhancedDeclaredVarAsFinal() { + methodBody = enhancedForLoopFinalVarDecl(); + vars = findLocalVariables(methodBody); + return "index" in vars.finals && "listenable" in vars.finals && + size(vars.finals) == 2; +} + +public test bool shouldHaveTheNonFinalVarsInEnhancedDeclaredVarAsFinal() { + methodBody = enhancedForLoopFinalVarDecl(); + vars = findLocalVariables(methodBody); + return "i" in vars.nonFinals && size(vars.nonFinals) == 1; +} + + + + + + + + diff --git a/src/LocalVariablesFinderTestResources.rsc b/src/LocalVariablesFinderTestResources.rsc new file mode 100644 index 0000000..4471389 --- /dev/null +++ b/src/LocalVariablesFinderTestResources.rsc @@ -0,0 +1,11 @@ +module LocalVariablesFinderTestResources + +import IO; +import lang::java::\syntax::Java18; +import ParseTree; + +public MethodBody enhancedForLoopFinalVarDecl() { + fileLoc = |project://rascal-Java8//testes/localVariables/EnhancedForLoopFinalVarDecl|; + content = readFile(fileLoc); + return parse(#MethodBody, content); +} \ No newline at end of file diff --git a/testes/localVariables/EnhancedForLoopFinalVarDecl b/testes/localVariables/EnhancedForLoopFinalVarDecl new file mode 100644 index 0000000..0254eff --- /dev/null +++ b/testes/localVariables/EnhancedForLoopFinalVarDecl @@ -0,0 +1,44 @@ +{ + // Corner case: List is empty. + if (futures.isEmpty()) { + handleAllCompleted(); + return; + } + + // NOTE: If we ever want to use a custom executor here, have a look at CombinedFuture as we'll + // need to handle RejectedExecutionException + + if (allMustSucceed) { + // We need fail fast, so we have to keep track of which future failed so we can propagate + // the exception immediately + + // Register a listener on each Future in the list to update the state of this future. + // Note that if all the futures on the list are done prior to completing this loop, the last + // call to addListener() will callback to setOneValue(), transitively call our cleanup + // listener, and set this.futures to null. + // This is not actually a problem, since the foreach only needs this.futures to be non-null + // at the beginning of the loop. + int i = 0; + for (final ListenableFuture listenable : futures) { + final int index = i++; + listenable.addListener( + new Runnable() { + @Override + public void run() { + try { + handleOneInputDone(index, listenable); + } finally { + decrementCountAndMaybeComplete(); + } + } + }, + directExecutor()); + } + } else { + // We'll only call the callback when all futures complete, regardless of whether some failed + // Hold off on calling setOneValue until all complete, so we can share the same listener + for (ListenableFuture listenable : futures) { + listenable.addListener(this, directExecutor()); + } + } + } \ No newline at end of file From 6c7f81be35cb35b2c267c119597d54feec43c61b Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 22 Mar 2017 00:40:39 -0300 Subject: [PATCH 029/154] More test cases for LocalVariablesFinder --- src/LocalVariablesFinderTest.rsc | 19 ++++++++++----- src/LocalVariablesFinderTestResources.rsc | 6 +++++ .../EnhancedForLoopWithException | 24 +++++++++++++++++++ 3 files changed, 43 insertions(+), 6 deletions(-) create mode 100644 testes/localVariables/EnhancedForLoopWithException diff --git a/src/LocalVariablesFinderTest.rsc b/src/LocalVariablesFinderTest.rsc index 9d8b2e9..84bbf42 100644 --- a/src/LocalVariablesFinderTest.rsc +++ b/src/LocalVariablesFinderTest.rsc @@ -24,10 +24,17 @@ public test bool shouldHaveTheNonFinalVarsInEnhancedDeclaredVarAsFinal() { return "i" in vars.nonFinals && size(vars.nonFinals) == 1; } +public test bool shouldHaveAllFinalVarsInEnhancedWithException() { + methodBody = enhancedForLoopWithException(); + vars = findLocalVariables(methodBody); + return "map" in vars.finals && "entrySet" in vars.finals && + "unmappedKey" in vars.finals && "unmappedValue" in vars.finals && + size(vars.finals) == 4; +} - - - - - - +public test bool shouldHaveAllNonFinalVarsIncludingExceptionInEnhancedWithException() { + methodBody = enhancedForLoopWithException(); + vars = findLocalVariables(methodBody); + return "e" in vars.nonFinals && "entry" in vars.nonFinals && + size(vars.nonFinals) == 2; +} \ No newline at end of file diff --git a/src/LocalVariablesFinderTestResources.rsc b/src/LocalVariablesFinderTestResources.rsc index 4471389..6fb9397 100644 --- a/src/LocalVariablesFinderTestResources.rsc +++ b/src/LocalVariablesFinderTestResources.rsc @@ -8,4 +8,10 @@ public MethodBody enhancedForLoopFinalVarDecl() { fileLoc = |project://rascal-Java8//testes/localVariables/EnhancedForLoopFinalVarDecl|; content = readFile(fileLoc); return parse(#MethodBody, content); +} + +public MethodBody enhancedForLoopWithException() { + fileLoc = |project://rascal-Java8//testes/localVariables/EnhancedForLoopWithException|; + content = readFile(fileLoc); + return parse(#MethodBody, content); } \ No newline at end of file diff --git a/testes/localVariables/EnhancedForLoopWithException b/testes/localVariables/EnhancedForLoopWithException new file mode 100644 index 0000000..d87dbb5 --- /dev/null +++ b/testes/localVariables/EnhancedForLoopWithException @@ -0,0 +1,24 @@ +{ + final Map map; + final Set> entrySet; + try { + map = makePopulatedMap(); + } catch (UnsupportedOperationException e) { + return; + } + assertInvariants(map); + + entrySet = map.entrySet(); + final K unmappedKey; + final V unmappedValue; + try { + unmappedKey = getKeyNotInPopulatedMap(); + unmappedValue = getValueNotInPopulatedMap(); + } catch (UnsupportedOperationException e) { + return; + } + for (Entry entry : entrySet) { + assertFalse(unmappedKey.equals(entry.getKey())); + assertFalse(unmappedValue.equals(entry.getValue())); + } + } \ No newline at end of file From fbee8cc4c0a9060c8e11367ccf791224260aee72 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 22 Mar 2017 00:40:39 -0300 Subject: [PATCH 030/154] Starting to get variable types. --- src/LocalVariablesFinder.rsc | 50 ++++++++++++++----- src/LocalVariablesFinderTest.rsc | 27 ++++++---- src/MethodVar.rsc | 29 +++++++++++ .../EnhancedForLoopFinalVarDecl | 4 +- 4 files changed, 87 insertions(+), 23 deletions(-) create mode 100644 src/MethodVar.rsc diff --git a/src/LocalVariablesFinder.rsc b/src/LocalVariablesFinder.rsc index 41faaa4..d9a69e4 100644 --- a/src/LocalVariablesFinder.rsc +++ b/src/LocalVariablesFinder.rsc @@ -5,28 +5,54 @@ import lang::java::\syntax::Java18; import String; import ParseTree; import IO; +import MethodVar; // syntax LocalVariableDeclarationStatement = LocalVariableDeclaration ";"+ ; // syntax LocalVariableDeclaration = VariableModifier* UnannType VariableDeclaratorList ; // syntax VariableDeclaratorList = variableDeclaratorList: {VariableDeclarator ","}+ ; // syntax VariableDeclarator = variableDeclarator: VariableDeclaratorId ("=" VariableInitializer)? ; -public tuple[set[str] finals, set[str] nonFinals] findLocalVariables(MethodBody methodBody) { - set[str] finals = {}; - set[str] nonFinals = {}; +public set[MethodVar] findLocalVariables(MethodBody methodBody) { + set[MethodVar] methodVars = {}; visit(methodBody) { - case (EnhancedForStatement) `for ( final : ) `: - finals += trim(unparse(varId)); - case (LocalVariableDeclaration) `final `: { + + case (EnhancedForStatement) `for ( : ) `: + methodVars += createMethodVar(figureIfIsFinal(varMod), varId, varType); + + case (LocalVariableDeclaration) ` `: { visit(vdl) { case (VariableDeclaratorId) ` `: - finals += trim(unparse(varId)); + methodVars += createMethodVar(figureIfIsFinal(varMod), varId, varType); } } - // finding all variables declared, including ones in loop declaration - case VariableDeclaratorId varId: nonFinals += trim(unparse(varId)); + + case(CatchFormalParameter) ` `: + methodVars += createMethodVar(figureIfIsFinal(varMod), varId, varType); + } - // nonFinals must not have finals - nonFinals -= finals; - return ; + return methodVars; +} + +private MethodVar createMethodVar(bool isFinal, VariableDeclaratorId varId, UnannType varType) { + name = trim(unparse(varId)); + varTypeStr = trim(unparse(varType)); + return methodVar(isFinal, name, varTypeStr, true); +} + +private MethodVar createMethodVar(bool isFinal, Identifier varId, UnannType varType) { + name = trim(unparse(varId)); + varTypeStr = trim(unparse(varType)); + return methodVar(isFinal, name, varTypeStr, true); +} + +private MethodVar createMethodVar(bool isFinal, VariableDeclaratorId varId, CatchType varType) { + name = trim(unparse(varId)); + varTypeStr = trim(unparse(varType)); + return methodVar(isFinal, name, varTypeStr, true); +} + +private bool figureIfIsFinal(VariableModifier* varMod) { + if ("" := "final") + return true; + return false; } \ No newline at end of file diff --git a/src/LocalVariablesFinderTest.rsc b/src/LocalVariablesFinderTest.rsc index 84bbf42..555f16c 100644 --- a/src/LocalVariablesFinderTest.rsc +++ b/src/LocalVariablesFinderTest.rsc @@ -4,37 +4,46 @@ import IO; import LocalVariablesFinderTestResources; import LocalVariablesFinder; import Set; +import MethodVar; public test bool shouldHaveTheEnhancedDeclaredVarAsFinal() { methodBody = enhancedForLoopFinalVarDecl(); vars = findLocalVariables(methodBody); - return "listenable" in vars.finals; + finalsNames = retrieveFinalsNames(vars); + return "listenableFinal" in finalsNames; } public test bool shouldHaveAllFinalVarsInTheEnhancedDeclaredVarAsFinal() { methodBody = enhancedForLoopFinalVarDecl(); vars = findLocalVariables(methodBody); - return "index" in vars.finals && "listenable" in vars.finals && - size(vars.finals) == 2; + finalsNames = retrieveFinalsNames(vars); + return "index" in finalsNames && "listenableFinal" in finalsNames && + size(finalsNames) == 2; } public test bool shouldHaveTheNonFinalVarsInEnhancedDeclaredVarAsFinal() { methodBody = enhancedForLoopFinalVarDecl(); vars = findLocalVariables(methodBody); - return "i" in vars.nonFinals && size(vars.nonFinals) == 1; + nonFinalsNames = retrieveNonFinalsNames(vars); + println(vars); + println(nonFinalsNames); + return "i" in nonFinalsNames && "listenableNonFinal" in nonFinalsNames && + size(nonFinalsNames) == 2; } public test bool shouldHaveAllFinalVarsInEnhancedWithException() { methodBody = enhancedForLoopWithException(); vars = findLocalVariables(methodBody); - return "map" in vars.finals && "entrySet" in vars.finals && - "unmappedKey" in vars.finals && "unmappedValue" in vars.finals && - size(vars.finals) == 4; + finalsNames = retrieveFinalsNames(vars); + return "map" in finalsNames && "entrySet" in finalsNames && + "unmappedKey" in finalsNames && "unmappedValue" in finalsNames && + size(finalsNames) == 4; } public test bool shouldHaveAllNonFinalVarsIncludingExceptionInEnhancedWithException() { methodBody = enhancedForLoopWithException(); vars = findLocalVariables(methodBody); - return "e" in vars.nonFinals && "entry" in vars.nonFinals && - size(vars.nonFinals) == 2; + nonFinalsNames = retrieveNonFinalsNames(vars); + return "e" in nonFinalsNames && "entry" in nonFinalsNames && + size(nonFinalsNames) == 2; } \ No newline at end of file diff --git a/src/MethodVar.rsc b/src/MethodVar.rsc new file mode 100644 index 0000000..6874062 --- /dev/null +++ b/src/MethodVar.rsc @@ -0,0 +1,29 @@ +module MethodVar + +public data MethodVar = methodVar(bool isFinal, str name, str varType, bool isLocal); + +public bool isArray(MethodVar methodVar) { + return methodVar.varType == "array"; +} + +public bool isParameter(MethodVar methodVar) { + return !methodVar.isLocal; +} + +// may be improved. O(n) right now. +public set[MethodVar] retrieveFinals(set[MethodVar] methodVars) { + return { var | MethodVar var <- methodVars, var.isFinal }; +} + +// may be improved. O(n) right now. +public set[MethodVar] retrieveNonFinals(set[MethodVar] methodVars) { + return { var | MethodVar var <- methodVars, !var.isFinal }; +} + +public set[str] retrieveFinalsNames(set[MethodVar] methodVars) { + return { var.name | MethodVar var <- methodVars, var.isFinal }; +} + +public set[str] retrieveNonFinalsNames(set[MethodVar] methodVars) { + return { var.name | MethodVar var <- methodVars, !var.isFinal }; +} \ No newline at end of file diff --git a/testes/localVariables/EnhancedForLoopFinalVarDecl b/testes/localVariables/EnhancedForLoopFinalVarDecl index 0254eff..eec540b 100644 --- a/testes/localVariables/EnhancedForLoopFinalVarDecl +++ b/testes/localVariables/EnhancedForLoopFinalVarDecl @@ -19,7 +19,7 @@ // This is not actually a problem, since the foreach only needs this.futures to be non-null // at the beginning of the loop. int i = 0; - for (final ListenableFuture listenable : futures) { + for (final ListenableFuture listenableFinal : futures) { final int index = i++; listenable.addListener( new Runnable() { @@ -37,7 +37,7 @@ } else { // We'll only call the callback when all futures complete, regardless of whether some failed // Hold off on calling setOneValue until all complete, so we can share the same listener - for (ListenableFuture listenable : futures) { + for (ListenableFuture listenableNonFinal : futures) { listenable.addListener(this, directExecutor()); } } From c5417e133e39932043b529328522fd2ec2f2a54b Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 22 Mar 2017 00:40:39 -0300 Subject: [PATCH 031/154] Finding 'array' local variables. Missing discouraged array syntax vars --- src/LocalVariablesFinderTest.rsc | 49 +++++++++++++++++-- src/LocalVariablesFinderTestResources.rsc | 48 ++++++++++++++++++ src/MethodVar.rsc | 14 +++++- .../MultiplePlainArrayDeclarations | 15 ++++++ 4 files changed, 121 insertions(+), 5 deletions(-) create mode 100644 testes/localVariables/MultiplePlainArrayDeclarations diff --git a/src/LocalVariablesFinderTest.rsc b/src/LocalVariablesFinderTest.rsc index 555f16c..dc1bb74 100644 --- a/src/LocalVariablesFinderTest.rsc +++ b/src/LocalVariablesFinderTest.rsc @@ -25,8 +25,6 @@ public test bool shouldHaveTheNonFinalVarsInEnhancedDeclaredVarAsFinal() { methodBody = enhancedForLoopFinalVarDecl(); vars = findLocalVariables(methodBody); nonFinalsNames = retrieveNonFinalsNames(vars); - println(vars); - println(nonFinalsNames); return "i" in nonFinalsNames && "listenableNonFinal" in nonFinalsNames && size(nonFinalsNames) == 2; } @@ -46,4 +44,49 @@ public test bool shouldHaveAllNonFinalVarsIncludingExceptionInEnhancedWithExcept nonFinalsNames = retrieveNonFinalsNames(vars); return "e" in nonFinalsNames && "entry" in nonFinalsNames && size(nonFinalsNames) == 2; -} \ No newline at end of file +} + +public test bool intVarShouldHaveItsCorrectType() { + methodBody = enhancedForLoopFinalVarDecl(); + vars = findLocalVariables(methodBody); + varI = findByName(vars, "i"); + return varI.varType == "int"; +} + +public test bool encouragedDeclaredArrayVarsShouldBeArrays() { + methodBody = arrayVariables(); + vars = findLocalVariables(methodBody); + for(methodVar <- getEncouragedArrays(vars)) { + if(!isTypePlainArray(methodVar)) return false; + } + return true; +} + +public test bool discouragedDeclaredArrayVarsShouldBeArrays() { + methodBody = arrayVariables(); + vars = findLocalVariables(methodBody); + for(methodVar <- getDiscouragedArrays(vars)) { + if(!isTypePlainArray(methodVar)) return false; + } + return true; +} + +public test bool nonFinalArraysShouldBeNonFinal() { + methodBody = arrayVariables(); + vars = findLocalVariables(methodBody); + for(methodVar <- getAllNonFinalArrays(vars)) { + if(methodVar.isFinal) return false; + } + return true; +} + +public test bool finalArraysShouldBeFinal() { + methodBody = arrayVariables(); + vars = findLocalVariables(methodBody); + for(methodVar <- getAllFinalArrays(vars)) { + if(!methodVar.isFinal) return false; + } + return true; +} + + \ No newline at end of file diff --git a/src/LocalVariablesFinderTestResources.rsc b/src/LocalVariablesFinderTestResources.rsc index 6fb9397..027612a 100644 --- a/src/LocalVariablesFinderTestResources.rsc +++ b/src/LocalVariablesFinderTestResources.rsc @@ -3,6 +3,7 @@ module LocalVariablesFinderTestResources import IO; import lang::java::\syntax::Java18; import ParseTree; +import MethodVar; public MethodBody enhancedForLoopFinalVarDecl() { fileLoc = |project://rascal-Java8//testes/localVariables/EnhancedForLoopFinalVarDecl|; @@ -14,4 +15,51 @@ public MethodBody enhancedForLoopWithException() { fileLoc = |project://rascal-Java8//testes/localVariables/EnhancedForLoopWithException|; content = readFile(fileLoc); return parse(#MethodBody, content); +} + +public MethodBody arrayVariables() { + fileLoc = |project://rascal-Java8//testes/localVariables/MultiplePlainArrayDeclarations|; + content = readFile(fileLoc); + return parse(#MethodBody, content); +} + +public set[MethodVar] getEncouragedArrays(set[MethodVar] vars) { + return getNonFinalEncouragedArrays(vars) + getFinalEncouragedArrays(vars); +} + +public set[MethodVar] getNonFinalEncouragedArrays(set[MethodVar] vars) { + varIntArray = findByName(vars, "intArray"); + varStrArray = findByName(vars, "strArray"); + varObjArray = findByName(vars, "objArray"); + return {varIntArray, varStrArray, varObjArray}; +} + +public set[MethodVar] getFinalEncouragedArrays(set[MethodVar] vars) { + varFinalObjArray = findByName(vars, "finalObjArray"); + varFinalStrArray = findByName(vars, "finalStrArray"); + return {varFinalObjArray, varFinalStrArray}; +} + +public set[MethodVar] getDiscouragedArrays(set[MethodVar] vars) { + return getNonFinalDiscouragedArrays(vars) + getFinalDiscouragedArrays(vars); +} + +public set[MethodVar] getNonFinalDiscouragedArrays(set[MethodVar] vars) { + varObjDiscouraged = findByName(vars, "objDiscouraged"); + varStrDiscouraged = findByName(vars, "strDiscouraged"); + return {varObjDiscouraged, varStrDiscouraged}; +} + +public set[MethodVar] getFinalDiscouragedArrays(set[MethodVar] vars) { + varFinalObjDiscouraged = findByName(vars, "finalObjDiscouraged"); + varFinalIntDiscouraged = findByName(vars, "finalIntDiscouraged"); + return {varFinalObjDiscouraged, varFinalIntDiscouraged}; +} + +public set[MethodVar] getAllNonFinalArrays(set[MethodVar] vars) { + return getNonFinalEncouragedArrays(vars) + getNonFinalDiscouragedArrays(vars); +} + +public set[MethodVar] getAllFinalArrays(set[MethodVar] vars) { + return getFinalEncouragedArrays(vars) + getFinalDiscouragedArrays(vars); } \ No newline at end of file diff --git a/src/MethodVar.rsc b/src/MethodVar.rsc index 6874062..9e8cfc4 100644 --- a/src/MethodVar.rsc +++ b/src/MethodVar.rsc @@ -1,5 +1,9 @@ module MethodVar +import Set; +import String; + +// TODO Review if using a Set is the best choice. Probably not. public data MethodVar = methodVar(bool isFinal, str name, str varType, bool isLocal); public bool isArray(MethodVar methodVar) { @@ -10,12 +14,10 @@ public bool isParameter(MethodVar methodVar) { return !methodVar.isLocal; } -// may be improved. O(n) right now. public set[MethodVar] retrieveFinals(set[MethodVar] methodVars) { return { var | MethodVar var <- methodVars, var.isFinal }; } -// may be improved. O(n) right now. public set[MethodVar] retrieveNonFinals(set[MethodVar] methodVars) { return { var | MethodVar var <- methodVars, !var.isFinal }; } @@ -26,4 +28,12 @@ public set[str] retrieveFinalsNames(set[MethodVar] methodVars) { public set[str] retrieveNonFinalsNames(set[MethodVar] methodVars) { return { var.name | MethodVar var <- methodVars, !var.isFinal }; +} + +public MethodVar findByName(set[MethodVar] methodVars, str name) { + return getOneFrom({ var | MethodVar var <- methodVars, var.name == name }); +} + +public bool isTypePlainArray(MethodVar methodVar) { + return endsWith(methodVar.varType, "[]"); } \ No newline at end of file diff --git a/testes/localVariables/MultiplePlainArrayDeclarations b/testes/localVariables/MultiplePlainArrayDeclarations new file mode 100644 index 0000000..0e65cea --- /dev/null +++ b/testes/localVariables/MultiplePlainArrayDeclarations @@ -0,0 +1,15 @@ +{ + int[] intArray; + intArray = new int[5]; + String[] strArray = {"a", "b", "c"}; + Object[] objArray; + final Object[] finalObjArray; + final String[] finalStrArray = {"c", "b", "a"}; + + // discouraged syntax + Object objDiscouraged[]; + String strDiscouraged[] = {"a", "b", "c"}; + final Object finalObjDiscouraged[]; + final int finalIntDiscouraged[]; + finalIntDiscouraged = new int[5]; +} \ No newline at end of file From a6cd4ab12db91805488c940533f426fa04a24f72 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 22 Mar 2017 00:40:39 -0300 Subject: [PATCH 032/154] Finding 'array' local variables with discouraged syntax. --- src/LocalVariablesFinder.rsc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/LocalVariablesFinder.rsc b/src/LocalVariablesFinder.rsc index d9a69e4..ac3c2c0 100644 --- a/src/LocalVariablesFinder.rsc +++ b/src/LocalVariablesFinder.rsc @@ -21,8 +21,8 @@ public set[MethodVar] findLocalVariables(MethodBody methodBody) { case (LocalVariableDeclaration) ` `: { visit(vdl) { - case (VariableDeclaratorId) ` `: - methodVars += createMethodVar(figureIfIsFinal(varMod), varId, varType); + case (VariableDeclaratorId) ` `: + methodVars += createMethodVar(figureIfIsFinal(varMod), varId, varType, dims); } } @@ -39,9 +39,14 @@ private MethodVar createMethodVar(bool isFinal, VariableDeclaratorId varId, Unan return methodVar(isFinal, name, varTypeStr, true); } -private MethodVar createMethodVar(bool isFinal, Identifier varId, UnannType varType) { +private MethodVar createMethodVar(bool isFinal, Identifier varId, UnannType varType, Dims? dims) { name = trim(unparse(varId)); varTypeStr = trim(unparse(varType)); + dimsStr = trim(unparse(dims)); + + if(dimsStr == "[]") + varTypeStr += "[]"; + return methodVar(isFinal, name, varTypeStr, true); } From e95b2d93a7a5482d36fe2e1c81dc5d8a9b75797d Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 22 Mar 2017 00:40:39 -0300 Subject: [PATCH 033/154] Git ignore '*.rsc' in '/bin' --- bin/.gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bin/.gitignore b/bin/.gitignore index 63402fa..3040ad9 100644 --- a/bin/.gitignore +++ b/bin/.gitignore @@ -1,2 +1 @@ -/ExceptionFinder.rsc -/ExceptionFinderTest.rsc +/*.rsc From 7060988795b3cf0b48e5a4cafd53bcbb1bf8c2eb Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 22 Mar 2017 00:40:39 -0300 Subject: [PATCH 034/154] Comment explaining how array variables are stored. - [] --- src/LocalVariablesFinder.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/LocalVariablesFinder.rsc b/src/LocalVariablesFinder.rsc index ac3c2c0..6b6890b 100644 --- a/src/LocalVariablesFinder.rsc +++ b/src/LocalVariablesFinder.rsc @@ -44,6 +44,7 @@ private MethodVar createMethodVar(bool isFinal, Identifier varId, UnannType varT varTypeStr = trim(unparse(varType)); dimsStr = trim(unparse(dims)); + // Standarizing arrays to have varType == [] if(dimsStr == "[]") varTypeStr += "[]"; From c17d20ff32186d75af05b916c8085b844c6567f0 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 22 Mar 2017 00:40:39 -0300 Subject: [PATCH 035/154] Capturing iterated variable (only an identifier) --- src/ForLoop.rsc | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/src/ForLoop.rsc b/src/ForLoop.rsc index 77071da..640daa5 100644 --- a/src/ForLoop.rsc +++ b/src/ForLoop.rsc @@ -5,9 +5,12 @@ import lang::java::\syntax::Java18; import ParseTree; import util::Math; import LocalVariablesFinder; +import String; private set[str] checkedExceptionClasses; +private str iteratedVariable; + public void findForLoops(list[loc] locs, set[str] checkedExceptions) { checkedExceptionClasses = checkedExceptions; for(fileLoc <- locs) { @@ -21,25 +24,46 @@ public void findForLoops(list[loc] locs, set[str] checkedExceptions) { } private void lookForForStatements(CompilationUnit unit) { + iteratedVariable = ""; visit(unit) { - case (MethodDeclaration) ` `: { - bool findEffectiveFinalLocalVars = doesMethodHaveAnEligibleForLoop(methodBody); - if (findEffectiveFinalLocalVars) + case (MethodDeclaration) ` `: { + bool proceedToFindEffectiveFinalLocalVars = doesMethodHaveAnEligibleForLoop(methodBody); + if (proceedToFindEffectiveFinalLocalVars) findLocalVariables(methodBody); } } } private bool doesMethodHaveAnEligibleForLoop(MethodBody methodBody) { + bool eligible = false; visit(methodBody) { - case (EnhancedForStatement) `for ( : ) `: - return isLoopEligibleForRefactor(stmt); + case (EnhancedForStatement) `for ( : ) `: { + eligible = isLoopEligibleForRefactor(stmt); + if (eligible) { retrieveIteratedVariable(exp); println(methodBody); } + } case (EnhancedForStatementNoShortIf) `for ( : ) `: println("TODO"); } return false; } +// XXX Only checking iterable variables defined in method (local and parameter(SOON) ) +// Need to verify class and instance variables too! (not that hard) +// Doing the full check on a method call will be an entire new problem +// example: for (Object rowKey : table.rowKeySet()) +// TODO extract module and test +private void retrieveIteratedVariable(Expression exp) { + expStr = unparse(exp); + if (isExpVariableNameOnly(expStr)) { + iteratedVariable = expStr; + println(iteratedVariable); + } +} + +private bool isExpVariableNameOnly(str exp) { + return !contains(exp, ".") && !contains(exp, "("); +} + // TODO extract module and test it private bool isLoopEligibleForRefactor(Statement stmt) { returnCount = 0; From cad5c7180049e6204c23b28fa137c90c4650a167 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 22 Mar 2017 00:40:39 -0300 Subject: [PATCH 036/154] Checking if local variables are not arrays. --- src/EnhancedLoopExpression.rsc | 37 +++++++++++++++ src/ForLoop.rsc | 86 +++++++++++++--------------------- 2 files changed, 69 insertions(+), 54 deletions(-) create mode 100644 src/EnhancedLoopExpression.rsc diff --git a/src/EnhancedLoopExpression.rsc b/src/EnhancedLoopExpression.rsc new file mode 100644 index 0000000..71c71a5 --- /dev/null +++ b/src/EnhancedLoopExpression.rsc @@ -0,0 +1,37 @@ +module EnhancedLoopExpression + +import lang::java::\syntax::Java18; +import ParseTree; +import MethodVar; +import String; + +// XXX Only checking iterable variables defined in method (local and parameter(SOON) ) +// Need to verify class and instance variables too! (not that hard) +// Doing the full check on a method call will be an entire new problem +// example: for (Object rowKey : table.rowKeySet()) + +// Relying on compiler to help finding if it an array or not +// Compiler gives error if expression is not Array/Collection +// Therefore we only check if the expression is an Array +public bool isIteratingOnCollection(Expression exp, set[MethodVar] localVariables) { + if (isExpAnIdentifier(exp)) + return isIdentifierACollection(exp, localVariables); + else + return false; +} + +private bool isExpAnIdentifier(Expression exp) { + expStr = unparse(exp); + return !contains(expStr, ".") && !contains(expStr, "("); +} + +private bool isIdentifierACollection(Expression exp, set[MethodVar] localVariables) { + varName = unparse(exp); + var = findByName(localVariables, varName); + return !isTypePlainArray(var); +} + +// FIXME +private bool isExpressionReturningACollection(Expression exp) { + return false; +} \ No newline at end of file diff --git a/src/ForLoop.rsc b/src/ForLoop.rsc index 640daa5..43a48f5 100644 --- a/src/ForLoop.rsc +++ b/src/ForLoop.rsc @@ -3,14 +3,11 @@ module ForLoop import IO; import lang::java::\syntax::Java18; import ParseTree; -import util::Math; import LocalVariablesFinder; -import String; +import EnhancedLoopExpression; private set[str] checkedExceptionClasses; -private str iteratedVariable; - public void findForLoops(list[loc] locs, set[str] checkedExceptions) { checkedExceptionClasses = checkedExceptions; for(fileLoc <- locs) { @@ -26,74 +23,55 @@ public void findForLoops(list[loc] locs, set[str] checkedExceptions) { private void lookForForStatements(CompilationUnit unit) { iteratedVariable = ""; visit(unit) { - case (MethodDeclaration) ` `: { - bool proceedToFindEffectiveFinalLocalVars = doesMethodHaveAnEligibleForLoop(methodBody); - if (proceedToFindEffectiveFinalLocalVars) - findLocalVariables(methodBody); - } + case MethodDeclaration methodDeclaration: + lookForEnhancedForStatementsInMethod(methodDeclaration); } } -private bool doesMethodHaveAnEligibleForLoop(MethodBody methodBody) { - bool eligible = false; +private void lookForEnhancedForStatementsInMethod(MethodDeclaration methodDeclaration) { + visit(methodDeclaration) { + case (MethodDeclaration) ` `: + lookForEnhancedForStatementsInMethodBody(methodHeader, methodBody); + } +} + +private void lookForEnhancedForStatementsInMethodBody(MethodHeader methodHeader, MethodBody methodBody) { visit(methodBody) { - case (EnhancedForStatement) `for ( : ) `: { - eligible = isLoopEligibleForRefactor(stmt); - if (eligible) { retrieveIteratedVariable(exp); println(methodBody); } - } + case (EnhancedForStatement) `for ( : ) `: + checkLoopEligibilityForRefactor(methodBody, exp, stmt); case (EnhancedForStatementNoShortIf) `for ( : ) `: println("TODO"); } - return false; } -// XXX Only checking iterable variables defined in method (local and parameter(SOON) ) -// Need to verify class and instance variables too! (not that hard) -// Doing the full check on a method call will be an entire new problem -// example: for (Object rowKey : table.rowKeySet()) -// TODO extract module and test -private void retrieveIteratedVariable(Expression exp) { - expStr = unparse(exp); - if (isExpVariableNameOnly(expStr)) { - iteratedVariable = expStr; - println(iteratedVariable); +private void checkLoopEligibilityForRefactor(MethodBody methodBody, Expression exp, Statement stmt) { + if(loopBodyPassConditions(stmt)) { + localVariables = findLocalVariables(methodBody); + if (isIteratingOnCollection(exp, localVariables)) { + println("iterating on collection"); + println(methodBody); + println(); + } } } -private bool isExpVariableNameOnly(str exp) { - return !contains(exp, ".") && !contains(exp, "("); -} - // TODO extract module and test it -private bool isLoopEligibleForRefactor(Statement stmt) { +private bool loopBodyPassConditions(Statement stmt) { returnCount = 0; visit(stmt) { case (ThrowStatement) `throw new ( );`: { classNameStr = unparse(className); - if (classNameStr in checkedExceptionClasses) { - //println("found checked exception (" + classNameStr + ") thrown inside a for statement."); - return false; - } - } - case (BreakStatement) `break ;`: { - //println("found break statement inside a for statement."); - return false; - } - case (ReturnStatement) `return ;`: { - returnCount += 1; - } - // LambdaFicator restructures code to eliminate 'continue' - // if we don't do this, we should not allow 'continue' - // Even if we do it, no labeled 'continue' are allowed - case (ContinueStatement) `continue ;`: { - //println("found continue statement inside a for statement."); - return false; + if (classNameStr in checkedExceptionClasses) return false; } + + case (BreakStatement) `break ;`: return false; + + case (ReturnStatement) `return ;`: returnCount += 1; + + case (ContinueStatement) `continue ;`: return false; } - if (returnCount > 1) { - //println("more than one (" + toString(returnCount) + " total) return statements inside a for statement."); - // println(stmt); - return false; - } + + if (returnCount > 1) return false; + return true; } From d9d12e337c4c22d6eedca8b422b1223552769d8a Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 22 Mar 2017 00:40:39 -0300 Subject: [PATCH 037/154] Not printing debug lines in ExceptionFinder. --- src/ExceptionFinder.rsc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ExceptionFinder.rsc b/src/ExceptionFinder.rsc index 150b5b8..63a6bbd 100644 --- a/src/ExceptionFinder.rsc +++ b/src/ExceptionFinder.rsc @@ -92,10 +92,10 @@ private set[str] getAllDirectSubClassesOf(str className) { } private void printJavaFilesThatCouldNotBeParsed() { - str filesNotParsedCount = toString(size(fileLocationsThatCouldNotBeParsed)); - println(filesNotParsedCount + " Java File Locations that could not be parsed. "); - if (printAllFileNamesThatCouldNotBeParsed) { + str filesNotParsedCount = toString(size(fileLocationsThatCouldNotBeParsed)); + println(filesNotParsedCount + " Java File Locations that could not be parsed. "); + for(fileLoc <- fileLocationsThatCouldNotBeParsed) print(fileLoc.file + ", "); println(); From 2ee462a60abf38011c3efeb4da74c9709757c3ec Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 22 Mar 2017 00:40:39 -0300 Subject: [PATCH 038/154] LocalVariablesFinder finding variables from method parameters. - Maybe 'LocalVariables' isn't the best name. --- src/LocalVariablesFinder.rsc | 36 ++++++++--- src/LocalVariablesFinderTest.rsc | 74 +++++++++++++++++++---- src/LocalVariablesFinderTestResources.rsc | 30 +++++++++ src/MethodVar.rsc | 16 +++++ 4 files changed, 138 insertions(+), 18 deletions(-) diff --git a/src/LocalVariablesFinder.rsc b/src/LocalVariablesFinder.rsc index 6b6890b..805a153 100644 --- a/src/LocalVariablesFinder.rsc +++ b/src/LocalVariablesFinder.rsc @@ -12,34 +12,56 @@ import MethodVar; // syntax VariableDeclaratorList = variableDeclaratorList: {VariableDeclarator ","}+ ; // syntax VariableDeclarator = variableDeclarator: VariableDeclaratorId ("=" VariableInitializer)? ; -public set[MethodVar] findLocalVariables(MethodBody methodBody) { +public set[MethodVar] findLocalVariables(MethodHeader methodHeader, MethodBody methodBody) { + set[MethodVar] methodVars = {}; + methodVars += findVariablesAsParameters(methodHeader); + methodVars += findVariablesInsideBody(methodBody); + return methodVars; +} + +private set[MethodVar] findVariablesAsParameters(MethodHeader methodHeader) { + set[MethodVar] methodVars = {}; + visit(methodHeader) { + case (FormalParameter) ` `: + methodVars += createNonLocalMethodVar(figureIfIsFinal(varMod), varId, varType); + } + return methodVars; +} + +private set[MethodVar] findVariablesInsideBody(MethodBody methodBody) { set[MethodVar] methodVars = {}; visit(methodBody) { case (EnhancedForStatement) `for ( : ) `: - methodVars += createMethodVar(figureIfIsFinal(varMod), varId, varType); + methodVars += createLocalMethodVar(figureIfIsFinal(varMod), varId, varType); case (LocalVariableDeclaration) ` `: { visit(vdl) { case (VariableDeclaratorId) ` `: - methodVars += createMethodVar(figureIfIsFinal(varMod), varId, varType, dims); + methodVars += createLocalMethodVar(figureIfIsFinal(varMod), varId, varType, dims); } } case(CatchFormalParameter) ` `: - methodVars += createMethodVar(figureIfIsFinal(varMod), varId, varType); + methodVars += createLocalMethodVar(figureIfIsFinal(varMod), varId, varType); } return methodVars; } -private MethodVar createMethodVar(bool isFinal, VariableDeclaratorId varId, UnannType varType) { +private MethodVar createNonLocalMethodVar(bool isFinal, VariableDeclaratorId varId, UnannType varType) { + name = trim(unparse(varId)); + varTypeStr = trim(unparse(varType)); + return methodVar(isFinal, name, varTypeStr, false); +} + +private MethodVar createLocalMethodVar(bool isFinal, VariableDeclaratorId varId, UnannType varType) { name = trim(unparse(varId)); varTypeStr = trim(unparse(varType)); return methodVar(isFinal, name, varTypeStr, true); } -private MethodVar createMethodVar(bool isFinal, Identifier varId, UnannType varType, Dims? dims) { +private MethodVar createLocalMethodVar(bool isFinal, Identifier varId, UnannType varType, Dims? dims) { name = trim(unparse(varId)); varTypeStr = trim(unparse(varType)); dimsStr = trim(unparse(dims)); @@ -51,7 +73,7 @@ private MethodVar createMethodVar(bool isFinal, Identifier varId, UnannType varT return methodVar(isFinal, name, varTypeStr, true); } -private MethodVar createMethodVar(bool isFinal, VariableDeclaratorId varId, CatchType varType) { +private MethodVar createLocalMethodVar(bool isFinal, VariableDeclaratorId varId, CatchType varType) { name = trim(unparse(varId)); varTypeStr = trim(unparse(varType)); return methodVar(isFinal, name, varTypeStr, true); diff --git a/src/LocalVariablesFinderTest.rsc b/src/LocalVariablesFinderTest.rsc index dc1bb74..2d18697 100644 --- a/src/LocalVariablesFinderTest.rsc +++ b/src/LocalVariablesFinderTest.rsc @@ -8,14 +8,14 @@ import MethodVar; public test bool shouldHaveTheEnhancedDeclaredVarAsFinal() { methodBody = enhancedForLoopFinalVarDecl(); - vars = findLocalVariables(methodBody); + vars = findLocalVariables(emptyMethodHeader(), methodBody); finalsNames = retrieveFinalsNames(vars); return "listenableFinal" in finalsNames; } public test bool shouldHaveAllFinalVarsInTheEnhancedDeclaredVarAsFinal() { methodBody = enhancedForLoopFinalVarDecl(); - vars = findLocalVariables(methodBody); + vars = findLocalVariables(emptyMethodHeader(), methodBody); finalsNames = retrieveFinalsNames(vars); return "index" in finalsNames && "listenableFinal" in finalsNames && size(finalsNames) == 2; @@ -23,7 +23,7 @@ public test bool shouldHaveAllFinalVarsInTheEnhancedDeclaredVarAsFinal() { public test bool shouldHaveTheNonFinalVarsInEnhancedDeclaredVarAsFinal() { methodBody = enhancedForLoopFinalVarDecl(); - vars = findLocalVariables(methodBody); + vars = findLocalVariables(emptyMethodHeader(), methodBody); nonFinalsNames = retrieveNonFinalsNames(vars); return "i" in nonFinalsNames && "listenableNonFinal" in nonFinalsNames && size(nonFinalsNames) == 2; @@ -31,7 +31,7 @@ public test bool shouldHaveTheNonFinalVarsInEnhancedDeclaredVarAsFinal() { public test bool shouldHaveAllFinalVarsInEnhancedWithException() { methodBody = enhancedForLoopWithException(); - vars = findLocalVariables(methodBody); + vars = findLocalVariables(emptyMethodHeader(), methodBody); finalsNames = retrieveFinalsNames(vars); return "map" in finalsNames && "entrySet" in finalsNames && "unmappedKey" in finalsNames && "unmappedValue" in finalsNames && @@ -40,7 +40,7 @@ public test bool shouldHaveAllFinalVarsInEnhancedWithException() { public test bool shouldHaveAllNonFinalVarsIncludingExceptionInEnhancedWithException() { methodBody = enhancedForLoopWithException(); - vars = findLocalVariables(methodBody); + vars = findLocalVariables(emptyMethodHeader(), methodBody); nonFinalsNames = retrieveNonFinalsNames(vars); return "e" in nonFinalsNames && "entry" in nonFinalsNames && size(nonFinalsNames) == 2; @@ -48,14 +48,14 @@ public test bool shouldHaveAllNonFinalVarsIncludingExceptionInEnhancedWithExcept public test bool intVarShouldHaveItsCorrectType() { methodBody = enhancedForLoopFinalVarDecl(); - vars = findLocalVariables(methodBody); + vars = findLocalVariables(emptyMethodHeader(), methodBody); varI = findByName(vars, "i"); return varI.varType == "int"; } public test bool encouragedDeclaredArrayVarsShouldBeArrays() { methodBody = arrayVariables(); - vars = findLocalVariables(methodBody); + vars = findLocalVariables(emptyMethodHeader(), methodBody); for(methodVar <- getEncouragedArrays(vars)) { if(!isTypePlainArray(methodVar)) return false; } @@ -64,7 +64,7 @@ public test bool encouragedDeclaredArrayVarsShouldBeArrays() { public test bool discouragedDeclaredArrayVarsShouldBeArrays() { methodBody = arrayVariables(); - vars = findLocalVariables(methodBody); + vars = findLocalVariables(emptyMethodHeader(), methodBody); for(methodVar <- getDiscouragedArrays(vars)) { if(!isTypePlainArray(methodVar)) return false; } @@ -73,7 +73,7 @@ public test bool discouragedDeclaredArrayVarsShouldBeArrays() { public test bool nonFinalArraysShouldBeNonFinal() { methodBody = arrayVariables(); - vars = findLocalVariables(methodBody); + vars = findLocalVariables(emptyMethodHeader(), methodBody); for(methodVar <- getAllNonFinalArrays(vars)) { if(methodVar.isFinal) return false; } @@ -82,11 +82,63 @@ public test bool nonFinalArraysShouldBeNonFinal() { public test bool finalArraysShouldBeFinal() { methodBody = arrayVariables(); - vars = findLocalVariables(methodBody); + vars = findLocalVariables(emptyMethodHeader(), methodBody); for(methodVar <- getAllFinalArrays(vars)) { if(!methodVar.isFinal) return false; } return true; } - \ No newline at end of file +public test bool shouldReturnNonFinalSingleParameter() { + methodHeader = nonFinalSingleParameterMethodHeader(); + methodBody = emptyMethodBody(); + + vars = findLocalVariables(methodHeader, methodBody); + nonLocals = retrieveNonLocals(vars); + var = findByName(vars, "param"); + + return size(nonLocals) == 1 && !var.isFinal && !var.isLocal; +} + +public test bool shouldReturnFinalSingleParamater() { + methodHeader = finalSingleParameterMethodHeader(); + methodBody = emptyMethodBody(); + + vars = findLocalVariables(methodHeader, methodBody); + nonLocals = retrieveNonLocals(vars); + var = findByName(vars, "finalParam"); + + return size(nonLocals) == 1 && var.isFinal && !var.isLocal; +} + +public test bool shouldReturnCorrectParamsWithLastOneFinal() { + methodHeader = multipleParametersLastFinalMethodHeader(); + methodBody = emptyMethodBody(); + + vars = findLocalVariables(methodHeader, methodBody); + nonLocals = retrieveNonLocals(vars); + param = findByName(vars, "param"); + strParam = findByName(vars, "str"); + finalLastParam = findByName(vars, "finalLastParam"); + + return size(nonLocals) == 3 && + !param.isFinal && !param.isLocal && + !strParam.isFinal && !strParam.isLocal && + finalLastParam.isFinal && !finalLastParam.isLocal; +} + +public test bool shouldReturnCorrectParamsWithLastOneNonFinal() { + methodHeader = multipleParametersLastNonFinalMethodHeader(); + methodBody = emptyMethodBody(); + + vars = findLocalVariables(methodHeader, methodBody); + nonLocals = retrieveNonLocals(vars); + param = findByName(vars, "param"); + strParam = findByName(vars, "str"); + nonFinalLastParam = findByName(vars, "nonFinalLastParam"); + + return size(nonLocals) == 3 && + !param.isFinal && !param.isLocal && + !strParam.isFinal && !strParam.isLocal && + !nonFinalLastParam.isFinal && !nonFinalLastParam.isLocal; +} diff --git a/src/LocalVariablesFinderTestResources.rsc b/src/LocalVariablesFinderTestResources.rsc index 027612a..2afed50 100644 --- a/src/LocalVariablesFinderTestResources.rsc +++ b/src/LocalVariablesFinderTestResources.rsc @@ -5,6 +5,36 @@ import lang::java::\syntax::Java18; import ParseTree; import MethodVar; +public MethodHeader emptyMethodHeader() { + header = "void method()"; + return parse(#MethodHeader, header); +} + +public MethodHeader nonFinalSingleParameterMethodHeader() { + header = "void method(int param)"; + return parse(#MethodHeader, header); +} + +public MethodHeader finalSingleParameterMethodHeader() { + header = "void method(final int finalParam)"; + return parse(#MethodHeader, header); +} + +public MethodHeader multipleParametersLastFinalMethodHeader() { + header = "void method(int param, String str, final double finalLastParam)"; + return parse(#MethodHeader, header); +} + +public MethodHeader multipleParametersLastNonFinalMethodHeader() { + header = "void method(int param, String str, double nonFinalLastParam)"; + return parse(#MethodHeader, header); +} + +public MethodBody emptyMethodBody() { + body = "{}"; + return parse(#MethodBody, body); +} + public MethodBody enhancedForLoopFinalVarDecl() { fileLoc = |project://rascal-Java8//testes/localVariables/EnhancedForLoopFinalVarDecl|; content = readFile(fileLoc); diff --git a/src/MethodVar.rsc b/src/MethodVar.rsc index 9e8cfc4..d98b8f6 100644 --- a/src/MethodVar.rsc +++ b/src/MethodVar.rsc @@ -34,6 +34,22 @@ public MethodVar findByName(set[MethodVar] methodVars, str name) { return getOneFrom({ var | MethodVar var <- methodVars, var.name == name }); } +public set[MethodVar] retrieveLocals(set[MethodVar] methodVars) { + return { var | MethodVar var <- methodVars, var.isLocal }; +} + +public set[MethodVar] retrieveNonLocals(set[MethodVar] methodVars) { + return { var | MethodVar var <- methodVars, !var.isLocal }; +} + +public set[str] retrieveLocalNames(set[MethodVar] methodVars) { + return { var.name | MethodVar var <- methodVars, var.isLocal }; +} + +public set[str] retrieveNonLocalNames(set[MethodVar] methodVars) { + return { var.name | MethodVar var <- methodVars, !var.isLocal }; +} + public bool isTypePlainArray(MethodVar methodVar) { return endsWith(methodVar.varType, "[]"); } \ No newline at end of file From 36a0d97eeefbfc9cb5109041d4aa0533bc8be3e9 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 22 Mar 2017 00:40:39 -0300 Subject: [PATCH 039/154] Changing 'isLocal' to 'isParameter' --- src/LocalVariablesFinder.rsc | 12 ++++----- src/LocalVariablesFinderTest.rsc | 44 +++++++++++++++++++++++--------- src/MethodVar.rsc | 20 +++++++-------- 3 files changed, 48 insertions(+), 28 deletions(-) diff --git a/src/LocalVariablesFinder.rsc b/src/LocalVariablesFinder.rsc index 805a153..cd6cb38 100644 --- a/src/LocalVariablesFinder.rsc +++ b/src/LocalVariablesFinder.rsc @@ -23,7 +23,7 @@ private set[MethodVar] findVariablesAsParameters(MethodHeader methodHeader) { set[MethodVar] methodVars = {}; visit(methodHeader) { case (FormalParameter) ` `: - methodVars += createNonLocalMethodVar(figureIfIsFinal(varMod), varId, varType); + methodVars += createParameterMethodVar(figureIfIsFinal(varMod), varId, varType); } return methodVars; } @@ -49,16 +49,16 @@ private set[MethodVar] findVariablesInsideBody(MethodBody methodBody) { return methodVars; } -private MethodVar createNonLocalMethodVar(bool isFinal, VariableDeclaratorId varId, UnannType varType) { +private MethodVar createParameterMethodVar(bool isFinal, VariableDeclaratorId varId, UnannType varType) { name = trim(unparse(varId)); varTypeStr = trim(unparse(varType)); - return methodVar(isFinal, name, varTypeStr, false); + return methodVar(isFinal, name, varTypeStr, true); } private MethodVar createLocalMethodVar(bool isFinal, VariableDeclaratorId varId, UnannType varType) { name = trim(unparse(varId)); varTypeStr = trim(unparse(varType)); - return methodVar(isFinal, name, varTypeStr, true); + return methodVar(isFinal, name, varTypeStr, false); } private MethodVar createLocalMethodVar(bool isFinal, Identifier varId, UnannType varType, Dims? dims) { @@ -70,13 +70,13 @@ private MethodVar createLocalMethodVar(bool isFinal, Identifier varId, UnannType if(dimsStr == "[]") varTypeStr += "[]"; - return methodVar(isFinal, name, varTypeStr, true); + return methodVar(isFinal, name, varTypeStr, false); } private MethodVar createLocalMethodVar(bool isFinal, VariableDeclaratorId varId, CatchType varType) { name = trim(unparse(varId)); varTypeStr = trim(unparse(varType)); - return methodVar(isFinal, name, varTypeStr, true); + return methodVar(isFinal, name, varTypeStr, false); } private bool figureIfIsFinal(VariableModifier* varMod) { diff --git a/src/LocalVariablesFinderTest.rsc b/src/LocalVariablesFinderTest.rsc index 2d18697..716f9cd 100644 --- a/src/LocalVariablesFinderTest.rsc +++ b/src/LocalVariablesFinderTest.rsc @@ -9,14 +9,18 @@ import MethodVar; public test bool shouldHaveTheEnhancedDeclaredVarAsFinal() { methodBody = enhancedForLoopFinalVarDecl(); vars = findLocalVariables(emptyMethodHeader(), methodBody); + finalsNames = retrieveFinalsNames(vars); + return "listenableFinal" in finalsNames; } public test bool shouldHaveAllFinalVarsInTheEnhancedDeclaredVarAsFinal() { methodBody = enhancedForLoopFinalVarDecl(); vars = findLocalVariables(emptyMethodHeader(), methodBody); + finalsNames = retrieveFinalsNames(vars); + return "index" in finalsNames && "listenableFinal" in finalsNames && size(finalsNames) == 2; } @@ -24,7 +28,9 @@ public test bool shouldHaveAllFinalVarsInTheEnhancedDeclaredVarAsFinal() { public test bool shouldHaveTheNonFinalVarsInEnhancedDeclaredVarAsFinal() { methodBody = enhancedForLoopFinalVarDecl(); vars = findLocalVariables(emptyMethodHeader(), methodBody); + nonFinalsNames = retrieveNonFinalsNames(vars); + return "i" in nonFinalsNames && "listenableNonFinal" in nonFinalsNames && size(nonFinalsNames) == 2; } @@ -32,7 +38,9 @@ public test bool shouldHaveTheNonFinalVarsInEnhancedDeclaredVarAsFinal() { public test bool shouldHaveAllFinalVarsInEnhancedWithException() { methodBody = enhancedForLoopWithException(); vars = findLocalVariables(emptyMethodHeader(), methodBody); + finalsNames = retrieveFinalsNames(vars); + return "map" in finalsNames && "entrySet" in finalsNames && "unmappedKey" in finalsNames && "unmappedValue" in finalsNames && size(finalsNames) == 4; @@ -41,21 +49,27 @@ public test bool shouldHaveAllFinalVarsInEnhancedWithException() { public test bool shouldHaveAllNonFinalVarsIncludingExceptionInEnhancedWithException() { methodBody = enhancedForLoopWithException(); vars = findLocalVariables(emptyMethodHeader(), methodBody); + nonFinalsNames = retrieveNonFinalsNames(vars); + return "e" in nonFinalsNames && "entry" in nonFinalsNames && size(nonFinalsNames) == 2; } public test bool intVarShouldHaveItsCorrectType() { methodBody = enhancedForLoopFinalVarDecl(); + vars = findLocalVariables(emptyMethodHeader(), methodBody); varI = findByName(vars, "i"); + return varI.varType == "int"; } public test bool encouragedDeclaredArrayVarsShouldBeArrays() { methodBody = arrayVariables(); + vars = findLocalVariables(emptyMethodHeader(), methodBody); + for(methodVar <- getEncouragedArrays(vars)) { if(!isTypePlainArray(methodVar)) return false; } @@ -64,7 +78,9 @@ public test bool encouragedDeclaredArrayVarsShouldBeArrays() { public test bool discouragedDeclaredArrayVarsShouldBeArrays() { methodBody = arrayVariables(); + vars = findLocalVariables(emptyMethodHeader(), methodBody); + for(methodVar <- getDiscouragedArrays(vars)) { if(!isTypePlainArray(methodVar)) return false; } @@ -73,7 +89,9 @@ public test bool discouragedDeclaredArrayVarsShouldBeArrays() { public test bool nonFinalArraysShouldBeNonFinal() { methodBody = arrayVariables(); + vars = findLocalVariables(emptyMethodHeader(), methodBody); + for(methodVar <- getAllNonFinalArrays(vars)) { if(methodVar.isFinal) return false; } @@ -82,7 +100,9 @@ public test bool nonFinalArraysShouldBeNonFinal() { public test bool finalArraysShouldBeFinal() { methodBody = arrayVariables(); + vars = findLocalVariables(emptyMethodHeader(), methodBody); + for(methodVar <- getAllFinalArrays(vars)) { if(!methodVar.isFinal) return false; } @@ -94,10 +114,10 @@ public test bool shouldReturnNonFinalSingleParameter() { methodBody = emptyMethodBody(); vars = findLocalVariables(methodHeader, methodBody); - nonLocals = retrieveNonLocals(vars); + nonLocals = retrieveParameters(vars); var = findByName(vars, "param"); - return size(nonLocals) == 1 && !var.isFinal && !var.isLocal; + return size(nonLocals) == 1 && !var.isFinal && var.isParameter; } public test bool shouldReturnFinalSingleParamater() { @@ -105,10 +125,10 @@ public test bool shouldReturnFinalSingleParamater() { methodBody = emptyMethodBody(); vars = findLocalVariables(methodHeader, methodBody); - nonLocals = retrieveNonLocals(vars); + nonLocals = retrieveParameters(vars); var = findByName(vars, "finalParam"); - return size(nonLocals) == 1 && var.isFinal && !var.isLocal; + return size(nonLocals) == 1 && var.isFinal && var.isParameter; } public test bool shouldReturnCorrectParamsWithLastOneFinal() { @@ -116,15 +136,15 @@ public test bool shouldReturnCorrectParamsWithLastOneFinal() { methodBody = emptyMethodBody(); vars = findLocalVariables(methodHeader, methodBody); - nonLocals = retrieveNonLocals(vars); + nonLocals = retrieveParameters(vars); param = findByName(vars, "param"); strParam = findByName(vars, "str"); finalLastParam = findByName(vars, "finalLastParam"); return size(nonLocals) == 3 && - !param.isFinal && !param.isLocal && - !strParam.isFinal && !strParam.isLocal && - finalLastParam.isFinal && !finalLastParam.isLocal; + !param.isFinal && param.isParameter && + !strParam.isFinal && strParam.isParameter && + finalLastParam.isFinal && finalLastParam.isParameter; } public test bool shouldReturnCorrectParamsWithLastOneNonFinal() { @@ -132,13 +152,13 @@ public test bool shouldReturnCorrectParamsWithLastOneNonFinal() { methodBody = emptyMethodBody(); vars = findLocalVariables(methodHeader, methodBody); - nonLocals = retrieveNonLocals(vars); + nonLocals = retrieveParameters(vars); param = findByName(vars, "param"); strParam = findByName(vars, "str"); nonFinalLastParam = findByName(vars, "nonFinalLastParam"); return size(nonLocals) == 3 && - !param.isFinal && !param.isLocal && - !strParam.isFinal && !strParam.isLocal && - !nonFinalLastParam.isFinal && !nonFinalLastParam.isLocal; + !param.isFinal && param.isParameter && + !strParam.isFinal && strParam.isParameter && + !nonFinalLastParam.isFinal && nonFinalLastParam.isParameter; } diff --git a/src/MethodVar.rsc b/src/MethodVar.rsc index d98b8f6..ed85d8c 100644 --- a/src/MethodVar.rsc +++ b/src/MethodVar.rsc @@ -4,14 +4,14 @@ import Set; import String; // TODO Review if using a Set is the best choice. Probably not. -public data MethodVar = methodVar(bool isFinal, str name, str varType, bool isLocal); +public data MethodVar = methodVar(bool isFinal, str name, str varType, bool isParameter); public bool isArray(MethodVar methodVar) { return methodVar.varType == "array"; } public bool isParameter(MethodVar methodVar) { - return !methodVar.isLocal; + return !methodVar.isParameter; } public set[MethodVar] retrieveFinals(set[MethodVar] methodVars) { @@ -34,20 +34,20 @@ public MethodVar findByName(set[MethodVar] methodVars, str name) { return getOneFrom({ var | MethodVar var <- methodVars, var.name == name }); } -public set[MethodVar] retrieveLocals(set[MethodVar] methodVars) { - return { var | MethodVar var <- methodVars, var.isLocal }; +public set[MethodVar] retrieveParameters(set[MethodVar] methodVars) { + return { var | MethodVar var <- methodVars, var.isParameter }; } -public set[MethodVar] retrieveNonLocals(set[MethodVar] methodVars) { - return { var | MethodVar var <- methodVars, !var.isLocal }; +public set[MethodVar] retrieveNonParameters(set[MethodVar] methodVars) { + return { var | MethodVar var <- methodVars, !var.isParameter }; } -public set[str] retrieveLocalNames(set[MethodVar] methodVars) { - return { var.name | MethodVar var <- methodVars, var.isLocal }; +public set[str] retrieveParametersNames(set[MethodVar] methodVars) { + return { var.name | MethodVar var <- methodVars, var.isParameter }; } -public set[str] retrieveNonLocalNames(set[MethodVar] methodVars) { - return { var.name | MethodVar var <- methodVars, !var.isLocal }; +public set[str] retrieveNonParametersNames(set[MethodVar] methodVars) { + return { var.name | MethodVar var <- methodVars, !var.isParameter }; } public bool isTypePlainArray(MethodVar methodVar) { From 2936da1d438ef2f52f84ccda5b990065a74e766f Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 040/154] Starting to break loop in prospective operations. --- src/ForLoop.rsc | 29 +++-- .../forloop/ForLoopBodyReferences.rsc | 25 +++++ src/refactor/forloop/ProspectiveOperation.rsc | 106 ++++++++++++++++++ testes/localVariables/ForLoopToFunctional | 49 ++++++++ 4 files changed, 197 insertions(+), 12 deletions(-) create mode 100644 src/refactor/forloop/ForLoopBodyReferences.rsc create mode 100644 src/refactor/forloop/ProspectiveOperation.rsc create mode 100644 testes/localVariables/ForLoopToFunctional diff --git a/src/ForLoop.rsc b/src/ForLoop.rsc index 43a48f5..bb72f1f 100644 --- a/src/ForLoop.rsc +++ b/src/ForLoop.rsc @@ -5,6 +5,9 @@ import lang::java::\syntax::Java18; import ParseTree; import LocalVariablesFinder; import EnhancedLoopExpression; +import refactor::forloop::ForLoopBodyReferences; +import refactor::forloop::ProspectiveOperation; +import MethodVar; private set[str] checkedExceptionClasses; @@ -37,22 +40,24 @@ private void lookForEnhancedForStatementsInMethod(MethodDeclaration methodDeclar private void lookForEnhancedForStatementsInMethodBody(MethodHeader methodHeader, MethodBody methodBody) { visit(methodBody) { - case (EnhancedForStatement) `for ( : ) `: - checkLoopEligibilityForRefactor(methodBody, exp, stmt); + case EnhancedForStatement forStmt: { + visit(forStmt) { + case (EnhancedForStatement) `for ( : ) `: { + methodLocalVariables = findLocalVariables(methodHeader, methodBody); + checkLoopEligibilityForRefactor(methodLocalVariables, exp, stmt); + retrievePotentialOperations(methodLocalVariables, forStmt); + } + } + } + case (EnhancedForStatementNoShortIf) `for ( : ) `: println("TODO"); } } -private void checkLoopEligibilityForRefactor(MethodBody methodBody, Expression exp, Statement stmt) { - if(loopBodyPassConditions(stmt)) { - localVariables = findLocalVariables(methodBody); - if (isIteratingOnCollection(exp, localVariables)) { - println("iterating on collection"); - println(methodBody); - println(); - } - } +private bool checkLoopEligibilityForRefactor(set[MethodVar] methodLocalVariables, Expression exp, Statement stmt) { + return loopBodyPassConditions(stmt) && isIteratingOnCollection(exp, methodLocalVariables) && + atMostOneReferenceToNonEffectiveFinalVar(methodLocalVariables, stmt); } // TODO extract module and test it @@ -74,4 +79,4 @@ private bool loopBodyPassConditions(Statement stmt) { if (returnCount > 1) return false; return true; -} +} \ No newline at end of file diff --git a/src/refactor/forloop/ForLoopBodyReferences.rsc b/src/refactor/forloop/ForLoopBodyReferences.rsc new file mode 100644 index 0000000..431288f --- /dev/null +++ b/src/refactor/forloop/ForLoopBodyReferences.rsc @@ -0,0 +1,25 @@ +module refactor::forloop::ForLoopBodyReferences + +import lang::java::\syntax::Java18; +import String; +import ParseTree; +import IO; +import Set; +import MethodVar; + +// TODO still need to find effective final vars somewhere. +public bool atMostOneReferenceToNonEffectiveFinalVar(set[MethodVar] localVariables, Statement loopBody) { + varsReferenced = findVariablesReferenced(loopBody); + return size(varsReferenced) <= 1; +} + +private set[str] findVariablesReferenced(Statement stmt) { + set[str] varsReferenced = {}; + + visit (stmt) { + case (Assignment) ` `: + varsReferenced += trim(unparse(lhs)); + } + + return varsReferenced; +} \ No newline at end of file diff --git a/src/refactor/forloop/ProspectiveOperation.rsc b/src/refactor/forloop/ProspectiveOperation.rsc new file mode 100644 index 0000000..6e96401 --- /dev/null +++ b/src/refactor/forloop/ProspectiveOperation.rsc @@ -0,0 +1,106 @@ +module refactor::forloop::ProspectiveOperation + +import IO; +import lang::java::\syntax::Java18; +import ParseTree; +import ParseTreeVisualization; +import Set; +import util::Math; +import MethodVar; +import String; + +public data ProspectiveOperation = prospectiveOperation(Statement stmt, str operation); +public data ProspectiveOperation = prospectiveOperation(ExpressionStatement stmt2, str operation); + +str FILTER = "filter"; +str MAP = "map"; +str FOR_EACH = "forEach"; +str REDUCE = "reduce"; +str ANY_MATCH = "anyMatch"; +str NONE_MATCH = "noneMatch"; + +private set[MethodVar] methodLocalVars; + +public void retrievePotentialOperations(set[MethodVar] localVars, EnhancedForStatement forStmt) { + methodLocalVars = localVars; + visit(forStmt) { + case (EnhancedForStatement) `for ( : ) `: { + r = retrieveProspectiveOperationsFromStatement(stmt); + println("prospective operations: " + toString(size(r))); + for (prOp <- r) { + println(); + println(prOp.operation); + println(unparse(prOp.stmt2)); + } + } + } +} + +private set[ProspectiveOperation] retrieveProspectiveOperationsFromStatement(Statement stmt) { + set[ProspectiveOperation] prOps = {}; + top-down-break visit(stmt) { + case Block blockStmt: { + println("blockStatement"); + println(blockStmt); + println(); + prOps += retrieveProspectiveOperationsFromBlock(blockStmt); + } + case IfThenStatement ifStmt: { + println("ifThenStatement"); + println(ifStmt); + println(); + } + case IfThenElseStatement ifElseStmt: { + println("ifThenElseStatement"); + println(ifElseStmt); + println(); + } + case ExpressionStatement stmt: prOps += retrieveProspectiveOperationFromSingleStatement(stmt); + } + return prOps; +} + +private set[ProspectiveOperation] retrieveProspectiveOperationsFromBlock(Block blockStmt) { + set[ProspectiveOperation] prOps = {}; + top-down visit(blockStmt) { + case (IfThenStatement) `if ( ) `: { + prOps += retrieveProspectiveOperationsFromStatement(thenStmt); + } + case (IfThenElseStatement) `if ( ) else `: { + //retrieveProspectiveOperationsFromStatement(thenStmt); + println("if else"); + } + case ExpressionStatement stmt: prOps += retrieveProspectiveOperationFromSingleStatement(stmt); + } + println(); + return prOps; +} + +private set[ProspectiveOperation] retrieveProspectiveOperationFromSingleStatement(ExpressionStatement stmt) { + //visualize(stmt); + if (isReducer(stmt)) + return {prospectiveOperation(stmt, REDUCE)}; + else + return {prospectiveOperation(stmt, MAP)}; +} + +private bool isReducer(ExpressionStatement stmt) { + visit (stmt) { + case (Assignment) ` `: { + return isCompoundAssignmentOperator(assignmentOp) && isReferenceToNonFinalLocalVar(lhs); + } + } + return false; +} + +private bool isCompoundAssignmentOperator(AssignmentOperator assignmentOp) { + operatorStr = unparse(assignmentOp); + return operatorStr != "=" && operatorStr != "\>\>\>=" && + operatorStr != "^="; +} + +private bool isReferenceToNonFinalLocalVar(LeftHandSide lhs) { + varName = trim(unparse(lhs)); + var = findByName(methodLocalVars, varName); + return !var.isFinal; +} \ No newline at end of file diff --git a/testes/localVariables/ForLoopToFunctional b/testes/localVariables/ForLoopToFunctional new file mode 100644 index 0000000..752bf9a --- /dev/null +++ b/testes/localVariables/ForLoopToFunctional @@ -0,0 +1,49 @@ +class SimpleForEach { + + public void test1(List things, PrintWriter writer) { + for (String thing: things) { + writer.write(thing); + } + } +} + +class GrammarEngineImpl { + + boolean isEngineExisting(String grammarName) { + for(GrammarEngine e : importedEngines) { + if(e.getGrammarName() == null) continue; + if(e.getGrammarName().equals(grammarName)) + return true; + } + return false; + } + +} + +class StandardHost { + + List findReloadedContextMemoryLeaks(){ + List result = new ArrayList(); + for (Map.Entry entry : + childClassLoaders.entrySet()) + if(isValid(entry)) { + ClassLoader cl = entry.getKey(); + if (!((WebappClassLoader)cl).isStart()) + result.add(entry.getValue()); + } + return result; + } +} + +class EditorGutterColumnManager { + + int getNumberOfErrors() { + int count = 0; + for (ElementRule rule : getRules()) { + if(rule.hasErrors()) + count += rule.getErrors().size(); + } + return count; + } + +} \ No newline at end of file From 1702d16d4fff651d87c7016753b512dc3ec5d20b Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 041/154] Changing syntax of 'BlockStatements' following Java specs and ANTLR. - https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-BlockStatements - https://github.com/antlr/grammars-v4/blob/master/java8/Java8.g4#L719 --- src/lang/java/syntax/Java18.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lang/java/syntax/Java18.rsc b/src/lang/java/syntax/Java18.rsc index 15545af..a046015 100644 --- a/src/lang/java/syntax/Java18.rsc +++ b/src/lang/java/syntax/Java18.rsc @@ -461,7 +461,7 @@ syntax VariableInitializerList = { VariableInitializer "," }+ ; syntax Block = "{" BlockStatements? "}" ; -syntax BlockStatements = BlockStatement+ ; +syntax BlockStatements = BlockStatement BlockStatement* ; syntax BlockStatement = LocalVariableDeclarationStatement | ClassDeclaration From 3e6771fc4b2d0e82882652b7d2e63c2cb7258130 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 042/154] ProspectiveOperation - Starting slow. Working with really small example. --- src/MethodVar.rsc | 5 + src/refactor/forloop/ProspectiveOperation.rsc | 119 +++++++++++------- .../forloop/ProspectiveOperationsTest.rsc | 14 +++ .../ProspectiveOperationsTestResources.rsc | 12 ++ .../SimpleShortEnhancedLoop | 3 + 5 files changed, 109 insertions(+), 44 deletions(-) create mode 100644 src/refactor/forloop/ProspectiveOperationsTest.rsc create mode 100644 src/refactor/forloop/ProspectiveOperationsTestResources.rsc create mode 100644 testes/ProspectiveOperation/SimpleShortEnhancedLoop diff --git a/src/MethodVar.rsc b/src/MethodVar.rsc index ed85d8c..4b8a4be 100644 --- a/src/MethodVar.rsc +++ b/src/MethodVar.rsc @@ -5,6 +5,7 @@ import String; // TODO Review if using a Set is the best choice. Probably not. public data MethodVar = methodVar(bool isFinal, str name, str varType, bool isParameter); +public data MethodVar = methodVar(bool isFinal, str name, str varType, bool isParameter, bool isEffectiveFinal); public bool isArray(MethodVar methodVar) { return methodVar.varType == "array"; @@ -52,4 +53,8 @@ public set[str] retrieveNonParametersNames(set[MethodVar] methodVars) { public bool isTypePlainArray(MethodVar methodVar) { return endsWith(methodVar.varType, "[]"); +} + +public bool isEffectiveFinal(MethodVar methodVar) { + return methodVar.isFinal || methodVar.isEffectiveFinal; } \ No newline at end of file diff --git a/src/refactor/forloop/ProspectiveOperation.rsc b/src/refactor/forloop/ProspectiveOperation.rsc index 6e96401..4b138d3 100644 --- a/src/refactor/forloop/ProspectiveOperation.rsc +++ b/src/refactor/forloop/ProspectiveOperation.rsc @@ -4,13 +4,12 @@ import IO; import lang::java::\syntax::Java18; import ParseTree; import ParseTreeVisualization; -import Set; +import List; import util::Math; import MethodVar; import String; -public data ProspectiveOperation = prospectiveOperation(Statement stmt, str operation); -public data ProspectiveOperation = prospectiveOperation(ExpressionStatement stmt2, str operation); +public data ProspectiveOperation = prospectiveOperation(str stmt, str operation); str FILTER = "filter"; str MAP = "map"; @@ -19,73 +18,96 @@ str REDUCE = "reduce"; str ANY_MATCH = "anyMatch"; str NONE_MATCH = "noneMatch"; -private set[MethodVar] methodLocalVars; +private list[MethodVar] methodLocalVars; -public void retrievePotentialOperations(set[MethodVar] localVars, EnhancedForStatement forStmt) { +public list[ProspectiveOperation] retrievePotentialOperations(set[MethodVar] localVars, EnhancedForStatement forStmt) { methodLocalVars = localVars; - visit(forStmt) { - case (EnhancedForStatement) `for ( : ) `: { - r = retrieveProspectiveOperationsFromStatement(stmt); - println("prospective operations: " + toString(size(r))); - for (prOp <- r) { - println(); - println(prOp.operation); - println(unparse(prOp.stmt2)); - } + list[ProspectiveOperation] prospectiveOperations = []; + top-down visit(forStmt) { + case (EnhancedForStatement) `for ( : ) `: { + prospectiveOperations = retrieveProspectiveOperationsFromStatement(stmt); + prospectiveOperations = markLastStmtAsEager(prospectiveOperations); } } + return prospectiveOperations; } -private set[ProspectiveOperation] retrieveProspectiveOperationsFromStatement(Statement stmt) { - set[ProspectiveOperation] prOps = {}; +private list[ProspectiveOperation] retrieveProspectiveOperationsFromStatement(Statement stmt) { + list[ProspectiveOperation] prOps = []; top-down-break visit(stmt) { - case Block blockStmt: { - println("blockStatement"); - println(blockStmt); - println(); - prOps += retrieveProspectiveOperationsFromBlock(blockStmt); + case Block block: { + prOps += retrieveProspectiveOperationsFromBlock(block); } case IfThenStatement ifStmt: { - println("ifThenStatement"); - println(ifStmt); - println(); + prOps += retrieveProspectiveOperationsFromIfThenStatement(ifStmt); } case IfThenElseStatement ifElseStmt: { - println("ifThenElseStatement"); + println("IfThenElseStatement"); println(ifElseStmt); println(); } - case ExpressionStatement stmt: prOps += retrieveProspectiveOperationFromSingleStatement(stmt); + case ExpressionStatement expStmt: { + statement = parse(#Statement, unparse(expStmt)); + prOps += retrieveProspectiveOperationFromSingleStatement(statement); + } } return prOps; } -private set[ProspectiveOperation] retrieveProspectiveOperationsFromBlock(Block blockStmt) { - set[ProspectiveOperation] prOps = {}; - top-down visit(blockStmt) { - case (IfThenStatement) `if ( ) `: { - prOps += retrieveProspectiveOperationsFromStatement(thenStmt); - } - case (IfThenElseStatement) `if ( ) else `: { - //retrieveProspectiveOperationsFromStatement(thenStmt); - println("if else"); +private list[ProspectiveOperation] retrieveProspectiveOperationsFromBlock(Block block) { + list[ProspectiveOperation] prOps = []; + top-down visit(block) { + case BlockStatement blockStatement: { + top-down visit(blockStatement) { + case (IfThenStatement) `if ( ) `: { + prOps += retrieveProspectiveOperationsFromStatement(thenStmt); + } + case (IfThenElseStatement) `if ( ) else `: { + //retrieveProspectiveOperationsFromStatement(thenStmt); + println("if else"); + } + case StatementWithoutTrailingSubstatement otherStmt: { + statement = parse(#Statement, unparse(otherStmt)); + prOps += retrieveProspectiveOperationFromSingleStatement(statement); + } + } } - case ExpressionStatement stmt: prOps += retrieveProspectiveOperationFromSingleStatement(stmt); } println(); return prOps; } -private set[ProspectiveOperation] retrieveProspectiveOperationFromSingleStatement(ExpressionStatement stmt) { - //visualize(stmt); - if (isReducer(stmt)) - return {prospectiveOperation(stmt, REDUCE)}; +private list[ProspectiveOperation] retrieveProspectiveOperationsFromIfThenStatement(IfThenStatement ifStmt) { + list[ProspectiveOperation] prOps = []; + top-down visit (ifStmt) { + case (IfThenStatement) `if ( ) `: { + visit (thenStmt) { + case (ReturnStatement) `return ;`: { + if ("" == true) + prOps += prospectiveOperation(unparse(ifStmt), ANY_MATCH); + else if ("" == false) + prOps += prospectiveOperation(unparse(ifStmt), NONE_MATCH); + } + case Statement statement: { + // ifStmt ou exp ? + prOps += prospectiveOperation(unparse(exp), FILTER); + prOps += retrieveProspectiveOperationsFromStatement(statement); + } + } + } + } + return prOps; +} + +private list[ProspectiveOperation] retrieveProspectiveOperationFromSingleStatement(Statement statement) { + if (isReducer(statement)) + return [prospectiveOperation(unparse(statement), REDUCE)]; else - return {prospectiveOperation(stmt, MAP)}; + return [prospectiveOperation(unparse(statement), MAP)]; } -private bool isReducer(ExpressionStatement stmt) { - visit (stmt) { +private bool isReducer(Statement statement) { + visit (statement) { case (Assignment) ` `: { return isCompoundAssignmentOperator(assignmentOp) && isReferenceToNonFinalLocalVar(lhs); } @@ -102,5 +124,14 @@ private bool isCompoundAssignmentOperator(AssignmentOperator assignmentOp) { private bool isReferenceToNonFinalLocalVar(LeftHandSide lhs) { varName = trim(unparse(lhs)); var = findByName(methodLocalVars, varName); - return !var.isFinal; + return isEffectiveFinal(var); +} + +private list[ProspectiveOperation] markLastStmtAsEager(list[ProspectiveOperation] prOps) { + lastPrOp = prOps[-1]; + if(lastPrOp.operation == MAP) + lastPrOp.operation = FOR_EACH; + + // all elements but the last + the last one (eagerized or not) + return prefix(prOps) + lastPrOp; } \ No newline at end of file diff --git a/src/refactor/forloop/ProspectiveOperationsTest.rsc b/src/refactor/forloop/ProspectiveOperationsTest.rsc new file mode 100644 index 0000000..dbeece1 --- /dev/null +++ b/src/refactor/forloop/ProspectiveOperationsTest.rsc @@ -0,0 +1,14 @@ +module refactor::forloop::ProspectiveOperationsTest + +import refactor::forloop::ProspectiveOperation; +import refactor::forloop::ProspectiveOperationsTestResources; +import MethodVar; +import lang::java::\syntax::Java18; +import IO; + +public test bool shouldReturnAForEachOnSimpleShortExample() { + tuple [set[MethodVar] vars, EnhancedForStatement loop] simpleShort = simpleShort(); + prospectiveOperations = retrievePotentialOperations(simpleShort.vars, simpleShort.loop); + return prospectiveOperations[0].stmt == "writer.write(thing);" && + prospectiveOperations[0].operation == "forEach"; +} \ No newline at end of file diff --git a/src/refactor/forloop/ProspectiveOperationsTestResources.rsc b/src/refactor/forloop/ProspectiveOperationsTestResources.rsc new file mode 100644 index 0000000..d355946 --- /dev/null +++ b/src/refactor/forloop/ProspectiveOperationsTestResources.rsc @@ -0,0 +1,12 @@ +module refactor::forloop::ProspectiveOperationsTestResources + +import IO; +import lang::java::\syntax::Java18; +import ParseTree; +import MethodVar; + +public tuple [set[MethodVar] vars, EnhancedForStatement loop] simpleShort() { + fileLoc = |project://rascal-Java8//testes/ProspectiveOperation/SimpleShortEnhancedLoop|; + enhancedForLoop = parse(#EnhancedForStatement, readFile(fileLoc)); + return <{}, enhancedForLoop>; +} \ No newline at end of file diff --git a/testes/ProspectiveOperation/SimpleShortEnhancedLoop b/testes/ProspectiveOperation/SimpleShortEnhancedLoop new file mode 100644 index 0000000..317b394 --- /dev/null +++ b/testes/ProspectiveOperation/SimpleShortEnhancedLoop @@ -0,0 +1,3 @@ +for (String thing: things) { + writer.write(thing); +} \ No newline at end of file From ece30637cde947b5f64e90d5c35e22f2f90dc20c Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 043/154] Working through reduce example. --- src/MethodVar.rsc | 6 ++++- src/refactor/forloop/ProspectiveOperation.rsc | 11 ++++---- .../forloop/ProspectiveOperationsTest.rsc | 16 +++++++++++- .../ProspectiveOperationsTestResources.rsc | 25 +++++++++++++++++++ .../ContinueAndReturnEnhancedLoop | 5 ++++ .../FilterMapReduceEnhancedLoop | 4 +++ 6 files changed, 59 insertions(+), 8 deletions(-) create mode 100644 testes/ProspectiveOperation/ContinueAndReturnEnhancedLoop create mode 100644 testes/ProspectiveOperation/FilterMapReduceEnhancedLoop diff --git a/src/MethodVar.rsc b/src/MethodVar.rsc index 4b8a4be..14f0b13 100644 --- a/src/MethodVar.rsc +++ b/src/MethodVar.rsc @@ -55,6 +55,10 @@ public bool isTypePlainArray(MethodVar methodVar) { return endsWith(methodVar.varType, "[]"); } +// FIXME public bool isEffectiveFinal(MethodVar methodVar) { - return methodVar.isFinal || methodVar.isEffectiveFinal; + try + return methodVar.isFinal || methodVar.isEffectiveFinal; + catch NoSuchField("isEffectiveFinal"): + return methodVar.isFinal; } \ No newline at end of file diff --git a/src/refactor/forloop/ProspectiveOperation.rsc b/src/refactor/forloop/ProspectiveOperation.rsc index 4b138d3..7fc8689 100644 --- a/src/refactor/forloop/ProspectiveOperation.rsc +++ b/src/refactor/forloop/ProspectiveOperation.rsc @@ -58,8 +58,9 @@ private list[ProspectiveOperation] retrieveProspectiveOperationsFromBlock(Block list[ProspectiveOperation] prOps = []; top-down visit(block) { case BlockStatement blockStatement: { - top-down visit(blockStatement) { + top-down-break visit(blockStatement) { case (IfThenStatement) `if ( ) `: { + prOps += prospectiveOperation(unparse(exp), FILTER); prOps += retrieveProspectiveOperationsFromStatement(thenStmt); } case (IfThenElseStatement) `if ( ) else `: { @@ -73,7 +74,6 @@ private list[ProspectiveOperation] retrieveProspectiveOperationsFromBlock(Block } } } - println(); return prOps; } @@ -89,7 +89,6 @@ private list[ProspectiveOperation] retrieveProspectiveOperationsFromIfThenStatem prOps += prospectiveOperation(unparse(ifStmt), NONE_MATCH); } case Statement statement: { - // ifStmt ou exp ? prOps += prospectiveOperation(unparse(exp), FILTER); prOps += retrieveProspectiveOperationsFromStatement(statement); } @@ -108,10 +107,10 @@ private list[ProspectiveOperation] retrieveProspectiveOperationFromSingleStateme private bool isReducer(Statement statement) { visit (statement) { - case (Assignment) ` `: { + case (Assignment) ` `: return isCompoundAssignmentOperator(assignmentOp) && isReferenceToNonFinalLocalVar(lhs); - } } + return false; } @@ -124,7 +123,7 @@ private bool isCompoundAssignmentOperator(AssignmentOperator assignmentOp) { private bool isReferenceToNonFinalLocalVar(LeftHandSide lhs) { varName = trim(unparse(lhs)); var = findByName(methodLocalVars, varName); - return isEffectiveFinal(var); + return !isEffectiveFinal(var); } private list[ProspectiveOperation] markLastStmtAsEager(list[ProspectiveOperation] prOps) { diff --git a/src/refactor/forloop/ProspectiveOperationsTest.rsc b/src/refactor/forloop/ProspectiveOperationsTest.rsc index dbeece1..21d4e8f 100644 --- a/src/refactor/forloop/ProspectiveOperationsTest.rsc +++ b/src/refactor/forloop/ProspectiveOperationsTest.rsc @@ -11,4 +11,18 @@ public test bool shouldReturnAForEachOnSimpleShortExample() { prospectiveOperations = retrievePotentialOperations(simpleShort.vars, simpleShort.loop); return prospectiveOperations[0].stmt == "writer.write(thing);" && prospectiveOperations[0].operation == "forEach"; -} \ No newline at end of file +} + +public test bool shouldReturnCorrectlyOnFilterMapReduceExample() { + tuple [set[MethodVar] vars, EnhancedForStatement loop] filterMapReduce = filterMapReduce(); + prospectiveOperations = retrievePotentialOperations(filterMapReduce.vars, filterMapReduce.loop); + println(prospectiveOperations); + return false; +} + +//public test bool shouldReturnXOnContinueAndReturnEnhancedLoop() { +// tuple [set[MethodVar] vars, EnhancedForStatement loop] continueAndReturn = continueAndReturn(); +// prospectiveOperations = retrievePotentialOperations(continueAndReturn.vars, continueAndReturn.loop); +// println(prospectiveOperations); +// return false; +//} \ No newline at end of file diff --git a/src/refactor/forloop/ProspectiveOperationsTestResources.rsc b/src/refactor/forloop/ProspectiveOperationsTestResources.rsc index d355946..24db643 100644 --- a/src/refactor/forloop/ProspectiveOperationsTestResources.rsc +++ b/src/refactor/forloop/ProspectiveOperationsTestResources.rsc @@ -4,9 +4,34 @@ import IO; import lang::java::\syntax::Java18; import ParseTree; import MethodVar; +import LocalVariablesFinder; public tuple [set[MethodVar] vars, EnhancedForStatement loop] simpleShort() { fileLoc = |project://rascal-Java8//testes/ProspectiveOperation/SimpleShortEnhancedLoop|; enhancedForLoop = parse(#EnhancedForStatement, readFile(fileLoc)); return <{}, enhancedForLoop>; +} + +public tuple [set[MethodVar] vars, EnhancedForStatement loop] continueAndReturn() { + fileLoc = |project://rascal-Java8//testes/ProspectiveOperation/ContinueAndReturnEnhancedLoop|; + enhancedForLoop = parse(#EnhancedForStatement, readFile(fileLoc)); + return ; +} + +private set[MethodVar] continueAndReturnVars() { + methodHeader = parse(#MethodHeader, "boolean isEngineExisting(String grammarName)"); + methodBody = parse(#MethodBody, "{\n for(GrammarEngine e : importedEngines) { \n if(e.getGrammarName() == null) continue; \n if(e.getGrammarName().equals(grammarName))\n return true; \n } \n return false; \n}" ); + return findLocalVariables(methodHeader, methodBody); +} + +public tuple [set[MethodVar] vars, EnhancedForStatement loop] filterMapReduce() { + fileLoc = |project://rascal-Java8//testes/ProspectiveOperation/FilterMapReduceEnhancedLoop|; + enhancedForLoop = parse(#EnhancedForStatement, readFile(fileLoc)); + return ; +} + +private set[MethodVar] filterMapReduceVars() { + methodHeader = parse(#MethodHeader, "int getNumberOfErrors()"); + methodBody = parse(#MethodBody, "{\n int count = 0;\n for (ElementRule rule : getRules()) {\n if(rule.hasErrors())\n count += rule.getErrors().size();\n }\n return count;\n }"); + return findLocalVariables(methodHeader, methodBody); } \ No newline at end of file diff --git a/testes/ProspectiveOperation/ContinueAndReturnEnhancedLoop b/testes/ProspectiveOperation/ContinueAndReturnEnhancedLoop new file mode 100644 index 0000000..697c33f --- /dev/null +++ b/testes/ProspectiveOperation/ContinueAndReturnEnhancedLoop @@ -0,0 +1,5 @@ +for(GrammarEngine e : importedEngines) { + if(e.getGrammarName() == null) continue; + if(e.getGrammarName().equals(grammarName)) + return true; + } \ No newline at end of file diff --git a/testes/ProspectiveOperation/FilterMapReduceEnhancedLoop b/testes/ProspectiveOperation/FilterMapReduceEnhancedLoop new file mode 100644 index 0000000..1546dfa --- /dev/null +++ b/testes/ProspectiveOperation/FilterMapReduceEnhancedLoop @@ -0,0 +1,4 @@ +for (ElementRule rule : getRules()) { + if(rule.hasErrors()) + count += rule.getErrors().size(); + } \ No newline at end of file From d0db627e31933311e1e3b29cb17166380cccd90b Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 044/154] Correcting test for filterMapReduce example. --- src/refactor/forloop/ProspectiveOperationsTest.rsc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/refactor/forloop/ProspectiveOperationsTest.rsc b/src/refactor/forloop/ProspectiveOperationsTest.rsc index 21d4e8f..68556c8 100644 --- a/src/refactor/forloop/ProspectiveOperationsTest.rsc +++ b/src/refactor/forloop/ProspectiveOperationsTest.rsc @@ -16,8 +16,10 @@ public test bool shouldReturnAForEachOnSimpleShortExample() { public test bool shouldReturnCorrectlyOnFilterMapReduceExample() { tuple [set[MethodVar] vars, EnhancedForStatement loop] filterMapReduce = filterMapReduce(); prospectiveOperations = retrievePotentialOperations(filterMapReduce.vars, filterMapReduce.loop); - println(prospectiveOperations); - return false; + return prospectiveOperations[0].stmt == "rule.hasErrors()" && + prospectiveOperations[0].operation == "filter" && + prospectiveOperations[1].stmt == "count += rule.getErrors().size();" && + prospectiveOperations[1].operation == "reduce"; } //public test bool shouldReturnXOnContinueAndReturnEnhancedLoop() { From 0f5aab3e46be9caa3c80d81bf91b3f290f75eecf Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 045/154] Marking a local variable as declared within a loop or not. --- src/LocalVariablesFinder.rsc | 38 +++++++++++++++---- src/LocalVariablesFinderTest.rsc | 14 +++++++ src/LocalVariablesFinderTestResources.rsc | 11 ++++++ src/MethodVar.rsc | 12 +++++- .../EnhancedForLoopVarsWithinLoop | 9 +++++ 5 files changed, 75 insertions(+), 9 deletions(-) create mode 100644 testes/localVariables/EnhancedForLoopVarsWithinLoop diff --git a/src/LocalVariablesFinder.rsc b/src/LocalVariablesFinder.rsc index cd6cb38..83ca8db 100644 --- a/src/LocalVariablesFinder.rsc +++ b/src/LocalVariablesFinder.rsc @@ -6,6 +6,7 @@ import String; import ParseTree; import IO; import MethodVar; +import ParseTreeVisualization; // syntax LocalVariableDeclarationStatement = LocalVariableDeclaration ";"+ ; // syntax LocalVariableDeclaration = VariableModifier* UnannType VariableDeclaratorList ; @@ -31,10 +32,21 @@ private set[MethodVar] findVariablesAsParameters(MethodHeader methodHeader) { private set[MethodVar] findVariablesInsideBody(MethodBody methodBody) { set[MethodVar] methodVars = {}; visit(methodBody) { - - case (EnhancedForStatement) `for ( : ) `: - methodVars += createLocalMethodVar(figureIfIsFinal(varMod), varId, varType); + case EnhancedForStatement enhancedForStmt: { + visit(enhancedForStmt) { + case (EnhancedForStatement) `for ( : ) `: + methodVars += createLocalMethodVarWithinLoop(figureIfIsFinal(varMod), varId, varType); + + // TODO maybe there is a better way besides checking this two times. + case (LocalVariableDeclaration) ` `: + visit(vdl) { + case (VariableDeclaratorId) ` `: + methodVars += createLocalMethodVarWithinLoop(figureIfIsFinal(varMod), varId, varType, dims); + } + } + } + case (LocalVariableDeclaration) ` `: { visit(vdl) { case (VariableDeclaratorId) ` `: @@ -52,13 +64,19 @@ private set[MethodVar] findVariablesInsideBody(MethodBody methodBody) { private MethodVar createParameterMethodVar(bool isFinal, VariableDeclaratorId varId, UnannType varType) { name = trim(unparse(varId)); varTypeStr = trim(unparse(varType)); - return methodVar(isFinal, name, varTypeStr, true); + return methodVar(isFinal, name, varTypeStr, true, false); } private MethodVar createLocalMethodVar(bool isFinal, VariableDeclaratorId varId, UnannType varType) { name = trim(unparse(varId)); varTypeStr = trim(unparse(varType)); - return methodVar(isFinal, name, varTypeStr, false); + return methodVar(isFinal, name, varTypeStr, false, false); +} + +private MethodVar createLocalMethodVarWithinLoop(bool isFinal, VariableDeclaratorId varId, UnannType varType) { + name = trim(unparse(varId)); + varTypeStr = trim(unparse(varType)); + return methodVar(isFinal, name, varTypeStr, false, true); } private MethodVar createLocalMethodVar(bool isFinal, Identifier varId, UnannType varType, Dims? dims) { @@ -70,13 +88,19 @@ private MethodVar createLocalMethodVar(bool isFinal, Identifier varId, UnannType if(dimsStr == "[]") varTypeStr += "[]"; - return methodVar(isFinal, name, varTypeStr, false); + return methodVar(isFinal, name, varTypeStr, false, false); +} + +private MethodVar createLocalMethodVarWithinLoop(bool isFinal, Identifier varId, UnannType varType, Dims? dims) { + mv = createLocalMethodVar(isFinal, varId, varType, dims); + mv.isDeclaredWithinLoop = true; + return mv; } private MethodVar createLocalMethodVar(bool isFinal, VariableDeclaratorId varId, CatchType varType) { name = trim(unparse(varId)); varTypeStr = trim(unparse(varType)); - return methodVar(isFinal, name, varTypeStr, false); + return methodVar(isFinal, name, varTypeStr, false, false); } private bool figureIfIsFinal(VariableModifier* varMod) { diff --git a/src/LocalVariablesFinderTest.rsc b/src/LocalVariablesFinderTest.rsc index 716f9cd..b069195 100644 --- a/src/LocalVariablesFinderTest.rsc +++ b/src/LocalVariablesFinderTest.rsc @@ -162,3 +162,17 @@ public test bool shouldReturnCorrectParamsWithLastOneNonFinal() { !strParam.isFinal && strParam.isParameter && !nonFinalLastParam.isFinal && nonFinalLastParam.isParameter; } + +public test bool shouldReturnCorrectVarsDeclaredWithinLoop() { + methodHeader = varsWithinTheLoopMethodHeader(); + methodBody = varsWithinTheLoopMethodBody(); + + vars = findLocalVariables(methodHeader, methodBody); + varsWithinLoop = retrieveDeclaredWithinLoop(vars); + withinLoopNames = retrieveDeclaredWithinLoopNames(vars); + + return size(varsWithinLoop) == 3 && + "insideDecl" in withinLoopNames && + "insideBody" in withinLoopNames && + "insideBodyStr" in withinLoopNames; +} diff --git a/src/LocalVariablesFinderTestResources.rsc b/src/LocalVariablesFinderTestResources.rsc index 2afed50..00975e2 100644 --- a/src/LocalVariablesFinderTestResources.rsc +++ b/src/LocalVariablesFinderTestResources.rsc @@ -92,4 +92,15 @@ public set[MethodVar] getAllNonFinalArrays(set[MethodVar] vars) { public set[MethodVar] getAllFinalArrays(set[MethodVar] vars) { return getFinalEncouragedArrays(vars) + getFinalDiscouragedArrays(vars); +} + +public MethodHeader varsWithinTheLoopMethodHeader() { + header = "void method(int notWithinLoop, String notWithinLoopAgain)"; + return parse(#MethodHeader, header); +} + +public MethodBody varsWithinTheLoopMethodBody() { + fileLoc = |project://rascal-Java8//testes/localVariables/EnhancedForLoopVarsWithinLoop|; + content = readFile(fileLoc); + return parse(#MethodBody, content); } \ No newline at end of file diff --git a/src/MethodVar.rsc b/src/MethodVar.rsc index 14f0b13..1385983 100644 --- a/src/MethodVar.rsc +++ b/src/MethodVar.rsc @@ -4,8 +4,8 @@ import Set; import String; // TODO Review if using a Set is the best choice. Probably not. -public data MethodVar = methodVar(bool isFinal, str name, str varType, bool isParameter); -public data MethodVar = methodVar(bool isFinal, str name, str varType, bool isParameter, bool isEffectiveFinal); +public data MethodVar = methodVar(bool isFinal, str name, str varType, bool isParameter, bool isDeclaredWithinLoop); +public data MethodVar = methodVar(bool isFinal, str name, str varType, bool isParameter, bool isDeclaredWithinLoop, bool isEffectiveFinal); public bool isArray(MethodVar methodVar) { return methodVar.varType == "array"; @@ -55,6 +55,14 @@ public bool isTypePlainArray(MethodVar methodVar) { return endsWith(methodVar.varType, "[]"); } +public set[MethodVar] retrieveDeclaredWithinLoop(set[MethodVar] methodVars) { + return { var | MethodVar var <- methodVars, var.isDeclaredWithinLoop }; +} + +public set[str] retrieveDeclaredWithinLoopNames(set[MethodVar] methodVars) { + return { var.name | MethodVar var <- methodVars, var.isDeclaredWithinLoop }; +} + // FIXME public bool isEffectiveFinal(MethodVar methodVar) { try diff --git a/testes/localVariables/EnhancedForLoopVarsWithinLoop b/testes/localVariables/EnhancedForLoopVarsWithinLoop new file mode 100644 index 0000000..34829b7 --- /dev/null +++ b/testes/localVariables/EnhancedForLoopVarsWithinLoop @@ -0,0 +1,9 @@ +{ + int localVarNotWithinLoop; + Object localVarNotWithinLoopAgain; + for (String insideDecl : strings) { + final int insideBody = 50; + String insideBodyStr = "insideBody"; + } + Object notWithinLoopAfterLoop = null; +} \ No newline at end of file From 6a9eba1d4153307b437caf85e229ccf019f2bda1 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 046/154] Assuring that vars declared within loop are not added as not within loop. --- src/LocalVariablesFinder.rsc | 32 +++++++++++++++++++------------- src/LocalVariablesFinderTest.rsc | 16 ++++++++++++++++ src/MethodVar.rsc | 8 ++++++++ 3 files changed, 43 insertions(+), 13 deletions(-) diff --git a/src/LocalVariablesFinder.rsc b/src/LocalVariablesFinder.rsc index 83ca8db..28c44a4 100644 --- a/src/LocalVariablesFinder.rsc +++ b/src/LocalVariablesFinder.rsc @@ -29,28 +29,40 @@ private set[MethodVar] findVariablesAsParameters(MethodHeader methodHeader) { return methodVars; } +private MethodVar createParameterMethodVar(bool isFinal, VariableDeclaratorId varId, UnannType varType) { + name = trim(unparse(varId)); + varTypeStr = trim(unparse(varType)); + return methodVar(isFinal, name, varTypeStr, true, false); +} + +// XXX probably incorrect, ugly and not really DRY way of checking for vars within loop private set[MethodVar] findVariablesInsideBody(MethodBody methodBody) { set[MethodVar] methodVars = {}; - visit(methodBody) { - + set[str] varsWithinLoopNames = {}; + + top-down visit(methodBody) { + case EnhancedForStatement enhancedForStmt: { visit(enhancedForStmt) { case (EnhancedForStatement) `for ( : ) `: methodVars += createLocalMethodVarWithinLoop(figureIfIsFinal(varMod), varId, varType); - // TODO maybe there is a better way besides checking this two times. case (LocalVariableDeclaration) ` `: visit(vdl) { - case (VariableDeclaratorId) ` `: - methodVars += createLocalMethodVarWithinLoop(figureIfIsFinal(varMod), varId, varType, dims); + case (VariableDeclaratorId) ` `: { + varsWithinLoopNames += unparse(varId); + methodVars += createLocalMethodVarWithinLoop(figureIfIsFinal(varMod), varId, varType, dims); + } } } } case (LocalVariableDeclaration) ` `: { visit(vdl) { - case (VariableDeclaratorId) ` `: - methodVars += createLocalMethodVar(figureIfIsFinal(varMod), varId, varType, dims); + case (VariableDeclaratorId) ` `: { + if(unparse(varId) notin varsWithinLoopNames) + methodVars += createLocalMethodVar(figureIfIsFinal(varMod), varId, varType, dims); + } } } @@ -61,12 +73,6 @@ private set[MethodVar] findVariablesInsideBody(MethodBody methodBody) { return methodVars; } -private MethodVar createParameterMethodVar(bool isFinal, VariableDeclaratorId varId, UnannType varType) { - name = trim(unparse(varId)); - varTypeStr = trim(unparse(varType)); - return methodVar(isFinal, name, varTypeStr, true, false); -} - private MethodVar createLocalMethodVar(bool isFinal, VariableDeclaratorId varId, UnannType varType) { name = trim(unparse(varId)); varTypeStr = trim(unparse(varType)); diff --git a/src/LocalVariablesFinderTest.rsc b/src/LocalVariablesFinderTest.rsc index b069195..a29e6cc 100644 --- a/src/LocalVariablesFinderTest.rsc +++ b/src/LocalVariablesFinderTest.rsc @@ -176,3 +176,19 @@ public test bool shouldReturnCorrectVarsDeclaredWithinLoop() { "insideBody" in withinLoopNames && "insideBodyStr" in withinLoopNames; } + +public test bool shouldReturnCorrectVarsNotDeclaredWithinLoop() { + methodHeader = varsWithinTheLoopMethodHeader(); + methodBody = varsWithinTheLoopMethodBody(); + + vars = findLocalVariables(methodHeader, methodBody); + varsNotWithinLoop = retrieveNotDeclaredWithinLoop(vars); + notWithinLoopNames = retrieveNotDeclaredWithinLoopNames(vars); + + return size(varsNotWithinLoop) == 5 && + "notWithinLoop" in notWithinLoopNames && + "notWithinLoopAgain" in notWithinLoopNames && + "localVarNotWithinLoop" in notWithinLoopNames && + "localVarNotWithinLoopAgain" in notWithinLoopNames && + "notWithinLoopAfterLoop" in notWithinLoopNames; +} diff --git a/src/MethodVar.rsc b/src/MethodVar.rsc index 1385983..0cda4c9 100644 --- a/src/MethodVar.rsc +++ b/src/MethodVar.rsc @@ -63,6 +63,14 @@ public set[str] retrieveDeclaredWithinLoopNames(set[MethodVar] methodVars) { return { var.name | MethodVar var <- methodVars, var.isDeclaredWithinLoop }; } +public set[MethodVar] retrieveNotDeclaredWithinLoop(set[MethodVar] methodVars) { + return { var | MethodVar var <- methodVars, !var.isDeclaredWithinLoop }; +} + +public set[str] retrieveNotDeclaredWithinLoopNames(set[MethodVar] methodVars) { + return { var.name | MethodVar var <- methodVars, !var.isDeclaredWithinLoop }; +} + // FIXME public bool isEffectiveFinal(MethodVar methodVar) { try From 636d31b6f94d9b92d851930ff673cbd29d441a84 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 047/154] First attempt to start putting everything together towards a refactor. --- src/refactor/forloop/ForLoopToFunctional.rsc | 40 ++++++ src/refactor/forloop/ProspectiveOperation.rsc | 134 +++++++++++++++++- testes/localVariables/ForLoopToFunctional | 37 ----- 3 files changed, 173 insertions(+), 38 deletions(-) create mode 100644 src/refactor/forloop/ForLoopToFunctional.rsc diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/refactor/forloop/ForLoopToFunctional.rsc new file mode 100644 index 0000000..f81ebae --- /dev/null +++ b/src/refactor/forloop/ForLoopToFunctional.rsc @@ -0,0 +1,40 @@ +module refactor::forloop::ForLoopToFunctional + +import lang::java::\syntax::Java18; +import ParseTree; +import IO; +import refactor::forloop::ProspectiveOperation; +import List; +import MethodVar; + +public void refactorEnhancedToFunctional(EnhancedForStatement forStmt, set[MethodVar] methodVars) { + prospectiveOperations = retrieveProspectiveOperations(methodVars, forStmt); + println(mergeOperations(prospectiveOperations, methodVars)); +} + +private list[ProspectiveOperation] mergeOperations(list[ProspectiveOperation] prOps, set[MethodVar] methodVars) { + println("mergeOperations()"); + listIndexes = [0 .. size(prOps)]; + // iterating bottom-up + for (int i <- reverse(listIndexes)) { + curr = prOps[i]; + prev = prOps[i - 1]; + if (!areComposable(curr, prev, methodVars)) { + if (isMergeable(prev) && isMergeable(curr)) { + if (isFilter(prev) || isFilter(curr)) { + opsSize = size(prOps); + while(opsSize > i) { + last = prOps[opsSize - 1]; + beforeLast = prOps[opsSize - 2]; + merged = mergeOps(beforeLast, last, methodVars); + prOps = slice(prOps, 0, opsSize - 2) + merged; + } + } else { + merged = mergeOps(prev, curr); + prOps = slice(prOps, 0, opsSize - 2) + merged; + } + } + } + } + return prOps; +} \ No newline at end of file diff --git a/src/refactor/forloop/ProspectiveOperation.rsc b/src/refactor/forloop/ProspectiveOperation.rsc index 7fc8689..d727d0e 100644 --- a/src/refactor/forloop/ProspectiveOperation.rsc +++ b/src/refactor/forloop/ProspectiveOperation.rsc @@ -8,6 +8,7 @@ import List; import util::Math; import MethodVar; import String; +import Set; public data ProspectiveOperation = prospectiveOperation(str stmt, str operation); @@ -20,7 +21,7 @@ str NONE_MATCH = "noneMatch"; private list[MethodVar] methodLocalVars; -public list[ProspectiveOperation] retrievePotentialOperations(set[MethodVar] localVars, EnhancedForStatement forStmt) { +public list[ProspectiveOperation] retrieveProspectiveOperations(set[MethodVar] localVars, EnhancedForStatement forStmt) { methodLocalVars = localVars; list[ProspectiveOperation] prospectiveOperations = []; top-down visit(forStmt) { @@ -133,4 +134,135 @@ private list[ProspectiveOperation] markLastStmtAsEager(list[ProspectiveOperation // all elements but the last + the last one (eagerized or not) return prefix(prOps) + lastPrOp; +} + +public bool isMergeable(ProspectiveOperation prOp) { + operation = prOp.operation; + return operation == FILTER || operation == MAP || operation == FOR_EACH; +} + +public bool isFilter(ProspectiveOperation prOp) { + return prOp.operation == FILTER; +} + +// TODO needed and available called more than once. good idea to extract it. +public bool areComposable(ProspectiveOperation first, ProspectiveOperation second, set[MethodVar] methodVars) { + firstNeededVars = retrieveNeededVariables(first); + // second's available has to be in first's needed + secondAvailableVars = retrieveAvaliableVars(second, methodVars); + secondAvailableVarsInFirstNeeded = isSecondAvailableInFirstNeeded(firstNeededVars, secondAvailableVars); + return size(firstNeededVars) <= 1 && secondAvailableVarsInFirstNeeded; +} + +private bool isSecondAvailableInFirstNeeded(set[str] firstNeededVars, set[str] secondAvailableVars) { + for(secondAvailable <- secondAvailableVars) + if(secondAvailable notin firstNeededVars) return false; + return true; +} + +public ProspectiveOperation mergeOps(ProspectiveOperation first, ProspectiveOperation second, set[MethodVar] methodVars) { + if (isFilter(first)) { + return mergeTwoOpsInAnIfThenStmt(first, second); + } else { + list[str] statements = retrieveAllStatements(first) + retrieveAllStatements(second); + + set[str] firstAvailableVars = retrieveAvaliableVars(first, methodVars); + set[str] availableVars = firstAvailableVars; + availableVars += retrieveAvailableVars(second, methodVars); + + set[str] neededVars = retrieveNeededVariables(second); + neededVars -= firstAvailableVars; + neededVars += retrieveNeededVariables(first); + + neederVars -= retrieveNotDeclaredWithinLoop(methodVars); + + Block statementsAsOneBlock = transformStatementsInBlock(statements); + + return prospectiveOperation(unparse(statementsAsOneBlock), second.operation); + } +} + +private ProspectiveOperation mergeTwoOpsInAnIfThenStmt(ProspectiveOperation first, ProspectiveOperation second) { + Expression exp = parse(#Expression, first.stmt); + Statement thenStmt = parse(#Statement, second.stmt); + ifThenStmt = [IfThenStatement] "if () ;"; + return prospectiveOperation(unparse(ifThenStmt), second.operation); +} + +private list[str] retrieveAllStatements(ProspectiveOperation prOp) { + list[str] allStatements = []; + if (isBlock(prOp.stmt)) + return retrieveAllStatementsFromBlock(prOp.stmt); + else + return retrieveAllExpressionStatementsFromStatement(prOp.stmt); +} + +private bool isBlock(str stmt) { + try { + parse(#Block, stmt); + return true; + } catch: return false; +} + +private list[str] retrieveAllStatementsFromBlock(str blockStr) { + list[str] blockStatements = []; + block = parse(#Block, blockStr); + top-down visit(block) { + case BlockStatement blockStmt: + blockStatements += unparse(blockStmt); + } + return blockStatements; +} + +// XXX probably not this +private list[str] retrieveAllExpressionStatementsFromStatement(str statement) { + list[str] stmts = []; + Statement stmt = parse(#Statement, statement); + top-down visit(stmt) { + case ExpressionStatement expStmt: + blockStatements += unparse(expStmt); + } + return stmts; +} + +private set[str] retrieveAvaliableVars(ProspectiveOperation prOp, set[MethodVar] methodVars) { + // fields declared in class, inherited and visible from imported classes ?? + // variables declared in the Prospective Operation ?? + withinMethod = retrieveNotDeclaredWithinLoopNames(methodVars); + withinLoop = retrieveDeclaredWithinLoopNames(methodVars); + return withinMethod - withinLoop; +} + +private set[str] retrieveNeededVariables(ProspectiveOperation prOp) { + if (prOp.operation == FILTER) + return {}; + + set[str] neededVariables = {}; + set[str] declaredVariables = {}; + set[str] methodsNames = {}; + + stmt = parse(#Statement, prOp.stmt); + // If a var has the same name as a called method, this will fail + visit (stmt) { + case LocalVariableDeclaration lvdl: { + visit(lvdl) { + case (VariableDeclaratorId) ``: declaredVariables += id; + } + } + case (MethodInvocation) ` ( )`: methodsNames += methodName; + case Identifier id: neededVariables = {}; + } + + neededVariables -= declaredVariables; + neededVariables -= methodsNames; + + return neededVariables; +} + +private Block transformStatementsInBlock(list[Statement] stmts) { + str joined = "{\n"; + for(stmt <- stmts) + joined += (stmts + "\n"); + joined += "\n}"; + return parse(#Block, stmts); } \ No newline at end of file diff --git a/testes/localVariables/ForLoopToFunctional b/testes/localVariables/ForLoopToFunctional index 752bf9a..00e95ff 100644 --- a/testes/localVariables/ForLoopToFunctional +++ b/testes/localVariables/ForLoopToFunctional @@ -1,12 +1,3 @@ -class SimpleForEach { - - public void test1(List things, PrintWriter writer) { - for (String thing: things) { - writer.write(thing); - } - } -} - class GrammarEngineImpl { boolean isEngineExisting(String grammarName) { @@ -18,32 +9,4 @@ class GrammarEngineImpl { return false; } -} - -class StandardHost { - - List findReloadedContextMemoryLeaks(){ - List result = new ArrayList(); - for (Map.Entry entry : - childClassLoaders.entrySet()) - if(isValid(entry)) { - ClassLoader cl = entry.getKey(); - if (!((WebappClassLoader)cl).isStart()) - result.add(entry.getValue()); - } - return result; - } -} - -class EditorGutterColumnManager { - - int getNumberOfErrors() { - int count = 0; - for (ElementRule rule : getRules()) { - if(rule.hasErrors()) - count += rule.getErrors().size(); - } - return count; - } - } \ No newline at end of file From 204299654127d2702510a6ad79af011fd1390ab1 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 048/154] Fixing merging ops in an IfThenStmt. - Exp had already a ';' at the end. --- src/refactor/forloop/ProspectiveOperation.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/refactor/forloop/ProspectiveOperation.rsc b/src/refactor/forloop/ProspectiveOperation.rsc index d727d0e..6fd3a7f 100644 --- a/src/refactor/forloop/ProspectiveOperation.rsc +++ b/src/refactor/forloop/ProspectiveOperation.rsc @@ -185,7 +185,7 @@ public ProspectiveOperation mergeOps(ProspectiveOperation first, ProspectiveOper private ProspectiveOperation mergeTwoOpsInAnIfThenStmt(ProspectiveOperation first, ProspectiveOperation second) { Expression exp = parse(#Expression, first.stmt); Statement thenStmt = parse(#Statement, second.stmt); - ifThenStmt = [IfThenStatement] "if () ;"; + ifThenStmt = [IfThenStatement] "if () "; return prospectiveOperation(unparse(ifThenStmt), second.operation); } From 6275fc9251ea59ccfcc3cac2131fb09ffdf14ca4 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 049/154] Correcting some silly(spelling, wrong types) compilation mistakes. --- src/refactor/forloop/ProspectiveOperation.rsc | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/refactor/forloop/ProspectiveOperation.rsc b/src/refactor/forloop/ProspectiveOperation.rsc index 6fd3a7f..fd04a9d 100644 --- a/src/refactor/forloop/ProspectiveOperation.rsc +++ b/src/refactor/forloop/ProspectiveOperation.rsc @@ -149,7 +149,7 @@ public bool isFilter(ProspectiveOperation prOp) { public bool areComposable(ProspectiveOperation first, ProspectiveOperation second, set[MethodVar] methodVars) { firstNeededVars = retrieveNeededVariables(first); // second's available has to be in first's needed - secondAvailableVars = retrieveAvaliableVars(second, methodVars); + secondAvailableVars = retrieveAvailableVars(second, methodVars); secondAvailableVarsInFirstNeeded = isSecondAvailableInFirstNeeded(firstNeededVars, secondAvailableVars); return size(firstNeededVars) <= 1 && secondAvailableVarsInFirstNeeded; } @@ -166,7 +166,7 @@ public ProspectiveOperation mergeOps(ProspectiveOperation first, ProspectiveOper } else { list[str] statements = retrieveAllStatements(first) + retrieveAllStatements(second); - set[str] firstAvailableVars = retrieveAvaliableVars(first, methodVars); + set[str] firstAvailableVars = retrieveAvailableVars(first, methodVars); set[str] availableVars = firstAvailableVars; availableVars += retrieveAvailableVars(second, methodVars); @@ -174,7 +174,7 @@ public ProspectiveOperation mergeOps(ProspectiveOperation first, ProspectiveOper neededVars -= firstAvailableVars; neededVars += retrieveNeededVariables(first); - neederVars -= retrieveNotDeclaredWithinLoop(methodVars); + neededVars -= retrieveNotDeclaredWithinLoopNames(methodVars); Block statementsAsOneBlock = transformStatementsInBlock(statements); @@ -220,12 +220,12 @@ private list[str] retrieveAllExpressionStatementsFromStatement(str statement) { Statement stmt = parse(#Statement, statement); top-down visit(stmt) { case ExpressionStatement expStmt: - blockStatements += unparse(expStmt); + stmts += unparse(expStmt); } return stmts; } -private set[str] retrieveAvaliableVars(ProspectiveOperation prOp, set[MethodVar] methodVars) { +private set[str] retrieveAvailableVars(ProspectiveOperation prOp, set[MethodVar] methodVars) { // fields declared in class, inherited and visible from imported classes ?? // variables declared in the Prospective Operation ?? withinMethod = retrieveNotDeclaredWithinLoopNames(methodVars); @@ -246,10 +246,10 @@ private set[str] retrieveNeededVariables(ProspectiveOperation prOp) { visit (stmt) { case LocalVariableDeclaration lvdl: { visit(lvdl) { - case (VariableDeclaratorId) ``: declaredVariables += id; + case (VariableDeclaratorId) ``: declaredVariables += unparse(id); } } - case (MethodInvocation) ` ( )`: methodsNames += methodName; + case (MethodInvocation) ` ( )`: methodsNames += unparse(methodName); case Identifier id: neededVariables = {}; } @@ -259,10 +259,10 @@ private set[str] retrieveNeededVariables(ProspectiveOperation prOp) { return neededVariables; } -private Block transformStatementsInBlock(list[Statement] stmts) { +private Block transformStatementsInBlock(list[str] stmts) { str joined = "{\n"; for(stmt <- stmts) - joined += (stmts + "\n"); - joined += "\n}"; - return parse(#Block, stmts); + joined += (stmt + "\n"); + joined += "}"; + return parse(#Block, joined); } \ No newline at end of file From ee0c05875c25ecc5cd10c7312aa3a57de4cfa5de Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 050/154] Updating and improving ProspectiveOperations test. --- .../forloop/ProspectiveOperationsTest.rsc | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/refactor/forloop/ProspectiveOperationsTest.rsc b/src/refactor/forloop/ProspectiveOperationsTest.rsc index 68556c8..a7c3fd2 100644 --- a/src/refactor/forloop/ProspectiveOperationsTest.rsc +++ b/src/refactor/forloop/ProspectiveOperationsTest.rsc @@ -5,18 +5,25 @@ import refactor::forloop::ProspectiveOperationsTestResources; import MethodVar; import lang::java::\syntax::Java18; import IO; +import List; public test bool shouldReturnAForEachOnSimpleShortExample() { tuple [set[MethodVar] vars, EnhancedForStatement loop] simpleShort = simpleShort(); - prospectiveOperations = retrievePotentialOperations(simpleShort.vars, simpleShort.loop); - return prospectiveOperations[0].stmt == "writer.write(thing);" && + + prospectiveOperations = retrieveProspectiveOperations(simpleShort.vars, simpleShort.loop); + + return size(prospectiveOperations) == 1 && + prospectiveOperations[0].stmt == "writer.write(thing);" && prospectiveOperations[0].operation == "forEach"; } public test bool shouldReturnCorrectlyOnFilterMapReduceExample() { tuple [set[MethodVar] vars, EnhancedForStatement loop] filterMapReduce = filterMapReduce(); - prospectiveOperations = retrievePotentialOperations(filterMapReduce.vars, filterMapReduce.loop); - return prospectiveOperations[0].stmt == "rule.hasErrors()" && + + prospectiveOperations = retrieveProspectiveOperations(filterMapReduce.vars, filterMapReduce.loop); + + return size(prospectiveOperations) == 2 && + prospectiveOperations[0].stmt == "rule.hasErrors()" && prospectiveOperations[0].operation == "filter" && prospectiveOperations[1].stmt == "count += rule.getErrors().size();" && prospectiveOperations[1].operation == "reduce"; From 2a5b8829c52faa89e66850ee85da8e9fcddc0e72 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 051/154] Fixing some logical erros in ForLoopToFunctional. --- src/refactor/forloop/ForLoopToFunctional.rsc | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/refactor/forloop/ForLoopToFunctional.rsc index f81ebae..c1e6001 100644 --- a/src/refactor/forloop/ForLoopToFunctional.rsc +++ b/src/refactor/forloop/ForLoopToFunctional.rsc @@ -12,25 +12,28 @@ public void refactorEnhancedToFunctional(EnhancedForStatement forStmt, set[Metho println(mergeOperations(prospectiveOperations, methodVars)); } -private list[ProspectiveOperation] mergeOperations(list[ProspectiveOperation] prOps, set[MethodVar] methodVars) { - println("mergeOperations()"); - listIndexes = [0 .. size(prOps)]; +private list[ProspectiveOperation] mergeOperations(list[ProspectiveOperation] prOps, set[MethodVar] methodVars) { + // we don't want the first element (index 0) + listIndexes = [1 .. size(prOps)]; // iterating bottom-up for (int i <- reverse(listIndexes)) { curr = prOps[i]; prev = prOps[i - 1]; if (!areComposable(curr, prev, methodVars)) { if (isMergeable(prev) && isMergeable(curr)) { + opsSize = size(prOps); + if (isFilter(prev) || isFilter(curr)) { - opsSize = size(prOps); while(opsSize > i) { - last = prOps[opsSize - 1]; - beforeLast = prOps[opsSize - 2]; + ProspectiveOperation last = prOps[opsSize - 1]; + ProspectiveOperation beforeLast = prOps[opsSize - 2]; merged = mergeOps(beforeLast, last, methodVars); prOps = slice(prOps, 0, opsSize - 2) + merged; + + opsSize = size(prOps); } } else { - merged = mergeOps(prev, curr); + merged = mergeOps(prev, curr, methodVars); prOps = slice(prOps, 0, opsSize - 2) + merged; } } From c1d3397e134f8933f6cfebddfb78cc1a9f0ca85a Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 052/154] Improving breaking statements into Prospective Operations. - Considering a LocalVariableDeclarationStatement inside a block. --- This is a case in the example illustrated in the paper. --- src/refactor/forloop/ForLoopToFunctional.rsc | 2 +- src/refactor/forloop/ProspectiveOperation.rsc | 60 +++++++++++++------ .../forloop/ProspectiveOperationsTest.rsc | 20 ++++++- .../ProspectiveOperationsTestResources.rsc | 12 ++++ .../FilterAndMergedForEach | 7 +++ testes/localVariables/ForLoopToFunctional | 12 ---- 6 files changed, 79 insertions(+), 34 deletions(-) create mode 100644 testes/ProspectiveOperation/FilterAndMergedForEach delete mode 100644 testes/localVariables/ForLoopToFunctional diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/refactor/forloop/ForLoopToFunctional.rsc index c1e6001..10279b5 100644 --- a/src/refactor/forloop/ForLoopToFunctional.rsc +++ b/src/refactor/forloop/ForLoopToFunctional.rsc @@ -7,7 +7,7 @@ import refactor::forloop::ProspectiveOperation; import List; import MethodVar; -public void refactorEnhancedToFunctional(EnhancedForStatement forStmt, set[MethodVar] methodVars) { +public void refactorEnhancedToFunctional(set[MethodVar] methodVars, EnhancedForStatement forStmt) { prospectiveOperations = retrieveProspectiveOperations(methodVars, forStmt); println(mergeOperations(prospectiveOperations, methodVars)); } diff --git a/src/refactor/forloop/ProspectiveOperation.rsc b/src/refactor/forloop/ProspectiveOperation.rsc index fd04a9d..4463b1b 100644 --- a/src/refactor/forloop/ProspectiveOperation.rsc +++ b/src/refactor/forloop/ProspectiveOperation.rsc @@ -55,9 +55,11 @@ private list[ProspectiveOperation] retrieveProspectiveOperationsFromStatement(St return prOps; } + +// XXX we might need to save `if (exp)` when a filter is added private list[ProspectiveOperation] retrieveProspectiveOperationsFromBlock(Block block) { list[ProspectiveOperation] prOps = []; - top-down visit(block) { + top-down-break visit(block) { case BlockStatement blockStatement: { top-down-break visit(blockStatement) { case (IfThenStatement) `if ( ) `: { @@ -68,6 +70,10 @@ private list[ProspectiveOperation] retrieveProspectiveOperationsFromBlock(Block //retrieveProspectiveOperationsFromStatement(thenStmt); println("if else"); } + case LocalVariableDeclarationStatement lvdlStmt: { + // not an if, so it's a map + prOps += prospectiveOperation(unparse(lvdlStmt), MAP); + } case StatementWithoutTrailingSubstatement otherStmt: { statement = parse(#Statement, unparse(otherStmt)); prOps += retrieveProspectiveOperationFromSingleStatement(statement); @@ -80,18 +86,18 @@ private list[ProspectiveOperation] retrieveProspectiveOperationsFromBlock(Block private list[ProspectiveOperation] retrieveProspectiveOperationsFromIfThenStatement(IfThenStatement ifStmt) { list[ProspectiveOperation] prOps = []; - top-down visit (ifStmt) { + top-down-break visit (ifStmt) { case (IfThenStatement) `if ( ) `: { - visit (thenStmt) { + top-down-break visit (thenStmt) { case (ReturnStatement) `return ;`: { if ("" == true) prOps += prospectiveOperation(unparse(ifStmt), ANY_MATCH); else if ("" == false) prOps += prospectiveOperation(unparse(ifStmt), NONE_MATCH); } - case Statement statement: { + default: { prOps += prospectiveOperation(unparse(exp), FILTER); - prOps += retrieveProspectiveOperationsFromStatement(statement); + prOps += retrieveProspectiveOperationsFromStatement(thenStmt); } } } @@ -99,11 +105,11 @@ private list[ProspectiveOperation] retrieveProspectiveOperationsFromIfThenStatem return prOps; } -private list[ProspectiveOperation] retrieveProspectiveOperationFromSingleStatement(Statement statement) { +private ProspectiveOperation retrieveProspectiveOperationFromSingleStatement(Statement statement) { if (isReducer(statement)) - return [prospectiveOperation(unparse(statement), REDUCE)]; + return prospectiveOperation(unparse(statement), REDUCE); else - return [prospectiveOperation(unparse(statement), MAP)]; + return prospectiveOperation(unparse(statement), MAP); } private bool isReducer(Statement statement) { @@ -193,7 +199,9 @@ private list[str] retrieveAllStatements(ProspectiveOperation prOp) { list[str] allStatements = []; if (isBlock(prOp.stmt)) return retrieveAllStatementsFromBlock(prOp.stmt); - else + else if(isLocalVariableDeclarationStatement(prOp.stmt)) + return [prOp.stmt]; + else return retrieveAllExpressionStatementsFromStatement(prOp.stmt); } @@ -214,6 +222,13 @@ private list[str] retrieveAllStatementsFromBlock(str blockStr) { return blockStatements; } +private bool isLocalVariableDeclarationStatement(str stmt) { + try { + parse(#LocalVariableDeclarationStatement, stmt); + return true; + } catch: return false; +} + // XXX probably not this private list[str] retrieveAllExpressionStatementsFromStatement(str statement) { list[str] stmts = []; @@ -240,19 +255,26 @@ private set[str] retrieveNeededVariables(ProspectiveOperation prOp) { set[str] neededVariables = {}; set[str] declaredVariables = {}; set[str] methodsNames = {}; - - stmt = parse(#Statement, prOp.stmt); - // If a var has the same name as a called method, this will fail - visit (stmt) { - case LocalVariableDeclaration lvdl: { - visit(lvdl) { - case (VariableDeclaratorId) ``: declaredVariables += unparse(id); + + if (isLocalVariableDeclarationStatement(prOp.stmt)) { + lvdlStmt = parse(#LocalVariableDeclarationStatement, prOp.stmt); + visit(lvdlStmt) { + case (VariableDeclaratorId) ``: declaredVariables += unparse(id); + } + } else { + stmt = parse(#Statement, prOp.stmt); + // If a var has the same name as a called method, this will fail + visit (stmt) { + case LocalVariableDeclaration lvdl: { + visit(lvdl) { + case (VariableDeclaratorId) ``: declaredVariables += unparse(id); + } } + case (MethodInvocation) ` ( )`: methodsNames += unparse(methodName); + case Identifier id: neededVariables = {}; } - case (MethodInvocation) ` ( )`: methodsNames += unparse(methodName); - case Identifier id: neededVariables = {}; } - + neededVariables -= declaredVariables; neededVariables -= methodsNames; diff --git a/src/refactor/forloop/ProspectiveOperationsTest.rsc b/src/refactor/forloop/ProspectiveOperationsTest.rsc index a7c3fd2..40839f0 100644 --- a/src/refactor/forloop/ProspectiveOperationsTest.rsc +++ b/src/refactor/forloop/ProspectiveOperationsTest.rsc @@ -22,7 +22,7 @@ public test bool shouldReturnCorrectlyOnFilterMapReduceExample() { prospectiveOperations = retrieveProspectiveOperations(filterMapReduce.vars, filterMapReduce.loop); - return size(prospectiveOperations) == 2 && + return size(prospectiveOperations) == 2 && prospectiveOperations[0].stmt == "rule.hasErrors()" && prospectiveOperations[0].operation == "filter" && prospectiveOperations[1].stmt == "count += rule.getErrors().size();" && @@ -34,4 +34,20 @@ public test bool shouldReturnCorrectlyOnFilterMapReduceExample() { // prospectiveOperations = retrievePotentialOperations(continueAndReturn.vars, continueAndReturn.loop); // println(prospectiveOperations); // return false; -//} \ No newline at end of file +//} + +public test bool shouldReturnXOnFilterAndMergedForEach() { + tuple [set[MethodVar] vars, EnhancedForStatement loop] filterAndMergedForEach = filterAndMergedForEach(); + + prospectiveOperations = retrieveProspectiveOperations(filterAndMergedForEach.vars, filterAndMergedForEach.loop); + + return size(prospectiveOperations) == 4 && + prospectiveOperations[0].stmt == "isValid(entry)" && + prospectiveOperations[0].operation == "filter" && + prospectiveOperations[1].stmt == "ClassLoader cl = entry.getKey();" && + prospectiveOperations[1].operation == "map" && + prospectiveOperations[2].stmt == "!((WebappClassLoader)cl).isStart()" && + prospectiveOperations[2].operation == "filter" && + prospectiveOperations[3].stmt == "result.add(entry.getValue());" && + prospectiveOperations[3].operation == "forEach"; +} \ No newline at end of file diff --git a/src/refactor/forloop/ProspectiveOperationsTestResources.rsc b/src/refactor/forloop/ProspectiveOperationsTestResources.rsc index 24db643..3d9cfde 100644 --- a/src/refactor/forloop/ProspectiveOperationsTestResources.rsc +++ b/src/refactor/forloop/ProspectiveOperationsTestResources.rsc @@ -34,4 +34,16 @@ private set[MethodVar] filterMapReduceVars() { methodHeader = parse(#MethodHeader, "int getNumberOfErrors()"); methodBody = parse(#MethodBody, "{\n int count = 0;\n for (ElementRule rule : getRules()) {\n if(rule.hasErrors())\n count += rule.getErrors().size();\n }\n return count;\n }"); return findLocalVariables(methodHeader, methodBody); +} + +public tuple [set[MethodVar] vars, EnhancedForStatement loop] filterAndMergedForEach() { + fileLoc = |project://rascal-Java8//testes/ProspectiveOperation/FilterAndMergedForEach|; + enhancedForLoop = parse(#EnhancedForStatement, readFile(fileLoc)); + return ; +} + +private set[MethodVar] filterAndMergedForEachVars() { + methodHeader = parse(#MethodHeader, "List\ findReloadedContextMemoryLeaks()"); + methodBody = parse(#MethodBody, "{\n List\ result = new ArrayList\();\n for (Map.Entry\ entry :\n childClassLoaders.entrySet())\n if(isValid(entry)) {\n ClassLoader cl = entry.getKey();\n if (!((WebappClassLoader)cl).isStart())\n result.add(entry.getValue());\n }\n return result;\n }"); + return findLocalVariables(methodHeader, methodBody); } \ No newline at end of file diff --git a/testes/ProspectiveOperation/FilterAndMergedForEach b/testes/ProspectiveOperation/FilterAndMergedForEach new file mode 100644 index 0000000..af3f52b --- /dev/null +++ b/testes/ProspectiveOperation/FilterAndMergedForEach @@ -0,0 +1,7 @@ +for (Map.Entry entry : + childClassLoaders.entrySet()) + if(isValid(entry)) { + ClassLoader cl = entry.getKey(); + if (!((WebappClassLoader)cl).isStart()) + result.add(entry.getValue()); + } \ No newline at end of file diff --git a/testes/localVariables/ForLoopToFunctional b/testes/localVariables/ForLoopToFunctional deleted file mode 100644 index 00e95ff..0000000 --- a/testes/localVariables/ForLoopToFunctional +++ /dev/null @@ -1,12 +0,0 @@ -class GrammarEngineImpl { - - boolean isEngineExisting(String grammarName) { - for(GrammarEngine e : importedEngines) { - if(e.getGrammarName() == null) continue; - if(e.getGrammarName().equals(grammarName)) - return true; - } - return false; - } - -} \ No newline at end of file From 9c7e7e0c21342d33a10bc3cb0d0c5a2cfd0fb7c6 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 053/154] Retrieving if statements when merging ops when the first is not an filter --- src/refactor/forloop/ProspectiveOperation.rsc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/refactor/forloop/ProspectiveOperation.rsc b/src/refactor/forloop/ProspectiveOperation.rsc index 4463b1b..b223076 100644 --- a/src/refactor/forloop/ProspectiveOperation.rsc +++ b/src/refactor/forloop/ProspectiveOperation.rsc @@ -236,6 +236,8 @@ private list[str] retrieveAllExpressionStatementsFromStatement(str statement) { top-down visit(stmt) { case ExpressionStatement expStmt: stmts += unparse(expStmt); + case (IfThenStatement) `if () `: + stmts += "if (" + unparse(exp) + ")"; } return stmts; } From ebd6eba14c997a8f8a450e8b6dd034b7e6c70579 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 054/154] Improving our understanding of the algorithm and fixing it. - For two operations to be composable, all needed vars from the first have to be provided by the second. -- Therefore: the firsts' needed vars have to be available from the second --- src/refactor/forloop/ProspectiveOperation.rsc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/refactor/forloop/ProspectiveOperation.rsc b/src/refactor/forloop/ProspectiveOperation.rsc index b223076..527265f 100644 --- a/src/refactor/forloop/ProspectiveOperation.rsc +++ b/src/refactor/forloop/ProspectiveOperation.rsc @@ -154,15 +154,15 @@ public bool isFilter(ProspectiveOperation prOp) { // TODO needed and available called more than once. good idea to extract it. public bool areComposable(ProspectiveOperation first, ProspectiveOperation second, set[MethodVar] methodVars) { firstNeededVars = retrieveNeededVariables(first); - // second's available has to be in first's needed + // firsts' needed has to be available from second secondAvailableVars = retrieveAvailableVars(second, methodVars); - secondAvailableVarsInFirstNeeded = isSecondAvailableInFirstNeeded(firstNeededVars, secondAvailableVars); - return size(firstNeededVars) <= 1 && secondAvailableVarsInFirstNeeded; + firstNeededInSecondAvailable = isFirstNeededVarsInSecondAvailableVars(firstNeededVars, secondAvailableVars); + return size(firstNeededVars) <= 1 && firstNeededInSecondAvailable; } -private bool isSecondAvailableInFirstNeeded(set[str] firstNeededVars, set[str] secondAvailableVars) { - for(secondAvailable <- secondAvailableVars) - if(secondAvailable notin firstNeededVars) return false; +private bool isFirstNeededVarsInSecondAvailableVars(set[str] firstNeededVars, set[str] secondAvailableVars) { + for(firstNeededVar <- firstNeededVars) + if(firstNeededVar notin secondAvailableVars) return false; return true; } From 4144f5097419fa5beb16ab8fbc19d1d5f82ab848 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 055/154] Extracting module for OperationTypes. - Making reuse easier of the strings across other modules/tests. --- src/refactor/forloop/OperationType.rsc | 8 ++++++++ .../forloop/ProspectiveOperationsTest.rsc | 15 ++++++++------- 2 files changed, 16 insertions(+), 7 deletions(-) create mode 100644 src/refactor/forloop/OperationType.rsc diff --git a/src/refactor/forloop/OperationType.rsc b/src/refactor/forloop/OperationType.rsc new file mode 100644 index 0000000..a65568a --- /dev/null +++ b/src/refactor/forloop/OperationType.rsc @@ -0,0 +1,8 @@ +module refactor::forloop::OperationType + +public str FILTER = "filter"; +public str MAP = "map"; +public str FOR_EACH = "forEach"; +public str REDUCE = "reduce"; +public str ANY_MATCH = "anyMatch"; +public str NONE_MATCH = "noneMatch"; \ No newline at end of file diff --git a/src/refactor/forloop/ProspectiveOperationsTest.rsc b/src/refactor/forloop/ProspectiveOperationsTest.rsc index 40839f0..1506144 100644 --- a/src/refactor/forloop/ProspectiveOperationsTest.rsc +++ b/src/refactor/forloop/ProspectiveOperationsTest.rsc @@ -2,6 +2,7 @@ module refactor::forloop::ProspectiveOperationsTest import refactor::forloop::ProspectiveOperation; import refactor::forloop::ProspectiveOperationsTestResources; +import refactor::forloop::OperationType; import MethodVar; import lang::java::\syntax::Java18; import IO; @@ -14,7 +15,7 @@ public test bool shouldReturnAForEachOnSimpleShortExample() { return size(prospectiveOperations) == 1 && prospectiveOperations[0].stmt == "writer.write(thing);" && - prospectiveOperations[0].operation == "forEach"; + prospectiveOperations[0].operation == FOR_EACH; } public test bool shouldReturnCorrectlyOnFilterMapReduceExample() { @@ -24,9 +25,9 @@ public test bool shouldReturnCorrectlyOnFilterMapReduceExample() { return size(prospectiveOperations) == 2 && prospectiveOperations[0].stmt == "rule.hasErrors()" && - prospectiveOperations[0].operation == "filter" && + prospectiveOperations[0].operation == FILTER && prospectiveOperations[1].stmt == "count += rule.getErrors().size();" && - prospectiveOperations[1].operation == "reduce"; + prospectiveOperations[1].operation == REDUCE; } //public test bool shouldReturnXOnContinueAndReturnEnhancedLoop() { @@ -43,11 +44,11 @@ public test bool shouldReturnXOnFilterAndMergedForEach() { return size(prospectiveOperations) == 4 && prospectiveOperations[0].stmt == "isValid(entry)" && - prospectiveOperations[0].operation == "filter" && + prospectiveOperations[0].operation == FILTER && prospectiveOperations[1].stmt == "ClassLoader cl = entry.getKey();" && - prospectiveOperations[1].operation == "map" && + prospectiveOperations[1].operation == MAP && prospectiveOperations[2].stmt == "!((WebappClassLoader)cl).isStart()" && - prospectiveOperations[2].operation == "filter" && + prospectiveOperations[2].operation == FILTER && prospectiveOperations[3].stmt == "result.add(entry.getValue());" && - prospectiveOperations[3].operation == "forEach"; + prospectiveOperations[3].operation == FOREACH; } \ No newline at end of file From 5435129658997504bedabd30976a1af9c312a997 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 056/154] Module for NeededVariables. More robust and correct implementation. --- src/refactor/forloop/NeededVariables.rsc | 81 ++++++++++++++++++++ src/refactor/forloop/NeededVariablesTest.rsc | 65 ++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 src/refactor/forloop/NeededVariables.rsc create mode 100644 src/refactor/forloop/NeededVariablesTest.rsc diff --git a/src/refactor/forloop/NeededVariables.rsc b/src/refactor/forloop/NeededVariables.rsc new file mode 100644 index 0000000..cf729b4 --- /dev/null +++ b/src/refactor/forloop/NeededVariables.rsc @@ -0,0 +1,81 @@ +module refactor::forloop::NeededVariables + +import lang::java::\syntax::Java18; +import ParseTree; +import IO; +import refactor::forloop::ProspectiveOperation; +import MethodVar; +import Set; +import refactor::forloop::OperationType; +import String; + +public set[str] retrieveNeededVariables(ProspectiveOperation prOp) { + set[str] neededVariables = {}; + + if (prOp.operation == REDUCE) + return {}; + else if (isLocalVariableDeclarationStatement(prOp.stmt)) + neededVariables += retrieveNeededVarsFromLocalVariableDeclarationStmt(prOp.stmt); + else + neededVariables += retrieveNeededVarsFromStatement(prOp.stmt); + + return neededVariables; +} + +private bool isLocalVariableDeclarationStatement(str stmt) { + try { + parse(#LocalVariableDeclarationStatement, stmt); + return true; + } catch: return false; +} + +// XXX Parsing twice (isLocal... and this method) the stmt +// should not be a big deal since it's only a stmt from a prospective operation. +// Using this pattern (parsing to check if a stmt is of the type #Something) and then parsing again +// could refactor in the future to return a Tuple, with the bool and the parsed tree. +private set[str] retrieveNeededVarsFromLocalVariableDeclarationStmt(str stmt) { + set[str] neededVariables = {}; + + lvdlStmt = parse(#LocalVariableDeclarationStatement, stmt); + + visit(lvdlStmt) { + case (VariableDeclaratorId) ``: neededVariables += unparse(id); + + case ExpressionName expName: { + visit(expName) { + case Identifier id: neededVariables += unparse(id); + } + } + } + + return neededVariables; +} + +private set[str] retrieveNeededVarsFromStatement(str stmt) { + set[str] neededVariables = {}; + + stmt = parse(#Statement, getCorrectStatementAsString(stmt)); + + visit (stmt) { + case LocalVariableDeclaration lvdl: { + visit(lvdl) { + case (VariableDeclaratorId) ``: neededVariables += unparse(id); + } + } + case ExpressionName expName: { + visit(expName) { + case Identifier id: neededVariables += unparse(id); + } + } + } + + return neededVariables; +} + +private str getCorrectStatementAsString(str stmt) { + // stmt does not end with ';' it can't be parsed as a statement + // it can also be a block + if(!(endsWith(stmt, ";") || endsWith(stmt, "}"))) + return stmt + ";"; + return stmt; +} \ No newline at end of file diff --git a/src/refactor/forloop/NeededVariablesTest.rsc b/src/refactor/forloop/NeededVariablesTest.rsc new file mode 100644 index 0000000..f14ec72 --- /dev/null +++ b/src/refactor/forloop/NeededVariablesTest.rsc @@ -0,0 +1,65 @@ +module refactor::forloop::NeededVariablesTest + +import refactor::forloop::NeededVariables; +import refactor::forloop::ProspectiveOperation; +import refactor::forloop::OperationType; +import MethodVar; +import Set; +import IO; + +public test bool methodInvocationWithArg() { + prOp = prospectiveOperation("writer.write(thing);", FOR_EACH); + + neededVars = retrieveNeededVariables(prOp); + + return size(neededVars) == 2 && + "writer" in neededVars && + "thing" in neededVars; +} + +public test bool simpleMethodInvocationWithoutEndingSemiCollon() { + prOp = prospectiveOperation("rule.hasErrors()", FILTER); + + neededVars = retrieveNeededVariables(prOp); + + return size(neededVars) == 1 && + "rule" in neededVars; +} + +public test bool simpleMethodInvocationWithtEndingSemiCollon() { + prOp = prospectiveOperation("rule.hasErrors()", FILTER); + + neededVars = retrieveNeededVariables(prOp); + + return size(neededVars) == 1 && + "rule" in neededVars; +} + +public test bool variableAssignmentWithInitializer() { + prOp = prospectiveOperation("count = rule.getErrors().size();", MAP); + + neededVars = retrieveNeededVariables(prOp); + + return size(neededVars) == 2 && + "count" in neededVars && + "rule" in neededVars; +} + +public test bool localVariableDeclarationShouldReturnItselfWithInitializer() { + prOp = prospectiveOperation("ClassLoader cl = entry.getKey(argNeeded);", MAP); + + neededVars = retrieveNeededVariables(prOp); + + return size(neededVars) == 3 && + "cl" in neededVars && + "entry" in neededVars && + "argNeeded" in neededVars; +} + +public test bool reduceShouldReturnEmpty() { + prOp = prospectiveOperation("count += rule.getErrors().size();", REDUCE); + + neededVars = retrieveNeededVariables(prOp); + + return size(neededVars) == 0; +} \ No newline at end of file From 212a6646a9c1d04d24491d1fca573a54f0ab104a Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 057/154] ProspectiveOperation using the extracted modules. --- src/refactor/forloop/AvailableVariables.rsc | 15 ++++++ src/refactor/forloop/NeededVariables.rsc | 7 --- src/refactor/forloop/ProspectiveOperation.rsc | 53 ++----------------- 3 files changed, 19 insertions(+), 56 deletions(-) create mode 100644 src/refactor/forloop/AvailableVariables.rsc diff --git a/src/refactor/forloop/AvailableVariables.rsc b/src/refactor/forloop/AvailableVariables.rsc new file mode 100644 index 0000000..dd07a43 --- /dev/null +++ b/src/refactor/forloop/AvailableVariables.rsc @@ -0,0 +1,15 @@ +module refactor::forloop::AvailableVariables + +import refactor::forloop::ProspectiveOperation; +import MethodVar; +import Set; + +// XXX assess the necessity to verify these others conditions: + // fields declared in class, inherited and visible from imported classes ?? + // variables declared in the Prospective Operation ?? +// Right now they are being verified by elimination. +public set[str] retrieveAvailableVars(ProspectiveOperation prOp, set[MethodVar] methodVars) { + withinMethod = retrieveNotDeclaredWithinLoopNames(methodVars); + withinLoop = retrieveDeclaredWithinLoopNames(methodVars); + return withinMethod - withinLoop; +} \ No newline at end of file diff --git a/src/refactor/forloop/NeededVariables.rsc b/src/refactor/forloop/NeededVariables.rsc index cf729b4..8ef4ddd 100644 --- a/src/refactor/forloop/NeededVariables.rsc +++ b/src/refactor/forloop/NeededVariables.rsc @@ -22,13 +22,6 @@ public set[str] retrieveNeededVariables(ProspectiveOperation prOp) { return neededVariables; } -private bool isLocalVariableDeclarationStatement(str stmt) { - try { - parse(#LocalVariableDeclarationStatement, stmt); - return true; - } catch: return false; -} - // XXX Parsing twice (isLocal... and this method) the stmt // should not be a big deal since it's only a stmt from a prospective operation. // Using this pattern (parsing to check if a stmt is of the type #Something) and then parsing again diff --git a/src/refactor/forloop/ProspectiveOperation.rsc b/src/refactor/forloop/ProspectiveOperation.rsc index 527265f..61c6ffe 100644 --- a/src/refactor/forloop/ProspectiveOperation.rsc +++ b/src/refactor/forloop/ProspectiveOperation.rsc @@ -9,16 +9,12 @@ import util::Math; import MethodVar; import String; import Set; +import refactor::forloop::OperationType; +import refactor::forloop::NeededVariables; +import refactor::forloop::AvailableVariables; public data ProspectiveOperation = prospectiveOperation(str stmt, str operation); -str FILTER = "filter"; -str MAP = "map"; -str FOR_EACH = "forEach"; -str REDUCE = "reduce"; -str ANY_MATCH = "anyMatch"; -str NONE_MATCH = "noneMatch"; - private list[MethodVar] methodLocalVars; public list[ProspectiveOperation] retrieveProspectiveOperations(set[MethodVar] localVars, EnhancedForStatement forStmt) { @@ -222,7 +218,7 @@ private list[str] retrieveAllStatementsFromBlock(str blockStr) { return blockStatements; } -private bool isLocalVariableDeclarationStatement(str stmt) { +public bool isLocalVariableDeclarationStatement(str stmt) { try { parse(#LocalVariableDeclarationStatement, stmt); return true; @@ -242,47 +238,6 @@ private list[str] retrieveAllExpressionStatementsFromStatement(str statement) { return stmts; } -private set[str] retrieveAvailableVars(ProspectiveOperation prOp, set[MethodVar] methodVars) { - // fields declared in class, inherited and visible from imported classes ?? - // variables declared in the Prospective Operation ?? - withinMethod = retrieveNotDeclaredWithinLoopNames(methodVars); - withinLoop = retrieveDeclaredWithinLoopNames(methodVars); - return withinMethod - withinLoop; -} - -private set[str] retrieveNeededVariables(ProspectiveOperation prOp) { - if (prOp.operation == FILTER) - return {}; - - set[str] neededVariables = {}; - set[str] declaredVariables = {}; - set[str] methodsNames = {}; - - if (isLocalVariableDeclarationStatement(prOp.stmt)) { - lvdlStmt = parse(#LocalVariableDeclarationStatement, prOp.stmt); - visit(lvdlStmt) { - case (VariableDeclaratorId) ``: declaredVariables += unparse(id); - } - } else { - stmt = parse(#Statement, prOp.stmt); - // If a var has the same name as a called method, this will fail - visit (stmt) { - case LocalVariableDeclaration lvdl: { - visit(lvdl) { - case (VariableDeclaratorId) ``: declaredVariables += unparse(id); - } - } - case (MethodInvocation) ` ( )`: methodsNames += unparse(methodName); - case Identifier id: neededVariables = {}; - } - } - - neededVariables -= declaredVariables; - neededVariables -= methodsNames; - - return neededVariables; -} - private Block transformStatementsInBlock(list[str] stmts) { str joined = "{\n"; for(stmt <- stmts) From 0e392111a0588c716d3b1ea27d9812ea63ef0ac4 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 058/154] Moving some methods around from ProspectiveOperation. - avoiding circular dependencies --- src/refactor/forloop/AvailableVariables.rsc | 4 +- src/refactor/forloop/ForLoopToFunctional.rsc | 103 ++++++++++++++++- src/refactor/forloop/NeededVariables.rsc | 15 ++- src/refactor/forloop/ProspectiveOperation.rsc | 108 +----------------- 4 files changed, 115 insertions(+), 115 deletions(-) diff --git a/src/refactor/forloop/AvailableVariables.rsc b/src/refactor/forloop/AvailableVariables.rsc index dd07a43..7ba18f6 100644 --- a/src/refactor/forloop/AvailableVariables.rsc +++ b/src/refactor/forloop/AvailableVariables.rsc @@ -1,8 +1,8 @@ module refactor::forloop::AvailableVariables -import refactor::forloop::ProspectiveOperation; -import MethodVar; import Set; +import MethodVar; +import refactor::forloop::ProspectiveOperation; // XXX assess the necessity to verify these others conditions: // fields declared in class, inherited and visible from imported classes ?? diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/refactor/forloop/ForLoopToFunctional.rsc index 10279b5..c22c6f6 100644 --- a/src/refactor/forloop/ForLoopToFunctional.rsc +++ b/src/refactor/forloop/ForLoopToFunctional.rsc @@ -1,11 +1,16 @@ module refactor::forloop::ForLoopToFunctional -import lang::java::\syntax::Java18; -import ParseTree; import IO; -import refactor::forloop::ProspectiveOperation; import List; +import Set; +import lang::java::\syntax::Java18; +import ParseTree; import MethodVar; +import refactor::forloop::ProspectiveOperation; +import refactor::forloop::NeededVariables; +import refactor::forloop::AvailableVariables; + + public void refactorEnhancedToFunctional(set[MethodVar] methodVars, EnhancedForStatement forStmt) { prospectiveOperations = retrieveProspectiveOperations(methodVars, forStmt); @@ -40,4 +45,96 @@ private list[ProspectiveOperation] mergeOperations(list[ProspectiveOperation] pr } } return prOps; +} + +// TODO needed and available called more than once. good idea to extract it. +public bool areComposable(ProspectiveOperation first, ProspectiveOperation second, set[MethodVar] methodVars) { + firstNeededVars = retrieveNeededVariables(first); + // firsts' needed has to be available from second + secondAvailableVars = retrieveAvailableVars(second, methodVars); + firstNeededInSecondAvailable = isFirstNeededVarsInSecondAvailableVars(firstNeededVars, secondAvailableVars); + return size(firstNeededVars) <= 1 && firstNeededInSecondAvailable; +} + +private bool isFirstNeededVarsInSecondAvailableVars(set[str] firstNeededVars, set[str] secondAvailableVars) { + for(firstNeededVar <- firstNeededVars) + if(firstNeededVar notin secondAvailableVars) return false; + return true; +} + +public ProspectiveOperation mergeOps(ProspectiveOperation first, ProspectiveOperation second, set[MethodVar] methodVars) { + if (isFilter(first)) { + return mergeTwoOpsInAnIfThenStmt(first, second); + } else { + list[str] statements = retrieveAllStatements(first) + retrieveAllStatements(second); + + set[str] firstAvailableVars = retrieveAvailableVars(first, methodVars); + set[str] availableVars = firstAvailableVars; + availableVars += retrieveAvailableVars(second, methodVars); + + set[str] neededVars = retrieveNeededVariables(second); + neededVars -= firstAvailableVars; + neededVars += retrieveNeededVariables(first); + + neededVars -= retrieveNotDeclaredWithinLoopNames(methodVars); + + Block statementsAsOneBlock = transformStatementsInBlock(statements); + + return prospectiveOperation(unparse(statementsAsOneBlock), second.operation); + } +} + +private ProspectiveOperation mergeTwoOpsInAnIfThenStmt(ProspectiveOperation first, ProspectiveOperation second) { + Expression exp = parse(#Expression, first.stmt); + Statement thenStmt = parse(#Statement, second.stmt); + ifThenStmt = [IfThenStatement] "if () "; + return prospectiveOperation(unparse(ifThenStmt), second.operation); +} + +private list[str] retrieveAllStatements(ProspectiveOperation prOp) { + list[str] allStatements = []; + if (isBlock(prOp.stmt)) + return retrieveAllStatementsFromBlock(prOp.stmt); + else if(isLocalVariableDeclarationStatement(prOp.stmt)) + return [prOp.stmt]; + else + return retrieveAllExpressionStatementsFromStatement(prOp.stmt); +} + +private bool isBlock(str stmt) { + try { + parse(#Block, stmt); + return true; + } catch: return false; +} + +private list[str] retrieveAllStatementsFromBlock(str blockStr) { + list[str] blockStatements = []; + block = parse(#Block, blockStr); + top-down visit(block) { + case BlockStatement blockStmt: + blockStatements += unparse(blockStmt); + } + return blockStatements; +} + +// XXX probably not this +private list[str] retrieveAllExpressionStatementsFromStatement(str statement) { + list[str] stmts = []; + Statement stmt = parse(#Statement, statement); + top-down visit(stmt) { + case ExpressionStatement expStmt: + stmts += unparse(expStmt); + case (IfThenStatement) `if () `: + stmts += "if (" + unparse(exp) + ")"; + } + return stmts; +} + +private Block transformStatementsInBlock(list[str] stmts) { + str joined = "{\n"; + for(stmt <- stmts) + joined += (stmt + "\n"); + joined += "}"; + return parse(#Block, joined); } \ No newline at end of file diff --git a/src/refactor/forloop/NeededVariables.rsc b/src/refactor/forloop/NeededVariables.rsc index 8ef4ddd..2ee0b4c 100644 --- a/src/refactor/forloop/NeededVariables.rsc +++ b/src/refactor/forloop/NeededVariables.rsc @@ -1,13 +1,13 @@ module refactor::forloop::NeededVariables +import IO; +import String; +import Set; import lang::java::\syntax::Java18; import ParseTree; -import IO; -import refactor::forloop::ProspectiveOperation; import MethodVar; -import Set; +import refactor::forloop::ProspectiveOperation; import refactor::forloop::OperationType; -import String; public set[str] retrieveNeededVariables(ProspectiveOperation prOp) { set[str] neededVariables = {}; @@ -22,6 +22,13 @@ public set[str] retrieveNeededVariables(ProspectiveOperation prOp) { return neededVariables; } +public bool isLocalVariableDeclarationStatement(str stmt) { + try { + parse(#LocalVariableDeclarationStatement, stmt); + return true; + } catch: return false; +} + // XXX Parsing twice (isLocal... and this method) the stmt // should not be a big deal since it's only a stmt from a prospective operation. // Using this pattern (parsing to check if a stmt is of the type #Something) and then parsing again diff --git a/src/refactor/forloop/ProspectiveOperation.rsc b/src/refactor/forloop/ProspectiveOperation.rsc index 61c6ffe..4da1302 100644 --- a/src/refactor/forloop/ProspectiveOperation.rsc +++ b/src/refactor/forloop/ProspectiveOperation.rsc @@ -1,17 +1,12 @@ module refactor::forloop::ProspectiveOperation import IO; +import List; +import String; import lang::java::\syntax::Java18; import ParseTree; -import ParseTreeVisualization; -import List; -import util::Math; import MethodVar; -import String; -import Set; import refactor::forloop::OperationType; -import refactor::forloop::NeededVariables; -import refactor::forloop::AvailableVariables; public data ProspectiveOperation = prospectiveOperation(str stmt, str operation); @@ -145,103 +140,4 @@ public bool isMergeable(ProspectiveOperation prOp) { public bool isFilter(ProspectiveOperation prOp) { return prOp.operation == FILTER; -} - -// TODO needed and available called more than once. good idea to extract it. -public bool areComposable(ProspectiveOperation first, ProspectiveOperation second, set[MethodVar] methodVars) { - firstNeededVars = retrieveNeededVariables(first); - // firsts' needed has to be available from second - secondAvailableVars = retrieveAvailableVars(second, methodVars); - firstNeededInSecondAvailable = isFirstNeededVarsInSecondAvailableVars(firstNeededVars, secondAvailableVars); - return size(firstNeededVars) <= 1 && firstNeededInSecondAvailable; -} - -private bool isFirstNeededVarsInSecondAvailableVars(set[str] firstNeededVars, set[str] secondAvailableVars) { - for(firstNeededVar <- firstNeededVars) - if(firstNeededVar notin secondAvailableVars) return false; - return true; -} - -public ProspectiveOperation mergeOps(ProspectiveOperation first, ProspectiveOperation second, set[MethodVar] methodVars) { - if (isFilter(first)) { - return mergeTwoOpsInAnIfThenStmt(first, second); - } else { - list[str] statements = retrieveAllStatements(first) + retrieveAllStatements(second); - - set[str] firstAvailableVars = retrieveAvailableVars(first, methodVars); - set[str] availableVars = firstAvailableVars; - availableVars += retrieveAvailableVars(second, methodVars); - - set[str] neededVars = retrieveNeededVariables(second); - neededVars -= firstAvailableVars; - neededVars += retrieveNeededVariables(first); - - neededVars -= retrieveNotDeclaredWithinLoopNames(methodVars); - - Block statementsAsOneBlock = transformStatementsInBlock(statements); - - return prospectiveOperation(unparse(statementsAsOneBlock), second.operation); - } -} - -private ProspectiveOperation mergeTwoOpsInAnIfThenStmt(ProspectiveOperation first, ProspectiveOperation second) { - Expression exp = parse(#Expression, first.stmt); - Statement thenStmt = parse(#Statement, second.stmt); - ifThenStmt = [IfThenStatement] "if () "; - return prospectiveOperation(unparse(ifThenStmt), second.operation); -} - -private list[str] retrieveAllStatements(ProspectiveOperation prOp) { - list[str] allStatements = []; - if (isBlock(prOp.stmt)) - return retrieveAllStatementsFromBlock(prOp.stmt); - else if(isLocalVariableDeclarationStatement(prOp.stmt)) - return [prOp.stmt]; - else - return retrieveAllExpressionStatementsFromStatement(prOp.stmt); -} - -private bool isBlock(str stmt) { - try { - parse(#Block, stmt); - return true; - } catch: return false; -} - -private list[str] retrieveAllStatementsFromBlock(str blockStr) { - list[str] blockStatements = []; - block = parse(#Block, blockStr); - top-down visit(block) { - case BlockStatement blockStmt: - blockStatements += unparse(blockStmt); - } - return blockStatements; -} - -public bool isLocalVariableDeclarationStatement(str stmt) { - try { - parse(#LocalVariableDeclarationStatement, stmt); - return true; - } catch: return false; -} - -// XXX probably not this -private list[str] retrieveAllExpressionStatementsFromStatement(str statement) { - list[str] stmts = []; - Statement stmt = parse(#Statement, statement); - top-down visit(stmt) { - case ExpressionStatement expStmt: - stmts += unparse(expStmt); - case (IfThenStatement) `if () `: - stmts += "if (" + unparse(exp) + ")"; - } - return stmts; -} - -private Block transformStatementsInBlock(list[str] stmts) { - str joined = "{\n"; - for(stmt <- stmts) - joined += (stmt + "\n"); - joined += "}"; - return parse(#Block, joined); } \ No newline at end of file From 34acb5ffbde1ca05cda411bdf815d7e258f81bbe Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 059/154] NeededVariables working with Expressions. - `Expression` is the Statement in a Prospective Filter. - `Expression` does not parse as a `Statement`. --- src/refactor/forloop/NeededVariables.rsc | 27 ++++++++++++++++--- src/refactor/forloop/NeededVariablesTest.rsc | 9 +++++++ src/refactor/forloop/ProspectiveOperation.rsc | 9 +++---- 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/refactor/forloop/NeededVariables.rsc b/src/refactor/forloop/NeededVariables.rsc index 2ee0b4c..00dffa9 100644 --- a/src/refactor/forloop/NeededVariables.rsc +++ b/src/refactor/forloop/NeededVariables.rsc @@ -7,15 +7,16 @@ import lang::java::\syntax::Java18; import ParseTree; import MethodVar; import refactor::forloop::ProspectiveOperation; -import refactor::forloop::OperationType; public set[str] retrieveNeededVariables(ProspectiveOperation prOp) { set[str] neededVariables = {}; - if (prOp.operation == REDUCE) + if (isReduce(prOp)) return {}; + else if(isFilter(prOp)) + neededVariables += retrieveNeededVarsFromExpression(prOp.stmt); else if (isLocalVariableDeclarationStatement(prOp.stmt)) - neededVariables += retrieveNeededVarsFromLocalVariableDeclarationStmt(prOp.stmt); + neededVariables += retrieveNeededVarsFromLocalVariableDeclarationStmt(prOp.stmt); else neededVariables += retrieveNeededVarsFromStatement(prOp.stmt); @@ -51,9 +52,27 @@ private set[str] retrieveNeededVarsFromLocalVariableDeclarationStmt(str stmt) { return neededVariables; } -private set[str] retrieveNeededVarsFromStatement(str stmt) { +// TODO verify if visit(Tree) works for a more generic traversal +// maybe it's possible to traverse only once +private set[str] retrieveNeededVarsFromExpression(str stmt) { set[str] neededVariables = {}; + + exp = parse(#Expression, stmt); + + visit(exp) { + case ExpressionName expName: { + visit(expName) { + case Identifier id: neededVariables += unparse(id); + } + } + } + + return neededVariables; +} +private set[str] retrieveNeededVarsFromStatement(str stmt) { + set[str] neededVariables = {}; + stmt = parse(#Statement, getCorrectStatementAsString(stmt)); visit (stmt) { diff --git a/src/refactor/forloop/NeededVariablesTest.rsc b/src/refactor/forloop/NeededVariablesTest.rsc index f14ec72..b362c86 100644 --- a/src/refactor/forloop/NeededVariablesTest.rsc +++ b/src/refactor/forloop/NeededVariablesTest.rsc @@ -56,6 +56,15 @@ public test bool localVariableDeclarationShouldReturnItselfWithInitializer() { "argNeeded" in neededVars; } +public test bool expressionIsNotAStatement() { + prOp = prospectiveOperation("!((WebappClassLoader)cl).isStart()", FILTER); + + neededVars = retrieveNeededVariables(prOp); + + return size(neededVars) == 1 && + "cl" in neededVars; +} + public test bool reduceShouldReturnEmpty() { prOp = prospectiveOperation("count += rule.getErrors().size();", REDUCE); diff --git a/src/refactor/forloop/ProspectiveOperation.rsc b/src/refactor/forloop/ProspectiveOperation.rsc index 4da1302..03b6869 100644 --- a/src/refactor/forloop/ProspectiveOperation.rsc +++ b/src/refactor/forloop/ProspectiveOperation.rsc @@ -133,11 +133,10 @@ private list[ProspectiveOperation] markLastStmtAsEager(list[ProspectiveOperation return prefix(prOps) + lastPrOp; } -public bool isMergeable(ProspectiveOperation prOp) { - operation = prOp.operation; - return operation == FILTER || operation == MAP || operation == FOR_EACH; -} - public bool isFilter(ProspectiveOperation prOp) { return prOp.operation == FILTER; +} + +public bool isReduce(ProspectiveOperation prOp) { + return prOp.operation == REDUCE; } \ No newline at end of file From eef330261f248095b805d0f253fe17ccd918e01a Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 060/154] Local Variables declared are available vars! --- src/refactor/forloop/AvailableVariables.rsc | 32 ++++++++++++- .../forloop/AvailableVariablesTest.rsc | 48 +++++++++++++++++++ src/refactor/forloop/NeededVariables.rsc | 16 +------ src/refactor/forloop/NeededVariablesTest.rsc | 22 ++++----- src/refactor/forloop/ProspectiveOperation.rsc | 7 +++ 5 files changed, 96 insertions(+), 29 deletions(-) create mode 100644 src/refactor/forloop/AvailableVariablesTest.rsc diff --git a/src/refactor/forloop/AvailableVariables.rsc b/src/refactor/forloop/AvailableVariables.rsc index 7ba18f6..6b495ea 100644 --- a/src/refactor/forloop/AvailableVariables.rsc +++ b/src/refactor/forloop/AvailableVariables.rsc @@ -1,6 +1,8 @@ module refactor::forloop::AvailableVariables import Set; +import lang::java::\syntax::Java18; +import ParseTree; import MethodVar; import refactor::forloop::ProspectiveOperation; @@ -8,8 +10,34 @@ import refactor::forloop::ProspectiveOperation; // fields declared in class, inherited and visible from imported classes ?? // variables declared in the Prospective Operation ?? // Right now they are being verified by elimination. -public set[str] retrieveAvailableVars(ProspectiveOperation prOp, set[MethodVar] methodVars) { +public set[str] retrieveAvailableVariables(ProspectiveOperation prOp, set[MethodVar] methodVars) { + availableVars = retrieveLocalVariableDeclarations(prOp); withinMethod = retrieveNotDeclaredWithinLoopNames(methodVars); withinLoop = retrieveDeclaredWithinLoopNames(methodVars); - return withinMethod - withinLoop; + + availableVars += withinMethod; + availableVars -= withinLoop; + + return availableVars; +} + +private set[str] retrieveLocalVariableDeclarations(ProspectiveOperation prOp) { + if (isFilter(prOp)) return {}; + + localVars = {}; + Tree stmt; + + if (isLocalVariableDeclarationStatement(prOp.stmt)) + stmt = parse(#LocalVariableDeclarationStatement, prOp.stmt); + else + stmt = parse(#Statement, prOp.stmt); + + visit(stmt) { + case LocalVariableDeclaration lvdl: { + visit(lvdl) { + case (VariableDeclaratorId) ``: localVars += unparse(id); + } + } + } + return localVars; } \ No newline at end of file diff --git a/src/refactor/forloop/AvailableVariablesTest.rsc b/src/refactor/forloop/AvailableVariablesTest.rsc new file mode 100644 index 0000000..a493051 --- /dev/null +++ b/src/refactor/forloop/AvailableVariablesTest.rsc @@ -0,0 +1,48 @@ +module refactor::forloop::AvailableVariablesTest + +import refactor::forloop::AvailableVariables; +import refactor::forloop::ProspectiveOperation; +import refactor::forloop::OperationType; +import MethodVar; +import Set; +import IO; + +public test bool methodParamShouldBeAvailableVar() { + prOp = prospectiveOperation("writer.write(thing);", FOR_EACH); + methodVars = {methodVar(false, "thing", "String", false, true), + methodVar(false, "writer", "PrintWriter", true, false)}; + + availableVars = retrieveAvailableVariables(prOp, methodVars); + + return size(availableVars) == 1 && + "writer" in availableVars; +} + +public test bool varWithinLoopShouldNotBeAvailable() { + prOp = prospectiveOperation("rule.hasErrors()", FILTER); + methodVars = {methodVar(false, "count", "int", false, false), + methodVar(false, "rule", "ElementRule", false, true)}; + + availableVars = retrieveAvailableVariables(prOp, methodVars); + + return "rule" notin availableVars; +} + +public test bool varNotWithinLoopShouldBeAvailable() { + prOp = prospectiveOperation("rule.hasErrors()", FILTER); + methodVars = {methodVar(false, "count", "int", false, false), + methodVar(false, "rule", "ElementRule", false, true)}; + + availableVars = retrieveAvailableVariables(prOp, methodVars); + + return "count" in availableVars; +} + +public test bool localVariableDeclarationShouldBeAvailableVar() { + prOp = prospectiveOperation("ClassLoader cl = entry.getKey(argNeeded);", MAP); + methodVars = {}; // Independent in this case + + availableVars = retrieveAvailableVariables(prOp, methodVars); + + return "cl" in availableVars; +} \ No newline at end of file diff --git a/src/refactor/forloop/NeededVariables.rsc b/src/refactor/forloop/NeededVariables.rsc index 00dffa9..c39a7fc 100644 --- a/src/refactor/forloop/NeededVariables.rsc +++ b/src/refactor/forloop/NeededVariables.rsc @@ -23,13 +23,6 @@ public set[str] retrieveNeededVariables(ProspectiveOperation prOp) { return neededVariables; } -public bool isLocalVariableDeclarationStatement(str stmt) { - try { - parse(#LocalVariableDeclarationStatement, stmt); - return true; - } catch: return false; -} - // XXX Parsing twice (isLocal... and this method) the stmt // should not be a big deal since it's only a stmt from a prospective operation. // Using this pattern (parsing to check if a stmt is of the type #Something) and then parsing again @@ -39,9 +32,7 @@ private set[str] retrieveNeededVarsFromLocalVariableDeclarationStmt(str stmt) { lvdlStmt = parse(#LocalVariableDeclarationStatement, stmt); - visit(lvdlStmt) { - case (VariableDeclaratorId) ``: neededVariables += unparse(id); - + visit(lvdlStmt) { case ExpressionName expName: { visit(expName) { case Identifier id: neededVariables += unparse(id); @@ -76,11 +67,6 @@ private set[str] retrieveNeededVarsFromStatement(str stmt) { stmt = parse(#Statement, getCorrectStatementAsString(stmt)); visit (stmt) { - case LocalVariableDeclaration lvdl: { - visit(lvdl) { - case (VariableDeclaratorId) ``: neededVariables += unparse(id); - } - } case ExpressionName expName: { visit(expName) { case Identifier id: neededVariables += unparse(id); diff --git a/src/refactor/forloop/NeededVariablesTest.rsc b/src/refactor/forloop/NeededVariablesTest.rsc index b362c86..8998c7d 100644 --- a/src/refactor/forloop/NeededVariablesTest.rsc +++ b/src/refactor/forloop/NeededVariablesTest.rsc @@ -26,33 +26,31 @@ public test bool simpleMethodInvocationWithoutEndingSemiCollon() { "rule" in neededVars; } -public test bool simpleMethodInvocationWithtEndingSemiCollon() { - prOp = prospectiveOperation("rule.hasErrors()", FILTER); +public test bool variableAssignmentWithInitializer() { + prOp = prospectiveOperation("count = rule.getErrors().size();", MAP); neededVars = retrieveNeededVariables(prOp); - return size(neededVars) == 1 && + return size(neededVars) == 2 && + "count" in neededVars && "rule" in neededVars; } -public test bool variableAssignmentWithInitializer() { - prOp = prospectiveOperation("count = rule.getErrors().size();", MAP); +public test bool localVariableDeclarationShouldNotReturnItself() { + prOp = prospectiveOperation("ClassLoader cl = entry.getKey(argNeeded);", MAP); neededVars = retrieveNeededVariables(prOp); - return size(neededVars) == 2 && - "count" in neededVars && - "rule" in neededVars; + return "cl" notin neededVars; } -public test bool localVariableDeclarationShouldReturnItselfWithInitializer() { +public test bool localVariableDeclarationShouldReturnVarsUsedInInitializer() { prOp = prospectiveOperation("ClassLoader cl = entry.getKey(argNeeded);", MAP); neededVars = retrieveNeededVariables(prOp); - return size(neededVars) == 3 && - "cl" in neededVars && - "entry" in neededVars && + return size(neededVars) == 2 && + "entry" in neededVars && "argNeeded" in neededVars; } diff --git a/src/refactor/forloop/ProspectiveOperation.rsc b/src/refactor/forloop/ProspectiveOperation.rsc index 03b6869..4550d50 100644 --- a/src/refactor/forloop/ProspectiveOperation.rsc +++ b/src/refactor/forloop/ProspectiveOperation.rsc @@ -139,4 +139,11 @@ public bool isFilter(ProspectiveOperation prOp) { public bool isReduce(ProspectiveOperation prOp) { return prOp.operation == REDUCE; +} + +public bool isLocalVariableDeclarationStatement(str stmt) { + try { + parse(#LocalVariableDeclarationStatement, stmt); + return true; + } catch: return false; } \ No newline at end of file From 0d8cf605f64fd97683cc63275e3a3744718fcc3b Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 061/154] Correcting typo that was causing test to fail. --- src/refactor/forloop/ProspectiveOperationsTest.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/refactor/forloop/ProspectiveOperationsTest.rsc b/src/refactor/forloop/ProspectiveOperationsTest.rsc index 1506144..cbc26d4 100644 --- a/src/refactor/forloop/ProspectiveOperationsTest.rsc +++ b/src/refactor/forloop/ProspectiveOperationsTest.rsc @@ -50,5 +50,5 @@ public test bool shouldReturnXOnFilterAndMergedForEach() { prospectiveOperations[2].stmt == "!((WebappClassLoader)cl).isStart()" && prospectiveOperations[2].operation == FILTER && prospectiveOperations[3].stmt == "result.add(entry.getValue());" && - prospectiveOperations[3].operation == FOREACH; + prospectiveOperations[3].operation == FOR_EACH; } \ No newline at end of file From 8e5a675259243d0f6749a52dccdb8a1cf87e65f5 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 062/154] More test cases for Available Variables. --- src/refactor/forloop/AvailableVariables.rsc | 5 +++- .../forloop/AvailableVariablesTest.rsc | 24 ++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/refactor/forloop/AvailableVariables.rsc b/src/refactor/forloop/AvailableVariables.rsc index 6b495ea..6004786 100644 --- a/src/refactor/forloop/AvailableVariables.rsc +++ b/src/refactor/forloop/AvailableVariables.rsc @@ -11,12 +11,15 @@ import refactor::forloop::ProspectiveOperation; // variables declared in the Prospective Operation ?? // Right now they are being verified by elimination. public set[str] retrieveAvailableVariables(ProspectiveOperation prOp, set[MethodVar] methodVars) { - availableVars = retrieveLocalVariableDeclarations(prOp); + availableVars = {}; + withinMethod = retrieveNotDeclaredWithinLoopNames(methodVars); withinLoop = retrieveDeclaredWithinLoopNames(methodVars); availableVars += withinMethod; availableVars -= withinLoop; + // Probably redundant somehow. This will catch some withinLoop. + availableVars += retrieveLocalVariableDeclarations(prOp); return availableVars; } diff --git a/src/refactor/forloop/AvailableVariablesTest.rsc b/src/refactor/forloop/AvailableVariablesTest.rsc index a493051..1b87fba 100644 --- a/src/refactor/forloop/AvailableVariablesTest.rsc +++ b/src/refactor/forloop/AvailableVariablesTest.rsc @@ -39,10 +39,32 @@ public test bool varNotWithinLoopShouldBeAvailable() { } public test bool localVariableDeclarationShouldBeAvailableVar() { + prOp = prospectiveOperation("ClassLoader cl = entry.getKey();", MAP); + methodVars = {}; // Independent in this case + + availableVars = retrieveAvailableVariables(prOp, methodVars); + + return size(availableVars) == 1 && + "cl" in availableVars; +} + +public test bool LocalVariableDeclAlongWithVarNotWithinLoopShouldBeAvailableVars() { + prOp = prospectiveOperation("ClassLoader cl = entry.getKey();", MAP); + methodVars = {methodVar(false, "result", "List\", false, false)}; + + availableVars = retrieveAvailableVariables(prOp, methodVars); + + return size(availableVars) == 2 && + "cl" in availableVars && + "result" in availableVars; +} + +public test bool localVariableDeclarationWithArgsInInitializerShouldBeAvailableVar() { prOp = prospectiveOperation("ClassLoader cl = entry.getKey(argNeeded);", MAP); methodVars = {}; // Independent in this case availableVars = retrieveAvailableVariables(prOp, methodVars); - return "cl" in availableVars; + return size(availableVars) == 1 && + "cl" in availableVars; } \ No newline at end of file From 8ea3685d8bf2600bc348827d91fc824ef2c66bd0 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 063/154] Changing module NeededVariables to UsedVariables. - The module was finding the used variables. - In fact NeededVariables = UsedVariables - AvailableVariables. --- src/refactor/forloop/NeededVariablesTest.rsc | 72 ------------------- ...{NeededVariables.rsc => UsedVariables.rsc} | 38 +++++----- src/refactor/forloop/UsedVariablesTest.rsc | 72 +++++++++++++++++++ 3 files changed, 91 insertions(+), 91 deletions(-) delete mode 100644 src/refactor/forloop/NeededVariablesTest.rsc rename src/refactor/forloop/{NeededVariables.rsc => UsedVariables.rsc} (59%) create mode 100644 src/refactor/forloop/UsedVariablesTest.rsc diff --git a/src/refactor/forloop/NeededVariablesTest.rsc b/src/refactor/forloop/NeededVariablesTest.rsc deleted file mode 100644 index 8998c7d..0000000 --- a/src/refactor/forloop/NeededVariablesTest.rsc +++ /dev/null @@ -1,72 +0,0 @@ -module refactor::forloop::NeededVariablesTest - -import refactor::forloop::NeededVariables; -import refactor::forloop::ProspectiveOperation; -import refactor::forloop::OperationType; -import MethodVar; -import Set; -import IO; - -public test bool methodInvocationWithArg() { - prOp = prospectiveOperation("writer.write(thing);", FOR_EACH); - - neededVars = retrieveNeededVariables(prOp); - - return size(neededVars) == 2 && - "writer" in neededVars && - "thing" in neededVars; -} - -public test bool simpleMethodInvocationWithoutEndingSemiCollon() { - prOp = prospectiveOperation("rule.hasErrors()", FILTER); - - neededVars = retrieveNeededVariables(prOp); - - return size(neededVars) == 1 && - "rule" in neededVars; -} - -public test bool variableAssignmentWithInitializer() { - prOp = prospectiveOperation("count = rule.getErrors().size();", MAP); - - neededVars = retrieveNeededVariables(prOp); - - return size(neededVars) == 2 && - "count" in neededVars && - "rule" in neededVars; -} - -public test bool localVariableDeclarationShouldNotReturnItself() { - prOp = prospectiveOperation("ClassLoader cl = entry.getKey(argNeeded);", MAP); - - neededVars = retrieveNeededVariables(prOp); - - return "cl" notin neededVars; -} - -public test bool localVariableDeclarationShouldReturnVarsUsedInInitializer() { - prOp = prospectiveOperation("ClassLoader cl = entry.getKey(argNeeded);", MAP); - - neededVars = retrieveNeededVariables(prOp); - - return size(neededVars) == 2 && - "entry" in neededVars && - "argNeeded" in neededVars; -} - -public test bool expressionIsNotAStatement() { - prOp = prospectiveOperation("!((WebappClassLoader)cl).isStart()", FILTER); - - neededVars = retrieveNeededVariables(prOp); - - return size(neededVars) == 1 && - "cl" in neededVars; -} - -public test bool reduceShouldReturnEmpty() { - prOp = prospectiveOperation("count += rule.getErrors().size();", REDUCE); - - neededVars = retrieveNeededVariables(prOp); - - return size(neededVars) == 0; -} \ No newline at end of file diff --git a/src/refactor/forloop/NeededVariables.rsc b/src/refactor/forloop/UsedVariables.rsc similarity index 59% rename from src/refactor/forloop/NeededVariables.rsc rename to src/refactor/forloop/UsedVariables.rsc index c39a7fc..bf1ff7c 100644 --- a/src/refactor/forloop/NeededVariables.rsc +++ b/src/refactor/forloop/UsedVariables.rsc @@ -1,4 +1,4 @@ -module refactor::forloop::NeededVariables +module refactor::forloop::UsedVariables import IO; import String; @@ -8,73 +8,73 @@ import ParseTree; import MethodVar; import refactor::forloop::ProspectiveOperation; -public set[str] retrieveNeededVariables(ProspectiveOperation prOp) { - set[str] neededVariables = {}; +public set[str] retrieveUsedVariables(ProspectiveOperation prOp) { + set[str] usedVariables = {}; if (isReduce(prOp)) return {}; else if(isFilter(prOp)) - neededVariables += retrieveNeededVarsFromExpression(prOp.stmt); + usedVariables += retrieveUsedVarsFromExpression(prOp.stmt); else if (isLocalVariableDeclarationStatement(prOp.stmt)) - neededVariables += retrieveNeededVarsFromLocalVariableDeclarationStmt(prOp.stmt); + usedVariables += retrieveUsedVarsFromLocalVariableDeclarationStmt(prOp.stmt); else - neededVariables += retrieveNeededVarsFromStatement(prOp.stmt); + usedVariables += retrieveUsedVarsFromStatement(prOp.stmt); - return neededVariables; + return usedVariables; } // XXX Parsing twice (isLocal... and this method) the stmt // should not be a big deal since it's only a stmt from a prospective operation. // Using this pattern (parsing to check if a stmt is of the type #Something) and then parsing again // could refactor in the future to return a Tuple, with the bool and the parsed tree. -private set[str] retrieveNeededVarsFromLocalVariableDeclarationStmt(str stmt) { - set[str] neededVariables = {}; +private set[str] retrieveUsedVarsFromLocalVariableDeclarationStmt(str stmt) { + set[str] usedVariables = {}; lvdlStmt = parse(#LocalVariableDeclarationStatement, stmt); visit(lvdlStmt) { case ExpressionName expName: { visit(expName) { - case Identifier id: neededVariables += unparse(id); + case Identifier id: usedVariables += unparse(id); } } } - return neededVariables; + return usedVariables; } // TODO verify if visit(Tree) works for a more generic traversal // maybe it's possible to traverse only once -private set[str] retrieveNeededVarsFromExpression(str stmt) { - set[str] neededVariables = {}; +private set[str] retrieveUsedVarsFromExpression(str stmt) { + set[str] usedVariables = {}; exp = parse(#Expression, stmt); visit(exp) { case ExpressionName expName: { visit(expName) { - case Identifier id: neededVariables += unparse(id); + case Identifier id: usedVariables += unparse(id); } } } - return neededVariables; + return usedVariables; } -private set[str] retrieveNeededVarsFromStatement(str stmt) { - set[str] neededVariables = {}; +private set[str] retrieveUsedVarsFromStatement(str stmt) { + set[str] usedVariables = {}; stmt = parse(#Statement, getCorrectStatementAsString(stmt)); visit (stmt) { case ExpressionName expName: { visit(expName) { - case Identifier id: neededVariables += unparse(id); + case Identifier id: usedVariables += unparse(id); } } } - return neededVariables; + return usedVariables; } private str getCorrectStatementAsString(str stmt) { diff --git a/src/refactor/forloop/UsedVariablesTest.rsc b/src/refactor/forloop/UsedVariablesTest.rsc new file mode 100644 index 0000000..5f5ac5d --- /dev/null +++ b/src/refactor/forloop/UsedVariablesTest.rsc @@ -0,0 +1,72 @@ +module refactor::forloop::UsedVariablesTest + +import refactor::forloop::UsedVariables; +import refactor::forloop::ProspectiveOperation; +import refactor::forloop::OperationType; +import MethodVar; +import Set; +import IO; + +public test bool methodInvocationWithArg() { + prOp = prospectiveOperation("writer.write(thing);", FOR_EACH); + + usedVars = retrieveUsedVariables(prOp); + + return size(usedVars) == 2 && + "writer" in usedVars && + "thing" in usedVars; +} + +public test bool simpleMethodInvocationWithoutEndingSemiCollon() { + prOp = prospectiveOperation("rule.hasErrors()", FILTER); + + usedVars = retrieveUsedVariables(prOp); + + return size(usedVars) == 1 && + "rule" in usedVars; +} + +public test bool variableAssignmentWithInitializer() { + prOp = prospectiveOperation("count = rule.getErrors().size();", MAP); + + usedVars = retrieveUsedVariables(prOp); + + return size(usedVars) == 2 && + "count" in usedVars && + "rule" in usedVars; +} + +public test bool localVariableDeclarationShouldNotReturnItself() { + prOp = prospectiveOperation("ClassLoader cl = entry.getKey(argUsed);", MAP); + + usedVars = retrieveUsedVariables(prOp); + + return "cl" notin usedVars; +} + +public test bool localVariableDeclarationShouldReturnVarsUsedInInitializer() { + prOp = prospectiveOperation("ClassLoader cl = entry.getKey(argUsed);", MAP); + + usedVars = retrieveUsedVariables(prOp); + + return size(usedVars) == 2 && + "entry" in usedVars && + "argUsed" in usedVars; +} + +public test bool expressionIsNotAStatement() { + prOp = prospectiveOperation("!((WebappClassLoader)cl).isStart()", FILTER); + + usedVars = retrieveUsedVariables(prOp); + + return size(usedVars) == 1 && + "cl" in usedVars; +} + +public test bool reduceShouldReturnEmpty() { + prOp = prospectiveOperation("count += rule.getErrors().size();", REDUCE); + + usedVars = retrieveUsedVariables(prOp); + + return size(usedVars) == 0; +} \ No newline at end of file From a0d2e0e9b290c5ec857321e20dcfbc0c596a15c4 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 064/154] Big refactor but still merging incorrectly. - Creating a ComposableProspectiveOperation -- Allows the neededVars and availableVars to be computed only once. --- Makes easier to merge both. - Changing 'first' to 'curr' and 'second' to 'prev' -- Since we are iterating bottom up, the first and second are not what i meant. --- src/refactor/forloop/ForLoopToFunctional.rsc | 126 +++++++++++-------- 1 file changed, 75 insertions(+), 51 deletions(-) diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/refactor/forloop/ForLoopToFunctional.rsc index c22c6f6..529ff4e 100644 --- a/src/refactor/forloop/ForLoopToFunctional.rsc +++ b/src/refactor/forloop/ForLoopToFunctional.rsc @@ -7,88 +7,112 @@ import lang::java::\syntax::Java18; import ParseTree; import MethodVar; import refactor::forloop::ProspectiveOperation; -import refactor::forloop::NeededVariables; +import refactor::forloop::UsedVariables; import refactor::forloop::AvailableVariables; +import refactor::forloop::OperationType; +public data ComposibleProspectiveOperation = composibleProspectiveOperation(ProspectiveOperation prOp, set[str] neededVars, set[str] availableVars); - -public void refactorEnhancedToFunctional(set[MethodVar] methodVars, EnhancedForStatement forStmt) { +public list[ComposibleProspectiveOperation] refactorEnhancedToFunctional(set[MethodVar] methodVars, EnhancedForStatement forStmt) { prospectiveOperations = retrieveProspectiveOperations(methodVars, forStmt); - println(mergeOperations(prospectiveOperations, methodVars)); + composiblePrOps = createComposibleProspectiveOperationsWithVariableAvailability(prospectiveOperations, methodVars); + + return mergeIntoComposableOperations(composiblePrOps); +} + +private list[ComposibleProspectiveOperation] createComposibleProspectiveOperationsWithVariableAvailability(list[ProspectiveOperation] prOps, set[MethodVar] methodVars) { + composiblePrOps = []; + for (prOp <- prOps) { + availableVars = retrieveAvailableVariables(prOp, methodVars); + neededVars = retrieveUsedVariables(prOp); + neededVars -= availableVars; + + composiblePrOps += composibleProspectiveOperation(prOp, neededVars, availableVars); + } + + return composiblePrOps; } -private list[ProspectiveOperation] mergeOperations(list[ProspectiveOperation] prOps, set[MethodVar] methodVars) { - // we don't want the first element (index 0) - listIndexes = [1 .. size(prOps)]; +private list[ComposibleProspectiveOperation] mergeIntoComposableOperations(list[ComposibleProspectiveOperation] composiblePrOps) { + + // we don't want the curr element (index 0) + listIndexes = [1 .. size(composiblePrOps)]; // iterating bottom-up for (int i <- reverse(listIndexes)) { - curr = prOps[i]; - prev = prOps[i - 1]; - if (!areComposable(curr, prev, methodVars)) { + curr = composiblePrOps[i]; + prev = composiblePrOps[i - 1]; + if (!areComposable(curr, prev)) { if (isMergeable(prev) && isMergeable(curr)) { - opsSize = size(prOps); + opsSize = size(composiblePrOps); - if (isFilter(prev) || isFilter(curr)) { + if (isFilter(prev.prOp) || isFilter(curr.prOp)) { while(opsSize > i) { - ProspectiveOperation last = prOps[opsSize - 1]; - ProspectiveOperation beforeLast = prOps[opsSize - 2]; - merged = mergeOps(beforeLast, last, methodVars); - prOps = slice(prOps, 0, opsSize - 2) + merged; + ComposibleProspectiveOperation last = composiblePrOps[opsSize - 1]; + ComposibleProspectiveOperation beforeLast = composiblePrOps[opsSize - 2]; + + merged = mergeComposiblePrOps(beforeLast, last); + composiblePrOps = slice(composiblePrOps, 0, opsSize - 2) + merged; - opsSize = size(prOps); + opsSize = size(composiblePrOps); } } else { - merged = mergeOps(prev, curr, methodVars); - prOps = slice(prOps, 0, opsSize - 2) + merged; + merged = mergeComposiblePrOps(prev, curr); + composiblePrOps = slice(composiblePrOps, 0, opsSize - 2) + merged; } } } } - return prOps; + return composiblePrOps; } -// TODO needed and available called more than once. good idea to extract it. -public bool areComposable(ProspectiveOperation first, ProspectiveOperation second, set[MethodVar] methodVars) { - firstNeededVars = retrieveNeededVariables(first); - // firsts' needed has to be available from second - secondAvailableVars = retrieveAvailableVars(second, methodVars); - firstNeededInSecondAvailable = isFirstNeededVarsInSecondAvailableVars(firstNeededVars, secondAvailableVars); - return size(firstNeededVars) <= 1 && firstNeededInSecondAvailable; +public bool areComposable(ComposibleProspectiveOperation curr, ComposibleProspectiveOperation prev) { + currNeededInPrevAvailable = isCurrNeededVarsInPrevAvailableVars(curr.neededVars, prev.availableVars); + return size(curr.neededVars) <= 1 && currNeededInPrevAvailable; } -private bool isFirstNeededVarsInSecondAvailableVars(set[str] firstNeededVars, set[str] secondAvailableVars) { - for(firstNeededVar <- firstNeededVars) - if(firstNeededVar notin secondAvailableVars) return false; +public bool isMergeable(ComposibleProspectiveOperation cPrOp) { + operation = cPrOp.prOp.operation; + return operation == FILTER || operation == MAP || operation == FOR_EACH; +} + +private bool isCurrNeededVarsInPrevAvailableVars(set[str] currNeededVars, set[str] prevAvailableVars) { + for(currNeededVar <- currNeededVars) + if(currNeededVar notin prevAvailableVars) return false; return true; } -public ProspectiveOperation mergeOps(ProspectiveOperation first, ProspectiveOperation second, set[MethodVar] methodVars) { - if (isFilter(first)) { - return mergeTwoOpsInAnIfThenStmt(first, second); +public ComposibleProspectiveOperation mergeComposiblePrOps(ComposibleProspectiveOperation curr, ComposibleProspectiveOperation prev) { + if (isFilter(curr.prOp)) { + prOp = mergeTwoOpsInAnIfThenStmt(curr.prOp, prev.prOp); + return mergeComposibleProspectiveOperation(prOp, curr, prev); } else { - list[str] statements = retrieveAllStatements(first) + retrieveAllStatements(second); - - set[str] firstAvailableVars = retrieveAvailableVars(first, methodVars); - set[str] availableVars = firstAvailableVars; - availableVars += retrieveAvailableVars(second, methodVars); - - set[str] neededVars = retrieveNeededVariables(second); - neededVars -= firstAvailableVars; - neededVars += retrieveNeededVariables(first); - - neededVars -= retrieveNotDeclaredWithinLoopNames(methodVars); - + list[str] statements = retrieveAllStatements(curr.prOp) + retrieveAllStatements(prev.prOp); Block statementsAsOneBlock = transformStatementsInBlock(statements); - - return prospectiveOperation(unparse(statementsAsOneBlock), second.operation); + prOp = prospectiveOperation(unparse(statementsAsOneBlock), prev.prOp.operation); + return mergeComposibleProspectiveOperation(prOp, curr, prev); } } -private ProspectiveOperation mergeTwoOpsInAnIfThenStmt(ProspectiveOperation first, ProspectiveOperation second) { - Expression exp = parse(#Expression, first.stmt); - Statement thenStmt = parse(#Statement, second.stmt); +private ProspectiveOperation mergeTwoOpsInAnIfThenStmt(ProspectiveOperation curr, ProspectiveOperation prev) { + Expression exp = parse(#Expression, curr.stmt); + Statement thenStmt = parse(#Statement, prev.stmt); ifThenStmt = [IfThenStatement] "if () "; - return prospectiveOperation(unparse(ifThenStmt), second.operation); + return prospectiveOperation(unparse(ifThenStmt), prev.operation); +} + +private ComposibleProspectiveOperation mergeComposibleProspectiveOperation(ProspectiveOperation prOp, ComposibleProspectiveOperation curr, ComposibleProspectiveOperation prev) { + mergedAvailableVars = mergeAvailableVars(curr.availableVars, prev.availableVars); + mergedNeededVars = mergeNeededVars(curr.neededVars, prev.neededVars, mergedAvailableVars); + return composibleProspectiveOperation(prOp, mergedNeededVars, mergedAvailableVars); +} + +private set[str] mergeAvailableVars(set[str] currAvailableVars, prevAvailableVars) { + return currAvailableVars + prevAvailableVars; +} + +private set[str] mergeNeededVars(set[str] currNeededVars, set[str] prevNeededVars, set[str] mergedAvailableVars) { + neededVars = currNeededVars + prevNeededVars; + return neededVars - mergedAvailableVars; } private list[str] retrieveAllStatements(ProspectiveOperation prOp) { From e4f3f9caef6a08f075f05bb686f2afdbe211fcfe Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 065/154] 'Composable' not composible. --- src/refactor/forloop/ForLoopToFunctional.rsc | 78 +++++++++++--------- 1 file changed, 45 insertions(+), 33 deletions(-) diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/refactor/forloop/ForLoopToFunctional.rsc index 529ff4e..495a45c 100644 --- a/src/refactor/forloop/ForLoopToFunctional.rsc +++ b/src/refactor/forloop/ForLoopToFunctional.rsc @@ -11,66 +11,74 @@ import refactor::forloop::UsedVariables; import refactor::forloop::AvailableVariables; import refactor::forloop::OperationType; -public data ComposibleProspectiveOperation = composibleProspectiveOperation(ProspectiveOperation prOp, set[str] neededVars, set[str] availableVars); +public data ComposableProspectiveOperation = composableProspectiveOperation(ProspectiveOperation prOp, set[str] neededVars, set[str] availableVars); -public list[ComposibleProspectiveOperation] refactorEnhancedToFunctional(set[MethodVar] methodVars, EnhancedForStatement forStmt) { +private set[MethodVar] methodAvailableVars; + +public list[ComposableProspectiveOperation] refactorEnhancedToFunctional(set[MethodVar] methodVars, EnhancedForStatement forStmt) { prospectiveOperations = retrieveProspectiveOperations(methodVars, forStmt); - composiblePrOps = createComposibleProspectiveOperationsWithVariableAvailability(prospectiveOperations, methodVars); + composablePrOps = createComposableProspectiveOperationsWithVariableAvailability(prospectiveOperations, methodVars); + + methodAvailableVars = methodVars; - return mergeIntoComposableOperations(composiblePrOps); + return mergeIntoComposableOperations(composablePrOps); } -private list[ComposibleProspectiveOperation] createComposibleProspectiveOperationsWithVariableAvailability(list[ProspectiveOperation] prOps, set[MethodVar] methodVars) { - composiblePrOps = []; +private list[ComposableProspectiveOperation] createComposableProspectiveOperationsWithVariableAvailability(list[ProspectiveOperation] prOps, set[MethodVar] methodVars) { + composablePrOps = []; for (prOp <- prOps) { availableVars = retrieveAvailableVariables(prOp, methodVars); - neededVars = retrieveUsedVariables(prOp); - neededVars -= availableVars; - - composiblePrOps += composibleProspectiveOperation(prOp, neededVars, availableVars); + neededVars = retrieveNeededVars(prOp, availableVars); + composablePrOps += composableProspectiveOperation(prOp, neededVars, availableVars); } - return composiblePrOps; + return composablePrOps; +} + +private set[str] retrieveNeededVars(ProspectiveOperation prOp, set[str] availableVars) { + neededVars = retrieveUsedVariables(prOp); + neededVars -= availableVars; + return neededVars; } -private list[ComposibleProspectiveOperation] mergeIntoComposableOperations(list[ComposibleProspectiveOperation] composiblePrOps) { +private list[ComposableProspectiveOperation] mergeIntoComposableOperations(list[ComposableProspectiveOperation] composablePrOps) { // we don't want the curr element (index 0) - listIndexes = [1 .. size(composiblePrOps)]; + listIndexes = [1 .. size(composablePrOps)]; // iterating bottom-up for (int i <- reverse(listIndexes)) { - curr = composiblePrOps[i]; - prev = composiblePrOps[i - 1]; + curr = composablePrOps[i]; + prev = composablePrOps[i - 1]; if (!areComposable(curr, prev)) { if (isMergeable(prev) && isMergeable(curr)) { - opsSize = size(composiblePrOps); + opsSize = size(composablePrOps); if (isFilter(prev.prOp) || isFilter(curr.prOp)) { while(opsSize > i) { - ComposibleProspectiveOperation last = composiblePrOps[opsSize - 1]; - ComposibleProspectiveOperation beforeLast = composiblePrOps[opsSize - 2]; + ComposableProspectiveOperation last = composablePrOps[opsSize - 1]; + ComposableProspectiveOperation beforeLast = composablePrOps[opsSize - 2]; - merged = mergeComposiblePrOps(beforeLast, last); - composiblePrOps = slice(composiblePrOps, 0, opsSize - 2) + merged; + merged = mergeComposablePrOps(beforeLast, last); + composablePrOps = slice(composablePrOps, 0, opsSize - 2) + merged; - opsSize = size(composiblePrOps); + opsSize = size(composablePrOps); } } else { - merged = mergeComposiblePrOps(prev, curr); - composiblePrOps = slice(composiblePrOps, 0, opsSize - 2) + merged; + merged = mergeComposablePrOps(prev, curr); + composablePrOps = slice(composablePrOps, 0, opsSize - 2) + merged; } } } } - return composiblePrOps; + return composablePrOps; } -public bool areComposable(ComposibleProspectiveOperation curr, ComposibleProspectiveOperation prev) { +public bool areComposable(ComposableProspectiveOperation curr, ComposableProspectiveOperation prev) { currNeededInPrevAvailable = isCurrNeededVarsInPrevAvailableVars(curr.neededVars, prev.availableVars); return size(curr.neededVars) <= 1 && currNeededInPrevAvailable; } -public bool isMergeable(ComposibleProspectiveOperation cPrOp) { +public bool isMergeable(ComposableProspectiveOperation cPrOp) { operation = cPrOp.prOp.operation; return operation == FILTER || operation == MAP || operation == FOR_EACH; } @@ -81,15 +89,17 @@ private bool isCurrNeededVarsInPrevAvailableVars(set[str] currNeededVars, set[st return true; } -public ComposibleProspectiveOperation mergeComposiblePrOps(ComposibleProspectiveOperation curr, ComposibleProspectiveOperation prev) { +public ComposableProspectiveOperation mergeComposablePrOps(ComposableProspectiveOperation curr, ComposableProspectiveOperation prev) { if (isFilter(curr.prOp)) { prOp = mergeTwoOpsInAnIfThenStmt(curr.prOp, prev.prOp); - return mergeComposibleProspectiveOperation(prOp, curr, prev); + availableVars = retrieveAvailableVariables(prOp, methodAvailableVars); + neededVars = retrieveNeededVars(prOp, availableVars); + return composableProspectiveOperation(prOp, neededVars, availableVars); } else { list[str] statements = retrieveAllStatements(curr.prOp) + retrieveAllStatements(prev.prOp); Block statementsAsOneBlock = transformStatementsInBlock(statements); prOp = prospectiveOperation(unparse(statementsAsOneBlock), prev.prOp.operation); - return mergeComposibleProspectiveOperation(prOp, curr, prev); + return mergeComposableProspectiveOperation(prOp, curr, prev); } } @@ -100,10 +110,10 @@ private ProspectiveOperation mergeTwoOpsInAnIfThenStmt(ProspectiveOperation curr return prospectiveOperation(unparse(ifThenStmt), prev.operation); } -private ComposibleProspectiveOperation mergeComposibleProspectiveOperation(ProspectiveOperation prOp, ComposibleProspectiveOperation curr, ComposibleProspectiveOperation prev) { +private ComposableProspectiveOperation mergeComposableProspectiveOperation(ProspectiveOperation prOp, ComposableProspectiveOperation curr, ComposableProspectiveOperation prev) { mergedAvailableVars = mergeAvailableVars(curr.availableVars, prev.availableVars); mergedNeededVars = mergeNeededVars(curr.neededVars, prev.neededVars, mergedAvailableVars); - return composibleProspectiveOperation(prOp, mergedNeededVars, mergedAvailableVars); + return composableProspectiveOperation(prOp, mergedNeededVars, mergedAvailableVars); } private set[str] mergeAvailableVars(set[str] currAvailableVars, prevAvailableVars) { @@ -111,8 +121,10 @@ private set[str] mergeAvailableVars(set[str] currAvailableVars, prevAvailableVar } private set[str] mergeNeededVars(set[str] currNeededVars, set[str] prevNeededVars, set[str] mergedAvailableVars) { - neededVars = currNeededVars + prevNeededVars; - return neededVars - mergedAvailableVars; + neededVars = currNeededVars; + neededVars -= mergedAvailableVars; + neededVars += prevNeededVars; + return neededVars ; } private list[str] retrieveAllStatements(ProspectiveOperation prOp) { From fb0b15118e7585967c8a1c7412acbfb856beea51 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 066/154] Another case (IfThenStatement) for UsedVariables. - If Then Else will have to be added aswell. --- src/refactor/forloop/UsedVariables.rsc | 54 ++++++++++++++++------ src/refactor/forloop/UsedVariablesTest.rsc | 11 +++++ 2 files changed, 52 insertions(+), 13 deletions(-) diff --git a/src/refactor/forloop/UsedVariables.rsc b/src/refactor/forloop/UsedVariables.rsc index bf1ff7c..14b05f5 100644 --- a/src/refactor/forloop/UsedVariables.rsc +++ b/src/refactor/forloop/UsedVariables.rsc @@ -14,7 +14,7 @@ public set[str] retrieveUsedVariables(ProspectiveOperation prOp) { if (isReduce(prOp)) return {}; else if(isFilter(prOp)) - usedVariables += retrieveUsedVarsFromExpression(prOp.stmt); + usedVariables += retrieveUsedVarsFromFilter(prOp.stmt); else if (isLocalVariableDeclarationStatement(prOp.stmt)) usedVariables += retrieveUsedVarsFromLocalVariableDeclarationStmt(prOp.stmt); else @@ -23,31 +23,39 @@ public set[str] retrieveUsedVariables(ProspectiveOperation prOp) { return usedVariables; } -// XXX Parsing twice (isLocal... and this method) the stmt -// should not be a big deal since it's only a stmt from a prospective operation. -// Using this pattern (parsing to check if a stmt is of the type #Something) and then parsing again -// could refactor in the future to return a Tuple, with the bool and the parsed tree. -private set[str] retrieveUsedVarsFromLocalVariableDeclarationStmt(str stmt) { + +private set[str] retrieveUsedVarsFromFilter(str stmt) { + if(isIfThenStatement(stmt)) + return retrieveUsedVarsFromIfThenStmt(stmt); + else + return retrieveUsedVarsFromExpression(stmt); +} + +public bool isIfThenStatement(str stmt) { + try { + parse(#IfThenStatement, stmt); + return true; + } catch: return false; +} + +// XXX pretty redundant lookups for 'ExpressionName' around this module +private set[str] retrieveUsedVarsFromIfThenStmt(str stmt) { set[str] usedVariables = {}; + ifThenStmt = parse(#IfThenStatement, stmt); - lvdlStmt = parse(#LocalVariableDeclarationStatement, stmt); - - visit(lvdlStmt) { + visit(ifThenStmt) { case ExpressionName expName: { visit(expName) { case Identifier id: usedVariables += unparse(id); } - } + } } return usedVariables; } -// TODO verify if visit(Tree) works for a more generic traversal -// maybe it's possible to traverse only once private set[str] retrieveUsedVarsFromExpression(str stmt) { set[str] usedVariables = {}; - exp = parse(#Expression, stmt); visit(exp) { @@ -61,6 +69,26 @@ private set[str] retrieveUsedVarsFromExpression(str stmt) { return usedVariables; } +// XXX Parsing twice (isLocal... and this method) the stmt +// should not be a big deal since it's only a stmt from a prospective operation. +// Using this pattern (parsing to check if a stmt is of the type #Something) and then parsing again +// could refactor in the future to return a Tuple, with the bool and the parsed tree. +private set[str] retrieveUsedVarsFromLocalVariableDeclarationStmt(str stmt) { + set[str] usedVariables = {}; + + lvdlStmt = parse(#LocalVariableDeclarationStatement, stmt); + + visit(lvdlStmt) { + case ExpressionName expName: { + visit(expName) { + case Identifier id: usedVariables += unparse(id); + } + } + } + + return usedVariables; +} + private set[str] retrieveUsedVarsFromStatement(str stmt) { set[str] usedVariables = {}; diff --git a/src/refactor/forloop/UsedVariablesTest.rsc b/src/refactor/forloop/UsedVariablesTest.rsc index 5f5ac5d..44b9330 100644 --- a/src/refactor/forloop/UsedVariablesTest.rsc +++ b/src/refactor/forloop/UsedVariablesTest.rsc @@ -63,6 +63,17 @@ public test bool expressionIsNotAStatement() { "cl" in usedVars; } +public test bool ifThenStatement() { + prOp = prospectiveOperation("if (!((WebappClassLoader)cl).isStart()) result.add(entry.getValue());", FILTER); + + usedVars = retrieveUsedVariables(prOp); + + return size(usedVars) == 3 && + "cl" in usedVars && + "result" in usedVars && + "entry" in usedVars; +} + public test bool reduceShouldReturnEmpty() { prOp = prospectiveOperation("count += rule.getErrors().size();", REDUCE); From 18cbec80fe5bd50f1db9557665d23c81c6dbd0ea Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 067/154] Standarizing passing arguments prev before curr. --- src/refactor/forloop/ForLoopToFunctional.rsc | 27 ++++++++++---------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/refactor/forloop/ForLoopToFunctional.rsc index 495a45c..4ed066f 100644 --- a/src/refactor/forloop/ForLoopToFunctional.rsc +++ b/src/refactor/forloop/ForLoopToFunctional.rsc @@ -49,7 +49,7 @@ private list[ComposableProspectiveOperation] mergeIntoComposableOperations(list[ for (int i <- reverse(listIndexes)) { curr = composablePrOps[i]; prev = composablePrOps[i - 1]; - if (!areComposable(curr, prev)) { + if (!areComposable(prev, curr)) { if (isMergeable(prev) && isMergeable(curr)) { opsSize = size(composablePrOps); @@ -73,7 +73,7 @@ private list[ComposableProspectiveOperation] mergeIntoComposableOperations(list[ return composablePrOps; } -public bool areComposable(ComposableProspectiveOperation curr, ComposableProspectiveOperation prev) { +public bool areComposable(ComposableProspectiveOperation prev, ComposableProspectiveOperation curr) { currNeededInPrevAvailable = isCurrNeededVarsInPrevAvailableVars(curr.neededVars, prev.availableVars); return size(curr.neededVars) <= 1 && currNeededInPrevAvailable; } @@ -89,28 +89,29 @@ private bool isCurrNeededVarsInPrevAvailableVars(set[str] currNeededVars, set[st return true; } -public ComposableProspectiveOperation mergeComposablePrOps(ComposableProspectiveOperation curr, ComposableProspectiveOperation prev) { - if (isFilter(curr.prOp)) { - prOp = mergeTwoOpsInAnIfThenStmt(curr.prOp, prev.prOp); +public ComposableProspectiveOperation mergeComposablePrOps(ComposableProspectiveOperation prev, ComposableProspectiveOperation curr) { + if (isFilter(prev.prOp)) { + prOp = mergeTwoOpsInAnIfThenStmt(prev.prOp, curr.prOp); availableVars = retrieveAvailableVariables(prOp, methodAvailableVars); neededVars = retrieveNeededVars(prOp, availableVars); return composableProspectiveOperation(prOp, neededVars, availableVars); + } else { - list[str] statements = retrieveAllStatements(curr.prOp) + retrieveAllStatements(prev.prOp); + list[str] statements = retrieveAllStatements(prev.prOp) + retrieveAllStatements(curr.prOp); Block statementsAsOneBlock = transformStatementsInBlock(statements); - prOp = prospectiveOperation(unparse(statementsAsOneBlock), prev.prOp.operation); - return mergeComposableProspectiveOperation(prOp, curr, prev); + prOp = prospectiveOperation(unparse(statementsAsOneBlock), curr.prOp.operation); + return mergeComposableProspectiveOperation(prOp, prev, curr); } } -private ProspectiveOperation mergeTwoOpsInAnIfThenStmt(ProspectiveOperation curr, ProspectiveOperation prev) { - Expression exp = parse(#Expression, curr.stmt); - Statement thenStmt = parse(#Statement, prev.stmt); +private ProspectiveOperation mergeTwoOpsInAnIfThenStmt(ProspectiveOperation prev, ProspectiveOperation curr) { + Expression exp = parse(#Expression, prev.stmt); + Statement thenStmt = parse(#Statement, curr.stmt); ifThenStmt = [IfThenStatement] "if () "; - return prospectiveOperation(unparse(ifThenStmt), prev.operation); + return prospectiveOperation(unparse(ifThenStmt), curr.operation); } -private ComposableProspectiveOperation mergeComposableProspectiveOperation(ProspectiveOperation prOp, ComposableProspectiveOperation curr, ComposableProspectiveOperation prev) { +private ComposableProspectiveOperation mergeComposableProspectiveOperation(ProspectiveOperation prOp, ComposableProspectiveOperation prev, ComposableProspectiveOperation curr) { mergedAvailableVars = mergeAvailableVars(curr.availableVars, prev.availableVars); mergedNeededVars = mergeNeededVars(curr.neededVars, prev.neededVars, mergedAvailableVars); return composableProspectiveOperation(prOp, mergedNeededVars, mergedAvailableVars); From f7f1568ea45aa5f4dea576477d23e2436e6044bd Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 068/154] Getting right if two operations can be chained or not. - According to the paper, two operations O and O' can be chained if: -- size of neededVars of O' is 1 or less -- neededVars of O' is contained in availability set of O --- availability set is the union of neededVars with availableVars --- src/refactor/forloop/ForLoopToFunctional.rsc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/refactor/forloop/ForLoopToFunctional.rsc index 4ed066f..883f7d3 100644 --- a/src/refactor/forloop/ForLoopToFunctional.rsc +++ b/src/refactor/forloop/ForLoopToFunctional.rsc @@ -49,7 +49,7 @@ private list[ComposableProspectiveOperation] mergeIntoComposableOperations(list[ for (int i <- reverse(listIndexes)) { curr = composablePrOps[i]; prev = composablePrOps[i - 1]; - if (!areComposable(prev, curr)) { + if (!canBeChained(prev, curr)) { if (isMergeable(prev) && isMergeable(curr)) { opsSize = size(composablePrOps); @@ -73,9 +73,9 @@ private list[ComposableProspectiveOperation] mergeIntoComposableOperations(list[ return composablePrOps; } -public bool areComposable(ComposableProspectiveOperation prev, ComposableProspectiveOperation curr) { - currNeededInPrevAvailable = isCurrNeededVarsInPrevAvailableVars(curr.neededVars, prev.availableVars); - return size(curr.neededVars) <= 1 && currNeededInPrevAvailable; +public bool canBeChained(ComposableProspectiveOperation prev, ComposableProspectiveOperation curr) { + currNeededVarsInPrevAvailabilitySet = isCurrNeededVarsInPrevAvailabilitySet(curr.neededVars, prev); + return size(curr.neededVars) <= 1 && currNeededVarsInPrevAvailabilitySet; } public bool isMergeable(ComposableProspectiveOperation cPrOp) { @@ -83,9 +83,10 @@ public bool isMergeable(ComposableProspectiveOperation cPrOp) { return operation == FILTER || operation == MAP || operation == FOR_EACH; } -private bool isCurrNeededVarsInPrevAvailableVars(set[str] currNeededVars, set[str] prevAvailableVars) { +private bool isCurrNeededVarsInPrevAvailabilitySet(set[str] currNeededVars, ComposableProspectiveOperation prev) { + prevAvailabilitySet = prev.availableVars + prev.neededVars; for(currNeededVar <- currNeededVars) - if(currNeededVar notin prevAvailableVars) return false; + if(currNeededVar notin prevAvailabilitySet) return false; return true; } From e87cd1e94ccfd421e8daebd3212c0343d23eedfd Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 069/154] Identifying operation as 'anyMatch' --- src/refactor/forloop/ProspectiveOperation.rsc | 30 ++++++++----- ...sTest.rsc => ProspectiveOperationTest.rsc} | 45 ++++++++++++++----- ... => ProspectiveOperationTestResources.rsc} | 2 +- 3 files changed, 55 insertions(+), 22 deletions(-) rename src/refactor/forloop/{ProspectiveOperationsTest.rsc => ProspectiveOperationTest.rsc} (53%) rename src/refactor/forloop/{ProspectiveOperationsTestResources.rsc => ProspectiveOperationTestResources.rsc} (97%) diff --git a/src/refactor/forloop/ProspectiveOperation.rsc b/src/refactor/forloop/ProspectiveOperation.rsc index 4550d50..bc4832b 100644 --- a/src/refactor/forloop/ProspectiveOperation.rsc +++ b/src/refactor/forloop/ProspectiveOperation.rsc @@ -7,6 +7,7 @@ import lang::java::\syntax::Java18; import ParseTree; import MethodVar; import refactor::forloop::OperationType; +import ParseTreeVisualization; public data ProspectiveOperation = prospectiveOperation(str stmt, str operation); @@ -54,8 +55,8 @@ private list[ProspectiveOperation] retrieveProspectiveOperationsFromBlock(Block case BlockStatement blockStatement: { top-down-break visit(blockStatement) { case (IfThenStatement) `if ( ) `: { - prOps += prospectiveOperation(unparse(exp), FILTER); - prOps += retrieveProspectiveOperationsFromStatement(thenStmt); + ifThenStmt = [IfThenStatement] "if () "; + prOps += retrieveProspectiveOperationsFromIfThenStatement(ifThenStmt); } case (IfThenElseStatement) `if ( ) else `: { //retrieveProspectiveOperationsFromStatement(thenStmt); @@ -77,18 +78,25 @@ private list[ProspectiveOperation] retrieveProspectiveOperationsFromBlock(Block private list[ProspectiveOperation] retrieveProspectiveOperationsFromIfThenStatement(IfThenStatement ifStmt) { list[ProspectiveOperation] prOps = []; + foundReturn = false; top-down-break visit (ifStmt) { case (IfThenStatement) `if ( ) `: { top-down-break visit (thenStmt) { - case (ReturnStatement) `return ;`: { - if ("" == true) - prOps += prospectiveOperation(unparse(ifStmt), ANY_MATCH); - else if ("" == false) - prOps += prospectiveOperation(unparse(ifStmt), NONE_MATCH); - } - default: { - prOps += prospectiveOperation(unparse(exp), FILTER); - prOps += retrieveProspectiveOperationsFromStatement(thenStmt); + case Statement stmt: { + visit(stmt) { + case (ReturnStatement) `return ;`: { + foundReturn = true; + if ("" == "true") + prOps += prospectiveOperation(unparse(exp), ANY_MATCH); + else if ("" == "false") + prOps += prospectiveOperation(unparse(exp), NONE_MATCH); + } + } + + if (!foundReturn) { + prOps += prospectiveOperation(unparse(exp), FILTER); + prOps += retrieveProspectiveOperationsFromStatement(thenStmt); + } } } } diff --git a/src/refactor/forloop/ProspectiveOperationsTest.rsc b/src/refactor/forloop/ProspectiveOperationTest.rsc similarity index 53% rename from src/refactor/forloop/ProspectiveOperationsTest.rsc rename to src/refactor/forloop/ProspectiveOperationTest.rsc index cbc26d4..c6ac1ba 100644 --- a/src/refactor/forloop/ProspectiveOperationsTest.rsc +++ b/src/refactor/forloop/ProspectiveOperationTest.rsc @@ -1,7 +1,7 @@ -module refactor::forloop::ProspectiveOperationsTest +module refactor::forloop::ProspectiveOperationTest import refactor::forloop::ProspectiveOperation; -import refactor::forloop::ProspectiveOperationsTestResources; +import refactor::forloop::ProspectiveOperationTestResources; import refactor::forloop::OperationType; import MethodVar; import lang::java::\syntax::Java18; @@ -18,7 +18,7 @@ public test bool shouldReturnAForEachOnSimpleShortExample() { prospectiveOperations[0].operation == FOR_EACH; } -public test bool shouldReturnCorrectlyOnFilterMapReduceExample() { +public test bool shouldHandleReduce() { tuple [set[MethodVar] vars, EnhancedForStatement loop] filterMapReduce = filterMapReduce(); prospectiveOperations = retrieveProspectiveOperations(filterMapReduce.vars, filterMapReduce.loop); @@ -30,14 +30,39 @@ public test bool shouldReturnCorrectlyOnFilterMapReduceExample() { prospectiveOperations[1].operation == REDUCE; } -//public test bool shouldReturnXOnContinueAndReturnEnhancedLoop() { -// tuple [set[MethodVar] vars, EnhancedForStatement loop] continueAndReturn = continueAndReturn(); -// prospectiveOperations = retrievePotentialOperations(continueAndReturn.vars, continueAndReturn.loop); -// println(prospectiveOperations); -// return false; -//} +public test bool shouldHandleAnyMatchAndIfWithContinue() { + tuple [set[MethodVar] vars, EnhancedForStatement loop] continueAndReturn = continueAndReturn(); + + prospectiveOperations = retrieveProspectiveOperations(continueAndReturn.vars, continueAndReturn.loop); + println(prospectiveOperations); + + return size(prospectiveOperations) == 2 && + prospectiveOperations[0].stmt == "e.getGrammarName() != null" && + prospectiveOperations[0].operation == FILTER && + prospectiveOperations[1].stmt == "e.getGrammarName().equals(grammarName)" && + prospectiveOperations[1].operation == ANY_MATCH; +} + +public test bool shouldHandleIfWithContinue() { + tuple [set[MethodVar] vars, EnhancedForStatement loop] continueAndReturn = continueAndReturn(); + + prospectiveOperations = retrieveProspectiveOperations(continueAndReturn.vars, continueAndReturn.loop); + println(prospectiveOperations); + + return prospectiveOperations[0].stmt == "e.getGrammarName() != null" && + prospectiveOperations[0].operation == FILTER; +} + +public test bool shouldHandleAnyMatch() { + tuple [set[MethodVar] vars, EnhancedForStatement loop] continueAndReturn = continueAndReturn(); + + prospectiveOperations = retrieveProspectiveOperations(continueAndReturn.vars, continueAndReturn.loop); + + return prospectiveOperations[1].stmt == "e.getGrammarName().equals(grammarName)" && + prospectiveOperations[1].operation == ANY_MATCH; +} -public test bool shouldReturnXOnFilterAndMergedForEach() { +public test bool shouldBreakAndChooseCorrectOperationsOnMultipleStatements() { tuple [set[MethodVar] vars, EnhancedForStatement loop] filterAndMergedForEach = filterAndMergedForEach(); prospectiveOperations = retrieveProspectiveOperations(filterAndMergedForEach.vars, filterAndMergedForEach.loop); diff --git a/src/refactor/forloop/ProspectiveOperationsTestResources.rsc b/src/refactor/forloop/ProspectiveOperationTestResources.rsc similarity index 97% rename from src/refactor/forloop/ProspectiveOperationsTestResources.rsc rename to src/refactor/forloop/ProspectiveOperationTestResources.rsc index 3d9cfde..872eada 100644 --- a/src/refactor/forloop/ProspectiveOperationsTestResources.rsc +++ b/src/refactor/forloop/ProspectiveOperationTestResources.rsc @@ -1,4 +1,4 @@ -module refactor::forloop::ProspectiveOperationsTestResources +module refactor::forloop::ProspectiveOperationTestResources import IO; import lang::java::\syntax::Java18; From e4abf1b7366fd7928bc2d11e33f0064d54bcd6bf Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 070/154] Minor clarity changes. --- src/ForLoop.rsc | 6 +++--- src/refactor/forloop/ForLoopToFunctional.rsc | 8 +++----- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/ForLoop.rsc b/src/ForLoop.rsc index bb72f1f..f78608a 100644 --- a/src/ForLoop.rsc +++ b/src/ForLoop.rsc @@ -24,7 +24,6 @@ public void findForLoops(list[loc] locs, set[str] checkedExceptions) { } private void lookForForStatements(CompilationUnit unit) { - iteratedVariable = ""; visit(unit) { case MethodDeclaration methodDeclaration: lookForEnhancedForStatementsInMethod(methodDeclaration); @@ -72,8 +71,9 @@ private bool loopBodyPassConditions(Statement stmt) { case (BreakStatement) `break ;`: return false; case (ReturnStatement) `return ;`: returnCount += 1; - - case (ContinueStatement) `continue ;`: return false; + + // labeled continue. + case (ContinueStatement) `continue ;`: return false; } if (returnCount > 1) return false; diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/refactor/forloop/ForLoopToFunctional.rsc index 883f7d3..3baf703 100644 --- a/src/refactor/forloop/ForLoopToFunctional.rsc +++ b/src/refactor/forloop/ForLoopToFunctional.rsc @@ -15,7 +15,7 @@ public data ComposableProspectiveOperation = composableProspectiveOperation(Pros private set[MethodVar] methodAvailableVars; -public list[ComposableProspectiveOperation] refactorEnhancedToFunctional(set[MethodVar] methodVars, EnhancedForStatement forStmt) { +public list[ComposableProspectiveOperation] refactorEnhancedToFunctional(set[MethodVar] methodVars, EnhancedForStatement forStmt) { prospectiveOperations = retrieveProspectiveOperations(methodVars, forStmt); composablePrOps = createComposableProspectiveOperationsWithVariableAvailability(prospectiveOperations, methodVars); @@ -42,8 +42,7 @@ private set[str] retrieveNeededVars(ProspectiveOperation prOp, set[str] availabl } private list[ComposableProspectiveOperation] mergeIntoComposableOperations(list[ComposableProspectiveOperation] composablePrOps) { - - // we don't want the curr element (index 0) + // exclude first, since we iterate index and index-1 listIndexes = [1 .. size(composablePrOps)]; // iterating bottom-up for (int i <- reverse(listIndexes)) { @@ -156,7 +155,6 @@ private list[str] retrieveAllStatementsFromBlock(str blockStr) { return blockStatements; } -// XXX probably not this private list[str] retrieveAllExpressionStatementsFromStatement(str statement) { list[str] stmts = []; Statement stmt = parse(#Statement, statement); @@ -164,7 +162,7 @@ private list[str] retrieveAllExpressionStatementsFromStatement(str statement) { case ExpressionStatement expStmt: stmts += unparse(expStmt); case (IfThenStatement) `if () `: - stmts += "if (" + unparse(exp) + ")"; + stmts += "if ()"; } return stmts; } From f689db7412bfa8355693bbbbbe898ab8bcb82b95 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 071/154] Commenting test cases with 'continue' operations. - They need to be refactored. And I'm not entirely sure right now about the process. --- .../forloop/ProspectiveOperationTest.rsc | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/refactor/forloop/ProspectiveOperationTest.rsc b/src/refactor/forloop/ProspectiveOperationTest.rsc index c6ac1ba..a2024b2 100644 --- a/src/refactor/forloop/ProspectiveOperationTest.rsc +++ b/src/refactor/forloop/ProspectiveOperationTest.rsc @@ -30,28 +30,28 @@ public test bool shouldHandleReduce() { prospectiveOperations[1].operation == REDUCE; } -public test bool shouldHandleAnyMatchAndIfWithContinue() { - tuple [set[MethodVar] vars, EnhancedForStatement loop] continueAndReturn = continueAndReturn(); - - prospectiveOperations = retrieveProspectiveOperations(continueAndReturn.vars, continueAndReturn.loop); - println(prospectiveOperations); - - return size(prospectiveOperations) == 2 && - prospectiveOperations[0].stmt == "e.getGrammarName() != null" && - prospectiveOperations[0].operation == FILTER && - prospectiveOperations[1].stmt == "e.getGrammarName().equals(grammarName)" && - prospectiveOperations[1].operation == ANY_MATCH; -} - -public test bool shouldHandleIfWithContinue() { - tuple [set[MethodVar] vars, EnhancedForStatement loop] continueAndReturn = continueAndReturn(); - - prospectiveOperations = retrieveProspectiveOperations(continueAndReturn.vars, continueAndReturn.loop); - println(prospectiveOperations); - - return prospectiveOperations[0].stmt == "e.getGrammarName() != null" && - prospectiveOperations[0].operation == FILTER; -} +//public test bool shouldHandleAnyMatchAndIfWithContinue() { +// tuple [set[MethodVar] vars, EnhancedForStatement loop] continueAndReturn = continueAndReturn(); +// +// prospectiveOperations = retrieveProspectiveOperations(continueAndReturn.vars, continueAndReturn.loop); +// println(prospectiveOperations); +// +// return size(prospectiveOperations) == 2 && +// prospectiveOperations[0].stmt == "e.getGrammarName() != null" && +// prospectiveOperations[0].operation == FILTER && +// prospectiveOperations[1].stmt == "e.getGrammarName().equals(grammarName)" && +// prospectiveOperations[1].operation == ANY_MATCH; +//} +// +//public test bool shouldHandleIfWithContinue() { +// tuple [set[MethodVar] vars, EnhancedForStatement loop] continueAndReturn = continueAndReturn(); +// +// prospectiveOperations = retrieveProspectiveOperations(continueAndReturn.vars, continueAndReturn.loop); +// println(prospectiveOperations); +// +// return prospectiveOperations[0].stmt == "e.getGrammarName() != null" && +// prospectiveOperations[0].operation == FILTER; +//} public test bool shouldHandleAnyMatch() { tuple [set[MethodVar] vars, EnhancedForStatement loop] continueAndReturn = continueAndReturn(); From 7cd806a5cb941c420625bb1de67ac423b9146fbf Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 072/154] More clarity changes. --- src/refactor/forloop/ForLoopToFunctional.rsc | 42 +++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/refactor/forloop/ForLoopToFunctional.rsc index 3baf703..8d2b5b7 100644 --- a/src/refactor/forloop/ForLoopToFunctional.rsc +++ b/src/refactor/forloop/ForLoopToFunctional.rsc @@ -72,12 +72,12 @@ private list[ComposableProspectiveOperation] mergeIntoComposableOperations(list[ return composablePrOps; } -public bool canBeChained(ComposableProspectiveOperation prev, ComposableProspectiveOperation curr) { +private bool canBeChained(ComposableProspectiveOperation prev, ComposableProspectiveOperation curr) { currNeededVarsInPrevAvailabilitySet = isCurrNeededVarsInPrevAvailabilitySet(curr.neededVars, prev); return size(curr.neededVars) <= 1 && currNeededVarsInPrevAvailabilitySet; } -public bool isMergeable(ComposableProspectiveOperation cPrOp) { +private bool isMergeable(ComposableProspectiveOperation cPrOp) { operation = cPrOp.prOp.operation; return operation == FILTER || operation == MAP || operation == FOR_EACH; } @@ -89,19 +89,18 @@ private bool isCurrNeededVarsInPrevAvailabilitySet(set[str] currNeededVars, Comp return true; } -public ComposableProspectiveOperation mergeComposablePrOps(ComposableProspectiveOperation prev, ComposableProspectiveOperation curr) { - if (isFilter(prev.prOp)) { - prOp = mergeTwoOpsInAnIfThenStmt(prev.prOp, curr.prOp); - availableVars = retrieveAvailableVariables(prOp, methodAvailableVars); - neededVars = retrieveNeededVars(prOp, availableVars); - return composableProspectiveOperation(prOp, neededVars, availableVars); - - } else { - list[str] statements = retrieveAllStatements(prev.prOp) + retrieveAllStatements(curr.prOp); - Block statementsAsOneBlock = transformStatementsInBlock(statements); - prOp = prospectiveOperation(unparse(statementsAsOneBlock), curr.prOp.operation); - return mergeComposableProspectiveOperation(prOp, prev, curr); - } +private ComposableProspectiveOperation mergeComposablePrOps(ComposableProspectiveOperation prev, ComposableProspectiveOperation curr) { + if (isFilter(prev.prOp)) + return mergeIntoAnIfThenStmt(prev, curr); + else + return mergeIntoABlock(prev, curr); +} + +private ComposableProspectiveOperation mergeIntoAnIfThenStmt(ComposableProspectiveOperation prev, ComposableProspectiveOperation curr) { + prOp = mergeTwoOpsInAnIfThenStmt(prev.prOp, curr.prOp); + availableVars = retrieveAvailableVariables(prOp, methodAvailableVars); + neededVars = retrieveNeededVars(prOp, availableVars); + return composableProspectiveOperation(prOp, neededVars, availableVars); } private ProspectiveOperation mergeTwoOpsInAnIfThenStmt(ProspectiveOperation prev, ProspectiveOperation curr) { @@ -111,6 +110,13 @@ private ProspectiveOperation mergeTwoOpsInAnIfThenStmt(ProspectiveOperation prev return prospectiveOperation(unparse(ifThenStmt), curr.operation); } +private ComposableProspectiveOperation mergeIntoABlock(ComposableProspectiveOperation prev, ComposableProspectiveOperation curr) { + list[str] statements = retrieveAllStatements(prev.prOp) + retrieveAllStatements(curr.prOp); + Block statementsAsOneBlock = transformStatementsInBlock(statements); + prOp = prospectiveOperation(unparse(statementsAsOneBlock), curr.prOp.operation); + return mergeComposableProspectiveOperation(prOp, prev, curr); +} + private ComposableProspectiveOperation mergeComposableProspectiveOperation(ProspectiveOperation prOp, ComposableProspectiveOperation prev, ComposableProspectiveOperation curr) { mergedAvailableVars = mergeAvailableVars(curr.availableVars, prev.availableVars); mergedNeededVars = mergeNeededVars(curr.neededVars, prev.neededVars, mergedAvailableVars); @@ -122,10 +128,8 @@ private set[str] mergeAvailableVars(set[str] currAvailableVars, prevAvailableVar } private set[str] mergeNeededVars(set[str] currNeededVars, set[str] prevNeededVars, set[str] mergedAvailableVars) { - neededVars = currNeededVars; - neededVars -= mergedAvailableVars; - neededVars += prevNeededVars; - return neededVars ; + neededVars = currNeededVars + prevNeededVars; + return neededVars - mergedAvailableVars; } private list[str] retrieveAllStatements(ProspectiveOperation prOp) { From 630b249ec47dd83a2c339736f057e136fe62e896 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 29 Mar 2017 21:57:39 -0300 Subject: [PATCH 073/154] Computing the right availability set when merging into an if statement. - In practice just calling mergeComposableProspectiveOperations() --- src/refactor/forloop/ForLoopToFunctional.rsc | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/refactor/forloop/ForLoopToFunctional.rsc index 8d2b5b7..65cff4b 100644 --- a/src/refactor/forloop/ForLoopToFunctional.rsc +++ b/src/refactor/forloop/ForLoopToFunctional.rsc @@ -98,9 +98,7 @@ private ComposableProspectiveOperation mergeComposablePrOps(ComposableProspectiv private ComposableProspectiveOperation mergeIntoAnIfThenStmt(ComposableProspectiveOperation prev, ComposableProspectiveOperation curr) { prOp = mergeTwoOpsInAnIfThenStmt(prev.prOp, curr.prOp); - availableVars = retrieveAvailableVariables(prOp, methodAvailableVars); - neededVars = retrieveNeededVars(prOp, availableVars); - return composableProspectiveOperation(prOp, neededVars, availableVars); + return mergeComposableProspectiveOperations(prOp, prev, curr); } private ProspectiveOperation mergeTwoOpsInAnIfThenStmt(ProspectiveOperation prev, ProspectiveOperation curr) { @@ -110,14 +108,7 @@ private ProspectiveOperation mergeTwoOpsInAnIfThenStmt(ProspectiveOperation prev return prospectiveOperation(unparse(ifThenStmt), curr.operation); } -private ComposableProspectiveOperation mergeIntoABlock(ComposableProspectiveOperation prev, ComposableProspectiveOperation curr) { - list[str] statements = retrieveAllStatements(prev.prOp) + retrieveAllStatements(curr.prOp); - Block statementsAsOneBlock = transformStatementsInBlock(statements); - prOp = prospectiveOperation(unparse(statementsAsOneBlock), curr.prOp.operation); - return mergeComposableProspectiveOperation(prOp, prev, curr); -} - -private ComposableProspectiveOperation mergeComposableProspectiveOperation(ProspectiveOperation prOp, ComposableProspectiveOperation prev, ComposableProspectiveOperation curr) { +private ComposableProspectiveOperation mergeComposableProspectiveOperations(ProspectiveOperation prOp, ComposableProspectiveOperation prev, ComposableProspectiveOperation curr) { mergedAvailableVars = mergeAvailableVars(curr.availableVars, prev.availableVars); mergedNeededVars = mergeNeededVars(curr.neededVars, prev.neededVars, mergedAvailableVars); return composableProspectiveOperation(prOp, mergedNeededVars, mergedAvailableVars); @@ -132,6 +123,13 @@ private set[str] mergeNeededVars(set[str] currNeededVars, set[str] prevNeededVar return neededVars - mergedAvailableVars; } +private ComposableProspectiveOperation mergeIntoABlock(ComposableProspectiveOperation prev, ComposableProspectiveOperation curr) { + list[str] statements = retrieveAllStatements(prev.prOp) + retrieveAllStatements(curr.prOp); + Block statementsAsOneBlock = transformStatementsInBlock(statements); + prOp = prospectiveOperation(unparse(statementsAsOneBlock), curr.prOp.operation); + return mergeComposableProspectiveOperations(prOp, prev, curr); +} + private list[str] retrieveAllStatements(ProspectiveOperation prOp) { list[str] allStatements = []; if (isBlock(prOp.stmt)) From 0ff334e2825c898c8c9cc9c269299688a7fef38c Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Mon, 10 Apr 2017 01:05:25 -0300 Subject: [PATCH 074/154] Returning a transformed MethodBody with single forEach refactor. - Not transforming source file yet. - We need to change some modules and methods names. - Also needed to change modules folder location. --- src/ForLoop.rsc | 16 ++++--- src/refactor/forloop/ForLoopToFunctional.rsc | 50 ++++++++++++++++++-- 2 files changed, 55 insertions(+), 11 deletions(-) diff --git a/src/ForLoop.rsc b/src/ForLoop.rsc index f78608a..ceb0136 100644 --- a/src/ForLoop.rsc +++ b/src/ForLoop.rsc @@ -6,7 +6,7 @@ import ParseTree; import LocalVariablesFinder; import EnhancedLoopExpression; import refactor::forloop::ForLoopBodyReferences; -import refactor::forloop::ProspectiveOperation; +import refactor::forloop::ForLoopToFunctional; import MethodVar; private set[str] checkedExceptionClasses; @@ -41,10 +41,14 @@ private void lookForEnhancedForStatementsInMethodBody(MethodHeader methodHeader, visit(methodBody) { case EnhancedForStatement forStmt: { visit(forStmt) { - case (EnhancedForStatement) `for ( : ) `: { - methodLocalVariables = findLocalVariables(methodHeader, methodBody); - checkLoopEligibilityForRefactor(methodLocalVariables, exp, stmt); - retrievePotentialOperations(methodLocalVariables, forStmt); + case EnhancedForStatement enhancedForStmt: { + visit(enhancedForStmt) { + case (EnhancedForStatement) `for ( : ) `: { + methodLocalVariables = findLocalVariables(methodHeader, methodBody); + if(isLoopRefactorable(methodLocalVariables, exp, stmt)) + refactorEnhancedToFunctional(methodLocalVariables, enhancedForStmt, methodBody); + } + } } } } @@ -54,7 +58,7 @@ private void lookForEnhancedForStatementsInMethodBody(MethodHeader methodHeader, } } -private bool checkLoopEligibilityForRefactor(set[MethodVar] methodLocalVariables, Expression exp, Statement stmt) { +private bool isLoopRefactorable(set[MethodVar] methodLocalVariables, Expression exp, Statement stmt) { return loopBodyPassConditions(stmt) && isIteratingOnCollection(exp, methodLocalVariables) && atMostOneReferenceToNonEffectiveFinalVar(methodLocalVariables, stmt); } diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/refactor/forloop/ForLoopToFunctional.rsc index 65cff4b..fc7a060 100644 --- a/src/refactor/forloop/ForLoopToFunctional.rsc +++ b/src/refactor/forloop/ForLoopToFunctional.rsc @@ -3,6 +3,7 @@ module refactor::forloop::ForLoopToFunctional import IO; import List; import Set; +import String; import lang::java::\syntax::Java18; import ParseTree; import MethodVar; @@ -13,14 +14,28 @@ import refactor::forloop::OperationType; public data ComposableProspectiveOperation = composableProspectiveOperation(ProspectiveOperation prOp, set[str] neededVars, set[str] availableVars); -private set[MethodVar] methodAvailableVars; +public MethodBody refactorEnhancedToFunctional(set[MethodVar] methodVars, EnhancedForStatement forStmt, MethodBody methodBody) { + composablePrOps = retrieveComposableProspectiveOperations(methodVars, forStmt); + + Statement refactored = buildFunctionalStatement(composablePrOps, forStmt); + refactoredMethodBody = refactorToFunctional(methodBody, refactored); + + println("\n --- APPLYING REFACTOR ---"); + println(methodBody); + println("refactored to:"); + println(refactoredMethodBody); + + return refactoredMethodBody; +} -public list[ComposableProspectiveOperation] refactorEnhancedToFunctional(set[MethodVar] methodVars, EnhancedForStatement forStmt) { +MethodBody refactorToFunctional(MethodBody methodBody, Statement refactored) = top-down-break visit(methodBody) { + case (Statement) `for ( : ) ` + => refactored +}; + +public list[ComposableProspectiveOperation] retrieveComposableProspectiveOperations(set[MethodVar] methodVars, EnhancedForStatement forStmt) { prospectiveOperations = retrieveProspectiveOperations(methodVars, forStmt); composablePrOps = createComposableProspectiveOperationsWithVariableAvailability(prospectiveOperations, methodVars); - - methodAvailableVars = methodVars; - return mergeIntoComposableOperations(composablePrOps); } @@ -175,4 +190,29 @@ private Block transformStatementsInBlock(list[str] stmts) { joined += (stmt + "\n"); joined += "}"; return parse(#Block, joined); +} + +private Statement buildFunctionalStatement(list[ComposableProspectiveOperation] composablePrOps, EnhancedForStatement forStmt) { + visit(forStmt) { + case (EnhancedForStatement) `for ( : ) `: { + if(size(composablePrOps) == 1 && composablePrOps[0].prOp.operation == FOR_EACH) { + prOp = composablePrOps[0].prOp; + stmtBlock = transformIntoBlock(prOp.stmt); + iteratedVarName = trimEndingBlankSpace(iteratedVarName); + return parse(#Statement, ".forEach(() -\> );"); + } + + } + } + + return parse(#Statement, ";"); +} + +private Block transformIntoBlock(str stmt) { + if(isBlock(stmt)) return parse(#Block, stmt); + return parse(#Block, "{\n\n}"); +} + +private VariableDeclaratorId trimEndingBlankSpace(VariableDeclaratorId varId) { + return parse(#VariableDeclaratorId, trim(unparse(varId))); } \ No newline at end of file From 858dd7baf7bbbb3aa0454c0da4a9fd7604ebf90a Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Mon, 10 Apr 2017 11:39:18 -0300 Subject: [PATCH 075/154] Trying to match the exact loop to be refactored. --- src/ForLoop.rsc | 7 +++-- src/refactor/forloop/ForLoopToFunctional.rsc | 33 +++++++++----------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/ForLoop.rsc b/src/ForLoop.rsc index ceb0136..0c4ca30 100644 --- a/src/ForLoop.rsc +++ b/src/ForLoop.rsc @@ -43,10 +43,11 @@ private void lookForEnhancedForStatementsInMethodBody(MethodHeader methodHeader, visit(forStmt) { case EnhancedForStatement enhancedForStmt: { visit(enhancedForStmt) { - case (EnhancedForStatement) `for ( : ) `: { + case (EnhancedForStatement) `for ( : ) `: { methodLocalVariables = findLocalVariables(methodHeader, methodBody); - if(isLoopRefactorable(methodLocalVariables, exp, stmt)) - refactorEnhancedToFunctional(methodLocalVariables, enhancedForStmt, methodBody); + if(isLoopRefactorable(methodLocalVariables, collectionId, stmt)) + // TODO Create data structure + refactorEnhancedToFunctional(methodLocalVariables, enhancedForStmt, methodBody, iteratedVarName, collectionId); } } } diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/refactor/forloop/ForLoopToFunctional.rsc index fc7a060..f09c75b 100644 --- a/src/refactor/forloop/ForLoopToFunctional.rsc +++ b/src/refactor/forloop/ForLoopToFunctional.rsc @@ -14,11 +14,12 @@ import refactor::forloop::OperationType; public data ComposableProspectiveOperation = composableProspectiveOperation(ProspectiveOperation prOp, set[str] neededVars, set[str] availableVars); -public MethodBody refactorEnhancedToFunctional(set[MethodVar] methodVars, EnhancedForStatement forStmt, MethodBody methodBody) { +public MethodBody refactorEnhancedToFunctional(set[MethodVar] methodVars, EnhancedForStatement forStmt, MethodBody methodBody, VariableDeclaratorId iteratedVarName, Expression collectionId) { composablePrOps = retrieveComposableProspectiveOperations(methodVars, forStmt); - Statement refactored = buildFunctionalStatement(composablePrOps, forStmt); - refactoredMethodBody = refactorToFunctional(methodBody, refactored); + Statement refactored = buildFunctionalStatement(composablePrOps, forStmt, iteratedVarName, collectionId); + forStatement = parse(#Statement, unparse(forStmt)); + refactoredMethodBody = refactorToFunctional(methodBody, forStatement, refactored); println("\n --- APPLYING REFACTOR ---"); println(methodBody); @@ -28,8 +29,8 @@ public MethodBody refactorEnhancedToFunctional(set[MethodVar] methodVars, Enhanc return refactoredMethodBody; } -MethodBody refactorToFunctional(MethodBody methodBody, Statement refactored) = top-down-break visit(methodBody) { - case (Statement) `for ( : ) ` +MethodBody refactorToFunctional(MethodBody methodBody, Statement forStmt, Statement refactored) = top-down-break visit(methodBody) { + case forStmt => refactored }; @@ -192,20 +193,16 @@ private Block transformStatementsInBlock(list[str] stmts) { return parse(#Block, joined); } -private Statement buildFunctionalStatement(list[ComposableProspectiveOperation] composablePrOps, EnhancedForStatement forStmt) { - visit(forStmt) { - case (EnhancedForStatement) `for ( : ) `: { - if(size(composablePrOps) == 1 && composablePrOps[0].prOp.operation == FOR_EACH) { - prOp = composablePrOps[0].prOp; - stmtBlock = transformIntoBlock(prOp.stmt); - iteratedVarName = trimEndingBlankSpace(iteratedVarName); - return parse(#Statement, ".forEach(() -\> );"); - } - - } - } +private Statement buildFunctionalStatement(list[ComposableProspectiveOperation] composablePrOps, EnhancedForStatement forStmt, VariableDeclaratorId iteratedVarName, Expression collectionId) { + if(size(composablePrOps) == 1 && composablePrOps[0].prOp.operation == FOR_EACH) { + prOp = composablePrOps[0].prOp; + stmtBlock = transformIntoBlock(prOp.stmt); + iteratedVarName = trimEndingBlankSpace(iteratedVarName); + return parse(#Statement, ".forEach(() -\> );"); + } + - return parse(#Statement, ";"); + return parse(#Statement, unparse(forStmt)); } private Block transformIntoBlock(str stmt) { From f3e8121d1602764f7d5f9ea06ac2c2e0e6b10037 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Mon, 10 Apr 2017 15:09:17 -0300 Subject: [PATCH 076/154] Gitignore --- bin/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/.gitignore b/bin/.gitignore index 3040ad9..3c6e732 100644 --- a/bin/.gitignore +++ b/bin/.gitignore @@ -1 +1,2 @@ /*.rsc +/refactor/ From 385c97129ee8b0187d196e2db33234c679fcd957 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Tue, 11 Apr 2017 21:19:26 -0300 Subject: [PATCH 077/154] Starting to chain operations. --- src/refactor/forloop/ForLoopToFunctional.rsc | 74 ++++++++++++++++--- src/refactor/forloop/ProspectiveOperation.rsc | 16 ++++ testes/ForLoopToFunctional/SimpleForEach.java | 8 ++ 3 files changed, 86 insertions(+), 12 deletions(-) create mode 100644 testes/ForLoopToFunctional/SimpleForEach.java diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/refactor/forloop/ForLoopToFunctional.rsc index f09c75b..ad31720 100644 --- a/src/refactor/forloop/ForLoopToFunctional.rsc +++ b/src/refactor/forloop/ForLoopToFunctional.rsc @@ -21,10 +21,10 @@ public MethodBody refactorEnhancedToFunctional(set[MethodVar] methodVars, Enhanc forStatement = parse(#Statement, unparse(forStmt)); refactoredMethodBody = refactorToFunctional(methodBody, forStatement, refactored); - println("\n --- APPLYING REFACTOR ---"); - println(methodBody); - println("refactored to:"); - println(refactoredMethodBody); + //println("\n --- APPLYING REFACTOR ---"); + //println(forStmt); + //println("refactored to:"); + //println(refactored); return refactoredMethodBody; } @@ -194,15 +194,19 @@ private Block transformStatementsInBlock(list[str] stmts) { } private Statement buildFunctionalStatement(list[ComposableProspectiveOperation] composablePrOps, EnhancedForStatement forStmt, VariableDeclaratorId iteratedVarName, Expression collectionId) { - if(size(composablePrOps) == 1 && composablePrOps[0].prOp.operation == FOR_EACH) { - prOp = composablePrOps[0].prOp; - stmtBlock = transformIntoBlock(prOp.stmt); - iteratedVarName = trimEndingBlankSpace(iteratedVarName); - return parse(#Statement, ".forEach(() -\> );"); - } - + if(size(composablePrOps) == 1 && isForEach(composablePrOps[0].prOp)) + return buildStatementForOnlyOneForEach(composablePrOps[0].prOp, iteratedVarName, collectionId); - return parse(#Statement, unparse(forStmt)); + println(); + println(forStmt); + println("\nrefactored to:"); + return chainOperationsIntoStatement(composablePrOps, collectionId); +} + +private Statement buildStatementForOnlyOneForEach(ProspectiveOperation prOp, VariableDeclaratorId iteratedVarName, Expression collectionId) { + stmtBlock = transformIntoBlock(prOp.stmt); + iteratedVarName = trimEndingBlankSpace(iteratedVarName); + return parse(#Statement, ".forEach(() -\> );"); } private Block transformIntoBlock(str stmt) { @@ -212,4 +216,50 @@ private Block transformIntoBlock(str stmt) { private VariableDeclaratorId trimEndingBlankSpace(VariableDeclaratorId varId) { return parse(#VariableDeclaratorId, trim(unparse(varId))); +} + +private Statement chainOperationsIntoStatement(list[ComposableProspectiveOperation] composablePrOps, Expression collectionId) { + str chainStr = ".stream()"; + + for(composablePrOp <- composablePrOps) { + chainStr = "." + buildChainableOperation(composablePrOp); + } + + println(chainStr); + return parse(#Statement, ";"); +} + +private str buildChainableOperation(ComposableProspectiveOperation cPrOp) { + prOp = cPrOp.prOp; + return prOp.operation + "(" + retrieveLambdaParameterName(cPrOp) + " -\> " + + retrieveLambdaBody(prOp) + ")"; +} + +private str retrieveLambdaParameterName(ComposableProspectiveOperation cPrOp) { + return isEmpty(cPrOp.neededVars) ? "_item" : getOneFrom(cPrOp.neededVars); +} + +private str retrieveLambdaBody(ProspectiveOperation prOp) { + if(isFilter(prOp) || isAnyMatch(prOp) || isNoneMatch(prOp) || isBlock(prOp.stmt)) + return prOp.stmt; + else if(isMap(prOp)) { + return getLambdaBodyForMap(prOp.stmt); + } + else if(isReduce(prOp)) + return getLambdaBodyForReduce(prOp.stmt); + else // isForEach(prOp) + return unparse(transformIntoBlock(prOp.stmt)); +} + +private str getLambdaBodyForMap(str stmt) { + // XXX Are other kind of statements maps? + lvdl = parse(#LocalVariableDeclaration, stmt); + visit(lvdl) { + case VariableInitializer vi: return unparse(vi); + } + throw "No variable initializer in MAP"; +} + +private str getLambdaBodyForReduce(str stmt) { + return "REDUCE_NOT_IMPLEMENTED_YET;"; } \ No newline at end of file diff --git a/src/refactor/forloop/ProspectiveOperation.rsc b/src/refactor/forloop/ProspectiveOperation.rsc index bc4832b..1fe51a5 100644 --- a/src/refactor/forloop/ProspectiveOperation.rsc +++ b/src/refactor/forloop/ProspectiveOperation.rsc @@ -149,6 +149,22 @@ public bool isReduce(ProspectiveOperation prOp) { return prOp.operation == REDUCE; } +public bool isAnyMatch(ProspectiveOperation prOp) { + return prOp.operation == ANY_MATCH; +} + +public bool isNoneMatch(ProspectiveOperation prOp) { + return prOp.operation == NONE_MATCH; +} + +public bool isMap(ProspectiveOperation prOp) { + return prOp.operation == MAP; +} + +public bool isForEach(ProspectiveOperation prOp) { + return prOp.operation == FOR_EACH; +} + public bool isLocalVariableDeclarationStatement(str stmt) { try { parse(#LocalVariableDeclarationStatement, stmt); diff --git a/testes/ForLoopToFunctional/SimpleForEach.java b/testes/ForLoopToFunctional/SimpleForEach.java new file mode 100644 index 0000000..56ec92b --- /dev/null +++ b/testes/ForLoopToFunctional/SimpleForEach.java @@ -0,0 +1,8 @@ +class SimpleForEach { + + public void test1(List things, PrintWriter writer) { + for (String thing: things) { + writer.write(thing); + } + } +} \ No newline at end of file From 997a4a5f6955dfee8e15ee290db713cd3ce3c94a Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sat, 15 Apr 2017 11:18:08 -0300 Subject: [PATCH 078/154] Catching case when LocalVariableDeclaration ends with ";". - LocalVariableDeclaration can't be parsed with ending ";" --- src/refactor/forloop/ForLoopToFunctional.rsc | 3 +++ .../forloop/ForLoopToFunctionalTest.rsc | 23 +++++++++++++++++++ testes/ForLoopToFunctional/T1.java | 23 +++++++++++++++++++ 3 files changed, 49 insertions(+) create mode 100644 src/refactor/forloop/ForLoopToFunctionalTest.rsc create mode 100644 testes/ForLoopToFunctional/T1.java diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/refactor/forloop/ForLoopToFunctional.rsc index ad31720..55f69ea 100644 --- a/src/refactor/forloop/ForLoopToFunctional.rsc +++ b/src/refactor/forloop/ForLoopToFunctional.rsc @@ -253,6 +253,9 @@ private str retrieveLambdaBody(ProspectiveOperation prOp) { private str getLambdaBodyForMap(str stmt) { // XXX Are other kind of statements maps? + if(endsWith(stmt, ";")) + stmt = substring(stmt, 0, size(stmt)-1); + lvdl = parse(#LocalVariableDeclaration, stmt); visit(lvdl) { case VariableInitializer vi: return unparse(vi); diff --git a/src/refactor/forloop/ForLoopToFunctionalTest.rsc b/src/refactor/forloop/ForLoopToFunctionalTest.rsc new file mode 100644 index 0000000..9c5ac98 --- /dev/null +++ b/src/refactor/forloop/ForLoopToFunctionalTest.rsc @@ -0,0 +1,23 @@ +module refactor::forloop::ForLoopToFunctionalTest + +import IO; +import lang::java::\syntax::Java18; +import ParseTree; +import refactor::forloop::ForLoopToFunctional; +import MethodVar; +import LocalVariablesFinder; +import ParseTreeVisualization; + +public test bool x() { + fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T1.java|; + methodBody = parse(#MethodBody, readFile(fileLoc)); + methodHeader = parse(#MethodHeader, "TestSuite createTestSuite()"); + set[MethodVar] methodVars = findLocalVariables(methodHeader, methodBody); + EnhancedForStatement forStmt = parse(#EnhancedForStatement, "for (Class\ testerClass : testers) {\n final TestSuite testerSuite =\n makeSuiteForTesterClass((Class\\>) testerClass);\n if (testerSuite.countTestCases() \> 0) {\n suite.addTest(testerSuite);\n }\n }"); + VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "testerClass"); + Expression collectionId = parse(#Expression, "testers"); + + println(refactorEnhancedToFunctional(methodVars, forStmt, methodBody, iteratedVarName, collectionId)); + + return false; +} \ No newline at end of file diff --git a/testes/ForLoopToFunctional/T1.java b/testes/ForLoopToFunctional/T1.java new file mode 100644 index 0000000..3b16dc4 --- /dev/null +++ b/testes/ForLoopToFunctional/T1.java @@ -0,0 +1,23 @@ +{ + checkCanCreate(); + + logger.fine(" Testing: " + name); + logger.fine("Features: " + formatFeatureSet(features)); + + FeatureUtil.addImpliedFeatures(features); + + logger.fine("Expanded: " + formatFeatureSet(features)); + + // Class parameters must be raw. + List> testers = getTesters(); + + TestSuite suite = new TestSuite(name); + for (Class testerClass : testers) { + final TestSuite testerSuite = + makeSuiteForTesterClass((Class>) testerClass); + if (testerSuite.countTestCases() > 0) { + suite.addTest(testerSuite); + } + } + return suite; + } \ No newline at end of file From 8945f0dc751ba002fe9f243e2da6450dc5782da0 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sat, 15 Apr 2017 11:48:48 -0300 Subject: [PATCH 079/154] Extracting method to facilitate testing. --- src/refactor/forloop/ForLoopToFunctional.rsc | 9 ++++++--- src/refactor/forloop/ForLoopToFunctionalTest.rsc | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/refactor/forloop/ForLoopToFunctional.rsc index 55f69ea..facc1af 100644 --- a/src/refactor/forloop/ForLoopToFunctional.rsc +++ b/src/refactor/forloop/ForLoopToFunctional.rsc @@ -15,12 +15,10 @@ import refactor::forloop::OperationType; public data ComposableProspectiveOperation = composableProspectiveOperation(ProspectiveOperation prOp, set[str] neededVars, set[str] availableVars); public MethodBody refactorEnhancedToFunctional(set[MethodVar] methodVars, EnhancedForStatement forStmt, MethodBody methodBody, VariableDeclaratorId iteratedVarName, Expression collectionId) { - composablePrOps = retrieveComposableProspectiveOperations(methodVars, forStmt); - Statement refactored = buildFunctionalStatement(composablePrOps, forStmt, iteratedVarName, collectionId); forStatement = parse(#Statement, unparse(forStmt)); + refactored = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); refactoredMethodBody = refactorToFunctional(methodBody, forStatement, refactored); - //println("\n --- APPLYING REFACTOR ---"); //println(forStmt); //println("refactored to:"); @@ -29,6 +27,11 @@ public MethodBody refactorEnhancedToFunctional(set[MethodVar] methodVars, Enhanc return refactoredMethodBody; } +public Statement buildRefactoredEnhancedFor(set[MethodVar] methodVars, EnhancedForStatement forStmt, MethodBody methodBody, VariableDeclaratorId iteratedVarName, Expression collectionId) { + composablePrOps = retrieveComposableProspectiveOperations(methodVars, forStmt); + return buildFunctionalStatement(composablePrOps, forStmt, iteratedVarName, collectionId); +} + MethodBody refactorToFunctional(MethodBody methodBody, Statement forStmt, Statement refactored) = top-down-break visit(methodBody) { case forStmt => refactored diff --git a/src/refactor/forloop/ForLoopToFunctionalTest.rsc b/src/refactor/forloop/ForLoopToFunctionalTest.rsc index 9c5ac98..2842c54 100644 --- a/src/refactor/forloop/ForLoopToFunctionalTest.rsc +++ b/src/refactor/forloop/ForLoopToFunctionalTest.rsc @@ -17,7 +17,7 @@ public test bool x() { VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "testerClass"); Expression collectionId = parse(#Expression, "testers"); - println(refactorEnhancedToFunctional(methodVars, forStmt, methodBody, iteratedVarName, collectionId)); + refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); - return false; + return unparse(refactoredStatement) == "testers.stream().map(testerClass -\> makeSuiteForTesterClass((Class\\>) testerClass)).filter(testerSuite -\> testerSuite.countTestCases() \> 0).forEach(testerSuite -\> {\nsuite.addTest(testerSuite);\n});"; } \ No newline at end of file From 2efcd3b625722f484a08d19a66b382d4002dc166 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 16 Apr 2017 18:31:16 -0300 Subject: [PATCH 080/154] Adjusting the temporary impl of the lambda body for a reduce. - It was resulting in a parse error. -- Obviously, invalid syntax. --- src/refactor/forloop/ForLoopToFunctional.rsc | 2 +- .../forloop/ForLoopToFunctionalTest.rsc | 19 ++++- testes/ForLoopToFunctional/T2.java | 83 +++++++++++++++++++ testes/ForLoopToFunctional/T2For.java | 10 +++ 4 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 testes/ForLoopToFunctional/T2.java create mode 100644 testes/ForLoopToFunctional/T2For.java diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/refactor/forloop/ForLoopToFunctional.rsc index facc1af..f024b6a 100644 --- a/src/refactor/forloop/ForLoopToFunctional.rsc +++ b/src/refactor/forloop/ForLoopToFunctional.rsc @@ -267,5 +267,5 @@ private str getLambdaBodyForMap(str stmt) { } private str getLambdaBodyForReduce(str stmt) { - return "REDUCE_NOT_IMPLEMENTED_YET;"; + return "needToImplementReduce()"; } \ No newline at end of file diff --git a/src/refactor/forloop/ForLoopToFunctionalTest.rsc b/src/refactor/forloop/ForLoopToFunctionalTest.rsc index 2842c54..0f7be34 100644 --- a/src/refactor/forloop/ForLoopToFunctionalTest.rsc +++ b/src/refactor/forloop/ForLoopToFunctionalTest.rsc @@ -1,6 +1,7 @@ module refactor::forloop::ForLoopToFunctionalTest import IO; +import String; import lang::java::\syntax::Java18; import ParseTree; import refactor::forloop::ForLoopToFunctional; @@ -8,7 +9,7 @@ import MethodVar; import LocalVariablesFinder; import ParseTreeVisualization; -public test bool x() { +public test bool ex1() { fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T1.java|; methodBody = parse(#MethodBody, readFile(fileLoc)); methodHeader = parse(#MethodHeader, "TestSuite createTestSuite()"); @@ -20,4 +21,20 @@ public test bool x() { refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); return unparse(refactoredStatement) == "testers.stream().map(testerClass -\> makeSuiteForTesterClass((Class\\>) testerClass)).filter(testerSuite -\> testerSuite.countTestCases() \> 0).forEach(testerSuite -\> {\nsuite.addTest(testerSuite);\n});"; +} + +// FIXME workaround for now. not really useful test. +public test bool reduceShouldNotBeEmpty() { + fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T2.java|; + methodBody = parse(#MethodBody, readFile(fileLoc)); + methodHeader = parse(#MethodHeader, "void assertInvariants(Map\ map)"); + set[MethodVar] methodVars = findLocalVariables(methodHeader, methodBody); + fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T2For.java|; + EnhancedForStatement forStmt = parse(#EnhancedForStatement, readFile(fileForLoc)); + VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "key"); + Expression collectionId = parse(#Expression, "keySet"); + + refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); + + return !isEmpty(""); } \ No newline at end of file diff --git a/testes/ForLoopToFunctional/T2.java b/testes/ForLoopToFunctional/T2.java new file mode 100644 index 0000000..d78572f --- /dev/null +++ b/testes/ForLoopToFunctional/T2.java @@ -0,0 +1,83 @@ +{ + Set keySet = map.keySet(); + Collection valueCollection = map.values(); + Set> entrySet = map.entrySet(); + + assertEquals(map.size() == 0, map.isEmpty()); + assertEquals(map.size(), keySet.size()); + assertEquals(keySet.size() == 0, keySet.isEmpty()); + assertEquals(!keySet.isEmpty(), keySet.iterator().hasNext()); + + int expectedKeySetHash = 0; + for (K key : keySet) { + V value = map.get(key); + expectedKeySetHash += key != null ? key.hashCode() : 0; + assertTrue(map.containsKey(key)); + assertTrue(map.containsValue(value)); + assertTrue(valueCollection.contains(value)); + assertTrue(valueCollection.containsAll(Collections.singleton(value))); + assertTrue(entrySet.contains(mapEntry(key, value))); + assertTrue(allowsNullKeys || (key != null)); + } + assertEquals(expectedKeySetHash, keySet.hashCode()); + + assertEquals(map.size(), valueCollection.size()); + assertEquals(valueCollection.size() == 0, valueCollection.isEmpty()); + assertEquals(!valueCollection.isEmpty(), valueCollection.iterator().hasNext()); + for (V value : valueCollection) { + assertTrue(map.containsValue(value)); + assertTrue(allowsNullValues || (value != null)); + } + + assertEquals(map.size(), entrySet.size()); + assertEquals(entrySet.size() == 0, entrySet.isEmpty()); + assertEquals(!entrySet.isEmpty(), entrySet.iterator().hasNext()); + assertEntrySetNotContainsString(entrySet); + + boolean supportsValuesHashCode = supportsValuesHashCode(map); + if (supportsValuesHashCode) { + int expectedEntrySetHash = 0; + for (Entry entry : entrySet) { + assertTrue(map.containsKey(entry.getKey())); + assertTrue(map.containsValue(entry.getValue())); + int expectedHash = + (entry.getKey() == null ? 0 : entry.getKey().hashCode()) + ^ (entry.getValue() == null ? 0 : entry.getValue().hashCode()); + assertEquals(expectedHash, entry.hashCode()); + expectedEntrySetHash += expectedHash; + } + assertEquals(expectedEntrySetHash, entrySet.hashCode()); + assertTrue(entrySet.containsAll(new HashSet>(entrySet))); + assertTrue(entrySet.equals(new HashSet>(entrySet))); + } + + Object[] entrySetToArray1 = entrySet.toArray(); + assertEquals(map.size(), entrySetToArray1.length); + assertTrue(Arrays.asList(entrySetToArray1).containsAll(entrySet)); + + Entry[] entrySetToArray2 = new Entry[map.size() + 2]; + entrySetToArray2[map.size()] = mapEntry("foo", 1); + assertSame(entrySetToArray2, entrySet.toArray(entrySetToArray2)); + assertNull(entrySetToArray2[map.size()]); + assertTrue(Arrays.asList(entrySetToArray2).containsAll(entrySet)); + + Object[] valuesToArray1 = valueCollection.toArray(); + assertEquals(map.size(), valuesToArray1.length); + assertTrue(Arrays.asList(valuesToArray1).containsAll(valueCollection)); + + Object[] valuesToArray2 = new Object[map.size() + 2]; + valuesToArray2[map.size()] = "foo"; + assertSame(valuesToArray2, valueCollection.toArray(valuesToArray2)); + assertNull(valuesToArray2[map.size()]); + assertTrue(Arrays.asList(valuesToArray2).containsAll(valueCollection)); + + if (supportsValuesHashCode) { + int expectedHash = 0; + for (Entry entry : entrySet) { + expectedHash += entry.hashCode(); + } + assertEquals(expectedHash, map.hashCode()); + } + + assertMoreInvariants(map); + } \ No newline at end of file diff --git a/testes/ForLoopToFunctional/T2For.java b/testes/ForLoopToFunctional/T2For.java new file mode 100644 index 0000000..75117b3 --- /dev/null +++ b/testes/ForLoopToFunctional/T2For.java @@ -0,0 +1,10 @@ +for (K key : keySet) { + V value = map.get(key); + expectedKeySetHash += key != null ? key.hashCode() : 0; + assertTrue(map.containsKey(key)); + assertTrue(map.containsValue(value)); + assertTrue(valueCollection.contains(value)); + assertTrue(valueCollection.containsAll(Collections.singleton(value))); + assertTrue(entrySet.contains(mapEntry(key, value))); + assertTrue(allowsNullKeys || (key != null)); + } \ No newline at end of file From db6aafb2f853ea71475a369dcad303a885c7b4ad Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 16 Apr 2017 18:31:16 -0300 Subject: [PATCH 081/154] Writing a faling test for nested loops (not really supported right now). - At least how we break stmts in prospective operations needs to be changed --- .../forloop/ForLoopToFunctionalTest.rsc | 17 ++++++++++ testes/ForLoopToFunctional/NestedLoops.java | 33 +++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 testes/ForLoopToFunctional/NestedLoops.java diff --git a/src/refactor/forloop/ForLoopToFunctionalTest.rsc b/src/refactor/forloop/ForLoopToFunctionalTest.rsc index 0f7be34..a7a9498 100644 --- a/src/refactor/forloop/ForLoopToFunctionalTest.rsc +++ b/src/refactor/forloop/ForLoopToFunctionalTest.rsc @@ -37,4 +37,21 @@ public test bool reduceShouldNotBeEmpty() { refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); return !isEmpty(""); +} + +// TODO nested loops needed to be changed in ProspectiveOperation +public test bool nestedLoops() { + fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/NestedLoops.java|; + methodBody = parse(#MethodBody, readFile(fileLoc)); + methodHeader = parse(#MethodHeader, "void testComplexBuilder()"); + set[MethodVar] methodVars = findLocalVariables(methodHeader, methodBody); + fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T2For.java|; + EnhancedForStatement forStmt = parse(#EnhancedForStatement, "for (Integer red : colorElem) {\n for (Integer green : colorElem) {\n for (Integer blue : colorElem) {\n webSafeColorsBuilder.add((red \<\< 16) + (green \<\< 8) + blue);\n }\n }\n }"); + VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "red"); + Expression collectionId = parse(#Expression, "colorElem"); + + refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); + println(refactoredStatement); + + return false; } \ No newline at end of file diff --git a/testes/ForLoopToFunctional/NestedLoops.java b/testes/ForLoopToFunctional/NestedLoops.java new file mode 100644 index 0000000..7c6098e --- /dev/null +++ b/testes/ForLoopToFunctional/NestedLoops.java @@ -0,0 +1,33 @@ +{ + List colorElem = asList(0x00, 0x33, 0x66, 0x99, 0xCC, 0xFF); + // javac won't compile this without "this." + ImmutableSet.Builder webSafeColorsBuilder + = this.builder(); + for (Integer red : colorElem) { + for (Integer green : colorElem) { + for (Integer blue : colorElem) { + webSafeColorsBuilder.add((red << 16) + (green << 8) + blue); + } + } + } + ImmutableSet webSafeColors = webSafeColorsBuilder.build(); + assertEquals(216, webSafeColors.size()); + Integer[] webSafeColorArray = + webSafeColors.toArray(new Integer[webSafeColors.size()]); + assertEquals(0x000000, (int) webSafeColorArray[0]); + assertEquals(0x000033, (int) webSafeColorArray[1]); + assertEquals(0x000066, (int) webSafeColorArray[2]); + assertEquals(0x003300, (int) webSafeColorArray[6]); + assertEquals(0x330000, (int) webSafeColorArray[36]); + ImmutableSet addedColor + = webSafeColorsBuilder.add(LAST_COLOR_ADDED).build(); + assertEquals( + "Modifying the builder should not have changed any already built sets", + 216, webSafeColors.size()); + assertEquals("the new array should be one bigger than webSafeColors", + 217, addedColor.size()); + Integer[] appendColorArray = + addedColor.toArray(new Integer[addedColor.size()]); + assertEquals( + getComplexBuilderSetLastElement(), (int) appendColorArray[216]); + } \ No newline at end of file From 28d144976719c50cf626a0483ebfde085b151408 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 16 Apr 2017 18:31:16 -0300 Subject: [PATCH 082/154] Not refactoring when there is an eager operation as non last operation. --- src/refactor/forloop/ForLoopToFunctional.rsc | 29 ++++++++++++------- .../forloop/ForLoopToFunctionalTest.rsc | 27 ++++++++++++++--- src/refactor/forloop/ProspectiveOperation.rsc | 24 +++++++++++++++ testes/ForLoopToFunctional/T2For2.java | 9 ++++++ 4 files changed, 75 insertions(+), 14 deletions(-) create mode 100644 testes/ForLoopToFunctional/T2For2.java diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/refactor/forloop/ForLoopToFunctional.rsc index f024b6a..dce7a16 100644 --- a/src/refactor/forloop/ForLoopToFunctional.rsc +++ b/src/refactor/forloop/ForLoopToFunctional.rsc @@ -15,10 +15,16 @@ import refactor::forloop::OperationType; public data ComposableProspectiveOperation = composableProspectiveOperation(ProspectiveOperation prOp, set[str] neededVars, set[str] availableVars); public MethodBody refactorEnhancedToFunctional(set[MethodVar] methodVars, EnhancedForStatement forStmt, MethodBody methodBody, VariableDeclaratorId iteratedVarName, Expression collectionId) { - - forStatement = parse(#Statement, unparse(forStmt)); + try + return buildRefactoredMethodBody(methodVars, forStmt, methodBody, iteratedVarName, collectionId); + catch: + return methodBody; +} + +private MethodBody buildRefactoredMethodBody(set[MethodVar] methodVars, EnhancedForStatement forStmt, MethodBody methodBody, VariableDeclaratorId iteratedVarName, Expression collectionId) { refactored = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); - refactoredMethodBody = refactorToFunctional(methodBody, forStatement, refactored); + forStatement = parse(#Statement, unparse(forStmt)); + refactoredMethodBody = refactorToFunctional(methodBody, forStatement, refactored); //println("\n --- APPLYING REFACTOR ---"); //println(forStmt); //println("refactored to:"); @@ -39,8 +45,12 @@ MethodBody refactorToFunctional(MethodBody methodBody, Statement forStmt, Statem public list[ComposableProspectiveOperation] retrieveComposableProspectiveOperations(set[MethodVar] methodVars, EnhancedForStatement forStmt) { prospectiveOperations = retrieveProspectiveOperations(methodVars, forStmt); - composablePrOps = createComposableProspectiveOperationsWithVariableAvailability(prospectiveOperations, methodVars); - return mergeIntoComposableOperations(composablePrOps); + if (canOperationsBeRefactored(prospectiveOperations)) { + composablePrOps = createComposableProspectiveOperationsWithVariableAvailability(prospectiveOperations, methodVars); + return mergeIntoComposableOperations(composablePrOps); + } else + // Throwing the exception is not the best option, but the easiest to implement right now + throw "CanNotBeRefactored"; } private list[ComposableProspectiveOperation] createComposableProspectiveOperationsWithVariableAvailability(list[ProspectiveOperation] prOps, set[MethodVar] methodVars) { @@ -68,7 +78,7 @@ private list[ComposableProspectiveOperation] mergeIntoComposableOperations(list[ curr = composablePrOps[i]; prev = composablePrOps[i - 1]; if (!canBeChained(prev, curr)) { - if (isMergeable(prev) && isMergeable(curr)) { + if (canBeMerged(prev, curr)) { opsSize = size(composablePrOps); if (isFilter(prev.prOp) || isFilter(curr.prOp)) { @@ -96,9 +106,8 @@ private bool canBeChained(ComposableProspectiveOperation prev, ComposableProspec return size(curr.neededVars) <= 1 && currNeededVarsInPrevAvailabilitySet; } -private bool isMergeable(ComposableProspectiveOperation cPrOp) { - operation = cPrOp.prOp.operation; - return operation == FILTER || operation == MAP || operation == FOR_EACH; +private bool canBeMerged(ComposableProspectiveOperation prev, ComposableProspectiveOperation curr) { + return isMergeable(prev.prOp) && isMergeable(curr.prOp); } private bool isCurrNeededVarsInPrevAvailabilitySet(set[str] currNeededVars, ComposableProspectiveOperation prev) { @@ -258,7 +267,7 @@ private str getLambdaBodyForMap(str stmt) { // XXX Are other kind of statements maps? if(endsWith(stmt, ";")) stmt = substring(stmt, 0, size(stmt)-1); - + lvdl = parse(#LocalVariableDeclaration, stmt); visit(lvdl) { case VariableInitializer vi: return unparse(vi); diff --git a/src/refactor/forloop/ForLoopToFunctionalTest.rsc b/src/refactor/forloop/ForLoopToFunctionalTest.rsc index a7a9498..1b87bba 100644 --- a/src/refactor/forloop/ForLoopToFunctionalTest.rsc +++ b/src/refactor/forloop/ForLoopToFunctionalTest.rsc @@ -23,8 +23,7 @@ public test bool ex1() { return unparse(refactoredStatement) == "testers.stream().map(testerClass -\> makeSuiteForTesterClass((Class\\>) testerClass)).filter(testerSuite -\> testerSuite.countTestCases() \> 0).forEach(testerSuite -\> {\nsuite.addTest(testerSuite);\n});"; } -// FIXME workaround for now. not really useful test. -public test bool reduceShouldNotBeEmpty() { +public test bool reduceAsNotTheLastOperationShouldNotBeRefactored() { fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T2.java|; methodBody = parse(#MethodBody, readFile(fileLoc)); methodHeader = parse(#MethodHeader, "void assertInvariants(Map\ map)"); @@ -34,9 +33,13 @@ public test bool reduceShouldNotBeEmpty() { VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "key"); Expression collectionId = parse(#Expression, "keySet"); - refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); + try + refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); + catch: + return true; - return !isEmpty(""); + // Should have thrown exception + return false; } // TODO nested loops needed to be changed in ProspectiveOperation @@ -54,4 +57,20 @@ public test bool nestedLoops() { println(refactoredStatement); return false; +} + +public test bool ex() { + fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T2.java|; + methodBody = parse(#MethodBody, readFile(fileLoc)); + methodHeader = parse(#MethodHeader, "void assertInvariants(Map\ map)"); + set[MethodVar] methodVars = findLocalVariables(methodHeader, methodBody); + fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T2For2.java|; + EnhancedForStatement forStmt = parse(#EnhancedForStatement, readFile(fileForLoc)); + VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "entry"); + Expression collectionId = parse(#Expression, "entrySet"); + + refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); + println(refactoredStatement); + + return !isEmpty(""); } \ No newline at end of file diff --git a/src/refactor/forloop/ProspectiveOperation.rsc b/src/refactor/forloop/ProspectiveOperation.rsc index 1fe51a5..45528f9 100644 --- a/src/refactor/forloop/ProspectiveOperation.rsc +++ b/src/refactor/forloop/ProspectiveOperation.rsc @@ -141,6 +141,18 @@ private list[ProspectiveOperation] markLastStmtAsEager(list[ProspectiveOperation return prefix(prOps) + lastPrOp; } +public bool isMergeable(ProspectiveOperation prOp) { + return isFilter(prOp) || isMap (prOp) || isForEach(prOp); +} + +public bool isEagerOperation(ProspectiveOperation prOp) { + return !isLazyOperation(prOp); +} + +public bool isLazyOperation(ProspectiveOperation prOp) { + return isFilter(prOp) || isMap(prOp); +} + public bool isFilter(ProspectiveOperation prOp) { return prOp.operation == FILTER; } @@ -170,4 +182,16 @@ public bool isLocalVariableDeclarationStatement(str stmt) { parse(#LocalVariableDeclarationStatement, stmt); return true; } catch: return false; +} + +public bool canOperationsBeRefactored(list[ProspectiveOperation] prOps) { + return !haveEagerOperationAsNonLast(prOps); +} + +private bool haveEagerOperationAsNonLast(list[ProspectiveOperation] prOps) { + operationsWithoutLast = prefix(prOps); + for(prOp <- operationsWithoutLast) + if(isEagerOperation(prOp)) return true; + + return false; } \ No newline at end of file diff --git a/testes/ForLoopToFunctional/T2For2.java b/testes/ForLoopToFunctional/T2For2.java new file mode 100644 index 0000000..5362a43 --- /dev/null +++ b/testes/ForLoopToFunctional/T2For2.java @@ -0,0 +1,9 @@ +for (Entry entry : entrySet) { + assertTrue(map.containsKey(entry.getKey())); + assertTrue(map.containsValue(entry.getValue())); + int expectedHash = + (entry.getKey() == null ? 0 : entry.getKey().hashCode()) + ^ (entry.getValue() == null ? 0 : entry.getValue().hashCode()); + assertEquals(expectedHash, entry.hashCode()); + expectedEntrySetHash += expectedHash; + } \ No newline at end of file From 1801def795ba133c1cb0e8c3070308b274510a5f Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 16 Apr 2017 18:31:16 -0300 Subject: [PATCH 083/154] A Map Prospective Operation can be an 'ExpressionStatement' too! - Previously we were only considering 'LocalVariableDeclaration's --- src/refactor/forloop/ForLoopToFunctional.rsc | 20 ++++++++++++++++++- .../forloop/ForLoopToFunctionalTest.rsc | 4 +++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/refactor/forloop/ForLoopToFunctional.rsc index dce7a16..5bda31b 100644 --- a/src/refactor/forloop/ForLoopToFunctional.rsc +++ b/src/refactor/forloop/ForLoopToFunctional.rsc @@ -264,10 +264,28 @@ private str retrieveLambdaBody(ProspectiveOperation prOp) { } private str getLambdaBodyForMap(str stmt) { - // XXX Are other kind of statements maps? + try { + expStmt = parse(#ExpressionStatement, stmt); + return getLambdaBodyForMapWhenExpressionStatement(expStmt); + } catch: + return getLambdaBodyForMapWhenLocalVariableDeclaration(stmt); +} + +private str getLambdaBodyForMapWhenExpressionStatement(ExpressionStatement expStmt) { + stmtStr = unparse(expStmt); + stmtStr = removeEndingSemiCollonIfPresent(stmtStr); + return stmtStr; +} + +private str removeEndingSemiCollonIfPresent(str stmt) { if(endsWith(stmt, ";")) stmt = substring(stmt, 0, size(stmt)-1); + return stmt; +} +private str getLambdaBodyForMapWhenLocalVariableDeclaration(str stmt) { + stmt = removeEndingSemiCollonIfPresent(stmt); + lvdl = parse(#LocalVariableDeclaration, stmt); visit(lvdl) { case VariableInitializer vi: return unparse(vi); diff --git a/src/refactor/forloop/ForLoopToFunctionalTest.rsc b/src/refactor/forloop/ForLoopToFunctionalTest.rsc index 1b87bba..e982e61 100644 --- a/src/refactor/forloop/ForLoopToFunctionalTest.rsc +++ b/src/refactor/forloop/ForLoopToFunctionalTest.rsc @@ -59,7 +59,9 @@ public test bool nestedLoops() { return false; } -public test bool ex() { +// not that useful of a test as it is now +// TODO test the prospective operations with this methodBody. +public test bool shouldNotBreakWithExpressionStatementAsMapOperation() { fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T2.java|; methodBody = parse(#MethodBody, readFile(fileLoc)); methodHeader = parse(#MethodHeader, "void assertInvariants(Map\ map)"); From 170c97676a0bd23cf94ac338a3e66f5f234dddc7 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 16 Apr 2017 18:31:16 -0300 Subject: [PATCH 084/154] Assuring that a problem is ocurring in chaining&merging, rather than ProspectiveOperation. --- .../forloop/ProspectiveOperationTest.rsc | 20 ++++++++++++++++++- .../ProspectiveOperationTestResources.rsc | 13 ++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/refactor/forloop/ProspectiveOperationTest.rsc b/src/refactor/forloop/ProspectiveOperationTest.rsc index a2024b2..a237975 100644 --- a/src/refactor/forloop/ProspectiveOperationTest.rsc +++ b/src/refactor/forloop/ProspectiveOperationTest.rsc @@ -62,7 +62,7 @@ public test bool shouldHandleAnyMatch() { prospectiveOperations[1].operation == ANY_MATCH; } -public test bool shouldBreakAndChooseCorrectOperationsOnMultipleStatements() { +public test bool shouldSeparateAndChooseCorrectOperationsOnMultipleStatements() { tuple [set[MethodVar] vars, EnhancedForStatement loop] filterAndMergedForEach = filterAndMergedForEach(); prospectiveOperations = retrieveProspectiveOperations(filterAndMergedForEach.vars, filterAndMergedForEach.loop); @@ -76,4 +76,22 @@ public test bool shouldBreakAndChooseCorrectOperationsOnMultipleStatements() { prospectiveOperations[2].operation == FILTER && prospectiveOperations[3].stmt == "result.add(entry.getValue());" && prospectiveOperations[3].operation == FOR_EACH; +} + +public test bool shouldSeparateAndChooseCorrectOperationsOnMultipleMapsEndingWithAReduce() { + tuple [set[MethodVar] vars, EnhancedForStatement loop] multipleMapsAndEndingReducer = multipleMapsAndEndingReducer(); + + prospectiveOperations = retrieveProspectiveOperations(multipleMapsAndEndingReducer.vars, multipleMapsAndEndingReducer.loop); + + return size(prospectiveOperations) == 5 && + prospectiveOperations[0].stmt == "assertTrue(map.containsKey(entry.getKey()));" && + prospectiveOperations[0].operation == MAP && + prospectiveOperations[1].stmt == "assertTrue(map.containsValue(entry.getValue()));" && + prospectiveOperations[1].operation == MAP && + prospectiveOperations[2].stmt == "int expectedHash =\r\n (entry.getKey() == null ? 0 : entry.getKey().hashCode())\r\n ^ (entry.getValue() == null ? 0 : entry.getValue().hashCode());" && + prospectiveOperations[2].operation == MAP && + prospectiveOperations[3].stmt == "assertEquals(expectedHash, entry.hashCode());" && + prospectiveOperations[3].operation == MAP && + prospectiveOperations[4].stmt == "expectedEntrySetHash += expectedHash;" && + prospectiveOperations[4].operation == REDUCE; } \ No newline at end of file diff --git a/src/refactor/forloop/ProspectiveOperationTestResources.rsc b/src/refactor/forloop/ProspectiveOperationTestResources.rsc index 872eada..2023ae3 100644 --- a/src/refactor/forloop/ProspectiveOperationTestResources.rsc +++ b/src/refactor/forloop/ProspectiveOperationTestResources.rsc @@ -46,4 +46,17 @@ private set[MethodVar] filterAndMergedForEachVars() { methodHeader = parse(#MethodHeader, "List\ findReloadedContextMemoryLeaks()"); methodBody = parse(#MethodBody, "{\n List\ result = new ArrayList\();\n for (Map.Entry\ entry :\n childClassLoaders.entrySet())\n if(isValid(entry)) {\n ClassLoader cl = entry.getKey();\n if (!((WebappClassLoader)cl).isStart())\n result.add(entry.getValue());\n }\n return result;\n }"); return findLocalVariables(methodHeader, methodBody); +} + +public tuple [set[MethodVar] vars, EnhancedForStatement loop] multipleMapsAndEndingReducer() { + fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T2For2.java|; + EnhancedForStatement forStmt = parse(#EnhancedForStatement, readFile(fileForLoc)); + return ; +} + +private set[MethodVar] multipleMapsAndEndingReducerVars() { + fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T2.java|; + methodBody = parse(#MethodBody, readFile(fileLoc)); + methodHeader = parse(#MethodHeader, "void assertInvariants(Map\ map)"); + return findLocalVariables(methodHeader, methodBody); } \ No newline at end of file From 8f8f18625f8f65475f144d44d77e76b2a0163a57 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 16 Apr 2017 18:31:16 -0300 Subject: [PATCH 085/154] Not losing last operation in list when merging both operations that are not filters - Slices done wrong. --- src/refactor/forloop/ForLoopToFunctional.rsc | 44 ++++++++++---------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/refactor/forloop/ForLoopToFunctional.rsc index 5bda31b..ce918db 100644 --- a/src/refactor/forloop/ForLoopToFunctional.rsc +++ b/src/refactor/forloop/ForLoopToFunctional.rsc @@ -78,36 +78,34 @@ private list[ComposableProspectiveOperation] mergeIntoComposableOperations(list[ curr = composablePrOps[i]; prev = composablePrOps[i - 1]; if (!canBeChained(prev, curr)) { - if (canBeMerged(prev, curr)) { - opsSize = size(composablePrOps); - - if (isFilter(prev.prOp) || isFilter(curr.prOp)) { - while(opsSize > i) { - ComposableProspectiveOperation last = composablePrOps[opsSize - 1]; - ComposableProspectiveOperation beforeLast = composablePrOps[opsSize - 2]; - - merged = mergeComposablePrOps(beforeLast, last); - composablePrOps = slice(composablePrOps, 0, opsSize - 2) + merged; - - opsSize = size(composablePrOps); - } - } else { - merged = mergeComposablePrOps(prev, curr); + if(neitherCanBeMerged(prev, curr)) + throw "CanNotBeRefactored. Both operations are not mergeable"; + + opsSize = size(composablePrOps); + + if (isFilter(prev.prOp) || isFilter(curr.prOp)) { + while(opsSize > i) { + ComposableProspectiveOperation last = composablePrOps[opsSize - 1]; + ComposableProspectiveOperation beforeLast = composablePrOps[opsSize - 2]; + + merged = mergeComposablePrOps(beforeLast, last); + // XXX analyze if this "merging" is correct. probably not composablePrOps = slice(composablePrOps, 0, opsSize - 2) + merged; + + opsSize = size(composablePrOps); } + } else { + merged = mergeComposablePrOps(prev, curr); + composablePrOps = composablePrOps[0..i] + merged + composablePrOps[i + 1..]; } + } } return composablePrOps; } private bool canBeChained(ComposableProspectiveOperation prev, ComposableProspectiveOperation curr) { - currNeededVarsInPrevAvailabilitySet = isCurrNeededVarsInPrevAvailabilitySet(curr.neededVars, prev); - return size(curr.neededVars) <= 1 && currNeededVarsInPrevAvailabilitySet; -} - -private bool canBeMerged(ComposableProspectiveOperation prev, ComposableProspectiveOperation curr) { - return isMergeable(prev.prOp) && isMergeable(curr.prOp); + return size(curr.neededVars) <= 1 && isCurrNeededVarsInPrevAvailabilitySet(curr.neededVars, prev); } private bool isCurrNeededVarsInPrevAvailabilitySet(set[str] currNeededVars, ComposableProspectiveOperation prev) { @@ -117,6 +115,10 @@ private bool isCurrNeededVarsInPrevAvailabilitySet(set[str] currNeededVars, Comp return true; } +private bool neitherCanBeMerged(ComposableProspectiveOperation prev, ComposableProspectiveOperation curr) { + return !isMergeable(prev.prOp) || !isMergeable(curr.prOp); +} + private ComposableProspectiveOperation mergeComposablePrOps(ComposableProspectiveOperation prev, ComposableProspectiveOperation curr) { if (isFilter(prev.prOp)) return mergeIntoAnIfThenStmt(prev, curr); From 2c8bfba7273310ab4ea49a6a22a7d14c280f44e4 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 16 Apr 2017 18:31:16 -0300 Subject: [PATCH 086/154] Fixing slices again! When both operations are not filters. - Was happening in the example with multiple maps in sequence. - Also commenting the nestedLoops example. --- src/refactor/forloop/ForLoopToFunctional.rsc | 2 +- .../forloop/ForLoopToFunctionalTest.rsc | 31 +++++++++---------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/refactor/forloop/ForLoopToFunctional.rsc index ce918db..dd008b3 100644 --- a/src/refactor/forloop/ForLoopToFunctional.rsc +++ b/src/refactor/forloop/ForLoopToFunctional.rsc @@ -96,7 +96,7 @@ private list[ComposableProspectiveOperation] mergeIntoComposableOperations(list[ } } else { merged = mergeComposablePrOps(prev, curr); - composablePrOps = composablePrOps[0..i] + merged + composablePrOps[i + 1..]; + composablePrOps = composablePrOps[0..(i - 1)] + merged + composablePrOps[(i + 1)..]; } } diff --git a/src/refactor/forloop/ForLoopToFunctionalTest.rsc b/src/refactor/forloop/ForLoopToFunctionalTest.rsc index e982e61..519b313 100644 --- a/src/refactor/forloop/ForLoopToFunctionalTest.rsc +++ b/src/refactor/forloop/ForLoopToFunctionalTest.rsc @@ -43,24 +43,22 @@ public test bool reduceAsNotTheLastOperationShouldNotBeRefactored() { } // TODO nested loops needed to be changed in ProspectiveOperation -public test bool nestedLoops() { - fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/NestedLoops.java|; - methodBody = parse(#MethodBody, readFile(fileLoc)); - methodHeader = parse(#MethodHeader, "void testComplexBuilder()"); - set[MethodVar] methodVars = findLocalVariables(methodHeader, methodBody); - fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T2For.java|; - EnhancedForStatement forStmt = parse(#EnhancedForStatement, "for (Integer red : colorElem) {\n for (Integer green : colorElem) {\n for (Integer blue : colorElem) {\n webSafeColorsBuilder.add((red \<\< 16) + (green \<\< 8) + blue);\n }\n }\n }"); - VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "red"); - Expression collectionId = parse(#Expression, "colorElem"); - - refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); - println(refactoredStatement); - - return false; -} +//public test bool nestedLoops() { +// fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/NestedLoops.java|; +// methodBody = parse(#MethodBody, readFile(fileLoc)); +// methodHeader = parse(#MethodHeader, "void testComplexBuilder()"); +// set[MethodVar] methodVars = findLocalVariables(methodHeader, methodBody); +// fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T2For.java|; +// EnhancedForStatement forStmt = parse(#EnhancedForStatement, "for (Integer red : colorElem) {\n for (Integer green : colorElem) {\n for (Integer blue : colorElem) {\n webSafeColorsBuilder.add((red \<\< 16) + (green \<\< 8) + blue);\n }\n }\n }"); +// VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "red"); +// Expression collectionId = parse(#Expression, "colorElem"); +// +// refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); +// +// return false; +//} // not that useful of a test as it is now -// TODO test the prospective operations with this methodBody. public test bool shouldNotBreakWithExpressionStatementAsMapOperation() { fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T2.java|; methodBody = parse(#MethodBody, readFile(fileLoc)); @@ -72,7 +70,6 @@ public test bool shouldNotBreakWithExpressionStatementAsMapOperation() { Expression collectionId = parse(#Expression, "entrySet"); refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); - println(refactoredStatement); return !isEmpty(""); } \ No newline at end of file From 049f63319d193f50582c5846ba0c1a5d5ac2567f Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 16 Apr 2017 18:31:16 -0300 Subject: [PATCH 087/154] Rearranging map bodies when a return is needed. - A return is not needed when a variable declared in the previous statement is needed in the next statement. - We should consider the java DOCS. -- https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html#syntax -- If you specify a single expression there is no need to return it. - Need more tests to analyze. --- src/refactor/forloop/ForLoopToFunctional.rsc | 79 +++++++++++++++++-- .../forloop/ForLoopToFunctionalTest.rsc | 2 +- 2 files changed, 73 insertions(+), 8 deletions(-) diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/refactor/forloop/ForLoopToFunctional.rsc index dd008b3..28d57b5 100644 --- a/src/refactor/forloop/ForLoopToFunctional.rsc +++ b/src/refactor/forloop/ForLoopToFunctional.rsc @@ -47,6 +47,9 @@ public list[ComposableProspectiveOperation] retrieveComposableProspectiveOperati prospectiveOperations = retrieveProspectiveOperations(methodVars, forStmt); if (canOperationsBeRefactored(prospectiveOperations)) { composablePrOps = createComposableProspectiveOperationsWithVariableAvailability(prospectiveOperations, methodVars); + + composablePrOps = rearrangeMapBodiesIfNeeded(composablePrOps); + return mergeIntoComposableOperations(composablePrOps); } else // Throwing the exception is not the best option, but the easiest to implement right now @@ -207,6 +210,63 @@ private Block transformStatementsInBlock(list[str] stmts) { return parse(#Block, joined); } +private list[ComposableProspectiveOperation] rearrangeMapBodiesIfNeeded(list[ComposableProspectiveOperation] composablePrOps) { + listIndexes = [1 .. size(composablePrOps)]; + for (int i <- reverse(listIndexes)) { + curr = composablePrOps[i - 1]; + next = composablePrOps[i]; + if (isMap(curr.prOp)) + // Modifying in place + composablePrOps[i - 1] = rearrangeMapBody(curr, next.neededVars); + } + + return composablePrOps; +} + +private ComposableProspectiveOperation rearrangeMapBody(ComposableProspectiveOperation curr, set[str] nextNeededVars) { + prOp = curr.prOp; + + if(isLocalVariableDeclarationStatement(prOp.stmt)) + return rearrangeLocalVariableDeclarationMapBody(curr, nextNeededVars); + else if(isNumericLiteral(prOp.stmt)) + return curr; + else + return addReturnToMapBody(curr, nextNeededVars); +} + +private ComposableProspectiveOperation rearrangeLocalVariableDeclarationMapBody(ComposableProspectiveOperation curr, set[str] nextNeededVars) { + lvdl = parse(#LocalVariableDeclarationStatement, curr.prOp.stmt); + varName = ""; + visit(lvdl) { + case VariableDeclaratorId varId: varName = trim(unparse(varId)); + } + + if (varName notin nextNeededVars) + return addReturnToMapBody(curr, nextNeededVars); + + return curr; +} + +private bool isNumericLiteral(str stmt) { + // FIXME + return false; +} + +private ComposableProspectiveOperation addReturnToMapBody(ComposableProspectiveOperation curr, set[str] nextNeededVars) { + list[str] stmts = []; + if (isBlock(curr.prOp.stmt)) + stmts += retrieveAllStatementsFromBlock(curr.prOp.stmt); + else + stmts += curr.prOp.stmt; + + varName = isEmpty(nextNeededVars) ? "_item" : getOneFrom(nextNeededVars); + stmts += "return ;"; + block = transformStatementsInBlock(stmts); + + curr.prOp.stmt = unparse(block); + return curr; +} + private Statement buildFunctionalStatement(list[ComposableProspectiveOperation] composablePrOps, EnhancedForStatement forStmt, VariableDeclaratorId iteratedVarName, Expression collectionId) { if(size(composablePrOps) == 1 && isForEach(composablePrOps[0].prOp)) return buildStatementForOnlyOneForEach(composablePrOps[0].prOp, iteratedVarName, collectionId); @@ -266,17 +326,22 @@ private str retrieveLambdaBody(ProspectiveOperation prOp) { } private str getLambdaBodyForMap(str stmt) { + if(isExpressionStatement(stmt)) + return getLambdaBodyForMapWhenExpressionStatement(stmt); + else + return getLambdaBodyForMapWhenLocalVariableDeclaration(stmt); +} + +private bool isExpressionStatement(str stmt) { try { - expStmt = parse(#ExpressionStatement, stmt); - return getLambdaBodyForMapWhenExpressionStatement(expStmt); + parse(#ExpressionStatement, stmt); + return true; } catch: - return getLambdaBodyForMapWhenLocalVariableDeclaration(stmt); + return false; } -private str getLambdaBodyForMapWhenExpressionStatement(ExpressionStatement expStmt) { - stmtStr = unparse(expStmt); - stmtStr = removeEndingSemiCollonIfPresent(stmtStr); - return stmtStr; +private str getLambdaBodyForMapWhenExpressionStatement(str stmt) { + return removeEndingSemiCollonIfPresent(stmt); } private str removeEndingSemiCollonIfPresent(str stmt) { diff --git a/src/refactor/forloop/ForLoopToFunctionalTest.rsc b/src/refactor/forloop/ForLoopToFunctionalTest.rsc index 519b313..edda36c 100644 --- a/src/refactor/forloop/ForLoopToFunctionalTest.rsc +++ b/src/refactor/forloop/ForLoopToFunctionalTest.rsc @@ -58,7 +58,7 @@ public test bool reduceAsNotTheLastOperationShouldNotBeRefactored() { // return false; //} -// not that useful of a test as it is now +// TODO Complete the test with full output when REDUCE implemented public test bool shouldNotBreakWithExpressionStatementAsMapOperation() { fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T2.java|; methodBody = parse(#MethodBody, readFile(fileLoc)); From 7a1d9597adb9fbedca0c1bde8fd6dacd208b3a68 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 16 Apr 2017 18:31:16 -0300 Subject: [PATCH 088/154] UsedVariables working properly when operation is reduce. - Differing our implementation from Lambdaficator --- src/refactor/forloop/UsedVariables.rsc | 4 +--- src/refactor/forloop/UsedVariablesTest.rsc | 6 ++++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/refactor/forloop/UsedVariables.rsc b/src/refactor/forloop/UsedVariables.rsc index 14b05f5..5ab7656 100644 --- a/src/refactor/forloop/UsedVariables.rsc +++ b/src/refactor/forloop/UsedVariables.rsc @@ -11,9 +11,7 @@ import refactor::forloop::ProspectiveOperation; public set[str] retrieveUsedVariables(ProspectiveOperation prOp) { set[str] usedVariables = {}; - if (isReduce(prOp)) - return {}; - else if(isFilter(prOp)) + if(isFilter(prOp)) usedVariables += retrieveUsedVarsFromFilter(prOp.stmt); else if (isLocalVariableDeclarationStatement(prOp.stmt)) usedVariables += retrieveUsedVarsFromLocalVariableDeclarationStmt(prOp.stmt); diff --git a/src/refactor/forloop/UsedVariablesTest.rsc b/src/refactor/forloop/UsedVariablesTest.rsc index 44b9330..37a9162 100644 --- a/src/refactor/forloop/UsedVariablesTest.rsc +++ b/src/refactor/forloop/UsedVariablesTest.rsc @@ -74,10 +74,12 @@ public test bool ifThenStatement() { "entry" in usedVars; } -public test bool reduceShouldReturnEmpty() { +public test bool reduce() { prOp = prospectiveOperation("count += rule.getErrors().size();", REDUCE); usedVars = retrieveUsedVariables(prOp); - return size(usedVars) == 0; + return size(usedVars) == 2 && + "count" in usedVars && + "rule" in usedVars; } \ No newline at end of file From b127f7021530a19495d56d32bfce9fdcd096487d Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 16 Apr 2017 18:31:16 -0300 Subject: [PATCH 089/154] Implementation of reduce with compound assignment operator. --- src/MethodVar.rsc | 9 +++ src/refactor/forloop/ForLoopToFunctional.rsc | 79 ++++++++++++++++--- src/refactor/forloop/ProspectiveOperation.rsc | 1 + 3 files changed, 76 insertions(+), 13 deletions(-) diff --git a/src/MethodVar.rsc b/src/MethodVar.rsc index 0cda4c9..ccbcf0d 100644 --- a/src/MethodVar.rsc +++ b/src/MethodVar.rsc @@ -11,6 +11,15 @@ public bool isArray(MethodVar methodVar) { return methodVar.varType == "array"; } +public bool isString(MethodVar methodVar) { + return methodVar.varType == "String"; +} + +public bool isInteger(MethodVar methodVar) { + varType = methodVar.varType; + return varType == "int" || varType == "Integer"; +} + public bool isParameter(MethodVar methodVar) { return !methodVar.isParameter; } diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/refactor/forloop/ForLoopToFunctional.rsc index 28d57b5..6717d73 100644 --- a/src/refactor/forloop/ForLoopToFunctional.rsc +++ b/src/refactor/forloop/ForLoopToFunctional.rsc @@ -11,6 +11,7 @@ import refactor::forloop::ProspectiveOperation; import refactor::forloop::UsedVariables; import refactor::forloop::AvailableVariables; import refactor::forloop::OperationType; +import ParseTreeVisualization; public data ComposableProspectiveOperation = composableProspectiveOperation(ProspectiveOperation prOp, set[str] neededVars, set[str] availableVars); @@ -35,7 +36,7 @@ private MethodBody buildRefactoredMethodBody(set[MethodVar] methodVars, Enhanced public Statement buildRefactoredEnhancedFor(set[MethodVar] methodVars, EnhancedForStatement forStmt, MethodBody methodBody, VariableDeclaratorId iteratedVarName, Expression collectionId) { composablePrOps = retrieveComposableProspectiveOperations(methodVars, forStmt); - return buildFunctionalStatement(composablePrOps, forStmt, iteratedVarName, collectionId); + return buildFunctionalStatement(methodVars, composablePrOps, forStmt, iteratedVarName, collectionId); } MethodBody refactorToFunctional(MethodBody methodBody, Statement forStmt, Statement refactored) = top-down-break visit(methodBody) { @@ -242,8 +243,8 @@ private ComposableProspectiveOperation rearrangeLocalVariableDeclarationMapBody( } if (varName notin nextNeededVars) - return addReturnToMapBody(curr, nextNeededVars); - + return addReturnToMapBody(curr, nextNeededVars); + return curr; } @@ -258,7 +259,7 @@ private ComposableProspectiveOperation addReturnToMapBody(ComposableProspectiveO stmts += retrieveAllStatementsFromBlock(curr.prOp.stmt); else stmts += curr.prOp.stmt; - + varName = isEmpty(nextNeededVars) ? "_item" : getOneFrom(nextNeededVars); stmts += "return ;"; block = transformStatementsInBlock(stmts); @@ -267,14 +268,14 @@ private ComposableProspectiveOperation addReturnToMapBody(ComposableProspectiveO return curr; } -private Statement buildFunctionalStatement(list[ComposableProspectiveOperation] composablePrOps, EnhancedForStatement forStmt, VariableDeclaratorId iteratedVarName, Expression collectionId) { +private Statement buildFunctionalStatement(set[MethodVar] methodVars, list[ComposableProspectiveOperation] composablePrOps, EnhancedForStatement forStmt, VariableDeclaratorId iteratedVarName, Expression collectionId) { if(size(composablePrOps) == 1 && isForEach(composablePrOps[0].prOp)) return buildStatementForOnlyOneForEach(composablePrOps[0].prOp, iteratedVarName, collectionId); println(); println(forStmt); println("\nrefactored to:"); - return chainOperationsIntoStatement(composablePrOps, collectionId); + return chainOperationsIntoStatement(methodVars, composablePrOps, collectionId); } private Statement buildStatementForOnlyOneForEach(ProspectiveOperation prOp, VariableDeclaratorId iteratedVarName, Expression collectionId) { @@ -292,19 +293,22 @@ private VariableDeclaratorId trimEndingBlankSpace(VariableDeclaratorId varId) { return parse(#VariableDeclaratorId, trim(unparse(varId))); } -private Statement chainOperationsIntoStatement(list[ComposableProspectiveOperation] composablePrOps, Expression collectionId) { +private Statement chainOperationsIntoStatement(set[MethodVar] methodVars, list[ComposableProspectiveOperation] composablePrOps, Expression collectionId) { str chainStr = ".stream()"; for(composablePrOp <- composablePrOps) { - chainStr = "." + buildChainableOperation(composablePrOp); + chainStr = "." + buildChainableOperation(methodVars, composablePrOp); } println(chainStr); return parse(#Statement, ";"); } -private str buildChainableOperation(ComposableProspectiveOperation cPrOp) { +private str buildChainableOperation(set[MethodVar] methodVars, ComposableProspectiveOperation cPrOp) { prOp = cPrOp.prOp; + if(isReduce(prOp)) + return buildMapReduceOperation(methodVars, cPrOp); + return prOp.operation + "(" + retrieveLambdaParameterName(cPrOp) + " -\> " + retrieveLambdaBody(prOp) + ")"; } @@ -319,8 +323,6 @@ private str retrieveLambdaBody(ProspectiveOperation prOp) { else if(isMap(prOp)) { return getLambdaBodyForMap(prOp.stmt); } - else if(isReduce(prOp)) - return getLambdaBodyForReduce(prOp.stmt); else // isForEach(prOp) return unparse(transformIntoBlock(prOp.stmt)); } @@ -360,6 +362,57 @@ private str getLambdaBodyForMapWhenLocalVariableDeclaration(str stmt) { throw "No variable initializer in MAP"; } -private str getLambdaBodyForReduce(str stmt) { - return "needToImplementReduce()"; +// TODO check for prefix and postfix increment/decrement after ProspectiveOperation is working +private str buildMapReduceOperation(set[MethodVar] methodVars, ComposableProspectiveOperation cPrOp) { + mapOperation = ""; + reduceOperation = ""; + stmt = parse(#Statement, cPrOp.prOp.stmt); + bottom-up-break visit(stmt) { + case (Assignment) ` `: { + reducingVar = unparse(lhs); + + lambdaParamName = retrieveLambdaParameterName(cPrOp); + mapOperation = "map( -\> )"; + + reduceOperation += buildReduceOperation(methodVars, op, reducingVar); + } + } + + + + return "."; +} + +private str buildReduceOperation(set[MethodVar] methodVars, AssignmentOperator op, str reducingVar) { + reduceOperation = ""; + if("" == "+=") + reduceOperation = buildPlusAssignmentReduce(methodVars, reducingVar); + else + reduceOperation = buildSimpleExplicitReduce("", reducingVar); + + return reduceOperation; +} + +private str buildPlusAssignmentReduce(set[MethodVar] methodVars, str reducingVar) { + if(isString(methodVars, reducingVar)) + return "reduce(, String::concat)"; + else + if(isInteger(methodVars, reducingVar)) + return "reduce(, Integer::sum)"; + else + return buildSimpleExplicitReduce("+=", reducingVar); +} + +private bool isString(set[MethodVar] methodVars, str varName) { + var = findByName(methodVars, varName); + return isString(var); +} + +private bool isInteger(set[MethodVar] methodVars, str varName) { + var = findByName(methodVars, varName); + return isInteger(var); +} + +private str buildSimpleExplicitReduce(str op, str reducingVar) { + return "reduce(, (accumulator, _item) -\> accumulator _item)"; } \ No newline at end of file diff --git a/src/refactor/forloop/ProspectiveOperation.rsc b/src/refactor/forloop/ProspectiveOperation.rsc index 45528f9..b9ceba5 100644 --- a/src/refactor/forloop/ProspectiveOperation.rsc +++ b/src/refactor/forloop/ProspectiveOperation.rsc @@ -111,6 +111,7 @@ private ProspectiveOperation retrieveProspectiveOperationFromSingleStatement(Sta return prospectiveOperation(unparse(statement), MAP); } +// TODO implement prefix and postfix increment/decrement private bool isReducer(Statement statement) { visit (statement) { case (Assignment) ` `: From 8193c176d3acf7f345ede568bf966c4861358ba3 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 16 Apr 2017 18:31:16 -0300 Subject: [PATCH 090/154] Updating test with one reduce example --- src/refactor/forloop/ForLoopToFunctionalTest.rsc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/refactor/forloop/ForLoopToFunctionalTest.rsc b/src/refactor/forloop/ForLoopToFunctionalTest.rsc index edda36c..58ba331 100644 --- a/src/refactor/forloop/ForLoopToFunctionalTest.rsc +++ b/src/refactor/forloop/ForLoopToFunctionalTest.rsc @@ -59,7 +59,7 @@ public test bool reduceAsNotTheLastOperationShouldNotBeRefactored() { //} // TODO Complete the test with full output when REDUCE implemented -public test bool shouldNotBreakWithExpressionStatementAsMapOperation() { +public test bool shouldRefactorReduceWithCompoundPlusAssignmentOperator() { fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T2.java|; methodBody = parse(#MethodBody, readFile(fileLoc)); methodHeader = parse(#MethodHeader, "void assertInvariants(Map\ map)"); @@ -70,6 +70,6 @@ public test bool shouldNotBreakWithExpressionStatementAsMapOperation() { Expression collectionId = parse(#Expression, "entrySet"); refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); - - return !isEmpty(""); + + return unparse(refactoredStatement) == "entrySet.stream().map(entry -\> {\nassertTrue(map.containsKey(entry.getKey()));\nreturn entry;\n}).map(entry -\> {\nassertTrue(map.containsValue(entry.getValue()));\nreturn entry;\n}).map(entry -\> {\nint expectedHash =\r\n (entry.getKey() == null ? 0 : entry.getKey().hashCode())\r\n ^ (entry.getValue() == null ? 0 : entry.getValue().hashCode());\nassertEquals(expectedHash, entry.hashCode());\nreturn expectedHash;\n}).map(expectedHash -\> expectedHash).reduce(expectedEntrySetHash, Integer::sum);"; } \ No newline at end of file From d203cb9225798ed7f7865d2f01ee26eb696dad17 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 16 Apr 2017 18:31:16 -0300 Subject: [PATCH 091/154] EnhancedFor iterating on Iterable is not a collection => not refactorable. --- src/ForLoop.rsc | 2 +- src/MethodVar.rsc | 5 +++ .../forloop}/EnhancedLoopExpression.rsc | 10 +++--- .../forloop/EnhancedLoopExpressionTest.rsc | 32 +++++++++++++++++++ .../EnhancedForOnIterable.java | 15 +++++++++ 5 files changed, 58 insertions(+), 6 deletions(-) rename src/{ => refactor/forloop}/EnhancedLoopExpression.rsc (80%) create mode 100644 src/refactor/forloop/EnhancedLoopExpressionTest.rsc create mode 100644 testes/ForLoopToFunctional/EnhancedForOnIterable.java diff --git a/src/ForLoop.rsc b/src/ForLoop.rsc index 0c4ca30..e1ff20e 100644 --- a/src/ForLoop.rsc +++ b/src/ForLoop.rsc @@ -4,7 +4,7 @@ import IO; import lang::java::\syntax::Java18; import ParseTree; import LocalVariablesFinder; -import EnhancedLoopExpression; +import refactor::forloop::EnhancedLoopExpression; import refactor::forloop::ForLoopBodyReferences; import refactor::forloop::ForLoopToFunctional; import MethodVar; diff --git a/src/MethodVar.rsc b/src/MethodVar.rsc index ccbcf0d..d7dae03 100644 --- a/src/MethodVar.rsc +++ b/src/MethodVar.rsc @@ -20,6 +20,11 @@ public bool isInteger(MethodVar methodVar) { return varType == "int" || varType == "Integer"; } +public bool isIterable(MethodVar methodVar) { + varType = methodVar.varType; + return startsWith(varType, "Iterable"); +} + public bool isParameter(MethodVar methodVar) { return !methodVar.isParameter; } diff --git a/src/EnhancedLoopExpression.rsc b/src/refactor/forloop/EnhancedLoopExpression.rsc similarity index 80% rename from src/EnhancedLoopExpression.rsc rename to src/refactor/forloop/EnhancedLoopExpression.rsc index 71c71a5..e0b445c 100644 --- a/src/EnhancedLoopExpression.rsc +++ b/src/refactor/forloop/EnhancedLoopExpression.rsc @@ -1,16 +1,16 @@ -module EnhancedLoopExpression +module refactor::forloop::EnhancedLoopExpression import lang::java::\syntax::Java18; import ParseTree; import MethodVar; import String; -// XXX Only checking iterable variables defined in method (local and parameter(SOON) ) -// Need to verify class and instance variables too! (not that hard) +// XXX Only checking iterable variables defined in method (local and parameter) +// Need to verify class and instance variables too! // Doing the full check on a method call will be an entire new problem // example: for (Object rowKey : table.rowKeySet()) -// Relying on compiler to help finding if it an array or not +// Relying on compiler to help finding if it's an array or not // Compiler gives error if expression is not Array/Collection // Therefore we only check if the expression is an Array public bool isIteratingOnCollection(Expression exp, set[MethodVar] localVariables) { @@ -28,7 +28,7 @@ private bool isExpAnIdentifier(Expression exp) { private bool isIdentifierACollection(Expression exp, set[MethodVar] localVariables) { varName = unparse(exp); var = findByName(localVariables, varName); - return !isTypePlainArray(var); + return !isTypePlainArray(var) && !isIterable(var); } // FIXME diff --git a/src/refactor/forloop/EnhancedLoopExpressionTest.rsc b/src/refactor/forloop/EnhancedLoopExpressionTest.rsc new file mode 100644 index 0000000..fa34d7d --- /dev/null +++ b/src/refactor/forloop/EnhancedLoopExpressionTest.rsc @@ -0,0 +1,32 @@ +module refactor::forloop::EnhancedLoopExpressionTest + +import IO; +import lang::java::\syntax::Java18; +import ParseTree; +import MethodVar; +import LocalVariablesFinder; +import refactor::forloop::EnhancedLoopExpression; + +public test bool iterableShouldReturnFalse() { + params = paramsEnhancedForOnIterable(); + + return isIteratingOnCollection(params.exp, params.localVariables) == false; +} + +private tuple[Expression exp, set[MethodVar] localVariables] paramsEnhancedForOnIterable() { + tuple[MethodHeader methodHeader, MethodBody methodBody] method = getEnhancedForOnIterable(); + localVariables = findLocalVariables(method.methodHeader, method.methodBody); + // Making life easier + exp = parse(#Expression, "keys"); + return ; +} + +private tuple[MethodHeader methodHeader, MethodBody methodBody] getEnhancedForOnIterable() { + fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/EnhancedForOnIterable.java|; + methodDeclaration = parse(#MethodDeclaration, readFile(fileLoc)); + visit(methodDeclaration) { + case (MethodDeclaration) ` `: { + return ; + } + } +} \ No newline at end of file diff --git a/testes/ForLoopToFunctional/EnhancedForOnIterable.java b/testes/ForLoopToFunctional/EnhancedForOnIterable.java new file mode 100644 index 0000000..923243b --- /dev/null +++ b/testes/ForLoopToFunctional/EnhancedForOnIterable.java @@ -0,0 +1,15 @@ +@Override + public ImmutableMap getAllPresent(Iterable keys) { + Map result = Maps.newLinkedHashMap(); + for (Object key : keys) { + if (!result.containsKey(key)) { + @SuppressWarnings("unchecked") + K castKey = (K) key; + V value = getIfPresent(key); + if (value != null) { + result.put(castKey, value); + } + } + } + return ImmutableMap.copyOf(result); + } \ No newline at end of file From 16395ba7f8180ab35109aaec6f481e3d2ead3958 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 16 Apr 2017 18:31:16 -0300 Subject: [PATCH 092/154] Checking if loop returns a non literal boolean as pre condition to refactor --- src/ForLoop.rsc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/ForLoop.rsc b/src/ForLoop.rsc index e1ff20e..ab09248 100644 --- a/src/ForLoop.rsc +++ b/src/ForLoop.rsc @@ -69,13 +69,18 @@ private bool loopBodyPassConditions(Statement stmt) { returnCount = 0; visit(stmt) { case (ThrowStatement) `throw new ( );`: { - classNameStr = unparse(className); - if (classNameStr in checkedExceptionClasses) return false; + if ("" in checkedExceptionClasses) return false; } case (BreakStatement) `break ;`: return false; - case (ReturnStatement) `return ;`: returnCount += 1; + case (ReturnStatement) `return ;`: { + returnExpStr = unparse(returnExp); + if(returnExpStr != "true" || returnExpStr != "false") + return false; + + returnCount += 1; + } // labeled continue. case (ContinueStatement) `continue ;`: return false; From b475bf954e868b50f964aea211b113bd87c3b7ca Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 16 Apr 2017 18:31:16 -0300 Subject: [PATCH 093/154] Lambda bodies of Map Operations should be rearranged only AFTER merged. --- src/refactor/forloop/ForLoopToFunctional.rsc | 9 ++++----- .../forloop/ForLoopToFunctionalTest.rsc | 15 +++++++++++++++ .../ForWithMultiStatementMap.java | 7 +++++++ .../MethodBodyWithMultiStatementMap.java | 18 ++++++++++++++++++ 4 files changed, 44 insertions(+), 5 deletions(-) create mode 100644 testes/ForLoopToFunctional/ForWithMultiStatementMap.java create mode 100644 testes/ForLoopToFunctional/MethodBodyWithMultiStatementMap.java diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/refactor/forloop/ForLoopToFunctional.rsc index 6717d73..982ca3a 100644 --- a/src/refactor/forloop/ForLoopToFunctional.rsc +++ b/src/refactor/forloop/ForLoopToFunctional.rsc @@ -49,9 +49,9 @@ public list[ComposableProspectiveOperation] retrieveComposableProspectiveOperati if (canOperationsBeRefactored(prospectiveOperations)) { composablePrOps = createComposableProspectiveOperationsWithVariableAvailability(prospectiveOperations, methodVars); - composablePrOps = rearrangeMapBodiesIfNeeded(composablePrOps); + composablePrOps = mergeIntoComposableOperations(composablePrOps); - return mergeIntoComposableOperations(composablePrOps); + return rearrangeMapBodiesIfNeeded(composablePrOps); } else // Throwing the exception is not the best option, but the easiest to implement right now throw "CanNotBeRefactored"; @@ -226,13 +226,12 @@ private list[ComposableProspectiveOperation] rearrangeMapBodiesIfNeeded(list[Com private ComposableProspectiveOperation rearrangeMapBody(ComposableProspectiveOperation curr, set[str] nextNeededVars) { prOp = curr.prOp; - if(isLocalVariableDeclarationStatement(prOp.stmt)) return rearrangeLocalVariableDeclarationMapBody(curr, nextNeededVars); else if(isNumericLiteral(prOp.stmt)) return curr; else - return addReturnToMapBody(curr, nextNeededVars); + return addReturnToMapBody(curr, nextNeededVars); } private ComposableProspectiveOperation rearrangeLocalVariableDeclarationMapBody(ComposableProspectiveOperation curr, set[str] nextNeededVars) { @@ -255,7 +254,7 @@ private bool isNumericLiteral(str stmt) { private ComposableProspectiveOperation addReturnToMapBody(ComposableProspectiveOperation curr, set[str] nextNeededVars) { list[str] stmts = []; - if (isBlock(curr.prOp.stmt)) + if (isBlock(curr.prOp.stmt)) stmts += retrieveAllStatementsFromBlock(curr.prOp.stmt); else stmts += curr.prOp.stmt; diff --git a/src/refactor/forloop/ForLoopToFunctionalTest.rsc b/src/refactor/forloop/ForLoopToFunctionalTest.rsc index 58ba331..9d76ef0 100644 --- a/src/refactor/forloop/ForLoopToFunctionalTest.rsc +++ b/src/refactor/forloop/ForLoopToFunctionalTest.rsc @@ -72,4 +72,19 @@ public test bool shouldRefactorReduceWithCompoundPlusAssignmentOperator() { refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); return unparse(refactoredStatement) == "entrySet.stream().map(entry -\> {\nassertTrue(map.containsKey(entry.getKey()));\nreturn entry;\n}).map(entry -\> {\nassertTrue(map.containsValue(entry.getValue()));\nreturn entry;\n}).map(entry -\> {\nint expectedHash =\r\n (entry.getKey() == null ? 0 : entry.getKey().hashCode())\r\n ^ (entry.getValue() == null ? 0 : entry.getValue().hashCode());\nassertEquals(expectedHash, entry.hashCode());\nreturn expectedHash;\n}).map(expectedHash -\> expectedHash).reduce(expectedEntrySetHash, Integer::sum);"; +} + +public test bool shouldAddReturnToMapWithMoreThanOneStatement() { + methodBodyLoc = |project://rascal-Java8//testes/ForLoopToFunctional/MethodBodyWithMultiStatementMap.java|; + methodBody = parse(#MethodBody, readFile(methodBodyLoc)); + methodHeader = parse(#MethodHeader, "Iterable\\> findAll()"); + set[MethodVar] methodVars = findLocalVariables(methodHeader, methodBody); + fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/ForWithMultiStatementMap.java|; + EnhancedForStatement forStmt = parse(#EnhancedForStatement, readFile(fileForLoc)); + VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "v"); + Expression collectionId = parse(#Expression, "values"); + + refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); + + return unparse(refactoredStatement) == "values.stream().map(v -\> {\nString key = keysIt.next();\nMetric\ value = deserialize(key, v, this.zSetOperations.score(key));\nreturn value;\n}).filter(value -\> value != null).forEach(value -\> {\nresult.add(value);\n});"; } \ No newline at end of file diff --git a/testes/ForLoopToFunctional/ForWithMultiStatementMap.java b/testes/ForLoopToFunctional/ForWithMultiStatementMap.java new file mode 100644 index 0000000..ec01d61 --- /dev/null +++ b/testes/ForLoopToFunctional/ForWithMultiStatementMap.java @@ -0,0 +1,7 @@ +for (String v : values) { + String key = keysIt.next(); + Metric value = deserialize(key, v, this.zSetOperations.score(key)); + if (value != null) { + result.add(value); + } + } \ No newline at end of file diff --git a/testes/ForLoopToFunctional/MethodBodyWithMultiStatementMap.java b/testes/ForLoopToFunctional/MethodBodyWithMultiStatementMap.java new file mode 100644 index 0000000..3bc474c --- /dev/null +++ b/testes/ForLoopToFunctional/MethodBodyWithMultiStatementMap.java @@ -0,0 +1,18 @@ +{ + + // This set is sorted + Set keys = this.zSetOperations.range(0, -1); + Iterator keysIt = keys.iterator(); + + List> result = new ArrayList<>(keys.size()); + List values = this.redisOperations.opsForValue().multiGet(keys); + for (String v : values) { + String key = keysIt.next(); + Metric value = deserialize(key, v, this.zSetOperations.score(key)); + if (value != null) { + result.add(value); + } + } + return result; + + } \ No newline at end of file From 7daa4654d44a0a6cac7a0940459f92f11a266697 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 16 Apr 2017 18:31:16 -0300 Subject: [PATCH 094/154] Making sure we are refactoring correctly a map body with 3 statements. - Was wrong before. --- .../forloop/ForLoopToFunctionalTest.rsc | 15 +++++++++++++++ .../ForWith3StatementsMapBody.java | 9 +++++++++ .../MethodBodyWIth3StatementsMapBody.java | 17 +++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 testes/ForLoopToFunctional/ForWith3StatementsMapBody.java create mode 100644 testes/ForLoopToFunctional/MethodBodyWIth3StatementsMapBody.java diff --git a/src/refactor/forloop/ForLoopToFunctionalTest.rsc b/src/refactor/forloop/ForLoopToFunctionalTest.rsc index 9d76ef0..6de92de 100644 --- a/src/refactor/forloop/ForLoopToFunctionalTest.rsc +++ b/src/refactor/forloop/ForLoopToFunctionalTest.rsc @@ -87,4 +87,19 @@ public test bool shouldAddReturnToMapWithMoreThanOneStatement() { refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); return unparse(refactoredStatement) == "values.stream().map(v -\> {\nString key = keysIt.next();\nMetric\ value = deserialize(key, v, this.zSetOperations.score(key));\nreturn value;\n}).filter(value -\> value != null).forEach(value -\> {\nresult.add(value);\n});"; +} + +public test bool shouldAddCorrectReturnTo3StmtsMapBody() { + methodBodyLoc = |project://rascal-Java8//testes/ForLoopToFunctional/MethodBodyWIth3StatementsMapBody.java|; + methodBody = parse(#MethodBody, readFile(methodBodyLoc)); + methodHeader = parse(#MethodHeader, "void updateSnapshots(Collection\ snapshots)"); + set[MethodVar] methodVars = findLocalVariables(methodHeader, methodBody); + fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/ForWith3StatementsMapBody.java|; + EnhancedForStatement forStmt = parse(#EnhancedForStatement, readFile(fileForLoc)); + VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "snapshot"); + Expression collectionId = parse(#Expression, "snapshots"); + + refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); + + return unparse(refactoredStatement) == "snapshots.stream().map(snapshot -\> {\nFolderSnapshot previous = this.folders.get(snapshot.getFolder());\nupdated.put(snapshot.getFolder(), snapshot);\nChangedFiles changedFiles = previous.getChangedFiles(snapshot,\r\n this.triggerFilter);\nreturn changedFiles;\n}).filter(changedFiles -\> !changedFiles.getFiles().isEmpty()).forEach(changedFiles -\> {\nchangeSet.add(changedFiles);\n});"; } \ No newline at end of file diff --git a/testes/ForLoopToFunctional/ForWith3StatementsMapBody.java b/testes/ForLoopToFunctional/ForWith3StatementsMapBody.java new file mode 100644 index 0000000..fa1b4e7 --- /dev/null +++ b/testes/ForLoopToFunctional/ForWith3StatementsMapBody.java @@ -0,0 +1,9 @@ +for (FolderSnapshot snapshot : snapshots) { + FolderSnapshot previous = this.folders.get(snapshot.getFolder()); + updated.put(snapshot.getFolder(), snapshot); + ChangedFiles changedFiles = previous.getChangedFiles(snapshot, + this.triggerFilter); + if (!changedFiles.getFiles().isEmpty()) { + changeSet.add(changedFiles); + } + } \ No newline at end of file diff --git a/testes/ForLoopToFunctional/MethodBodyWIth3StatementsMapBody.java b/testes/ForLoopToFunctional/MethodBodyWIth3StatementsMapBody.java new file mode 100644 index 0000000..dc7d677 --- /dev/null +++ b/testes/ForLoopToFunctional/MethodBodyWIth3StatementsMapBody.java @@ -0,0 +1,17 @@ +{ + Map updated = new LinkedHashMap<>(); + Set changeSet = new LinkedHashSet<>(); + for (FolderSnapshot snapshot : snapshots) { + FolderSnapshot previous = this.folders.get(snapshot.getFolder()); + updated.put(snapshot.getFolder(), snapshot); + ChangedFiles changedFiles = previous.getChangedFiles(snapshot, + this.triggerFilter); + if (!changedFiles.getFiles().isEmpty()) { + changeSet.add(changedFiles); + } + } + if (!changeSet.isEmpty()) { + fireListeners(Collections.unmodifiableSet(changeSet)); + } + this.folders = updated; + } \ No newline at end of file From 154c4c50fa50dbf52df1cab494845c7d09954742 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 16 Apr 2017 18:31:16 -0300 Subject: [PATCH 095/154] Making the creation of methodVars more clear. - A builder pattern would be nice. --- src/LocalVariablesFinder.rsc | 18 +++++++++++++----- src/LocalVariablesFinderTestResources.rsc | 11 +++++++++++ 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/LocalVariablesFinder.rsc b/src/LocalVariablesFinder.rsc index 28c44a4..c4c1897 100644 --- a/src/LocalVariablesFinder.rsc +++ b/src/LocalVariablesFinder.rsc @@ -76,13 +76,17 @@ private set[MethodVar] findVariablesInsideBody(MethodBody methodBody) { private MethodVar createLocalMethodVar(bool isFinal, VariableDeclaratorId varId, UnannType varType) { name = trim(unparse(varId)); varTypeStr = trim(unparse(varType)); - return methodVar(isFinal, name, varTypeStr, false, false); + bool isParameter = false; + bool isDeclaredWithinLoop = false; + return methodVar(isFinal, name, varTypeStr, isParameter, isDeclaredWithinLoop); } private MethodVar createLocalMethodVarWithinLoop(bool isFinal, VariableDeclaratorId varId, UnannType varType) { name = trim(unparse(varId)); varTypeStr = trim(unparse(varType)); - return methodVar(isFinal, name, varTypeStr, false, true); + bool isParameter = false; + bool isDeclaredWithinLoop = true; + return methodVar(isFinal, name, varTypeStr, isParameter, isDeclaredWithinLoop); } private MethodVar createLocalMethodVar(bool isFinal, Identifier varId, UnannType varType, Dims? dims) { @@ -93,8 +97,10 @@ private MethodVar createLocalMethodVar(bool isFinal, Identifier varId, UnannType // Standarizing arrays to have varType == [] if(dimsStr == "[]") varTypeStr += "[]"; - - return methodVar(isFinal, name, varTypeStr, false, false); + + bool isParameter = false; + bool isDeclaredWithinLoop = false; + return methodVar(isFinal, name, varTypeStr, isParameter, isDeclaredWithinLoop); } private MethodVar createLocalMethodVarWithinLoop(bool isFinal, Identifier varId, UnannType varType, Dims? dims) { @@ -106,7 +112,9 @@ private MethodVar createLocalMethodVarWithinLoop(bool isFinal, Identifier varId, private MethodVar createLocalMethodVar(bool isFinal, VariableDeclaratorId varId, CatchType varType) { name = trim(unparse(varId)); varTypeStr = trim(unparse(varType)); - return methodVar(isFinal, name, varTypeStr, false, false); + bool isParameter = false; + bool isDeclaredWithinLoop = false; + return methodVar(isFinal, name, varTypeStr, isParameter, isDeclaredWithinLoop); } private bool figureIfIsFinal(VariableModifier* varMod) { diff --git a/src/LocalVariablesFinderTestResources.rsc b/src/LocalVariablesFinderTestResources.rsc index 00975e2..507839c 100644 --- a/src/LocalVariablesFinderTestResources.rsc +++ b/src/LocalVariablesFinderTestResources.rsc @@ -103,4 +103,15 @@ public MethodBody varsWithinTheLoopMethodBody() { fileLoc = |project://rascal-Java8//testes/localVariables/EnhancedForLoopVarsWithinLoop|; content = readFile(fileLoc); return parse(#MethodBody, content); +} + +public MethodHeader nonEffectiveFinalUsedInEnhancedForMethodHeader() { + header = "void set(String group, Collection\\> values)"; + return parse(#MethodHeader, header); +} + +public MethodBody nonEffectiveFinalUsedInEnhancedForMethodBody() { + fileLoc = |project://rascal-Java8//testes/localVariables/NonEffectiveFinalUsedInEnhancedFor|; + content = readFile(fileLoc); + return parse(#MethodBody, content); } \ No newline at end of file From 7bc19b58ddda655e14bd6848b61963325553fa99 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 16 Apr 2017 18:31:16 -0300 Subject: [PATCH 096/154] Identifying non effective final vars outside loop. More tests would be great. - Not the best code ever, but mainly due to the usage of Set. --- src/LocalVariablesFinder.rsc | 51 +++++++++++++++---- src/LocalVariablesFinderTest.rsc | 12 ++++- src/MethodVar.rsc | 7 +-- .../NonEffectiveFinalUsedInEnhancedFor | 14 +++++ 4 files changed, 68 insertions(+), 16 deletions(-) create mode 100644 testes/localVariables/NonEffectiveFinalUsedInEnhancedFor diff --git a/src/LocalVariablesFinder.rsc b/src/LocalVariablesFinder.rsc index c4c1897..4d7b3b7 100644 --- a/src/LocalVariablesFinder.rsc +++ b/src/LocalVariablesFinder.rsc @@ -32,14 +32,17 @@ private set[MethodVar] findVariablesAsParameters(MethodHeader methodHeader) { private MethodVar createParameterMethodVar(bool isFinal, VariableDeclaratorId varId, UnannType varType) { name = trim(unparse(varId)); varTypeStr = trim(unparse(varType)); - return methodVar(isFinal, name, varTypeStr, true, false); + bool isParameter = true; + bool isDeclaredWithinLoop = false; + bool isEffectiveFinal = true; + return methodVar(isFinal, name, varTypeStr, isParameter, isDeclaredWithinLoop, isEffectiveFinal); } -// XXX probably incorrect, ugly and not really DRY way of checking for vars within loop +// XXX ugly and not really DRY way of checking for vars within loop private set[MethodVar] findVariablesInsideBody(MethodBody methodBody) { set[MethodVar] methodVars = {}; + set[str] nonEffectiveFinalOutsideLoopVars = {}; set[str] varsWithinLoopNames = {}; - top-down visit(methodBody) { case EnhancedForStatement enhancedForStmt: { @@ -56,7 +59,9 @@ private set[MethodVar] findVariablesInsideBody(MethodBody methodBody) { } } } - + + + case (LocalVariableDeclaration) ` `: { visit(vdl) { case (VariableDeclaratorId) ` `: { @@ -66,11 +71,15 @@ private set[MethodVar] findVariablesInsideBody(MethodBody methodBody) { } } + case (Assignment) ` `: nonEffectiveFinalOutsideLoopVars += ""; + case(CatchFormalParameter) ` `: methodVars += createLocalMethodVar(figureIfIsFinal(varMod), varId, varType); } - return methodVars; + + + return addNonEffectiveFinalVars(methodVars, nonEffectiveFinalOutsideLoopVars); } private MethodVar createLocalMethodVar(bool isFinal, VariableDeclaratorId varId, UnannType varType) { @@ -78,7 +87,8 @@ private MethodVar createLocalMethodVar(bool isFinal, VariableDeclaratorId varId, varTypeStr = trim(unparse(varType)); bool isParameter = false; bool isDeclaredWithinLoop = false; - return methodVar(isFinal, name, varTypeStr, isParameter, isDeclaredWithinLoop); + bool isEffectiveFinal = true; + return methodVar(isFinal, name, varTypeStr, isParameter, isDeclaredWithinLoop, isEffectiveFinal); } private MethodVar createLocalMethodVarWithinLoop(bool isFinal, VariableDeclaratorId varId, UnannType varType) { @@ -86,7 +96,8 @@ private MethodVar createLocalMethodVarWithinLoop(bool isFinal, VariableDeclarato varTypeStr = trim(unparse(varType)); bool isParameter = false; bool isDeclaredWithinLoop = true; - return methodVar(isFinal, name, varTypeStr, isParameter, isDeclaredWithinLoop); + bool isEffectiveFinal = true; + return methodVar(isFinal, name, varTypeStr, isParameter, isDeclaredWithinLoop, isEffectiveFinal); } private MethodVar createLocalMethodVar(bool isFinal, Identifier varId, UnannType varType, Dims? dims) { @@ -100,7 +111,8 @@ private MethodVar createLocalMethodVar(bool isFinal, Identifier varId, UnannType bool isParameter = false; bool isDeclaredWithinLoop = false; - return methodVar(isFinal, name, varTypeStr, isParameter, isDeclaredWithinLoop); + bool isEffectiveFinal = true; + return methodVar(isFinal, name, varTypeStr, isParameter, isDeclaredWithinLoop, isEffectiveFinal); } private MethodVar createLocalMethodVarWithinLoop(bool isFinal, Identifier varId, UnannType varType, Dims? dims) { @@ -114,11 +126,32 @@ private MethodVar createLocalMethodVar(bool isFinal, VariableDeclaratorId varId, varTypeStr = trim(unparse(varType)); bool isParameter = false; bool isDeclaredWithinLoop = false; - return methodVar(isFinal, name, varTypeStr, isParameter, isDeclaredWithinLoop); + bool isEffectiveFinal = true; + return methodVar(isFinal, name, varTypeStr, isParameter, isDeclaredWithinLoop, isEffectiveFinal); } private bool figureIfIsFinal(VariableModifier* varMod) { if ("" := "final") return true; return false; +} + + +// XXX ugly handling of non effective finals (mainly due to usage of sets) +private set[MethodVar] addNonEffectiveFinalVars(set[MethodVar] methodVars, set[str] nonEffectiveFinalOutsideLoopVars) { + completeMethodVars = methodVars; + for (methodVar <- methodVars) { + for (nonEffectiveFinalVar <- nonEffectiveFinalOutsideLoopVars) { + if (methodVar.name == nonEffectiveFinalVar) { + completeMethodVars -= methodVar; + completeMethodVars += cloneMethodVarAsNonEffectiveFinal(methodVar); + } + } + } + return completeMethodVars; +} + +private MethodVar cloneMethodVarAsNonEffectiveFinal(MethodVar m) { + bool isEffectiveFinal = false; + return methodVar(m.isFinal, m.name, m.varType, m.isParameter, m.isDeclaredWithinLoop, isEffectiveFinal); } \ No newline at end of file diff --git a/src/LocalVariablesFinderTest.rsc b/src/LocalVariablesFinderTest.rsc index a29e6cc..d80271e 100644 --- a/src/LocalVariablesFinderTest.rsc +++ b/src/LocalVariablesFinderTest.rsc @@ -120,7 +120,7 @@ public test bool shouldReturnNonFinalSingleParameter() { return size(nonLocals) == 1 && !var.isFinal && var.isParameter; } -public test bool shouldReturnFinalSingleParamater() { +public test bool shouldReturnFinalSingleParameter() { methodHeader = finalSingleParameterMethodHeader(); methodBody = emptyMethodBody(); @@ -192,3 +192,13 @@ public test bool shouldReturnCorrectVarsNotDeclaredWithinLoop() { "localVarNotWithinLoopAgain" in notWithinLoopNames && "notWithinLoopAfterLoop" in notWithinLoopNames; } + +public test bool shouldIdentifyNonEffectiveFinalVar() { + methodHeader = nonEffectiveFinalUsedInEnhancedForMethodHeader(); + methodBody = nonEffectiveFinalUsedInEnhancedForMethodBody(); + + vars = findLocalVariables(methodHeader, methodBody); + nonEffectiveFinalVar = findByName(vars, "prefix"); + + return !isEffectiveFinal(nonEffectiveFinalVar); +} diff --git a/src/MethodVar.rsc b/src/MethodVar.rsc index d7dae03..48f097d 100644 --- a/src/MethodVar.rsc +++ b/src/MethodVar.rsc @@ -4,7 +4,6 @@ import Set; import String; // TODO Review if using a Set is the best choice. Probably not. -public data MethodVar = methodVar(bool isFinal, str name, str varType, bool isParameter, bool isDeclaredWithinLoop); public data MethodVar = methodVar(bool isFinal, str name, str varType, bool isParameter, bool isDeclaredWithinLoop, bool isEffectiveFinal); public bool isArray(MethodVar methodVar) { @@ -85,10 +84,6 @@ public set[str] retrieveNotDeclaredWithinLoopNames(set[MethodVar] methodVars) { return { var.name | MethodVar var <- methodVars, !var.isDeclaredWithinLoop }; } -// FIXME public bool isEffectiveFinal(MethodVar methodVar) { - try - return methodVar.isFinal || methodVar.isEffectiveFinal; - catch NoSuchField("isEffectiveFinal"): - return methodVar.isFinal; + return methodVar.isFinal || methodVar.isEffectiveFinal; } \ No newline at end of file diff --git a/testes/localVariables/NonEffectiveFinalUsedInEnhancedFor b/testes/localVariables/NonEffectiveFinalUsedInEnhancedFor new file mode 100644 index 0000000..387209d --- /dev/null +++ b/testes/localVariables/NonEffectiveFinalUsedInEnhancedFor @@ -0,0 +1,14 @@ +{ + String prefix = group; + if (!prefix.endsWith(".")) { + prefix = prefix + "."; + } + for (Metric metric : values) { + if (!metric.getName().startsWith(prefix)) { + metric = new Metric(prefix + metric.getName(), metric.getValue(), + metric.getTimestamp()); + } + this.repository.set(metric); + } + this.groups.add(group); + } \ No newline at end of file From 4f573be05ce0684597b1fd6ba3bd8c166c9f120b Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 27 Apr 2017 00:07:51 -0300 Subject: [PATCH 097/154] Retrieving class fields from CompilationUnit. - Fields are effective final for the purpose of the refactor. -- Tested in loco on NetBeans. --- src/refactor/forloop/ClassFieldsFinder.rsc | 62 +++++++++++++++++++ .../forloop/ClassFieldsFinderTest.rsc | 22 +++++++ testes/localVariables/ClassWithFields.java | 18 ++++++ 3 files changed, 102 insertions(+) create mode 100644 src/refactor/forloop/ClassFieldsFinder.rsc create mode 100644 src/refactor/forloop/ClassFieldsFinderTest.rsc create mode 100644 testes/localVariables/ClassWithFields.java diff --git a/src/refactor/forloop/ClassFieldsFinder.rsc b/src/refactor/forloop/ClassFieldsFinder.rsc new file mode 100644 index 0000000..18956c9 --- /dev/null +++ b/src/refactor/forloop/ClassFieldsFinder.rsc @@ -0,0 +1,62 @@ +module refactor::forloop::ClassFieldsFinder + +import IO; +import lang::java::\syntax::Java18; +import ParseTree; +import String; +import Set; +import MethodVar; + +// M3 isn't very helpful here. +// We can't really get type + var name +public set[MethodVar] findClassFields(CompilationUnit unit) { + return findCurrentClassFields(unit); +} + +private set[MethodVar] findCurrentClassFields(CompilationUnit unit) { + classFields = {}; + + // syntax FieldDeclaration = fieldDeclaration: FieldModifier* UnannType VariableDeclaratorList ";"+ ; + + visit(unit) { + case (FieldDeclaration) ` ;`: { + visit(vdl) { + case (VariableDeclaratorId) ` `: + classFields += createEffectiveFinalVar(figureIfIsFinal(varMod), varId, varType, dims); + + } + } + } + + return classFields; +} + +private bool figureIfIsFinal(FieldModifier* varMod) { + return contains("", "final"); +} + +// Class fields are effectively final for the purpose of ForLoopToFunctional +private MethodVar createEffectiveFinalVar(bool isFinal, Identifier varId, UnannType varType, Dims? dims) { + name = trim(unparse(varId)); + varTypeStr = trim(unparse(varType)); + dimsStr = trim(unparse(dims)); + + // Standarizing arrays to have varType == [] + if(dimsStr == "[]") + varTypeStr += "[]"; + + bool isParameter = false; + bool isDeclaredWithinLoop = false; + bool isEffectiveFinal = true; + return methodVar(isFinal, name, varTypeStr, isParameter, isDeclaredWithinLoop, isEffectiveFinal); +} + +// XXX hard +private set[MethodVar] findInheritedFields() { + return {}; +} + +// XXX hard +private set[MethodVar] findImportedFields() { + return {}; +} \ No newline at end of file diff --git a/src/refactor/forloop/ClassFieldsFinderTest.rsc b/src/refactor/forloop/ClassFieldsFinderTest.rsc new file mode 100644 index 0000000..8afffd0 --- /dev/null +++ b/src/refactor/forloop/ClassFieldsFinderTest.rsc @@ -0,0 +1,22 @@ +module refactor::forloop::ClassFieldsFinderTest + +import lang::java::\syntax::Java18; +import ParseTree; +import refactor::forloop::ClassFieldsFinder; +import MethodVar; +import Set; + +public test bool shouldReturnAllClassFields() { + fileLoc = |project://rascal-Java8//testes/localVariables/ClassWithFields.java|; + unit = parse(#CompilationUnit, fileLoc); + + classFields = findClassFields(unit); + + return size(classFields) == 6 && + methodVar(true,"NAME","String",false,false,true) in classFields && + methodVar(false,"name","String",false,false,true) in classFields && + methodVar(true,"NUMBERS_SIZE","int",false,false,true) in classFields && + methodVar(false,"objArray2","Object[]",false,false,true) in classFields && + methodVar(false,"numbers","List\",false,false,true) in classFields && + methodVar(false,"objArray","Object[]",false,false,true) in classFields; +} \ No newline at end of file diff --git a/testes/localVariables/ClassWithFields.java b/testes/localVariables/ClassWithFields.java new file mode 100644 index 0000000..33bd7b7 --- /dev/null +++ b/testes/localVariables/ClassWithFields.java @@ -0,0 +1,18 @@ +import java.util.ArrayList; +import java.util.List; + +public class ClassWithFields { + + public static final String NAME = "Classe"; + + private static final int NUMBERS_SIZE = 10; + + private String name; + + private List numbers = new ArrayList<>(NUMBERS_SIZE); + + private Object[] objArray; + + private Object objArray2[]; + +} \ No newline at end of file From e3f61aa7932b9913cd79994ddcddda0ca21cf2e2 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 27 Apr 2017 00:08:36 -0300 Subject: [PATCH 098/154] Removing unecessary stuff from LocalVariablesFinder --- src/LocalVariablesFinder.rsc | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/src/LocalVariablesFinder.rsc b/src/LocalVariablesFinder.rsc index 4d7b3b7..7c3bd92 100644 --- a/src/LocalVariablesFinder.rsc +++ b/src/LocalVariablesFinder.rsc @@ -1,23 +1,14 @@ module LocalVariablesFinder -import Set; +import IO; import lang::java::\syntax::Java18; -import String; import ParseTree; -import IO; +import Set; +import String; import MethodVar; -import ParseTreeVisualization; - -// syntax LocalVariableDeclarationStatement = LocalVariableDeclaration ";"+ ; -// syntax LocalVariableDeclaration = VariableModifier* UnannType VariableDeclaratorList ; -// syntax VariableDeclaratorList = variableDeclaratorList: {VariableDeclarator ","}+ ; -// syntax VariableDeclarator = variableDeclarator: VariableDeclaratorId ("=" VariableInitializer)? ; public set[MethodVar] findLocalVariables(MethodHeader methodHeader, MethodBody methodBody) { - set[MethodVar] methodVars = {}; - methodVars += findVariablesAsParameters(methodHeader); - methodVars += findVariablesInsideBody(methodBody); - return methodVars; + return findVariablesAsParameters(methodHeader) + findVariablesInsideBody(methodBody); } private set[MethodVar] findVariablesAsParameters(MethodHeader methodHeader) { @@ -29,6 +20,10 @@ private set[MethodVar] findVariablesAsParameters(MethodHeader methodHeader) { return methodVars; } +private bool figureIfIsFinal(VariableModifier* varMod) { + return "" := "final"; +} + private MethodVar createParameterMethodVar(bool isFinal, VariableDeclaratorId varId, UnannType varType) { name = trim(unparse(varId)); varTypeStr = trim(unparse(varType)); @@ -130,13 +125,6 @@ private MethodVar createLocalMethodVar(bool isFinal, VariableDeclaratorId varId, return methodVar(isFinal, name, varTypeStr, isParameter, isDeclaredWithinLoop, isEffectiveFinal); } -private bool figureIfIsFinal(VariableModifier* varMod) { - if ("" := "final") - return true; - return false; -} - - // XXX ugly handling of non effective finals (mainly due to usage of sets) private set[MethodVar] addNonEffectiveFinalVars(set[MethodVar] methodVars, set[str] nonEffectiveFinalOutsideLoopVars) { completeMethodVars = methodVars; From c69060ccb08fb25e8a319fa9cb660cf921dd5692 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 27 Apr 2017 00:33:16 -0300 Subject: [PATCH 099/154] ForLoop using classFields to check for preconditions + Optimization attempt - If a method had more than one for, was looking for its variables N times - Trying to only compute class fields once, and only if it has at least one Enhanced For. --- src/ForLoop.rsc | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/src/ForLoop.rsc b/src/ForLoop.rsc index ab09248..15ea01b 100644 --- a/src/ForLoop.rsc +++ b/src/ForLoop.rsc @@ -7,16 +7,22 @@ import LocalVariablesFinder; import refactor::forloop::EnhancedLoopExpression; import refactor::forloop::ForLoopBodyReferences; import refactor::forloop::ForLoopToFunctional; +import refactor::forloop::ClassFieldsFinder; import MethodVar; private set[str] checkedExceptionClasses; +private set[MethodVar] currentClassFields = {}; + +private bool alreadyComputedClassFields; + public void findForLoops(list[loc] locs, set[str] checkedExceptions) { checkedExceptionClasses = checkedExceptions; for(fileLoc <- locs) { javaFileContent = readFile(fileLoc); try { unit = parse(#CompilationUnit, javaFileContent); + alreadyComputedClassFields = false; lookForForStatements(unit); } catch: continue; @@ -26,28 +32,41 @@ public void findForLoops(list[loc] locs, set[str] checkedExceptions) { private void lookForForStatements(CompilationUnit unit) { visit(unit) { case MethodDeclaration methodDeclaration: - lookForEnhancedForStatementsInMethod(methodDeclaration); + lookForEnhancedForStatementsInMethod(unit, methodDeclaration); } } -private void lookForEnhancedForStatementsInMethod(MethodDeclaration methodDeclaration) { +private void lookForEnhancedForStatementsInMethod(CompilationUnit unit, MethodDeclaration methodDeclaration) { visit(methodDeclaration) { case (MethodDeclaration) ` `: - lookForEnhancedForStatementsInMethodBody(methodHeader, methodBody); + lookForEnhancedForStatementsInMethodBody(unit, methodHeader, methodBody); } } -private void lookForEnhancedForStatementsInMethodBody(MethodHeader methodHeader, MethodBody methodBody) { +private void lookForEnhancedForStatementsInMethodBody(CompilationUnit unit, MethodHeader methodHeader, MethodBody methodBody) { + set[MethodVar] availableVars = {}; + alreadyComputedCurrentMethodAvailableVars = false; + visit(methodBody) { case EnhancedForStatement forStmt: { + + if(!alreadyComputedClassFields) { + currentClassFields = findClassFields(unit); + alreadyComputedClassFields = true; + } + + if(!alreadyComputedCurrentMethodAvailableVars) { + availableVars = currentClassFields + findLocalVariables(methodHeader, methodBody); + alreadyComputedAvailableVars = true; + } + visit(forStmt) { case EnhancedForStatement enhancedForStmt: { visit(enhancedForStmt) { case (EnhancedForStatement) `for ( : ) `: { - methodLocalVariables = findLocalVariables(methodHeader, methodBody); - if(isLoopRefactorable(methodLocalVariables, collectionId, stmt)) - // TODO Create data structure - refactorEnhancedToFunctional(methodLocalVariables, enhancedForStmt, methodBody, iteratedVarName, collectionId); + + if(isLoopRefactorable(availableVars, collectionId, stmt)) + refactorEnhancedToFunctional(availableVars, enhancedForStmt, methodBody, iteratedVarName, collectionId); } } } From 3ccb03003a1f877d918a0e56cdac6f3ca55970e1 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 3 May 2017 22:50:29 -0300 Subject: [PATCH 100/154] ForLoopToFunctional not catching exception. - It was making harder to count how many refactors we did. --- src/refactor/forloop/ForLoopToFunctional.rsc | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/refactor/forloop/ForLoopToFunctional.rsc index 982ca3a..34ff805 100644 --- a/src/refactor/forloop/ForLoopToFunctional.rsc +++ b/src/refactor/forloop/ForLoopToFunctional.rsc @@ -16,21 +16,13 @@ import ParseTreeVisualization; public data ComposableProspectiveOperation = composableProspectiveOperation(ProspectiveOperation prOp, set[str] neededVars, set[str] availableVars); public MethodBody refactorEnhancedToFunctional(set[MethodVar] methodVars, EnhancedForStatement forStmt, MethodBody methodBody, VariableDeclaratorId iteratedVarName, Expression collectionId) { - try - return buildRefactoredMethodBody(methodVars, forStmt, methodBody, iteratedVarName, collectionId); - catch: - return methodBody; + return buildRefactoredMethodBody(methodVars, forStmt, methodBody, iteratedVarName, collectionId); } private MethodBody buildRefactoredMethodBody(set[MethodVar] methodVars, EnhancedForStatement forStmt, MethodBody methodBody, VariableDeclaratorId iteratedVarName, Expression collectionId) { refactored = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); forStatement = parse(#Statement, unparse(forStmt)); refactoredMethodBody = refactorToFunctional(methodBody, forStatement, refactored); - //println("\n --- APPLYING REFACTOR ---"); - //println(forStmt); - //println("refactored to:"); - //println(refactored); - return refactoredMethodBody; } @@ -271,9 +263,6 @@ private Statement buildFunctionalStatement(set[MethodVar] methodVars, list[Compo if(size(composablePrOps) == 1 && isForEach(composablePrOps[0].prOp)) return buildStatementForOnlyOneForEach(composablePrOps[0].prOp, iteratedVarName, collectionId); - println(); - println(forStmt); - println("\nrefactored to:"); return chainOperationsIntoStatement(methodVars, composablePrOps, collectionId); } @@ -299,7 +288,6 @@ private Statement chainOperationsIntoStatement(set[MethodVar] methodVars, list[C chainStr = "." + buildChainableOperation(methodVars, composablePrOp); } - println(chainStr); return parse(#Statement, ";"); } From 87d24437f5cdc8667172a2fd6392cd1dadbdb55f Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 3 May 2017 22:52:23 -0300 Subject: [PATCH 101/154] Counting and showing refactors in ForLoop --- src/ForLoop.rsc | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/ForLoop.rsc b/src/ForLoop.rsc index 15ea01b..c451e0a 100644 --- a/src/ForLoop.rsc +++ b/src/ForLoop.rsc @@ -9,6 +9,7 @@ import refactor::forloop::ForLoopBodyReferences; import refactor::forloop::ForLoopToFunctional; import refactor::forloop::ClassFieldsFinder; import MethodVar; +import util::Math; private set[str] checkedExceptionClasses; @@ -16,7 +17,10 @@ private set[MethodVar] currentClassFields = {}; private bool alreadyComputedClassFields; +private int refactoredCount = 0; + public void findForLoops(list[loc] locs, set[str] checkedExceptions) { + refactoredCount = 0; checkedExceptionClasses = checkedExceptions; for(fileLoc <- locs) { javaFileContent = readFile(fileLoc); @@ -27,6 +31,7 @@ public void findForLoops(list[loc] locs, set[str] checkedExceptions) { } catch: continue; } + println("refactoredCount: " + toString(refactoredCount)); } private void lookForForStatements(CompilationUnit unit) { @@ -47,7 +52,7 @@ private void lookForEnhancedForStatementsInMethodBody(CompilationUnit unit, Meth set[MethodVar] availableVars = {}; alreadyComputedCurrentMethodAvailableVars = false; - visit(methodBody) { + top-down visit(methodBody) { case EnhancedForStatement forStmt: { if(!alreadyComputedClassFields) { @@ -60,13 +65,26 @@ private void lookForEnhancedForStatementsInMethodBody(CompilationUnit unit, Meth alreadyComputedAvailableVars = true; } - visit(forStmt) { + top-down visit(forStmt) { case EnhancedForStatement enhancedForStmt: { visit(enhancedForStmt) { case (EnhancedForStatement) `for ( : ) `: { - if(isLoopRefactorable(availableVars, collectionId, stmt)) - refactorEnhancedToFunctional(availableVars, enhancedForStmt, methodBody, iteratedVarName, collectionId); + if(isLoopRefactorable(availableVars, collectionId, stmt)) { + + try { + refactored = refactorEnhancedToFunctional(availableVars, enhancedForStmt, methodBody, iteratedVarName, collectionId); + refactoredCount += 1; + println("refactored: " + toString(refactoredCount)); + println(enhancedForStmt); + println("---"); + println(refactored); + println(); + } catch: { + continue; + } + + } } } } From f5d05c25c5215928651a5a62def278b67c02e0d7 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 4 May 2017 00:33:51 -0300 Subject: [PATCH 102/154] In case there is a duplicated localVariable and classField, retaining the local var. - Note sure when 'this.varName' is called. Probably will break. - As it probably breaks when a variable is declared more than once in inner scopes. --- src/ForLoop.rsc | 3 ++- src/LocalVariablesFinderTest.rsc | 10 +++++++ src/LocalVariablesFinderTestResources.rsc | 25 ++++++++++------- src/MethodVar.rsc | 12 +++++++++ .../forloop/EnhancedLoopExpression.rsc | 4 ++- .../forloop/EnhancedLoopExpressionTest.rsc | 27 +++++++++++++++++++ .../IterableParameterMethodBody | 9 +++++++ 7 files changed, 78 insertions(+), 12 deletions(-) create mode 100644 testes/localVariables/IterableParameterMethodBody diff --git a/src/ForLoop.rsc b/src/ForLoop.rsc index c451e0a..2327bae 100644 --- a/src/ForLoop.rsc +++ b/src/ForLoop.rsc @@ -61,7 +61,8 @@ private void lookForEnhancedForStatementsInMethodBody(CompilationUnit unit, Meth } if(!alreadyComputedCurrentMethodAvailableVars) { - availableVars = currentClassFields + findLocalVariables(methodHeader, methodBody); + methodVars = findLocalVariables(methodHeader, methodBody); + availableVars = retainLocalVariablesIfDuplicates(currentClassFields, methodVars); alreadyComputedAvailableVars = true; } diff --git a/src/LocalVariablesFinderTest.rsc b/src/LocalVariablesFinderTest.rsc index d80271e..b66c875 100644 --- a/src/LocalVariablesFinderTest.rsc +++ b/src/LocalVariablesFinderTest.rsc @@ -202,3 +202,13 @@ public test bool shouldIdentifyNonEffectiveFinalVar() { return !isEffectiveFinal(nonEffectiveFinalVar); } + +public test bool shouldParseCorrectTypeFromIterableParameter() { + methodHeader = iterableParameterMethodHeader(); + methodBody = iterableParameterMethodBody(); + + vars = findLocalVariables(methodHeader, methodBody); + iterableParam = findByName(vars, "types"); + + return iterableParam.varType == "Iterable\"; +} diff --git a/src/LocalVariablesFinderTestResources.rsc b/src/LocalVariablesFinderTestResources.rsc index 507839c..fa7ab14 100644 --- a/src/LocalVariablesFinderTestResources.rsc +++ b/src/LocalVariablesFinderTestResources.rsc @@ -37,20 +37,17 @@ public MethodBody emptyMethodBody() { public MethodBody enhancedForLoopFinalVarDecl() { fileLoc = |project://rascal-Java8//testes/localVariables/EnhancedForLoopFinalVarDecl|; - content = readFile(fileLoc); - return parse(#MethodBody, content); + return parse(#MethodBody, readFile(fileLoc)); } public MethodBody enhancedForLoopWithException() { fileLoc = |project://rascal-Java8//testes/localVariables/EnhancedForLoopWithException|; - content = readFile(fileLoc); - return parse(#MethodBody, content); + return parse(#MethodBody, readFile(fileLoc)); } public MethodBody arrayVariables() { fileLoc = |project://rascal-Java8//testes/localVariables/MultiplePlainArrayDeclarations|; - content = readFile(fileLoc); - return parse(#MethodBody, content); + return parse(#MethodBody, readFile(fileLoc)); } public set[MethodVar] getEncouragedArrays(set[MethodVar] vars) { @@ -101,8 +98,7 @@ public MethodHeader varsWithinTheLoopMethodHeader() { public MethodBody varsWithinTheLoopMethodBody() { fileLoc = |project://rascal-Java8//testes/localVariables/EnhancedForLoopVarsWithinLoop|; - content = readFile(fileLoc); - return parse(#MethodBody, content); + return parse(#MethodBody, readFile(fileLoc)); } public MethodHeader nonEffectiveFinalUsedInEnhancedForMethodHeader() { @@ -112,6 +108,15 @@ public MethodHeader nonEffectiveFinalUsedInEnhancedForMethodHeader() { public MethodBody nonEffectiveFinalUsedInEnhancedForMethodBody() { fileLoc = |project://rascal-Java8//testes/localVariables/NonEffectiveFinalUsedInEnhancedFor|; - content = readFile(fileLoc); - return parse(#MethodBody, content); + return parse(#MethodBody, readFile(fileLoc)); +} + +public MethodHeader iterableParameterMethodHeader() { + header = "ImmutableList\ collectTypes(Iterable\ types)"; + return parse(#MethodHeader, header); +} + +public MethodBody iterableParameterMethodBody() { + fileLoc = |project://rascal-Java8//testes/localVariables/IterableParameterMethodBody|; + return parse(#MethodBody, readFile(fileLoc)); } \ No newline at end of file diff --git a/src/MethodVar.rsc b/src/MethodVar.rsc index 48f097d..484760b 100644 --- a/src/MethodVar.rsc +++ b/src/MethodVar.rsc @@ -86,4 +86,16 @@ public set[str] retrieveNotDeclaredWithinLoopNames(set[MethodVar] methodVars) { public bool isEffectiveFinal(MethodVar methodVar) { return methodVar.isFinal || methodVar.isEffectiveFinal; +} + +// FIXME This will break if 'this.varName' is referenced, as we are removing the class field +// Would need to treat 'this.*' and change how we find vars by name +public set[MethodVar] retainLocalVariablesIfDuplicates(set[MethodVar] classFields, set[MethodVar] localVars) { + duplicatedNames = retrieveAllNames(classFields) & retrieveAllNames(localVars); + duplicatedClassFields = { field | MethodVar field <- classFields, field.name in duplicatedNames }; + return (classFields - duplicatedClassFields) + localVars; +} + +private set[str] retrieveAllNames(set[MethodVar] vars) { + return { var.name | MethodVar var <- vars }; } \ No newline at end of file diff --git a/src/refactor/forloop/EnhancedLoopExpression.rsc b/src/refactor/forloop/EnhancedLoopExpression.rsc index e0b445c..29f772d 100644 --- a/src/refactor/forloop/EnhancedLoopExpression.rsc +++ b/src/refactor/forloop/EnhancedLoopExpression.rsc @@ -4,6 +4,7 @@ import lang::java::\syntax::Java18; import ParseTree; import MethodVar; import String; +import IO; // XXX Only checking iterable variables defined in method (local and parameter) // Need to verify class and instance variables too! @@ -20,13 +21,14 @@ public bool isIteratingOnCollection(Expression exp, set[MethodVar] localVariable return false; } +// (Object[]) object will be treated as method invocation private bool isExpAnIdentifier(Expression exp) { expStr = unparse(exp); return !contains(expStr, ".") && !contains(expStr, "("); } private bool isIdentifierACollection(Expression exp, set[MethodVar] localVariables) { - varName = unparse(exp); + varName = trim(unparse(exp)); var = findByName(localVariables, varName); return !isTypePlainArray(var) && !isIterable(var); } diff --git a/src/refactor/forloop/EnhancedLoopExpressionTest.rsc b/src/refactor/forloop/EnhancedLoopExpressionTest.rsc index fa34d7d..f42dc63 100644 --- a/src/refactor/forloop/EnhancedLoopExpressionTest.rsc +++ b/src/refactor/forloop/EnhancedLoopExpressionTest.rsc @@ -5,6 +5,7 @@ import lang::java::\syntax::Java18; import ParseTree; import MethodVar; import LocalVariablesFinder; +import LocalVariablesFinderTestResources; import refactor::forloop::EnhancedLoopExpression; public test bool iterableShouldReturnFalse() { @@ -29,4 +30,30 @@ private tuple[MethodHeader methodHeader, MethodBody methodBody] getEnhancedForOn return ; } } +} + +public test bool objectCastedToArrayShouldReturnFalse() { + params = paramsObjectCastedToArray(); + + return isIteratingOnCollection(params.exp, params.localVariables) == false; +} + +private tuple [Expression exp, set[MethodVar] localVariables] paramsObjectCastedToArray() { + fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/MethodBodyObjectCastedToArray.java|; + methodBody = parse(#MethodBody, readFile(fileLoc)); + methodHeader = parse(#MethodHeader, "List\\> collectClasses(List\ list)"); + localVariables = findLocalVariables(methodHeader, methodBody); + + exp = parse(#Expression, "(Object[]) object"); + + return ; +} + +public test bool iterableParamShouldReturnFalse() { + exp = parse(#Expression, "types"); + methodHeader = iterableParameterMethodHeader(); + methodBody = iterableParameterMethodBody(); + localVariables = findLocalVariables(methodHeader, methodBody); + + return isIteratingOnCollection(exp, localVariables) == false; } \ No newline at end of file diff --git a/testes/localVariables/IterableParameterMethodBody b/testes/localVariables/IterableParameterMethodBody new file mode 100644 index 0000000..9701499 --- /dev/null +++ b/testes/localVariables/IterableParameterMethodBody @@ -0,0 +1,9 @@ +{ + ImmutableList.Builder builder = ImmutableList.builder(); + for (K type : types) { + if (!getRawType(type).isInterface()) { + builder.add(type); + } + } + return super.collectTypes(builder.build()); + } \ No newline at end of file From 4ce0f4dc18742392d6eaf9ec874655c70b971616 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 4 May 2017 00:53:07 -0300 Subject: [PATCH 103/154] Identifying methods' parameters inside an anonnymous inner class inside a method. --- src/LocalVariablesFinder.rsc | 11 +++++++---- src/LocalVariablesFinderTest.rsc | 10 ++++++++++ src/LocalVariablesFinderTestResources.rsc | 10 ++++++++++ .../MethodBodyWithAnonnymousInnerClass | 19 +++++++++++++++++++ 4 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 testes/localVariables/MethodBodyWithAnonnymousInnerClass diff --git a/src/LocalVariablesFinder.rsc b/src/LocalVariablesFinder.rsc index 7c3bd92..24842ba 100644 --- a/src/LocalVariablesFinder.rsc +++ b/src/LocalVariablesFinder.rsc @@ -12,12 +12,12 @@ public set[MethodVar] findLocalVariables(MethodHeader methodHeader, MethodBody m } private set[MethodVar] findVariablesAsParameters(MethodHeader methodHeader) { - set[MethodVar] methodVars = {}; + set[MethodVar] methodParams = {}; visit(methodHeader) { case (FormalParameter) ` `: - methodVars += createParameterMethodVar(figureIfIsFinal(varMod), varId, varType); + methodParams += createParameterMethodVar(figureIfIsFinal(varMod), varId, varType); } - return methodVars; + return methodParams; } private bool figureIfIsFinal(VariableModifier* varMod) { @@ -55,7 +55,10 @@ private set[MethodVar] findVariablesInsideBody(MethodBody methodBody) { } } - + // XXX Redundant. Doing this inside MethodHeader and MethodBody + // might just visit the MethodDeclaration here. + case (FormalParameter) ` `: + methodVars += createParameterMethodVar(figureIfIsFinal(varMod), varId, varType); case (LocalVariableDeclaration) ` `: { visit(vdl) { diff --git a/src/LocalVariablesFinderTest.rsc b/src/LocalVariablesFinderTest.rsc index b66c875..74f6e49 100644 --- a/src/LocalVariablesFinderTest.rsc +++ b/src/LocalVariablesFinderTest.rsc @@ -212,3 +212,13 @@ public test bool shouldParseCorrectTypeFromIterableParameter() { return iterableParam.varType == "Iterable\"; } + +public test bool shouldIdentifyAnonnymousInnerClassMethodParams() { + methodHeader = methodWithAnonnymousInnerClassMethodHeader(); + methodBody = methodWithAnonnymousInnerClassMethodBody(); + + vars = findLocalVariables(methodHeader, methodBody); + iterableParam = findByName(vars, "types"); + + return iterableParam.varType == "Iterable\"; +} diff --git a/src/LocalVariablesFinderTestResources.rsc b/src/LocalVariablesFinderTestResources.rsc index fa7ab14..693c4e6 100644 --- a/src/LocalVariablesFinderTestResources.rsc +++ b/src/LocalVariablesFinderTestResources.rsc @@ -119,4 +119,14 @@ public MethodHeader iterableParameterMethodHeader() { public MethodBody iterableParameterMethodBody() { fileLoc = |project://rascal-Java8//testes/localVariables/IterableParameterMethodBody|; return parse(#MethodBody, readFile(fileLoc)); +} + +public MethodHeader methodWithAnonnymousInnerClassMethodHeader() { + header = "TypeCollector\ classesOnly()"; + return parse(#MethodHeader, header); +} + +public MethodBody methodWithAnonnymousInnerClassMethodBody() { + fileLoc = |project://rascal-Java8//testes/localVariables/MethodBodyWithAnonnymousInnerClass|; + return parse(#MethodBody, readFile(fileLoc)); } \ No newline at end of file diff --git a/testes/localVariables/MethodBodyWithAnonnymousInnerClass b/testes/localVariables/MethodBodyWithAnonnymousInnerClass new file mode 100644 index 0000000..52cc226 --- /dev/null +++ b/testes/localVariables/MethodBodyWithAnonnymousInnerClass @@ -0,0 +1,19 @@ +{ + return new ForwardingTypeCollector(this) { + @Override + Iterable getInterfaces(K type) { + return ImmutableSet.of(); + } + + @Override + ImmutableList collectTypes(Iterable types) { + ImmutableList.Builder builder = ImmutableList.builder(); + for (K type : types) { + if (!getRawType(type).isInterface()) { + builder.add(type); + } + } + return super.collectTypes(builder.build()); + } + }; + } \ No newline at end of file From 384c08e2c711d3234183d6dc032964cc2993039d Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 4 May 2017 01:30:14 -0300 Subject: [PATCH 104/154] Removing deprecated test. --- src/refactor/forloop/EnhancedLoopExpression.rsc | 1 - .../forloop/EnhancedLoopExpressionTest.rsc | 17 ----------------- 2 files changed, 18 deletions(-) diff --git a/src/refactor/forloop/EnhancedLoopExpression.rsc b/src/refactor/forloop/EnhancedLoopExpression.rsc index 29f772d..6f2cbbd 100644 --- a/src/refactor/forloop/EnhancedLoopExpression.rsc +++ b/src/refactor/forloop/EnhancedLoopExpression.rsc @@ -21,7 +21,6 @@ public bool isIteratingOnCollection(Expression exp, set[MethodVar] localVariable return false; } -// (Object[]) object will be treated as method invocation private bool isExpAnIdentifier(Expression exp) { expStr = unparse(exp); return !contains(expStr, ".") && !contains(expStr, "("); diff --git a/src/refactor/forloop/EnhancedLoopExpressionTest.rsc b/src/refactor/forloop/EnhancedLoopExpressionTest.rsc index f42dc63..1dea380 100644 --- a/src/refactor/forloop/EnhancedLoopExpressionTest.rsc +++ b/src/refactor/forloop/EnhancedLoopExpressionTest.rsc @@ -32,23 +32,6 @@ private tuple[MethodHeader methodHeader, MethodBody methodBody] getEnhancedForOn } } -public test bool objectCastedToArrayShouldReturnFalse() { - params = paramsObjectCastedToArray(); - - return isIteratingOnCollection(params.exp, params.localVariables) == false; -} - -private tuple [Expression exp, set[MethodVar] localVariables] paramsObjectCastedToArray() { - fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/MethodBodyObjectCastedToArray.java|; - methodBody = parse(#MethodBody, readFile(fileLoc)); - methodHeader = parse(#MethodHeader, "List\\> collectClasses(List\ list)"); - localVariables = findLocalVariables(methodHeader, methodBody); - - exp = parse(#Expression, "(Object[]) object"); - - return ; -} - public test bool iterableParamShouldReturnFalse() { exp = parse(#Expression, "types"); methodHeader = iterableParameterMethodHeader(); From 66852565a4953c221827f82211204909ac174bc4 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 4 May 2017 01:37:04 -0300 Subject: [PATCH 105/154] Not refactoring inner loops, loops with while and (if AND else) statements. --- src/refactor/forloop/ProspectiveOperation.rsc | 18 ++++----- .../forloop/ProspectiveOperationTest.rsc | 33 ++++++++++++++++ .../ProspectiveOperationTestResources.rsc | 39 +++++++++++++++++++ testes/ForLoopToFunctional/InnerLoop1.java | 12 ++++++ testes/ForLoopToFunctional/InnerLoop2.java | 19 +++++++++ .../LoopWithInnerWhile.java | 16 ++++++++ .../MethodBodyInnerLoop1.java | 32 +++++++++++++++ .../MethodBodyInnerLoop2.java | 24 ++++++++++++ .../MethodBodyLoopWithInnerWhile.java | 22 +++++++++++ 9 files changed, 206 insertions(+), 9 deletions(-) create mode 100644 testes/ForLoopToFunctional/InnerLoop1.java create mode 100644 testes/ForLoopToFunctional/InnerLoop2.java create mode 100644 testes/ForLoopToFunctional/LoopWithInnerWhile.java create mode 100644 testes/ForLoopToFunctional/MethodBodyInnerLoop1.java create mode 100644 testes/ForLoopToFunctional/MethodBodyInnerLoop2.java create mode 100644 testes/ForLoopToFunctional/MethodBodyLoopWithInnerWhile.java diff --git a/src/refactor/forloop/ProspectiveOperation.rsc b/src/refactor/forloop/ProspectiveOperation.rsc index b9ceba5..e790ce2 100644 --- a/src/refactor/forloop/ProspectiveOperation.rsc +++ b/src/refactor/forloop/ProspectiveOperation.rsc @@ -34,21 +34,18 @@ private list[ProspectiveOperation] retrieveProspectiveOperationsFromStatement(St case IfThenStatement ifStmt: { prOps += retrieveProspectiveOperationsFromIfThenStatement(ifStmt); } - case IfThenElseStatement ifElseStmt: { - println("IfThenElseStatement"); - println(ifElseStmt); - println(); - } case ExpressionStatement expStmt: { statement = parse(#Statement, unparse(expStmt)); prOps += retrieveProspectiveOperationFromSingleStatement(statement); } + + case IfThenElseStatement ifElseStmt: throw "Not Refactoring If/Else for now"; + case ForStatement _: throw "Not Refactoring Inner Loops for now"; + case WhileStatement _: throw "Not Refactoring While Loops inside ForStatement for now"; } return prOps; } - -// XXX we might need to save `if (exp)` when a filter is added private list[ProspectiveOperation] retrieveProspectiveOperationsFromBlock(Block block) { list[ProspectiveOperation] prOps = []; top-down-break visit(block) { @@ -59,8 +56,7 @@ private list[ProspectiveOperation] retrieveProspectiveOperationsFromBlock(Block prOps += retrieveProspectiveOperationsFromIfThenStatement(ifThenStmt); } case (IfThenElseStatement) `if ( ) else `: { - //retrieveProspectiveOperationsFromStatement(thenStmt); - println("if else"); + throw "Not Refactoring If/Else for now"; } case LocalVariableDeclarationStatement lvdlStmt: { // not an if, so it's a map @@ -70,6 +66,10 @@ private list[ProspectiveOperation] retrieveProspectiveOperationsFromBlock(Block statement = parse(#Statement, unparse(otherStmt)); prOps += retrieveProspectiveOperationFromSingleStatement(statement); } + + case IfThenElseStatement ifElseStmt: throw "Not Refactoring If/Else for now"; + case ForStatement _: throw "Not Refactoring Inner Loops for now"; + case WhileStatement _: throw "Not Refactoring While Loops inside ForStatement for now"; } } } diff --git a/src/refactor/forloop/ProspectiveOperationTest.rsc b/src/refactor/forloop/ProspectiveOperationTest.rsc index a237975..5f5570e 100644 --- a/src/refactor/forloop/ProspectiveOperationTest.rsc +++ b/src/refactor/forloop/ProspectiveOperationTest.rsc @@ -94,4 +94,37 @@ public test bool shouldSeparateAndChooseCorrectOperationsOnMultipleMapsEndingWit prospectiveOperations[3].operation == MAP && prospectiveOperations[4].stmt == "expectedEntrySetHash += expectedHash;" && prospectiveOperations[4].operation == REDUCE; +} + +public test bool shouldThrowExceptionWhenInnerLoopIsFound() { + tuple [set[MethodVar] vars, EnhancedForStatement loop] innerLoop = innerLoop1(); + + try { + prospectiveOperations = retrieveProspectiveOperations(innerLoop.vars, innerLoop.loop); + } catch: + return true; + + return false; +} + +public test bool shouldThrowExceptionWhenAnotherInnerLoopIsFound() { + tuple [set[MethodVar] vars, EnhancedForStatement loop] innerLoop = innerLoop2(); + + try { + prospectiveOperations = retrieveProspectiveOperations(innerLoop.vars, innerLoop.loop); + } catch: + return true; + + return false; +} + +public test bool shouldThrowExceptionWhenLoopWithInnerWhileIsFound() { + tuple [set[MethodVar] vars, EnhancedForStatement loop] loopWithInnerWhile = loopWithInnerWhile(); + + try { + prospectiveOperations = retrieveProspectiveOperations(loopWithInnerWhile.vars, loopWithInnerWhile.loop); + } catch: + return true; + + return false; } \ No newline at end of file diff --git a/src/refactor/forloop/ProspectiveOperationTestResources.rsc b/src/refactor/forloop/ProspectiveOperationTestResources.rsc index 2023ae3..3eb96b9 100644 --- a/src/refactor/forloop/ProspectiveOperationTestResources.rsc +++ b/src/refactor/forloop/ProspectiveOperationTestResources.rsc @@ -59,4 +59,43 @@ private set[MethodVar] multipleMapsAndEndingReducerVars() { methodBody = parse(#MethodBody, readFile(fileLoc)); methodHeader = parse(#MethodHeader, "void assertInvariants(Map\ map)"); return findLocalVariables(methodHeader, methodBody); +} + +public tuple [set[MethodVar] vars, EnhancedForStatement loop] innerLoop1() { + fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/InnerLoop1.java|; + EnhancedForStatement forStmt = parse(#EnhancedForStatement, readFile(fileForLoc)); + return ; +} + +private set[MethodVar] innerLoop1Vars() { + fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/MethodBodyInnerLoop1.java|; + methodBody = parse(#MethodBody, readFile(fileLoc)); + methodHeader = parse(#MethodHeader, "\ Graph\ transitiveClosure(Graph\ graph)"); + return findLocalVariables(methodHeader, methodBody); +} + +public tuple [set[MethodVar] vars, EnhancedForStatement loop] innerLoop2() { + fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/InnerLoop2.java|; + EnhancedForStatement forStmt = parse(#EnhancedForStatement, readFile(fileForLoc)); + return ; +} + +private set[MethodVar] innerLoop2Vars() { + fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/MethodBodyInnerLoop2.java|; + methodBody = parse(#MethodBody, readFile(fileLoc)); + methodHeader = parse(#MethodHeader, "ImmutableList\ getAnnotatedMethodsNotCached(Class\ clazz)"); + return findLocalVariables(methodHeader, methodBody); +} + +public tuple [set[MethodVar] vars, EnhancedForStatement loop] loopWithInnerWhile() { + fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/LoopWithInnerWhile.java|; + EnhancedForStatement forStmt = parse(#EnhancedForStatement, readFile(fileForLoc)); + return ; +} + +private set[MethodVar] loopWithInnerWhileVars() { + fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/MethodBodyLoopWithInnerWhile.java|; + methodBody = parse(#MethodBody, readFile(fileLoc)); + methodHeader = parse(#MethodHeader, "ImmutableList\ getAnnotatedMethodsNotCached(Class\ clazz)"); + return findLocalVariables(methodHeader, methodBody); } \ No newline at end of file diff --git a/testes/ForLoopToFunctional/InnerLoop1.java b/testes/ForLoopToFunctional/InnerLoop1.java new file mode 100644 index 0000000..ddd4bb8 --- /dev/null +++ b/testes/ForLoopToFunctional/InnerLoop1.java @@ -0,0 +1,12 @@ +for (N node : graph.nodes()) { + if (!visitedNodes.contains(node)) { + Set reachableNodes = reachableNodes(graph, node); + visitedNodes.addAll(reachableNodes); + int pairwiseMatch = 1; // start at 1 to include self-loops + for (N nodeU : reachableNodes) { + for (N nodeV : Iterables.limit(reachableNodes, pairwiseMatch++)) { + transitiveClosure.putEdge(nodeU, nodeV); + } + } + } + } \ No newline at end of file diff --git a/testes/ForLoopToFunctional/InnerLoop2.java b/testes/ForLoopToFunctional/InnerLoop2.java new file mode 100644 index 0000000..4e648e0 --- /dev/null +++ b/testes/ForLoopToFunctional/InnerLoop2.java @@ -0,0 +1,19 @@ +for (Class supertype : supertypes) { + for (Method method : supertype.getDeclaredMethods()) { + if (method.isAnnotationPresent(Subscribe.class) && !method.isSynthetic()) { + // TODO(cgdecker): Should check for a generic parameter type and error out + Class[] parameterTypes = method.getParameterTypes(); + checkArgument( + parameterTypes.length == 1, + "Method %s has @Subscribe annotation but has %s parameters." + + "Subscriber methods must have exactly 1 parameter.", + method, + parameterTypes.length); + + MethodIdentifier ident = new MethodIdentifier(method); + if (!identifiers.containsKey(ident)) { + identifiers.put(ident, method); + } + } + } + } \ No newline at end of file diff --git a/testes/ForLoopToFunctional/LoopWithInnerWhile.java b/testes/ForLoopToFunctional/LoopWithInnerWhile.java new file mode 100644 index 0000000..f494d3c --- /dev/null +++ b/testes/ForLoopToFunctional/LoopWithInnerWhile.java @@ -0,0 +1,16 @@ +for (HttpMessageConverter defaultConverter : defaultConverters) { + Iterator> iterator = processing.iterator(); + while (iterator.hasNext()) { + HttpMessageConverter candidate = iterator.next(); + if (isReplacement(defaultConverter, candidate)) { + combined.add(candidate); + iterator.remove(); + } + } + combined.add(defaultConverter); + if (defaultConverter instanceof AllEncompassingFormHttpMessageConverter) { + configurePartConverters( + (AllEncompassingFormHttpMessageConverter) defaultConverter, + converters); + } + } \ No newline at end of file diff --git a/testes/ForLoopToFunctional/MethodBodyInnerLoop1.java b/testes/ForLoopToFunctional/MethodBodyInnerLoop1.java new file mode 100644 index 0000000..a9dd572 --- /dev/null +++ b/testes/ForLoopToFunctional/MethodBodyInnerLoop1.java @@ -0,0 +1,32 @@ +{ + MutableGraph transitiveClosure = GraphBuilder.from(graph).allowsSelfLoops(true).build(); + // Every node is, at a minimum, reachable from itself. Since the resulting transitive closure + // will have no isolated nodes, we can skip adding nodes explicitly and let putEdge() do it. + + if (graph.isDirected()) { + // Note: works for both directed and undirected graphs, but we only use in the directed case. + for (N node : graph.nodes()) { + for (N reachableNode : reachableNodes(graph, node)) { + transitiveClosure.putEdge(node, reachableNode); + } + } + } else { + // An optimization for the undirected case: for every node B reachable from node A, + // node A and node B have the same reachability set. + Set visitedNodes = new HashSet(); + for (N node : graph.nodes()) { + if (!visitedNodes.contains(node)) { + Set reachableNodes = reachableNodes(graph, node); + visitedNodes.addAll(reachableNodes); + int pairwiseMatch = 1; // start at 1 to include self-loops + for (N nodeU : reachableNodes) { + for (N nodeV : Iterables.limit(reachableNodes, pairwiseMatch++)) { + transitiveClosure.putEdge(nodeU, nodeV); + } + } + } + } + } + + return transitiveClosure; + } \ No newline at end of file diff --git a/testes/ForLoopToFunctional/MethodBodyInnerLoop2.java b/testes/ForLoopToFunctional/MethodBodyInnerLoop2.java new file mode 100644 index 0000000..06915b3 --- /dev/null +++ b/testes/ForLoopToFunctional/MethodBodyInnerLoop2.java @@ -0,0 +1,24 @@ +{ + Set> supertypes = TypeToken.of(clazz).getTypes().rawTypes(); + Map identifiers = Maps.newHashMap(); + for (Class supertype : supertypes) { + for (Method method : supertype.getDeclaredMethods()) { + if (method.isAnnotationPresent(Subscribe.class) && !method.isSynthetic()) { + // TODO(cgdecker): Should check for a generic parameter type and error out + Class[] parameterTypes = method.getParameterTypes(); + checkArgument( + parameterTypes.length == 1, + "Method %s has @Subscribe annotation but has %s parameters." + + "Subscriber methods must have exactly 1 parameter.", + method, + parameterTypes.length); + + MethodIdentifier ident = new MethodIdentifier(method); + if (!identifiers.containsKey(ident)) { + identifiers.put(ident, method); + } + } + } + } + return ImmutableList.copyOf(identifiers.values()); + } \ No newline at end of file diff --git a/testes/ForLoopToFunctional/MethodBodyLoopWithInnerWhile.java b/testes/ForLoopToFunctional/MethodBodyLoopWithInnerWhile.java new file mode 100644 index 0000000..895c4dc --- /dev/null +++ b/testes/ForLoopToFunctional/MethodBodyLoopWithInnerWhile.java @@ -0,0 +1,22 @@ +{ + List> combined = new ArrayList<>(); + List> processing = new ArrayList<>(converters); + for (HttpMessageConverter defaultConverter : defaultConverters) { + Iterator> iterator = processing.iterator(); + while (iterator.hasNext()) { + HttpMessageConverter candidate = iterator.next(); + if (isReplacement(defaultConverter, candidate)) { + combined.add(candidate); + iterator.remove(); + } + } + combined.add(defaultConverter); + if (defaultConverter instanceof AllEncompassingFormHttpMessageConverter) { + configurePartConverters( + (AllEncompassingFormHttpMessageConverter) defaultConverter, + converters); + } + } + combined.addAll(0, processing); + return combined; + } \ No newline at end of file From a785c2a4e18241ba80f87b06482e7b5d892530d6 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 4 May 2017 13:49:45 -0300 Subject: [PATCH 106/154] PostIncremented and PostDecremented vars should not be effective final. --- src/LocalVariablesFinder.rsc | 5 +++ src/LocalVariablesFinderTest.rsc | 40 +++++++++++++++++ src/LocalVariablesFinderTestResources.rsc | 43 +++++++++++++++++- .../MethodBodyPostDecrementedVar | 44 +++++++++++++++++++ .../MethodBodyPostIncrementedVar | 11 +++++ .../MethodBodyPostIncrementedVar2 | 43 ++++++++++++++++++ .../MethodBodyPostIncrementedVar3 | 8 ++++ 7 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 testes/localVariables/MethodBodyPostDecrementedVar create mode 100644 testes/localVariables/MethodBodyPostIncrementedVar create mode 100644 testes/localVariables/MethodBodyPostIncrementedVar2 create mode 100644 testes/localVariables/MethodBodyPostIncrementedVar3 diff --git a/src/LocalVariablesFinder.rsc b/src/LocalVariablesFinder.rsc index 24842ba..e92efd2 100644 --- a/src/LocalVariablesFinder.rsc +++ b/src/LocalVariablesFinder.rsc @@ -71,6 +71,11 @@ private set[MethodVar] findVariablesInsideBody(MethodBody methodBody) { case (Assignment) ` `: nonEffectiveFinalOutsideLoopVars += ""; + case (PreIncrementExpression) `++ `: nonEffectiveFinalOutsideLoopVars += ""; + case (PreDecrementExpression) `-- `: nonEffectiveFinalOutsideLoopVars += ""; + case (PostIncrementExpression) ` ++`: nonEffectiveFinalOutsideLoopVars += ""; + case (PostDecrementExpression) ` --`: nonEffectiveFinalOutsideLoopVars += ""; + case(CatchFormalParameter) ` `: methodVars += createLocalMethodVar(figureIfIsFinal(varMod), varId, varType); diff --git a/src/LocalVariablesFinderTest.rsc b/src/LocalVariablesFinderTest.rsc index 74f6e49..d955aeb 100644 --- a/src/LocalVariablesFinderTest.rsc +++ b/src/LocalVariablesFinderTest.rsc @@ -222,3 +222,43 @@ public test bool shouldIdentifyAnonnymousInnerClassMethodParams() { return iterableParam.varType == "Iterable\"; } + +public test bool postIncrementedVariableInsideLoopShouldBeNonEffectiveFinal() { + methodHeader = postIncrementedVarMethodHeader(); + methodBody = postIncrementedVarMethodBody(); + + vars = findLocalVariables(methodHeader, methodBody); + i = findByName(vars, "i"); + + return !i.isEffectiveFinal && !isEffectiveFinal(i); +} + +public test bool postIncrementedVariable2InsideLoopShouldBeNonEffectiveFinal() { + methodHeader = postIncrementedVar2MethodHeader(); + methodBody = postIncrementedVar2MethodBody(); + + vars = findLocalVariables(methodHeader, methodBody); + i = findByName(vars, "i"); + + return !i.isEffectiveFinal && !isEffectiveFinal(i); +} + +public test bool postIncrementedVariable3InsideLoopShouldBeNonEffectiveFinal() { + methodHeader = postIncrementedVar3MethodHeader(); + methodBody = postIncrementedVar3MethodBody(); + + vars = findLocalVariables(methodHeader, methodBody); + i = findByName(vars, "i"); + + return !i.isEffectiveFinal && !isEffectiveFinal(i); +} + +public test bool postDecrementedVariableInsideLoopShouldBeNonEffectiveFinal() { + methodHeader = postDecrementedVarMethodHeader(); + methodBody = postDecrementedVarMethodBody(); + + vars = findLocalVariables(methodHeader, methodBody); + misses = findByName(vars, "misses"); + + return !misses.isEffectiveFinal && !isEffectiveFinal(misses); +} \ No newline at end of file diff --git a/src/LocalVariablesFinderTestResources.rsc b/src/LocalVariablesFinderTestResources.rsc index 693c4e6..c79f349 100644 --- a/src/LocalVariablesFinderTestResources.rsc +++ b/src/LocalVariablesFinderTestResources.rsc @@ -129,4 +129,45 @@ public MethodHeader methodWithAnonnymousInnerClassMethodHeader() { public MethodBody methodWithAnonnymousInnerClassMethodBody() { fileLoc = |project://rascal-Java8//testes/localVariables/MethodBodyWithAnonnymousInnerClass|; return parse(#MethodBody, readFile(fileLoc)); -} \ No newline at end of file +} + +public MethodHeader postIncrementedVarMethodHeader() { + header = "void processCompleted()"; + return parse(#MethodHeader, header); +} + +public MethodBody postIncrementedVarMethodBody() { + fileLoc = |project://rascal-Java8//testes/localVariables/MethodBodyPostIncrementedVar|; + return parse(#MethodBody, readFile(fileLoc)); +} + +public MethodHeader postIncrementedVar2MethodHeader() { + header = "void init()"; + return parse(#MethodHeader, header); +} + +public MethodBody postIncrementedVar2MethodBody() { + fileLoc = |project://rascal-Java8//testes/localVariables/MethodBodyPostIncrementedVar2|; + return parse(#MethodBody, readFile(fileLoc)); +} + +public MethodHeader postIncrementedVar3MethodHeader() { + header = "\ ImmutableMap\ indexMap(Collection\ list)"; + return parse(#MethodHeader, header); +} + +public MethodBody postIncrementedVar3MethodBody() { + fileLoc = |project://rascal-Java8//testes/localVariables/MethodBodyPostIncrementedVar3|; + return parse(#MethodBody, readFile(fileLoc)); +} + + +public MethodHeader postDecrementedVarMethodHeader() { + header = "ImmutableMap\ getAll(Iterable\ keys) throws ExecutionException"; + return parse(#MethodHeader, header); +} + +public MethodBody postDecrementedVarMethodBody() { + fileLoc = |project://rascal-Java8//testes/localVariables/MethodBodyPostDecrementedVar|; + return parse(#MethodBody, readFile(fileLoc)); +} diff --git a/testes/localVariables/MethodBodyPostDecrementedVar b/testes/localVariables/MethodBodyPostDecrementedVar new file mode 100644 index 0000000..3b9e45f --- /dev/null +++ b/testes/localVariables/MethodBodyPostDecrementedVar @@ -0,0 +1,44 @@ +{ + int hits = 0; + int misses = 0; + + Map result = Maps.newLinkedHashMap(); + Set keysToLoad = Sets.newLinkedHashSet(); +// for (K key : keys) { +// V value = get(key); +// if (!result.containsKey(key)) { +// result.put(key, value); +// if (value == null) { +// misses++; +// keysToLoad.add(key); +// } else { +// hits++; +// } +// } +// } + + try { + if (!keysToLoad.isEmpty()) { + try { + Map newEntries = loadAll(keysToLoad, defaultLoader); + for (K key : keysToLoad) { + V value = newEntries.get(key); + if (value == null) { + throw new InvalidCacheLoadException("loadAll failed to return a value for " + key); + } + result.put(key, value); + } + } catch (UnsupportedLoadingOperationException e) { + // loadAll not implemented, fallback to load + for (K key : keysToLoad) { + misses--; // get will count this miss + result.put(key, get(key, defaultLoader)); + } + } + } + return ImmutableMap.copyOf(result); + } finally { + globalStatsCounter.recordHits(hits); + globalStatsCounter.recordMisses(misses); + } + } \ No newline at end of file diff --git a/testes/localVariables/MethodBodyPostIncrementedVar b/testes/localVariables/MethodBodyPostIncrementedVar new file mode 100644 index 0000000..73e9fc8 --- /dev/null +++ b/testes/localVariables/MethodBodyPostIncrementedVar @@ -0,0 +1,11 @@ +{ + // Collect the values if (a) our output requires collecting them and (b) we haven't been + // collecting them as we go. (We've collected them as we go only if we needed to fail fast) + if (collectsValues & !allMustSucceed) { + int i = 0; + for (ListenableFuture listenable : futures) { + handleOneInputDone(i++, listenable); + } + } + handleAllCompleted(); + } \ No newline at end of file diff --git a/testes/localVariables/MethodBodyPostIncrementedVar2 b/testes/localVariables/MethodBodyPostIncrementedVar2 new file mode 100644 index 0000000..569c8b9 --- /dev/null +++ b/testes/localVariables/MethodBodyPostIncrementedVar2 @@ -0,0 +1,43 @@ +{ + // Corner case: List is empty. + if (futures.isEmpty()) { + handleAllCompleted(); + return; + } + + // NOTE: If we ever want to use a custom executor here, have a look at CombinedFuture as we'll + // need to handle RejectedExecutionException + if (allMustSucceed) { + // We need fail fast, so we have to keep track of which future failed so we can propagate + // the exception immediately + + // Register a listener on each Future in the list to update the state of this future. + // Note that if all the futures on the list are done prior to completing this loop, the last + // call to addListener() will callback to setOneValue(), transitively call our cleanup + // listener, and set this.futures to null. + // This is not actually a problem, since the foreach only needs this.futures to be non-null + // at the beginning of the loop. + int i = 0; + for (final ListenableFuture listenable : futures) { + final int index = i++; + listenable.addListener( + new Runnable() { + @Override + public void run() { + try { + handleOneInputDone(index, listenable); + } finally { + decrementCountAndMaybeComplete(); + } + } + }, + directExecutor()); + } + } else { + // We'll only call the callback when all futures complete, regardless of whether some failed + // Hold off on calling setOneValue until all complete, so we can share the same listener + for (ListenableFuture listenable : futures) { + listenable.addListener(this, directExecutor()); + } + } + } \ No newline at end of file diff --git a/testes/localVariables/MethodBodyPostIncrementedVar3 b/testes/localVariables/MethodBodyPostIncrementedVar3 new file mode 100644 index 0000000..0253d77 --- /dev/null +++ b/testes/localVariables/MethodBodyPostIncrementedVar3 @@ -0,0 +1,8 @@ +{ + ImmutableMap.Builder builder = new ImmutableMap.Builder(list.size()); + int i = 0; + for (E e : list) { + builder.put(e, i++); + } + return builder.build(); + } \ No newline at end of file From 1a1b0ed6cb5a853a6d81ca5241d2edd15f6bbabc Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 4 May 2017 18:38:40 -0300 Subject: [PATCH 107/154] Assuring that assignment inside loop renders a non effective final var. --- src/LocalVariablesFinderTest.rsc | 18 ++++++++++++++---- src/LocalVariablesFinderTestResources.rsc | 10 ++++++++++ .../MethodBodyAssignmentInsideLoop | 11 +++++++++++ 3 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 testes/localVariables/MethodBodyAssignmentInsideLoop diff --git a/src/LocalVariablesFinderTest.rsc b/src/LocalVariablesFinderTest.rsc index d955aeb..1847737 100644 --- a/src/LocalVariablesFinderTest.rsc +++ b/src/LocalVariablesFinderTest.rsc @@ -223,7 +223,7 @@ public test bool shouldIdentifyAnonnymousInnerClassMethodParams() { return iterableParam.varType == "Iterable\"; } -public test bool postIncrementedVariableInsideLoopShouldBeNonEffectiveFinal() { +public test bool postIncrementedVariableInsideLoopShouldNotBeEffectiveFinal() { methodHeader = postIncrementedVarMethodHeader(); methodBody = postIncrementedVarMethodBody(); @@ -233,7 +233,7 @@ public test bool postIncrementedVariableInsideLoopShouldBeNonEffectiveFinal() { return !i.isEffectiveFinal && !isEffectiveFinal(i); } -public test bool postIncrementedVariable2InsideLoopShouldBeNonEffectiveFinal() { +public test bool postIncrementedVariable2InsideLoopShouldNotBeEffectiveFinal() { methodHeader = postIncrementedVar2MethodHeader(); methodBody = postIncrementedVar2MethodBody(); @@ -243,7 +243,7 @@ public test bool postIncrementedVariable2InsideLoopShouldBeNonEffectiveFinal() { return !i.isEffectiveFinal && !isEffectiveFinal(i); } -public test bool postIncrementedVariable3InsideLoopShouldBeNonEffectiveFinal() { +public test bool postIncrementedVariable3InsideLoopShouldNotBeEffectiveFinal() { methodHeader = postIncrementedVar3MethodHeader(); methodBody = postIncrementedVar3MethodBody(); @@ -253,7 +253,7 @@ public test bool postIncrementedVariable3InsideLoopShouldBeNonEffectiveFinal() { return !i.isEffectiveFinal && !isEffectiveFinal(i); } -public test bool postDecrementedVariableInsideLoopShouldBeNonEffectiveFinal() { +public test bool postDecrementedVariableInsideLoopShouldNotBeEffectiveFinal() { methodHeader = postDecrementedVarMethodHeader(); methodBody = postDecrementedVarMethodBody(); @@ -261,4 +261,14 @@ public test bool postDecrementedVariableInsideLoopShouldBeNonEffectiveFinal() { misses = findByName(vars, "misses"); return !misses.isEffectiveFinal && !isEffectiveFinal(misses); +} + +public test bool variableAssignedInsideLoopShouldNotBeEffectiveFinal() { + methodHeader = assignmentInsideForMethodHeader(); + methodBody = assignmentInsideForMethodBody(); + + vars = findLocalVariables(methodHeader, methodBody); + exceptions = findByName(vars, "exceptions"); + + return !exceptions.isEffectiveFinal && !isEffectiveFinal(exceptions); } \ No newline at end of file diff --git a/src/LocalVariablesFinderTestResources.rsc b/src/LocalVariablesFinderTestResources.rsc index c79f349..e8c3665 100644 --- a/src/LocalVariablesFinderTestResources.rsc +++ b/src/LocalVariablesFinderTestResources.rsc @@ -171,3 +171,13 @@ public MethodBody postDecrementedVarMethodBody() { fileLoc = |project://rascal-Java8//testes/localVariables/MethodBodyPostDecrementedVar|; return parse(#MethodBody, readFile(fileLoc)); } + +public MethodHeader assignmentInsideForMethodHeader() { + header = "Collection\ deleteDirectoryContentsInsecure(DirectoryStream\ dir)"; + return parse(#MethodHeader, header); +} + +public MethodBody assignmentInsideForMethodBody() { + fileLoc = |project://rascal-Java8//testes/localVariables/MethodBodyAssignmentInsideLoop|; + return parse(#MethodBody, readFile(fileLoc)); +} \ No newline at end of file diff --git a/testes/localVariables/MethodBodyAssignmentInsideLoop b/testes/localVariables/MethodBodyAssignmentInsideLoop new file mode 100644 index 0000000..8b30e1a --- /dev/null +++ b/testes/localVariables/MethodBodyAssignmentInsideLoop @@ -0,0 +1,11 @@ +{ + Collection exceptions = null; + try { + for (Path entry : dir) { + exceptions = concat(exceptions, deleteRecursivelyInsecure(entry)); + } + return exceptions; + } catch (DirectoryIteratorException e) { + return addException(exceptions, e.getCause()); + } + } \ No newline at end of file From 85d66cccd1ff1bdb627dbeaf1be447fb6f1ae739 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 4 May 2017 18:38:40 -0300 Subject: [PATCH 108/154] Names that reveal more intention in ForLoop --- src/ForLoop.rsc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ForLoop.rsc b/src/ForLoop.rsc index 2327bae..c4bfe3f 100644 --- a/src/ForLoop.rsc +++ b/src/ForLoop.rsc @@ -69,9 +69,9 @@ private void lookForEnhancedForStatementsInMethodBody(CompilationUnit unit, Meth top-down visit(forStmt) { case EnhancedForStatement enhancedForStmt: { visit(enhancedForStmt) { - case (EnhancedForStatement) `for ( : ) `: { + case (EnhancedForStatement) `for ( : ) `: { - if(isLoopRefactorable(availableVars, collectionId, stmt)) { + if(isLoopRefactorable(availableVars, collectionId, loopBody)) { try { refactored = refactorEnhancedToFunctional(availableVars, enhancedForStmt, methodBody, iteratedVarName, collectionId); @@ -97,13 +97,13 @@ private void lookForEnhancedForStatementsInMethodBody(CompilationUnit unit, Meth } } -private bool isLoopRefactorable(set[MethodVar] methodLocalVariables, Expression exp, Statement stmt) { - return loopBodyPassConditions(stmt) && isIteratingOnCollection(exp, methodLocalVariables) && - atMostOneReferenceToNonEffectiveFinalVar(methodLocalVariables, stmt); +private bool isLoopRefactorable(set[MethodVar] methodLocalVariables, Expression collectionId, Statement loopBody) { + return loopBodyPassConditions(loopBody) && isIteratingOnCollection(collectionId, methodLocalVariables) && + atMostOneReferenceToNonEffectiveFinalVar(methodLocalVariables, loopBody); } // TODO extract module and test it -private bool loopBodyPassConditions(Statement stmt) { +private bool loopBodyPassConditions(Statement loopBody) { returnCount = 0; visit(stmt) { case (ThrowStatement) `throw new ( );`: { From cb7cb060e8414c0419d692ecdacdf7d8f4596c98 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 4 May 2017 18:38:40 -0300 Subject: [PATCH 109/154] More robust implementation of ForLoopBodyReferences. - Really similar implementation of UsedVariables. --- .../forloop/ForLoopBodyReferences.rsc | 30 +++++++--- .../forloop/ForLoopToFunctionalTest.rsc | 1 - .../test/ForLoopBodyReferencesTest.rsc | 60 +++++++++++++++++++ 3 files changed, 83 insertions(+), 8 deletions(-) create mode 100644 src/refactor/forloop/test/ForLoopBodyReferencesTest.rsc diff --git a/src/refactor/forloop/ForLoopBodyReferences.rsc b/src/refactor/forloop/ForLoopBodyReferences.rsc index 431288f..84b81d4 100644 --- a/src/refactor/forloop/ForLoopBodyReferences.rsc +++ b/src/refactor/forloop/ForLoopBodyReferences.rsc @@ -7,18 +7,34 @@ import IO; import Set; import MethodVar; -// TODO still need to find effective final vars somewhere. public bool atMostOneReferenceToNonEffectiveFinalVar(set[MethodVar] localVariables, Statement loopBody) { - varsReferenced = findVariablesReferenced(loopBody); - return size(varsReferenced) <= 1; + return getTotalOfNonEffectiveFinalVarsReferenced(localVariables, loopBody) <= 1; } -private set[str] findVariablesReferenced(Statement stmt) { +public int getTotalOfNonEffectiveFinalVarsReferenced(set[MethodVar] localVariables, Statement loopBody) { + varsReferencedNames = findVariablesReferenced(loopBody); + nonEffectiveFinalVarsReferencedCount = 0; + + for (varReferencedName <- varsReferencedNames) { + var = findByName(localVariables, varReferencedName); + if (!isEffectiveFinal(var) && !var.isDeclaredWithinLoop) + nonEffectiveFinalVarsReferencedCount += 1; + } + + return nonEffectiveFinalVarsReferencedCount; +} + +// XXX UsedVariables could use the same thing +// XXX Ignoring class fields. ('this.x') +public set[str] findVariablesReferenced(Statement loopBody) { set[str] varsReferenced = {}; - visit (stmt) { - case (Assignment) ` `: - varsReferenced += trim(unparse(lhs)); + visit (loopBody) { + case ExpressionName expName: { + visit(expName) { + case Identifier id: varsReferenced += unparse(id); + } + } } return varsReferenced; diff --git a/src/refactor/forloop/ForLoopToFunctionalTest.rsc b/src/refactor/forloop/ForLoopToFunctionalTest.rsc index 6de92de..9b5b39a 100644 --- a/src/refactor/forloop/ForLoopToFunctionalTest.rsc +++ b/src/refactor/forloop/ForLoopToFunctionalTest.rsc @@ -58,7 +58,6 @@ public test bool reduceAsNotTheLastOperationShouldNotBeRefactored() { // return false; //} -// TODO Complete the test with full output when REDUCE implemented public test bool shouldRefactorReduceWithCompoundPlusAssignmentOperator() { fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T2.java|; methodBody = parse(#MethodBody, readFile(fileLoc)); diff --git a/src/refactor/forloop/test/ForLoopBodyReferencesTest.rsc b/src/refactor/forloop/test/ForLoopBodyReferencesTest.rsc new file mode 100644 index 0000000..0e08b50 --- /dev/null +++ b/src/refactor/forloop/test/ForLoopBodyReferencesTest.rsc @@ -0,0 +1,60 @@ +module refactor::forloop::\test::ForLoopBodyReferencesTest + +import IO; +import lang::java::\syntax::Java18; +import ParseTree; +import Set; +import refactor::forloop::ForLoopBodyReferences; +import MethodVar; + +public test bool variablesReferenced1() { + fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/ForWith3StatementsMapBody.java|; + forStmt = parse(#EnhancedForStatement, readFile(fileForLoc)); + loopBody = retrieveLoopBodyFromEnhancedFor(forStmt); + + result = findVariablesReferenced(loopBody); + + return size(result) == 5 && + "previous" in result && + "snapshot" in result && + "updated" in result && + "changedFiles" in result && + "changeSet" in result; +} + +private Statement retrieveLoopBodyFromEnhancedFor(EnhancedForStatement forStmt) { + visit (forStmt) { + case (EnhancedForStatement) `for ( : ) `: + return loopBody; + } + throw "Error"; +} + +public test bool variablesReferenced2() { + fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/ForWithMultiStatementMap.java|; + EnhancedForStatement forStmt = parse(#EnhancedForStatement, readFile(fileForLoc)); + loopBody = retrieveLoopBodyFromEnhancedFor(forStmt); + + result = findVariablesReferenced(loopBody); + + return size(result) == 5 && + "key" in result && + "keysIt" in result && + "value" in result && + "v" in result && + "result" in result; +} + +public test bool variablesReferenced3() { + fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T2For2.java|; + EnhancedForStatement forStmt = parse(#EnhancedForStatement, readFile(fileForLoc)); + loopBody = retrieveLoopBodyFromEnhancedFor(forStmt); + + result = findVariablesReferenced(loopBody); + + return size(result) == 4 && + "map" in result && + "entry" in result && + "expectedHash" in result && + "expectedEntrySetHash" in result; +} \ No newline at end of file From 9f4f044c6b90cc16c1676b5f6c4734a4eb62a105 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 4 May 2017 18:38:40 -0300 Subject: [PATCH 110/154] Removing parenthesis from lambda arguments when functional refactor is only a forEach. --- src/refactor/forloop/ForLoopToFunctional.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/refactor/forloop/ForLoopToFunctional.rsc index 34ff805..c1983ab 100644 --- a/src/refactor/forloop/ForLoopToFunctional.rsc +++ b/src/refactor/forloop/ForLoopToFunctional.rsc @@ -269,7 +269,7 @@ private Statement buildFunctionalStatement(set[MethodVar] methodVars, list[Compo private Statement buildStatementForOnlyOneForEach(ProspectiveOperation prOp, VariableDeclaratorId iteratedVarName, Expression collectionId) { stmtBlock = transformIntoBlock(prOp.stmt); iteratedVarName = trimEndingBlankSpace(iteratedVarName); - return parse(#Statement, ".forEach(() -\> );"); + return parse(#Statement, ".forEach( -\> );"); } private Block transformIntoBlock(str stmt) { From 0af923fef33df5e07b34305cd0b1a358f5ded5a6 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 4 May 2017 18:38:40 -0300 Subject: [PATCH 111/154] Only refactoring loops with one reference to outside NonEffectiveFinal if it's a reducer. --- src/refactor/forloop/ForLoopBodyReferences.rsc | 12 ++++++++++++ src/refactor/forloop/ForLoopToFunctional.rsc | 5 +++-- .../forloop/ForLoopToFunctionalTest.rsc | 18 ++++++++++++++++++ src/refactor/forloop/ProspectiveOperation.rsc | 11 +++++++++-- .../forloop/test/ForLoopBodyReferencesTest.rsc | 8 -------- 5 files changed, 42 insertions(+), 12 deletions(-) diff --git a/src/refactor/forloop/ForLoopBodyReferences.rsc b/src/refactor/forloop/ForLoopBodyReferences.rsc index 84b81d4..e16cb40 100644 --- a/src/refactor/forloop/ForLoopBodyReferences.rsc +++ b/src/refactor/forloop/ForLoopBodyReferences.rsc @@ -11,6 +11,18 @@ public bool atMostOneReferenceToNonEffectiveFinalVar(set[MethodVar] localVariabl return getTotalOfNonEffectiveFinalVarsReferenced(localVariables, loopBody) <= 1; } +public int getTotalOfNonEffectiveFinalVarsReferenced(set[MethodVar] localVariables, EnhancedForStatement forStmt) { + return getTotalOfNonEffectiveFinalVarsReferenced(localVariables, retrieveLoopBodyFromEnhancedFor(forStmt)); +} + +public Statement retrieveLoopBodyFromEnhancedFor(EnhancedForStatement forStmt) { + visit (forStmt) { + case (EnhancedForStatement) `for ( : ) `: + return loopBody; + } + throw "Error"; +} + public int getTotalOfNonEffectiveFinalVarsReferenced(set[MethodVar] localVariables, Statement loopBody) { varsReferencedNames = findVariablesReferenced(loopBody); nonEffectiveFinalVarsReferencedCount = 0; diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/refactor/forloop/ForLoopToFunctional.rsc index c1983ab..a694f24 100644 --- a/src/refactor/forloop/ForLoopToFunctional.rsc +++ b/src/refactor/forloop/ForLoopToFunctional.rsc @@ -11,7 +11,7 @@ import refactor::forloop::ProspectiveOperation; import refactor::forloop::UsedVariables; import refactor::forloop::AvailableVariables; import refactor::forloop::OperationType; -import ParseTreeVisualization; +import refactor::forloop::ForLoopBodyReferences; public data ComposableProspectiveOperation = composableProspectiveOperation(ProspectiveOperation prOp, set[str] neededVars, set[str] availableVars); @@ -38,7 +38,8 @@ MethodBody refactorToFunctional(MethodBody methodBody, Statement forStmt, Statem public list[ComposableProspectiveOperation] retrieveComposableProspectiveOperations(set[MethodVar] methodVars, EnhancedForStatement forStmt) { prospectiveOperations = retrieveProspectiveOperations(methodVars, forStmt); - if (canOperationsBeRefactored(prospectiveOperations)) { + nonEffectiveOutsideVarsReferencedCount = getTotalOfNonEffectiveFinalVarsReferenced(methodVars, forStmt); + if (canOperationsBeRefactored(prospectiveOperations, nonEffectiveOutsideVarsReferencedCount)) { composablePrOps = createComposableProspectiveOperationsWithVariableAvailability(prospectiveOperations, methodVars); composablePrOps = mergeIntoComposableOperations(composablePrOps); diff --git a/src/refactor/forloop/ForLoopToFunctionalTest.rsc b/src/refactor/forloop/ForLoopToFunctionalTest.rsc index 9b5b39a..33bb787 100644 --- a/src/refactor/forloop/ForLoopToFunctionalTest.rsc +++ b/src/refactor/forloop/ForLoopToFunctionalTest.rsc @@ -7,6 +7,7 @@ import ParseTree; import refactor::forloop::ForLoopToFunctional; import MethodVar; import LocalVariablesFinder; +import LocalVariablesFinderTestResources; import ParseTreeVisualization; public test bool ex1() { @@ -101,4 +102,21 @@ public test bool shouldAddCorrectReturnTo3StmtsMapBody() { refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); return unparse(refactoredStatement) == "snapshots.stream().map(snapshot -\> {\nFolderSnapshot previous = this.folders.get(snapshot.getFolder());\nupdated.put(snapshot.getFolder(), snapshot);\nChangedFiles changedFiles = previous.getChangedFiles(snapshot,\r\n this.triggerFilter);\nreturn changedFiles;\n}).filter(changedFiles -\> !changedFiles.getFiles().isEmpty()).forEach(changedFiles -\> {\nchangeSet.add(changedFiles);\n});"; +} + +public test bool shouldThrowExceptionWhenALoopWithOnlyOneReferenceToOutsideNonEffectiveFinalVarIsNotAReducer() { + methodHeader = assignmentInsideForMethodHeader(); + methodBody = assignmentInsideForMethodBody(); + methodVars = findLocalVariables(methodHeader, methodBody); + VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "entry"); + Expression collectionId = parse(#Expression, "dir"); + EnhancedForStatement forStmt = parse(#EnhancedForStatement, "for (Path entry : dir) {\n exceptions = concat(exceptions, deleteRecursivelyInsecure(entry));\n }"); + + try { + refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); + } catch: + return true; + + return false; + } \ No newline at end of file diff --git a/src/refactor/forloop/ProspectiveOperation.rsc b/src/refactor/forloop/ProspectiveOperation.rsc index e790ce2..424c120 100644 --- a/src/refactor/forloop/ProspectiveOperation.rsc +++ b/src/refactor/forloop/ProspectiveOperation.rsc @@ -185,8 +185,9 @@ public bool isLocalVariableDeclarationStatement(str stmt) { } catch: return false; } -public bool canOperationsBeRefactored(list[ProspectiveOperation] prOps) { - return !haveEagerOperationAsNonLast(prOps); +public bool canOperationsBeRefactored(list[ProspectiveOperation] prOps, int nonEffectiveOutsideVarsReferencedCount) { + return !haveEagerOperationAsNonLast(prOps) + && isLoopAReducerIfHasMoreThanOneReferenceToOutsideNonEffectiveFinalVar(prOps, nonEffectiveOutsideVarsReferencedCount); } private bool haveEagerOperationAsNonLast(list[ProspectiveOperation] prOps) { @@ -195,4 +196,10 @@ private bool haveEagerOperationAsNonLast(list[ProspectiveOperation] prOps) { if(isEagerOperation(prOp)) return true; return false; +} + +private bool isLoopAReducerIfHasMoreThanOneReferenceToOutsideNonEffectiveFinalVar(list[ProspectiveOperation] prOps, int outsideNonEffectiveReferencesCount) { + if (outsideNonEffectiveReferencesCount == 1) + return isReduce(last(prOps)); + return true; } \ No newline at end of file diff --git a/src/refactor/forloop/test/ForLoopBodyReferencesTest.rsc b/src/refactor/forloop/test/ForLoopBodyReferencesTest.rsc index 0e08b50..2f44aa3 100644 --- a/src/refactor/forloop/test/ForLoopBodyReferencesTest.rsc +++ b/src/refactor/forloop/test/ForLoopBodyReferencesTest.rsc @@ -22,14 +22,6 @@ public test bool variablesReferenced1() { "changeSet" in result; } -private Statement retrieveLoopBodyFromEnhancedFor(EnhancedForStatement forStmt) { - visit (forStmt) { - case (EnhancedForStatement) `for ( : ) `: - return loopBody; - } - throw "Error"; -} - public test bool variablesReferenced2() { fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/ForWithMultiStatementMap.java|; EnhancedForStatement forStmt = parse(#EnhancedForStatement, readFile(fileForLoc)); From 85fc52c4b46f1226b9c45e754efccf0a994a35c1 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 4 May 2017 18:38:40 -0300 Subject: [PATCH 112/154] More test cases when loop with one reference to outside NEFV is not a reduce --- src/LocalVariablesFinderTest.rsc | 12 ++++++++ src/LocalVariablesFinderTestResources.rsc | 10 +++++++ src/refactor/forloop/ForLoopToFunctional.rsc | 1 - .../forloop/ForLoopToFunctionalTest.rsc | 20 +++++++++++-- .../test/ForLoopBodyReferencesTest.rsc | 28 +++++++++++++++++++ ...WithTwoReferencesToOutsideNonEffectiveVars | 18 ++++++++++++ 6 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 testes/localVariables/MethodBodyWithTwoReferencesToOutsideNonEffectiveVars diff --git a/src/LocalVariablesFinderTest.rsc b/src/LocalVariablesFinderTest.rsc index 1847737..7074abc 100644 --- a/src/LocalVariablesFinderTest.rsc +++ b/src/LocalVariablesFinderTest.rsc @@ -271,4 +271,16 @@ public test bool variableAssignedInsideLoopShouldNotBeEffectiveFinal() { exceptions = findByName(vars, "exceptions"); return !exceptions.isEffectiveFinal && !isEffectiveFinal(exceptions); +} + +public test bool arrayAssignmentShouldStillKeepVarAsEffectiveFinal() { + methodHeader = twoNonEffectiveFinalVarsInsideLoopMethodHeader(); + methodBody = twoNonEffectiveFinalVarsInsideLoopMethodBody(); + + vars = findLocalVariables(methodHeader, methodBody); + + i = findByName(vars, "i"); + cumulativeCounts = findByName(vars, "cumulativeCounts"); + + return !isEffectiveFinal(i) && isEffectiveFinal(cumulativeCounts); } \ No newline at end of file diff --git a/src/LocalVariablesFinderTestResources.rsc b/src/LocalVariablesFinderTestResources.rsc index e8c3665..10e3506 100644 --- a/src/LocalVariablesFinderTestResources.rsc +++ b/src/LocalVariablesFinderTestResources.rsc @@ -180,4 +180,14 @@ public MethodHeader assignmentInsideForMethodHeader() { public MethodBody assignmentInsideForMethodBody() { fileLoc = |project://rascal-Java8//testes/localVariables/MethodBodyAssignmentInsideLoop|; return parse(#MethodBody, readFile(fileLoc)); +} + +public MethodHeader twoNonEffectiveFinalVarsInsideLoopMethodHeader() { + header = "\ ImmutableSortedMultiset\ copyOfSortedEntries(Comparator\ comparator, Collection\\> entries)"; + return parse(#MethodHeader, header); +} + +public MethodBody twoNonEffectiveFinalVarsInsideLoopMethodBody() { + methodBodyLoc = |project://rascal-Java8/testes/localVariables/MethodBodyWithTwoReferencesToOutsideNonEffectiveVars|; + return parse(#MethodBody, readFile(methodBodyLoc)); } \ No newline at end of file diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/refactor/forloop/ForLoopToFunctional.rsc index a694f24..659305c 100644 --- a/src/refactor/forloop/ForLoopToFunctional.rsc +++ b/src/refactor/forloop/ForLoopToFunctional.rsc @@ -46,7 +46,6 @@ public list[ComposableProspectiveOperation] retrieveComposableProspectiveOperati return rearrangeMapBodiesIfNeeded(composablePrOps); } else - // Throwing the exception is not the best option, but the easiest to implement right now throw "CanNotBeRefactored"; } diff --git a/src/refactor/forloop/ForLoopToFunctionalTest.rsc b/src/refactor/forloop/ForLoopToFunctionalTest.rsc index 33bb787..440cee6 100644 --- a/src/refactor/forloop/ForLoopToFunctionalTest.rsc +++ b/src/refactor/forloop/ForLoopToFunctionalTest.rsc @@ -117,6 +117,22 @@ public test bool shouldThrowExceptionWhenALoopWithOnlyOneReferenceToOutsideNonEf } catch: return true; - return false; - + return false; +} + +public test bool shouldThrowExceptionWhenALoopWithOnlyOneReferenceToOutsideNonEffectiveFinalVarIsNotAReducer2() { + methodHeader = parse(#MethodHeader, "\ ImmutableSortedMultiset\ copyOfSortedEntries(Comparator\ comparator, Collection\\> entries)"); + methodBodyLoc = |project://rascal-Java8/testes/localVariables/MethodBodyWithTwoReferencesToOutsideNonEffectiveVars|; + methodBody = parse(#MethodBody, readFile(methodBodyLoc)); + methodVars = findLocalVariables(methodHeader, methodBody); + forStmt = parse(#EnhancedForStatement, "for (Entry\ entry : entries) {\n elementsBuilder.add(entry.getElement());\n cumulativeCounts[i + 1] = cumulativeCounts[i] + entry.getCount();\n i++;\n }"); + VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "entry"); + Expression collectionId = parse(#Expression, "entries"); + + try { + refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); + } catch: + return true; + + return false; } \ No newline at end of file diff --git a/src/refactor/forloop/test/ForLoopBodyReferencesTest.rsc b/src/refactor/forloop/test/ForLoopBodyReferencesTest.rsc index 2f44aa3..cd68379 100644 --- a/src/refactor/forloop/test/ForLoopBodyReferencesTest.rsc +++ b/src/refactor/forloop/test/ForLoopBodyReferencesTest.rsc @@ -6,6 +6,7 @@ import ParseTree; import Set; import refactor::forloop::ForLoopBodyReferences; import MethodVar; +import LocalVariablesFinder; public test bool variablesReferenced1() { fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/ForWith3StatementsMapBody.java|; @@ -49,4 +50,31 @@ public test bool variablesReferenced3() { "entry" in result && "expectedHash" in result && "expectedEntrySetHash" in result; +} + +public test bool variablesReferenced4() { + forStmt = parse(#EnhancedForStatement, "for (Entry\ entry : entries) {\n elementsBuilder.add(entry.getElement());\n cumulativeCounts[i + 1] = cumulativeCounts[i] + entry.getCount();\n i++;\n }"); + loopBody = retrieveLoopBodyFromEnhancedFor(forStmt); + + result = findVariablesReferenced(loopBody); + + return size(result) == 4 && + "elementsBuilder" in result && + "entry" in result && + "cumulativeCounts" in result && + "i" in result; + +} + +public test bool shouldBeRefactorableWhenOneReferenceFound() { + methodHeader = parse(#MethodHeader, "\ ImmutableSortedMultiset\ copyOfSortedEntries(Comparator\ comparator, Collection\\> entries)"); + methodBodyLoc = |project://rascal-Java8/testes/localVariables/MethodBodyWithTwoReferencesToOutsideNonEffectiveVars|; + methodBody = parse(#MethodBody, readFile(methodBodyLoc)); + localVariables = findLocalVariables(methodHeader, methodBody); + forStmt = parse(#EnhancedForStatement, "for (Entry\ entry : entries) {\n elementsBuilder.add(entry.getElement());\n cumulativeCounts[i + 1] = cumulativeCounts[i] + entry.getCount();\n i++;\n }"); + + total = getTotalOfNonEffectiveFinalVarsReferenced(localVariables, forStmt); + refactorable = atMostOneReferenceToNonEffectiveFinalVar(localVariables, retrieveLoopBodyFromEnhancedFor(forStmt)); + + return total == 1 && refactorable; } \ No newline at end of file diff --git a/testes/localVariables/MethodBodyWithTwoReferencesToOutsideNonEffectiveVars b/testes/localVariables/MethodBodyWithTwoReferencesToOutsideNonEffectiveVars new file mode 100644 index 0000000..74ecedd --- /dev/null +++ b/testes/localVariables/MethodBodyWithTwoReferencesToOutsideNonEffectiveVars @@ -0,0 +1,18 @@ +{ + if (entries.isEmpty()) { + return emptyMultiset(comparator); + } + ImmutableList.Builder elementsBuilder = new ImmutableList.Builder(entries.size()); + long[] cumulativeCounts = new long[entries.size() + 1]; + int i = 0; + for (Entry entry : entries) { + elementsBuilder.add(entry.getElement()); + cumulativeCounts[i + 1] = cumulativeCounts[i] + entry.getCount(); + i++; + } + return new RegularImmutableSortedMultiset( + new RegularImmutableSortedSet(elementsBuilder.build(), comparator), + cumulativeCounts, + 0, + entries.size()); + } \ No newline at end of file From a03b29dc1a53e907e21b47986f9d0c7f93328375 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 4 May 2017 18:38:40 -0300 Subject: [PATCH 113/154] Writing tests to not yet implemented reduce with post increment. --- .../forloop/ForLoopToFunctionalTest.rsc | 19 +++++++++++++++++++ .../forloop/ProspectiveOperationTest.rsc | 13 +++++++++++++ .../ProspectiveOperationTestResources.rsc | 12 ++++++++++++ .../MethodBodyReduceWithPostIncrement | 18 ++++++++++++++++++ 4 files changed, 62 insertions(+) create mode 100644 testes/localVariables/MethodBodyReduceWithPostIncrement diff --git a/src/refactor/forloop/ForLoopToFunctionalTest.rsc b/src/refactor/forloop/ForLoopToFunctionalTest.rsc index 440cee6..ddbe415 100644 --- a/src/refactor/forloop/ForLoopToFunctionalTest.rsc +++ b/src/refactor/forloop/ForLoopToFunctionalTest.rsc @@ -129,6 +129,25 @@ public test bool shouldThrowExceptionWhenALoopWithOnlyOneReferenceToOutsideNonEf VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "entry"); Expression collectionId = parse(#Expression, "entries"); + try { + refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); + } catch: + return true; + + return false; +} + +public test bool shouldRefactorToReduceWithPostIncrement() { + throw "Not yet implemented"; + + methodHeader = parse(#MethodHeader, "\ ImmutableSortedMultiset\ copyOfSortedEntries(Comparator\ comparator, Collection\\> entries)"); + methodBodyLoc = |project://rascal-Java8/testes/localVariables/MethodBodyReduceWithPostIncrement|; + methodBody = parse(#MethodBody, readFile(methodBodyLoc)); + methodVars = findLocalVariables(methodHeader, methodBody); + forStmt = parse(#EnhancedForStatement, "for (Entry\ entry : entries) {\n elementsBuilder.add(entry.getElement());\n // cumulativeCounts[i + 1] = cumulativeCounts[i] + entry.getCount();\n i++;\n }"); + VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "entry"); + Expression collectionId = parse(#Expression, "entries"); + try { refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); } catch: diff --git a/src/refactor/forloop/ProspectiveOperationTest.rsc b/src/refactor/forloop/ProspectiveOperationTest.rsc index 5f5570e..7b496eb 100644 --- a/src/refactor/forloop/ProspectiveOperationTest.rsc +++ b/src/refactor/forloop/ProspectiveOperationTest.rsc @@ -127,4 +127,17 @@ public test bool shouldThrowExceptionWhenLoopWithInnerWhileIsFound() { return true; return false; +} + +public test bool shouldIdentifyPostIncrementAsReduce() { + throw "Not yet implemented"; + + tuple [set[MethodVar] vars, EnhancedForStatement loop] loopReduceWithPostIncrement = loopReduceWithPostIncrement(); + + prospectiveOperations = retrieveProspectiveOperations(loopReduceWithPostIncrement.vars, loopReduceWithPostIncrement.loop); + + println(prospectiveOperations); + + return false; + } \ No newline at end of file diff --git a/src/refactor/forloop/ProspectiveOperationTestResources.rsc b/src/refactor/forloop/ProspectiveOperationTestResources.rsc index 3eb96b9..4a2fe29 100644 --- a/src/refactor/forloop/ProspectiveOperationTestResources.rsc +++ b/src/refactor/forloop/ProspectiveOperationTestResources.rsc @@ -98,4 +98,16 @@ private set[MethodVar] loopWithInnerWhileVars() { methodBody = parse(#MethodBody, readFile(fileLoc)); methodHeader = parse(#MethodHeader, "ImmutableList\ getAnnotatedMethodsNotCached(Class\ clazz)"); return findLocalVariables(methodHeader, methodBody); +} + +public tuple [set[MethodVar] vars, EnhancedForStatement loop] loopReduceWithPostIncrement() { + forStmt = parse(#EnhancedForStatement, "for (Entry\ entry : entries) {\n elementsBuilder.add(entry.getElement());\n // cumulativeCounts[i + 1] = cumulativeCounts[i] + entry.getCount();\n i++;\n }"); + return ; +} + +private set[MethodVar] loopReduceWithPostIncrementVars() { + methodHeader = parse(#MethodHeader, "\ ImmutableSortedMultiset\ copyOfSortedEntries(Comparator\ comparator, Collection\\> entries)"); + methodBodyLoc = |project://rascal-Java8/testes/localVariables/MethodBodyReduceWithPostIncrement|; + methodBody = parse(#MethodBody, readFile(methodBodyLoc)); + return findLocalVariables(methodHeader, methodBody); } \ No newline at end of file diff --git a/testes/localVariables/MethodBodyReduceWithPostIncrement b/testes/localVariables/MethodBodyReduceWithPostIncrement new file mode 100644 index 0000000..f200967 --- /dev/null +++ b/testes/localVariables/MethodBodyReduceWithPostIncrement @@ -0,0 +1,18 @@ +{ + if (entries.isEmpty()) { + return emptyMultiset(comparator); + } + ImmutableList.Builder elementsBuilder = new ImmutableList.Builder(entries.size()); + long[] cumulativeCounts = new long[entries.size() + 1]; + int i = 0; + for (Entry entry : entries) { + elementsBuilder.add(entry.getElement()); + // cumulativeCounts[i + 1] = cumulativeCounts[i] + entry.getCount(); + i++; + } + return new RegularImmutableSortedMultiset( + new RegularImmutableSortedSet(elementsBuilder.build(), comparator), + cumulativeCounts, + 0, + entries.size()); + } \ No newline at end of file From c6bacc4ad503e7079bcc450d651f44a083eb61a1 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 4 May 2017 18:38:40 -0300 Subject: [PATCH 114/154] Keeping one single statement block as blocks when breaking operations. - As we were breaking operations, the single statement block was broken as an operation, and the block was dismissed. - Workaroundish solution for now. Not breaking regression and passing new one. --- src/refactor/forloop/ProspectiveOperation.rsc | 22 ++++++++++++++++++- .../forloop/ProspectiveOperationTest.rsc | 15 +++++++++++++ .../ProspectiveOperationTestResources.rsc | 12 ++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/refactor/forloop/ProspectiveOperation.rsc b/src/refactor/forloop/ProspectiveOperation.rsc index 424c120..3e37aca 100644 --- a/src/refactor/forloop/ProspectiveOperation.rsc +++ b/src/refactor/forloop/ProspectiveOperation.rsc @@ -95,7 +95,10 @@ private list[ProspectiveOperation] retrieveProspectiveOperationsFromIfThenStatem if (!foundReturn) { prOps += prospectiveOperation(unparse(exp), FILTER); - prOps += retrieveProspectiveOperationsFromStatement(thenStmt); + if (isSingleStatementBlock(thenStmt)) + prOps += retrieveProspectiveOperationFromSingleStatement(thenStmt); + else + prOps += retrieveProspectiveOperationsFromStatement(thenStmt); } } } @@ -133,6 +136,23 @@ private bool isReferenceToNonFinalLocalVar(LeftHandSide lhs) { return !isEffectiveFinal(var); } +// XXX Does this really work? +private bool isSingleStatementBlock(Statement thenStmt) { + if (isBlock("")) { + semiCollonOccurrences = findAll("", ";"); + return size(semiCollonOccurrences) == 1; + } + + return false; +} + +private bool isBlock(str stmt) { + try { + parse(#Block, stmt); + return true; + } catch: return false; +} + private list[ProspectiveOperation] markLastStmtAsEager(list[ProspectiveOperation] prOps) { lastPrOp = prOps[-1]; if(lastPrOp.operation == MAP) diff --git a/src/refactor/forloop/ProspectiveOperationTest.rsc b/src/refactor/forloop/ProspectiveOperationTest.rsc index 7b496eb..bffe3dd 100644 --- a/src/refactor/forloop/ProspectiveOperationTest.rsc +++ b/src/refactor/forloop/ProspectiveOperationTest.rsc @@ -139,5 +139,20 @@ public test bool shouldIdentifyPostIncrementAsReduce() { println(prospectiveOperations); return false; +} + +public test bool shouldKeepBlockAfterAnIf() { + tuple [set[MethodVar] vars, EnhancedForStatement loop] loopWithThrowStatement = loopWithThrowStatement(); + prospectiveOperations = retrieveProspectiveOperations(loopWithThrowStatement.vars, loopWithThrowStatement.loop); + + return size(prospectiveOperations) == 4 && + prospectiveOperations[0].stmt == "V value = newEntries.get(key);" && + prospectiveOperations[0].operation == MAP && + prospectiveOperations[1].stmt == "value == null" && + prospectiveOperations[1].operation == FILTER && + prospectiveOperations[2].stmt == "{\n throw new InvalidCacheLoadException(\"loadAll failed to return a value for \" + key);\n }" && + prospectiveOperations[2].operation == MAP && + prospectiveOperations[3].stmt == "result.put(key, value);" && + prospectiveOperations[3].operation == FOR_EACH; } \ No newline at end of file diff --git a/src/refactor/forloop/ProspectiveOperationTestResources.rsc b/src/refactor/forloop/ProspectiveOperationTestResources.rsc index 4a2fe29..75c3d51 100644 --- a/src/refactor/forloop/ProspectiveOperationTestResources.rsc +++ b/src/refactor/forloop/ProspectiveOperationTestResources.rsc @@ -110,4 +110,16 @@ private set[MethodVar] loopReduceWithPostIncrementVars() { methodBodyLoc = |project://rascal-Java8/testes/localVariables/MethodBodyReduceWithPostIncrement|; methodBody = parse(#MethodBody, readFile(methodBodyLoc)); return findLocalVariables(methodHeader, methodBody); +} + +public tuple [set[MethodVar] vars, EnhancedForStatement loop] loopWithThrowStatement() { + forStmt = parse(#EnhancedForStatement, "for (K key : keysToLoad) {\n V value = newEntries.get(key);\n if (value == null) {\n throw new InvalidCacheLoadException(\"loadAll failed to return a value for \" + key);\n }\n result.put(key, value);\n }"); + return ; +} + +private set[MethodVar] loopWithThrowStatementVars() { + methodHeader = parse(#MethodHeader, "ImmutableMap\ getAll(Iterable\ keys) throws ExecutionException"); + methodBodyLoc = |project://rascal-Java8//testes/localVariables/MethodBodyPostDecrementedVar|; + methodBody = parse(#MethodBody, readFile(methodBodyLoc)); + return findLocalVariables(methodHeader, methodBody); } \ No newline at end of file From cfc29870450412a69d0e1d07df1cb44925b1f51c Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 4 May 2017 18:38:40 -0300 Subject: [PATCH 115/154] Fixing some tests because our output changed when we kept blocks. - As we kept single stmt blocks intact, we might have preserved some identation. --- src/refactor/forloop/ForLoopToFunctionalTest.rsc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/refactor/forloop/ForLoopToFunctionalTest.rsc b/src/refactor/forloop/ForLoopToFunctionalTest.rsc index ddbe415..9886e3d 100644 --- a/src/refactor/forloop/ForLoopToFunctionalTest.rsc +++ b/src/refactor/forloop/ForLoopToFunctionalTest.rsc @@ -8,7 +8,6 @@ import refactor::forloop::ForLoopToFunctional; import MethodVar; import LocalVariablesFinder; import LocalVariablesFinderTestResources; -import ParseTreeVisualization; public test bool ex1() { fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T1.java|; @@ -21,7 +20,7 @@ public test bool ex1() { refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); - return unparse(refactoredStatement) == "testers.stream().map(testerClass -\> makeSuiteForTesterClass((Class\\>) testerClass)).filter(testerSuite -\> testerSuite.countTestCases() \> 0).forEach(testerSuite -\> {\nsuite.addTest(testerSuite);\n});"; + return "" == "testers.stream().map(testerClass -\> makeSuiteForTesterClass((Class\\>) testerClass)).filter(testerSuite -\> testerSuite.countTestCases() \> 0).forEach(testerSuite -\> {\n suite.addTest(testerSuite);\n });"; } public test bool reduceAsNotTheLastOperationShouldNotBeRefactored() { @@ -86,7 +85,7 @@ public test bool shouldAddReturnToMapWithMoreThanOneStatement() { refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); - return unparse(refactoredStatement) == "values.stream().map(v -\> {\nString key = keysIt.next();\nMetric\ value = deserialize(key, v, this.zSetOperations.score(key));\nreturn value;\n}).filter(value -\> value != null).forEach(value -\> {\nresult.add(value);\n});"; + return "" == "values.stream().map(v -\> {\nString key = keysIt.next();\nMetric\ value = deserialize(key, v, this.zSetOperations.score(key));\nreturn value;\n}).filter(value -\> value != null).forEach(value -\> {\r\n\t\t\t\tresult.add(value);\r\n\t\t\t});"; } public test bool shouldAddCorrectReturnTo3StmtsMapBody() { @@ -101,7 +100,7 @@ public test bool shouldAddCorrectReturnTo3StmtsMapBody() { refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); - return unparse(refactoredStatement) == "snapshots.stream().map(snapshot -\> {\nFolderSnapshot previous = this.folders.get(snapshot.getFolder());\nupdated.put(snapshot.getFolder(), snapshot);\nChangedFiles changedFiles = previous.getChangedFiles(snapshot,\r\n this.triggerFilter);\nreturn changedFiles;\n}).filter(changedFiles -\> !changedFiles.getFiles().isEmpty()).forEach(changedFiles -\> {\nchangeSet.add(changedFiles);\n});"; + return "" == "snapshots.stream().map(snapshot -\> {\nFolderSnapshot previous = this.folders.get(snapshot.getFolder());\nupdated.put(snapshot.getFolder(), snapshot);\nChangedFiles changedFiles = previous.getChangedFiles(snapshot,\r\n this.triggerFilter);\nreturn changedFiles;\n}).filter(changedFiles -\> !changedFiles.getFiles().isEmpty()).forEach(changedFiles -\> {\r\n changeSet.add(changedFiles);\r\n });"; } public test bool shouldThrowExceptionWhenALoopWithOnlyOneReferenceToOutsideNonEffectiveFinalVarIsNotAReducer() { From 62aff87304660c4798c13e93d0868f7da3d9aca2 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Wed, 10 May 2017 00:23:29 -0300 Subject: [PATCH 116/154] Trying to break the loop body in statements. - Main reason for now is to know if an if statement is the last statement. - Still need to figure out block inside blocks. -- The logic is probably the same, but we need to identify when there is an inner block, and then call this method. - If this works well enough, the whole ProspectiveOperation visit logic can be refactored. --- src/refactor/forloop/BreakIntoStatements.rsc | 37 ++++++++ .../forloop/test/BreakIntoStatementsTest.rsc | 88 +++++++++++++++++++ ...IfWithTwoStmtsInsideAndStmtAfterBlock.java | 12 +++ ...IfWithTwoStmtsInsideAndStmtAfterBlock.java | 20 +++++ 4 files changed, 157 insertions(+) create mode 100644 src/refactor/forloop/BreakIntoStatements.rsc create mode 100644 src/refactor/forloop/test/BreakIntoStatementsTest.rsc create mode 100644 testes/ForLoopToFunctional/ForIfWithTwoStmtsInsideAndStmtAfterBlock.java create mode 100644 testes/ForLoopToFunctional/MethodBodyIfWithTwoStmtsInsideAndStmtAfterBlock.java diff --git a/src/refactor/forloop/BreakIntoStatements.rsc b/src/refactor/forloop/BreakIntoStatements.rsc new file mode 100644 index 0000000..289aaa5 --- /dev/null +++ b/src/refactor/forloop/BreakIntoStatements.rsc @@ -0,0 +1,37 @@ +module refactor::forloop::BreakIntoStatements + +import IO; +import List; +import String; +import lang::java::\syntax::Java18; +import ParseTree; + +data Stmt = stmt(Tree statement, str stmtType); + +public list[Stmt] breakIntoStatements(Statement statement) { + list[Stmt] stmts = []; + top-down-break visit(statement) { + case IfThenStatement ifStmt: { + stmts += stmt(ifStmt, "IfThenStatement"); + } + case ExpressionStatement expStmt: { + stmts += stmt(expStmt, "ExpressionStatement"); + } + case LocalVariableDeclarationStatement lvdlStmt: { + stmts += stmt(lvdlStmt, "LocalVariableDeclarationStatement"); + } + + case IfThenElseStatement ifElseStmt: throw "Not Refactoring If/Else for now"; + case ForStatement _: throw "Not Refactoring Inner Loops for now"; + case WhileStatement _: throw "Not Refactoring While Loops inside ForStatement for now"; + } + return stmts; +} + +public void printStmtsBrokenInto(list[Stmt] stmts) { + for (stmt <- stmts) { + println("type: "); + println("stmt: "); + println(); + } +} \ No newline at end of file diff --git a/src/refactor/forloop/test/BreakIntoStatementsTest.rsc b/src/refactor/forloop/test/BreakIntoStatementsTest.rsc new file mode 100644 index 0000000..51aa688 --- /dev/null +++ b/src/refactor/forloop/test/BreakIntoStatementsTest.rsc @@ -0,0 +1,88 @@ +module refactor::forloop::\test::BreakIntoStatementsTest + +import IO; +import refactor::forloop::BreakIntoStatements; +import lang::java::\syntax::Java18; +import refactor::forloop::ProspectiveOperationTestResources; +import refactor::forloop::ForLoopBodyReferences; +import ParseTree; +import ParseTreeVisualization; + +public test bool ex1() { + fileLoc = |project://rascal-Java8//testes/ProspectiveOperation/SimpleShortEnhancedLoop|; + enhancedForLoop = parse(#EnhancedForStatement, readFile(fileLoc)); + loopBody = retrieveLoopBodyFromEnhancedFor(enhancedForLoop); + + stmts = breakIntoStatements(loopBody); + + Stmt stmt = stmts[0]; + return size(stmts) == 1 && + "" == "writer.write(thing);" && + stmt.stmtType == "ExpressionStatement"; +} + +public test bool ex2() { + fileLoc = |project://rascal-Java8//testes/ProspectiveOperation/ContinueAndReturnEnhancedLoop|; + enhancedForLoop = parse(#EnhancedForStatement, readFile(fileLoc)); + loopBody = retrieveLoopBodyFromEnhancedFor(enhancedForLoop); + + stmts = breakIntoStatements(loopBody); + + return size(stmts) == 2 && + "" == "if(e.getGrammarName() == null) continue;" && + stmts[1].stmtType == "IfThenStatement" && + "" == "if(e.getGrammarName().equals(grammarName))\r\n return true;" && + stmts[1].stmtType == "IfThenStatement"; +} + +public test bool ex3() { + fileLoc = |project://rascal-Java8//testes/ProspectiveOperation/FilterMapReduceEnhancedLoop|; + enhancedForLoop = parse(#EnhancedForStatement, readFile(fileLoc)); + loopBody = retrieveLoopBodyFromEnhancedFor(enhancedForLoop); + + stmts = breakIntoStatements(loopBody); + + Stmt stmt = stmts[0]; + return size(stmts) == 1 && + "" == "if(rule.hasErrors())\r\n count += rule.getErrors().size();" && + stmt.stmtType == "IfThenStatement"; +} + +public test bool ex4() { + enhancedForLoop = parse(#EnhancedForStatement, "for (Entry\ entry : entries) {\n elementsBuilder.add(entry.getElement());\n // cumulativeCounts[i + 1] = cumulativeCounts[i] + entry.getCount();\n i++;\n }"); + loopBody = retrieveLoopBodyFromEnhancedFor(enhancedForLoop); + + stmts = breakIntoStatements(loopBody); + + return size(stmts) == 2 && + "" == "elementsBuilder.add(entry.getElement());" && + stmts[0].stmtType == "ExpressionStatement" && + "" == "i++;" && + stmts[1].stmtType == "ExpressionStatement"; +} + +public test bool ex5() { + enhancedForLoop = parse(#EnhancedForStatement, "for (K key : keysToLoad) {\n V value = newEntries.get(key);\n if (value == null) {\n throw new InvalidCacheLoadException(\"loadAll failed to return a value for \" + key);\n }\n result.put(key, value);\n }"); + loopBody = retrieveLoopBodyFromEnhancedFor(enhancedForLoop); + + stmts = breakIntoStatements(loopBody); + + return size(stmts) == 3 && + "" == "V value = newEntries.get(key);" && + stmts[0].stmtType == "LocalVariableDeclarationStatement" && + "" == "if (value == null) {\n throw new InvalidCacheLoadException(\"loadAll failed to return a value for \" + key);\n }" && + stmts[1].stmtType == "IfThenStatement" && + "" == "result.put(key, value);" && + stmts[2].stmtType == "ExpressionStatement"; +} + +public test bool ex6() { + fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/ForIfWithTwoStmtsInsideAndStmtAfterBlock.java|; + enhancedForLoop = parse(#EnhancedForStatement, readFile(fileForLoc)); + loopBody = retrieveLoopBodyFromEnhancedFor(enhancedForLoop); + + stmts = breakIntoStatements(loopBody); + printStmtsBrokenInto(stmts); + + return false; +} \ No newline at end of file diff --git a/testes/ForLoopToFunctional/ForIfWithTwoStmtsInsideAndStmtAfterBlock.java b/testes/ForLoopToFunctional/ForIfWithTwoStmtsInsideAndStmtAfterBlock.java new file mode 100644 index 0000000..6022143 --- /dev/null +++ b/testes/ForLoopToFunctional/ForIfWithTwoStmtsInsideAndStmtAfterBlock.java @@ -0,0 +1,12 @@ +for (MvcEndpoint endpoint : endpoints) { + if (isIncluded(endpoint)) { + String path = endpointHandlerMapping.getPath(endpoint.getPath()); + paths.add(path); + if (!path.equals("")) { + paths.add(path + "/**"); + // Add Spring MVC-generated additional paths + paths.add(path + ".*"); + } + paths.add(path + "/"); + } + } \ No newline at end of file diff --git a/testes/ForLoopToFunctional/MethodBodyIfWithTwoStmtsInsideAndStmtAfterBlock.java b/testes/ForLoopToFunctional/MethodBodyIfWithTwoStmtsInsideAndStmtAfterBlock.java new file mode 100644 index 0000000..653303e --- /dev/null +++ b/testes/ForLoopToFunctional/MethodBodyIfWithTwoStmtsInsideAndStmtAfterBlock.java @@ -0,0 +1,20 @@ +{ + if (endpointHandlerMapping == null) { + return NO_PATHS; + } + Set endpoints = endpointHandlerMapping.getEndpoints(); + Set paths = new LinkedHashSet<>(endpoints.size()); + for (MvcEndpoint endpoint : endpoints) { + if (isIncluded(endpoint)) { + String path = endpointHandlerMapping.getPath(endpoint.getPath()); + paths.add(path); + if (!path.equals("")) { + paths.add(path + "/**"); + // Add Spring MVC-generated additional paths + paths.add(path + ".*"); + } + paths.add(path + "/"); + } + } + return paths.toArray(new String[paths.size()]); + } \ No newline at end of file From 07ed19150728717cc2ed025526255f2fe6257f1e Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 11 May 2017 15:52:56 -0300 Subject: [PATCH 117/154] Testing breaking statements from a Then Statement. --- .../forloop/test/BreakIntoStatementsTest.rsc | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/refactor/forloop/test/BreakIntoStatementsTest.rsc b/src/refactor/forloop/test/BreakIntoStatementsTest.rsc index 51aa688..a7d6e3a 100644 --- a/src/refactor/forloop/test/BreakIntoStatementsTest.rsc +++ b/src/refactor/forloop/test/BreakIntoStatementsTest.rsc @@ -82,7 +82,30 @@ public test bool ex6() { loopBody = retrieveLoopBodyFromEnhancedFor(enhancedForLoop); stmts = breakIntoStatements(loopBody); - printStmtsBrokenInto(stmts); - return false; + return size(stmts) == 1 && + "" == "if (isIncluded(endpoint)) {\r\n\t\t\t\t\tString path = endpointHandlerMapping.getPath(endpoint.getPath());\r\n\t\t\t\t\tpaths.add(path);\r\n\t\t\t\t\tif (!path.equals(\"\")) {\r\n\t\t\t\t\t\tpaths.add(path + \"/**\");\r\n\t\t\t\t\t\t// Add Spring MVC-generated additional paths\r\n\t\t\t\t\t\tpaths.add(path + \".*\");\r\n\t\t\t\t\t}\r\n\t\t\t\t\tpaths.add(path + \"/\");\r\n\t\t\t\t}" && + stmts[0].stmtType == "IfThenStatement"; +} + +// inside the if after the loop from previous example +public test bool ex7() { + fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/ForIfWithTwoStmtsInsideAndStmtAfterBlock.java|; + enhancedForLoop = parse(#EnhancedForStatement, readFile(fileForLoc)); + loopBody = retrieveLoopBodyFromEnhancedFor(enhancedForLoop); + list[Stmt] stmts = []; + top-down-break visit(loopBody) { + case (IfThenStatement) `if ( ) `: + stmts = breakIntoStatements(thenStmt); + } + + return size(stmts) == 4 && + "" == "String path = endpointHandlerMapping.getPath(endpoint.getPath());" && + stmts[0].stmtType == "LocalVariableDeclarationStatement" && + "" == "paths.add(path);" && + stmts[1].stmtType == "ExpressionStatement" && + "" == "if (!path.equals(\"\")) {\r\n\t\t\t\t\t\tpaths.add(path + \"/**\");\r\n\t\t\t\t\t\t// Add Spring MVC-generated additional paths\r\n\t\t\t\t\t\tpaths.add(path + \".*\");\r\n\t\t\t\t\t}" && + stmts[2].stmtType == "IfThenStatement" && + "" == "paths.add(path + \"/\");" && + stmts[3].stmtType == "ExpressionStatement"; } \ No newline at end of file From a3d3550a3f4bdc4f5d5741b12d5ebef6668402e8 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 11 May 2017 16:38:21 -0300 Subject: [PATCH 118/154] Identifying when an If it's not the last statement within it's block. - In this case the prospective operation is a MAP. --- src/refactor/forloop/BreakIntoStatements.rsc | 9 ++ src/refactor/forloop/ProspectiveOperation.rsc | 30 +++-- .../forloop/ProspectiveOperationTest.rsc | 105 +++++++++++------- .../ProspectiveOperationTestResources.rsc | 13 +++ 4 files changed, 106 insertions(+), 51 deletions(-) diff --git a/src/refactor/forloop/BreakIntoStatements.rsc b/src/refactor/forloop/BreakIntoStatements.rsc index 289aaa5..7474ef1 100644 --- a/src/refactor/forloop/BreakIntoStatements.rsc +++ b/src/refactor/forloop/BreakIntoStatements.rsc @@ -8,6 +8,15 @@ import ParseTree; data Stmt = stmt(Tree statement, str stmtType); +public list[Stmt] breakIntoStatements(Block block) { + list [Stmt] stmts = []; + top-down-break visit(block) { + case Statement stmt: + stmts += breakIntoStatements(stmt); + } + return stmts; +} + public list[Stmt] breakIntoStatements(Statement statement) { list[Stmt] stmts = []; top-down-break visit(statement) { diff --git a/src/refactor/forloop/ProspectiveOperation.rsc b/src/refactor/forloop/ProspectiveOperation.rsc index 3e37aca..4954036 100644 --- a/src/refactor/forloop/ProspectiveOperation.rsc +++ b/src/refactor/forloop/ProspectiveOperation.rsc @@ -8,6 +8,7 @@ import ParseTree; import MethodVar; import refactor::forloop::OperationType; import ParseTreeVisualization; +import refactor::forloop::BreakIntoStatements; public data ProspectiveOperation = prospectiveOperation(str stmt, str operation); @@ -32,7 +33,8 @@ private list[ProspectiveOperation] retrieveProspectiveOperationsFromStatement(St prOps += retrieveProspectiveOperationsFromBlock(block); } case IfThenStatement ifStmt: { - prOps += retrieveProspectiveOperationsFromIfThenStatement(ifStmt); + stmtsBrokenInto = breakIntoStatements(stmt); + prOps += retrieveProspectiveOperationsFromIfThenStatement(ifStmt, stmtsBrokenInto); } case ExpressionStatement expStmt: { statement = parse(#Statement, unparse(expStmt)); @@ -53,7 +55,8 @@ private list[ProspectiveOperation] retrieveProspectiveOperationsFromBlock(Block top-down-break visit(blockStatement) { case (IfThenStatement) `if ( ) `: { ifThenStmt = [IfThenStatement] "if () "; - prOps += retrieveProspectiveOperationsFromIfThenStatement(ifThenStmt); + stmtsBrokenInto = breakIntoStatements(block); + prOps += retrieveProspectiveOperationsFromIfThenStatement(ifThenStmt, stmtsBrokenInto); } case (IfThenElseStatement) `if ( ) else `: { throw "Not Refactoring If/Else for now"; @@ -76,7 +79,7 @@ private list[ProspectiveOperation] retrieveProspectiveOperationsFromBlock(Block return prOps; } -private list[ProspectiveOperation] retrieveProspectiveOperationsFromIfThenStatement(IfThenStatement ifStmt) { +private list[ProspectiveOperation] retrieveProspectiveOperationsFromIfThenStatement(IfThenStatement ifStmt, list[Stmt] currBlockStmts) { list[ProspectiveOperation] prOps = []; foundReturn = false; top-down-break visit (ifStmt) { @@ -94,11 +97,17 @@ private list[ProspectiveOperation] retrieveProspectiveOperationsFromIfThenStatem } if (!foundReturn) { - prOps += prospectiveOperation(unparse(exp), FILTER); - if (isSingleStatementBlock(thenStmt)) - prOps += retrieveProspectiveOperationFromSingleStatement(thenStmt); - else - prOps += retrieveProspectiveOperationsFromStatement(thenStmt); + if (!ifStatementHasNoStatementAfter(ifStmt, currBlockStmts)) { + prOps += prospectiveOperation(unparse(ifStmt), MAP); + } + else { + prOps += prospectiveOperation(unparse(exp), FILTER); + + if (isSingleStatementBlock(thenStmt)) + prOps += retrieveProspectiveOperationFromSingleStatement(thenStmt); + else + prOps += retrieveProspectiveOperationsFromStatement(thenStmt); + } } } } @@ -107,6 +116,11 @@ private list[ProspectiveOperation] retrieveProspectiveOperationsFromIfThenStatem return prOps; } +private bool ifStatementHasNoStatementAfter(IfThenStatement ifStmt, list[Stmt] currBlockStmts) { + lastStmt = last(currBlockStmts); + return lastStmt.stmtType == "IfThenStatement" && lastStmt.statement == ifStmt; +} + private ProspectiveOperation retrieveProspectiveOperationFromSingleStatement(Statement statement) { if (isReducer(statement)) return prospectiveOperation(unparse(statement), REDUCE); diff --git a/src/refactor/forloop/ProspectiveOperationTest.rsc b/src/refactor/forloop/ProspectiveOperationTest.rsc index bffe3dd..8b25973 100644 --- a/src/refactor/forloop/ProspectiveOperationTest.rsc +++ b/src/refactor/forloop/ProspectiveOperationTest.rsc @@ -30,29 +30,6 @@ public test bool shouldHandleReduce() { prospectiveOperations[1].operation == REDUCE; } -//public test bool shouldHandleAnyMatchAndIfWithContinue() { -// tuple [set[MethodVar] vars, EnhancedForStatement loop] continueAndReturn = continueAndReturn(); -// -// prospectiveOperations = retrieveProspectiveOperations(continueAndReturn.vars, continueAndReturn.loop); -// println(prospectiveOperations); -// -// return size(prospectiveOperations) == 2 && -// prospectiveOperations[0].stmt == "e.getGrammarName() != null" && -// prospectiveOperations[0].operation == FILTER && -// prospectiveOperations[1].stmt == "e.getGrammarName().equals(grammarName)" && -// prospectiveOperations[1].operation == ANY_MATCH; -//} -// -//public test bool shouldHandleIfWithContinue() { -// tuple [set[MethodVar] vars, EnhancedForStatement loop] continueAndReturn = continueAndReturn(); -// -// prospectiveOperations = retrieveProspectiveOperations(continueAndReturn.vars, continueAndReturn.loop); -// println(prospectiveOperations); -// -// return prospectiveOperations[0].stmt == "e.getGrammarName() != null" && -// prospectiveOperations[0].operation == FILTER; -//} - public test bool shouldHandleAnyMatch() { tuple [set[MethodVar] vars, EnhancedForStatement loop] continueAndReturn = continueAndReturn(); @@ -129,30 +106,72 @@ public test bool shouldThrowExceptionWhenLoopWithInnerWhileIsFound() { return false; } -public test bool shouldIdentifyPostIncrementAsReduce() { - throw "Not yet implemented"; - - tuple [set[MethodVar] vars, EnhancedForStatement loop] loopReduceWithPostIncrement = loopReduceWithPostIncrement(); - - prospectiveOperations = retrieveProspectiveOperations(loopReduceWithPostIncrement.vars, loopReduceWithPostIncrement.loop); - - println(prospectiveOperations); - - return false; -} - -public test bool shouldKeepBlockAfterAnIf() { +public test bool ifAsNotTheLastStatementShouldBeAMap() { tuple [set[MethodVar] vars, EnhancedForStatement loop] loopWithThrowStatement = loopWithThrowStatement(); prospectiveOperations = retrieveProspectiveOperations(loopWithThrowStatement.vars, loopWithThrowStatement.loop); - return size(prospectiveOperations) == 4 && + return size(prospectiveOperations) == 3 && prospectiveOperations[0].stmt == "V value = newEntries.get(key);" && prospectiveOperations[0].operation == MAP && - prospectiveOperations[1].stmt == "value == null" && - prospectiveOperations[1].operation == FILTER && - prospectiveOperations[2].stmt == "{\n throw new InvalidCacheLoadException(\"loadAll failed to return a value for \" + key);\n }" && + prospectiveOperations[1].stmt == "if (value == null) {\n throw new InvalidCacheLoadException(\"loadAll failed to return a value for \" + key);\n }" && + prospectiveOperations[1].operation == MAP && + prospectiveOperations[2].stmt == "result.put(key, value);" && + prospectiveOperations[2].operation == FOR_EACH; +} + +// This is actually a really nice example. +// The first if is a filter because it is the last statement from the outer block +// The inner if is not the last statement within the first if block, so it's a map +public test bool innerIfAsNotTheLastStatementShouldBeAMap() { + tuple [set[MethodVar] vars, EnhancedForStatement loop] loop = loopWithIfWithTwoStatementsInsideBlock(); + + prospectiveOperations = retrieveProspectiveOperations(loop.vars, loop.loop); + + return size(prospectiveOperations) == 5 && + prospectiveOperations[0].stmt == "isIncluded(endpoint)" && + prospectiveOperations[0].operation == FILTER && + prospectiveOperations[1].stmt == "String path = endpointHandlerMapping.getPath(endpoint.getPath());" && + prospectiveOperations[1].operation == MAP && + prospectiveOperations[2].stmt == "paths.add(path);" && prospectiveOperations[2].operation == MAP && - prospectiveOperations[3].stmt == "result.put(key, value);" && - prospectiveOperations[3].operation == FOR_EACH; -} \ No newline at end of file + prospectiveOperations[3].stmt == "if (!path.equals(\"\")) {\r\n\t\t\t\t\t\tpaths.add(path + \"/**\");\r\n\t\t\t\t\t\t// Add Spring MVC-generated additional paths\r\n\t\t\t\t\t\tpaths.add(path + \".*\");\r\n\t\t\t\t\t}" && + prospectiveOperations[3].operation == MAP && + prospectiveOperations[4].stmt == "paths.add(path + \"/\");" && + prospectiveOperations[4].operation == FOR_EACH; +} + +//public test bool shouldIdentifyPostIncrementAsReduce() { +// throw "Not yet implemented"; +// +// tuple [set[MethodVar] vars, EnhancedForStatement loop] loopReduceWithPostIncrement = loopReduceWithPostIncrement(); +// +// prospectiveOperations = retrieveProspectiveOperations(loopReduceWithPostIncrement.vars, loopReduceWithPostIncrement.loop); +// +// println(prospectiveOperations); +// +// return false; +//} + +//public test bool shouldHandleAnyMatchAndIfWithContinue() { +// tuple [set[MethodVar] vars, EnhancedForStatement loop] continueAndReturn = continueAndReturn(); +// +// prospectiveOperations = retrieveProspectiveOperations(continueAndReturn.vars, continueAndReturn.loop); +// println(prospectiveOperations); +// +// return size(prospectiveOperations) == 2 && +// prospectiveOperations[0].stmt == "e.getGrammarName() != null" && +// prospectiveOperations[0].operation == FILTER && +// prospectiveOperations[1].stmt == "e.getGrammarName().equals(grammarName)" && +// prospectiveOperations[1].operation == ANY_MATCH; +//} +// +//public test bool shouldHandleIfWithContinue() { +// tuple [set[MethodVar] vars, EnhancedForStatement loop] continueAndReturn = continueAndReturn(); +// +// prospectiveOperations = retrieveProspectiveOperations(continueAndReturn.vars, continueAndReturn.loop); +// println(prospectiveOperations); +// +// return prospectiveOperations[0].stmt == "e.getGrammarName() != null" && +// prospectiveOperations[0].operation == FILTER; +//} \ No newline at end of file diff --git a/src/refactor/forloop/ProspectiveOperationTestResources.rsc b/src/refactor/forloop/ProspectiveOperationTestResources.rsc index 75c3d51..e4f50f0 100644 --- a/src/refactor/forloop/ProspectiveOperationTestResources.rsc +++ b/src/refactor/forloop/ProspectiveOperationTestResources.rsc @@ -122,4 +122,17 @@ private set[MethodVar] loopWithThrowStatementVars() { methodBodyLoc = |project://rascal-Java8//testes/localVariables/MethodBodyPostDecrementedVar|; methodBody = parse(#MethodBody, readFile(methodBodyLoc)); return findLocalVariables(methodHeader, methodBody); +} + +public tuple [set[MethodVar] vars, EnhancedForStatement loop] loopWithIfWithTwoStatementsInsideBlock() { + fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/ForIfWithTwoStmtsInsideAndStmtAfterBlock.java|; + EnhancedForStatement forStmt = parse(#EnhancedForStatement, readFile(fileForLoc)); + return ; +} + +private set[MethodVar] loopWithIfWithTwoStatementsInsideBlockVars() { + methodHeader = parse(#MethodHeader, "String[] getPaths(EndpointHandlerMapping endpointHandlerMapping)"); + methodBodyLoc = |project://rascal-Java8//testes/ForLoopToFunctional/MethodBodyIfWithTwoStmtsInsideAndStmtAfterBlock.java|; + methodBody = parse(#MethodBody, readFile(methodBodyLoc)); + return findLocalVariables(methodHeader, methodBody); } \ No newline at end of file From 5aa58af0c27cca9d9faff85c370b2f793b964b46 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 11 May 2017 16:50:37 -0300 Subject: [PATCH 119/154] Extracting methods on ProspectiveOperation --- src/refactor/forloop/ProspectiveOperation.rsc | 52 +++++++++++-------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/src/refactor/forloop/ProspectiveOperation.rsc b/src/refactor/forloop/ProspectiveOperation.rsc index 4954036..df31ac5 100644 --- a/src/refactor/forloop/ProspectiveOperation.rsc +++ b/src/refactor/forloop/ProspectiveOperation.rsc @@ -83,30 +83,22 @@ private list[ProspectiveOperation] retrieveProspectiveOperationsFromIfThenStatem list[ProspectiveOperation] prOps = []; foundReturn = false; top-down-break visit (ifStmt) { - case (IfThenStatement) `if ( ) `: { + case (IfThenStatement) `if ( ) `: { top-down-break visit (thenStmt) { case Statement stmt: { visit(stmt) { case (ReturnStatement) `return ;`: { foundReturn = true; - if ("" == "true") - prOps += prospectiveOperation(unparse(exp), ANY_MATCH); - else if ("" == "false") - prOps += prospectiveOperation(unparse(exp), NONE_MATCH); + prOps += createAnyMatchOrNoneMatchPrOp("", ""); } } if (!foundReturn) { - if (!ifStatementHasNoStatementAfter(ifStmt, currBlockStmts)) { + if (!ifStatementHasNoStatementAfter(ifStmt, currBlockStmts)) prOps += prospectiveOperation(unparse(ifStmt), MAP); - } else { - prOps += prospectiveOperation(unparse(exp), FILTER); - - if (isSingleStatementBlock(thenStmt)) - prOps += retrieveProspectiveOperationFromSingleStatement(thenStmt); - else - prOps += retrieveProspectiveOperationsFromStatement(thenStmt); + prOps += prospectiveOperation(unparse(ifExp), FILTER); + prOps += retrieveProspectiveOperationsFromThenStatement(thenStmt); } } } @@ -116,11 +108,35 @@ private list[ProspectiveOperation] retrieveProspectiveOperationsFromIfThenStatem return prOps; } +private ProspectiveOperation createAnyMatchOrNoneMatchPrOp(str returnExp, str ifExp) { + if (returnExp == "true") + return prospectiveOperation(ifExp, ANY_MATCH); + else // (returnExp == "false") + return prospectiveOperation(ifExp, NONE_MATCH); +} + private bool ifStatementHasNoStatementAfter(IfThenStatement ifStmt, list[Stmt] currBlockStmts) { lastStmt = last(currBlockStmts); return lastStmt.stmtType == "IfThenStatement" && lastStmt.statement == ifStmt; } +private list[ProspectiveOperation] retrieveProspectiveOperationsFromThenStatement(Statement thenStmt) { + if (isSingleStatementBlock(thenStmt)) + return retrieveProspectiveOperationFromSingleStatement(thenStmt); + else + return retrieveProspectiveOperationsFromStatement(thenStmt); +} + +// XXX Does this really work? +private bool isSingleStatementBlock(Statement thenStmt) { + if (isBlock("")) { + semiCollonOccurrences = findAll("", ";"); + return size(semiCollonOccurrences) == 1; + } + + return false; +} + private ProspectiveOperation retrieveProspectiveOperationFromSingleStatement(Statement statement) { if (isReducer(statement)) return prospectiveOperation(unparse(statement), REDUCE); @@ -150,16 +166,6 @@ private bool isReferenceToNonFinalLocalVar(LeftHandSide lhs) { return !isEffectiveFinal(var); } -// XXX Does this really work? -private bool isSingleStatementBlock(Statement thenStmt) { - if (isBlock("")) { - semiCollonOccurrences = findAll("", ";"); - return size(semiCollonOccurrences) == 1; - } - - return false; -} - private bool isBlock(str stmt) { try { parse(#Block, stmt); From cdf180e3eaba7085aa3798b4404465f48ce5a58c Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 11 May 2017 17:44:07 -0300 Subject: [PATCH 120/154] Fixed mistake in returning from method. - Surprisingly the ProspectiveOperationsTest didn't catch it. - But more functional tests from ForLoopToFunctional did. --- src/refactor/forloop/ProspectiveOperation.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/refactor/forloop/ProspectiveOperation.rsc b/src/refactor/forloop/ProspectiveOperation.rsc index df31ac5..55e8b3c 100644 --- a/src/refactor/forloop/ProspectiveOperation.rsc +++ b/src/refactor/forloop/ProspectiveOperation.rsc @@ -122,7 +122,7 @@ private bool ifStatementHasNoStatementAfter(IfThenStatement ifStmt, list[Stmt] c private list[ProspectiveOperation] retrieveProspectiveOperationsFromThenStatement(Statement thenStmt) { if (isSingleStatementBlock(thenStmt)) - return retrieveProspectiveOperationFromSingleStatement(thenStmt); + return [retrieveProspectiveOperationFromSingleStatement(thenStmt)]; else return retrieveProspectiveOperationsFromStatement(thenStmt); } From 383ba40621c0b5ad389930ca6d30dd01b601ff4a Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 11 May 2017 19:49:08 -0300 Subject: [PATCH 121/154] BreakIntoStatements retrieving LocalVariableDeclarations from blocks --- src/refactor/forloop/BreakIntoStatements.rsc | 33 ++++++++++++++++--- src/refactor/forloop/ProspectiveOperation.rsc | 7 ---- .../forloop/test/BreakIntoStatementsTest.rsc | 13 ++++++++ 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/src/refactor/forloop/BreakIntoStatements.rsc b/src/refactor/forloop/BreakIntoStatements.rsc index 7474ef1..949dceb 100644 --- a/src/refactor/forloop/BreakIntoStatements.rsc +++ b/src/refactor/forloop/BreakIntoStatements.rsc @@ -6,13 +6,38 @@ import String; import lang::java::\syntax::Java18; import ParseTree; -data Stmt = stmt(Tree statement, str stmtType); +data Stmt = stmtBrokenInto(Tree statement, str stmtType); + +public list[str] breakIntoStatementsAsStringList(str stmt) { + stmts = breakIntoStatements(stmt); + return [ "" | Stmt stmt <- stmts ]; +} + +public list[str] breakIntoStatementsAsStringList(Block block) { + stmts = breakIntoStatements(block); + return [ "" | Stmt stmt <- stmts ]; +} + +public list[Stmt] breakIntoStatements(str stmt) { + if(isBlock(stmt)) + return breakIntoStatements(parse(#Block, stmt)); + return breakIntoStatements(parse(#Statement, stmt)); +} + +public bool isBlock(str stmt) { + try { + parse(#Block, stmt); + return true; + } catch: return false; +} public list[Stmt] breakIntoStatements(Block block) { list [Stmt] stmts = []; top-down-break visit(block) { case Statement stmt: stmts += breakIntoStatements(stmt); + case LocalVariableDeclaration lvdlStmt: + stmts += stmtBrokenInto(lvdlStmt, "LocalVariableDeclarationStatement"); } return stmts; } @@ -21,13 +46,13 @@ public list[Stmt] breakIntoStatements(Statement statement) { list[Stmt] stmts = []; top-down-break visit(statement) { case IfThenStatement ifStmt: { - stmts += stmt(ifStmt, "IfThenStatement"); + stmts += stmtBrokenInto(ifStmt, "IfThenStatement"); } case ExpressionStatement expStmt: { - stmts += stmt(expStmt, "ExpressionStatement"); + stmts += stmtBrokenInto(expStmt, "ExpressionStatement"); } case LocalVariableDeclarationStatement lvdlStmt: { - stmts += stmt(lvdlStmt, "LocalVariableDeclarationStatement"); + stmts += stmtBrokenInto(lvdlStmt, "LocalVariableDeclarationStatement"); } case IfThenElseStatement ifElseStmt: throw "Not Refactoring If/Else for now"; diff --git a/src/refactor/forloop/ProspectiveOperation.rsc b/src/refactor/forloop/ProspectiveOperation.rsc index 55e8b3c..6b77f38 100644 --- a/src/refactor/forloop/ProspectiveOperation.rsc +++ b/src/refactor/forloop/ProspectiveOperation.rsc @@ -166,13 +166,6 @@ private bool isReferenceToNonFinalLocalVar(LeftHandSide lhs) { return !isEffectiveFinal(var); } -private bool isBlock(str stmt) { - try { - parse(#Block, stmt); - return true; - } catch: return false; -} - private list[ProspectiveOperation] markLastStmtAsEager(list[ProspectiveOperation] prOps) { lastPrOp = prOps[-1]; if(lastPrOp.operation == MAP) diff --git a/src/refactor/forloop/test/BreakIntoStatementsTest.rsc b/src/refactor/forloop/test/BreakIntoStatementsTest.rsc index a7d6e3a..633968c 100644 --- a/src/refactor/forloop/test/BreakIntoStatementsTest.rsc +++ b/src/refactor/forloop/test/BreakIntoStatementsTest.rsc @@ -108,4 +108,17 @@ public test bool ex7() { stmts[2].stmtType == "IfThenStatement" && "" == "paths.add(path + \"/\");" && stmts[3].stmtType == "ExpressionStatement"; +} + +// Sometimes LocalVariableDeclaration does not end with a semi collon. +public test bool shouldIncludeLocalVariableDeclarationInsideBlock() { + block = "{\nupdated.put(snapshot.getFolder(), snapshot);\nChangedFiles changedFiles = previous.getChangedFiles(snapshot,\r\n this.triggerFilter);\n}"; + + stmts = breakIntoStatements(block); + + return size(stmts) == 2 && + "" == "updated.put(snapshot.getFolder(), snapshot);" && + stmts[0].stmtType == "ExpressionStatement" && + "" == "ChangedFiles changedFiles = previous.getChangedFiles(snapshot,\r\n this.triggerFilter)" && + stmts[1].stmtType == "LocalVariableDeclarationStatement"; } \ No newline at end of file From 95e43e69941bfc5660f6b888ad0dffef2dc2ee7d Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 11 May 2017 20:08:49 -0300 Subject: [PATCH 122/154] LocalVariableDeclaration != LocalVariableDeclarationStatement. - The first does not end the statement with a ';' --- src/refactor/forloop/BreakIntoStatements.rsc | 2 +- src/refactor/forloop/test/BreakIntoStatementsTest.rsc | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/refactor/forloop/BreakIntoStatements.rsc b/src/refactor/forloop/BreakIntoStatements.rsc index 949dceb..61a6c12 100644 --- a/src/refactor/forloop/BreakIntoStatements.rsc +++ b/src/refactor/forloop/BreakIntoStatements.rsc @@ -36,7 +36,7 @@ public list[Stmt] breakIntoStatements(Block block) { top-down-break visit(block) { case Statement stmt: stmts += breakIntoStatements(stmt); - case LocalVariableDeclaration lvdlStmt: + case LocalVariableDeclarationStatement lvdlStmt: stmts += stmtBrokenInto(lvdlStmt, "LocalVariableDeclarationStatement"); } return stmts; diff --git a/src/refactor/forloop/test/BreakIntoStatementsTest.rsc b/src/refactor/forloop/test/BreakIntoStatementsTest.rsc index 633968c..8cb746c 100644 --- a/src/refactor/forloop/test/BreakIntoStatementsTest.rsc +++ b/src/refactor/forloop/test/BreakIntoStatementsTest.rsc @@ -110,15 +110,14 @@ public test bool ex7() { stmts[3].stmtType == "ExpressionStatement"; } -// Sometimes LocalVariableDeclaration does not end with a semi collon. public test bool shouldIncludeLocalVariableDeclarationInsideBlock() { block = "{\nupdated.put(snapshot.getFolder(), snapshot);\nChangedFiles changedFiles = previous.getChangedFiles(snapshot,\r\n this.triggerFilter);\n}"; stmts = breakIntoStatements(block); - + printStmtsBrokenInto(stmts); return size(stmts) == 2 && "" == "updated.put(snapshot.getFolder(), snapshot);" && stmts[0].stmtType == "ExpressionStatement" && - "" == "ChangedFiles changedFiles = previous.getChangedFiles(snapshot,\r\n this.triggerFilter)" && + "" == "ChangedFiles changedFiles = previous.getChangedFiles(snapshot,\r\n this.triggerFilter);" && stmts[1].stmtType == "LocalVariableDeclarationStatement"; } \ No newline at end of file From d9df57269d6d2f98b3a9797bf3236c3acb635e50 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 11 May 2017 20:21:39 -0300 Subject: [PATCH 123/154] Example with throw statement working. - In the end it is working with an if that is not the last statement. - It is keeping the block - It is not disregarding the throw statement that was previously ignored. --- src/refactor/forloop/ForLoopToFunctional.rsc | 52 +++---------- .../forloop/ForLoopToFunctionalTest.rsc | 78 +++++++++++-------- 2 files changed, 58 insertions(+), 72 deletions(-) diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/refactor/forloop/ForLoopToFunctional.rsc index 659305c..4c93d68 100644 --- a/src/refactor/forloop/ForLoopToFunctional.rsc +++ b/src/refactor/forloop/ForLoopToFunctional.rsc @@ -12,6 +12,7 @@ import refactor::forloop::UsedVariables; import refactor::forloop::AvailableVariables; import refactor::forloop::OperationType; import refactor::forloop::ForLoopBodyReferences; +import refactor::forloop::BreakIntoStatements; public data ComposableProspectiveOperation = composableProspectiveOperation(ProspectiveOperation prOp, set[str] neededVars, set[str] availableVars); @@ -150,49 +151,18 @@ private set[str] mergeNeededVars(set[str] currNeededVars, set[str] prevNeededVar } private ComposableProspectiveOperation mergeIntoABlock(ComposableProspectiveOperation prev, ComposableProspectiveOperation curr) { - list[str] statements = retrieveAllStatements(prev.prOp) + retrieveAllStatements(curr.prOp); + prevStatements = retrieveAllStatements(prev.prOp); + currStatements = retrieveAllStatements(curr.prOp); + list[str] statements = prevStatements + currStatements ; Block statementsAsOneBlock = transformStatementsInBlock(statements); prOp = prospectiveOperation(unparse(statementsAsOneBlock), curr.prOp.operation); return mergeComposableProspectiveOperations(prOp, prev, curr); } private list[str] retrieveAllStatements(ProspectiveOperation prOp) { - list[str] allStatements = []; - if (isBlock(prOp.stmt)) - return retrieveAllStatementsFromBlock(prOp.stmt); - else if(isLocalVariableDeclarationStatement(prOp.stmt)) + if(isLocalVariableDeclarationStatement(prOp.stmt)) return [prOp.stmt]; - else - return retrieveAllExpressionStatementsFromStatement(prOp.stmt); -} - -private bool isBlock(str stmt) { - try { - parse(#Block, stmt); - return true; - } catch: return false; -} - -private list[str] retrieveAllStatementsFromBlock(str blockStr) { - list[str] blockStatements = []; - block = parse(#Block, blockStr); - top-down visit(block) { - case BlockStatement blockStmt: - blockStatements += unparse(blockStmt); - } - return blockStatements; -} - -private list[str] retrieveAllExpressionStatementsFromStatement(str statement) { - list[str] stmts = []; - Statement stmt = parse(#Statement, statement); - top-down visit(stmt) { - case ExpressionStatement expStmt: - stmts += unparse(expStmt); - case (IfThenStatement) `if () `: - stmts += "if ()"; - } - return stmts; + return breakIntoStatementsAsStringList(prOp.stmt); } private Block transformStatementsInBlock(list[str] stmts) { @@ -246,10 +216,11 @@ private bool isNumericLiteral(str stmt) { private ComposableProspectiveOperation addReturnToMapBody(ComposableProspectiveOperation curr, set[str] nextNeededVars) { list[str] stmts = []; - if (isBlock(curr.prOp.stmt)) - stmts += retrieveAllStatementsFromBlock(curr.prOp.stmt); + stmt = curr.prOp.stmt; + if (isBlock(stmt)) + stmts += breakIntoStatementsAsStringList(parse(#Block, stmt)); else - stmts += curr.prOp.stmt; + stmts += stmt; varName = isEmpty(nextNeededVars) ? "_item" : getOneFrom(nextNeededVars); stmts += "return ;"; @@ -285,7 +256,8 @@ private Statement chainOperationsIntoStatement(set[MethodVar] methodVars, list[C str chainStr = ".stream()"; for(composablePrOp <- composablePrOps) { - chainStr = "." + buildChainableOperation(methodVars, composablePrOp); + chainableOperation = buildChainableOperation(methodVars, composablePrOp); + chainStr = "." + chainableOperation; } return parse(#Statement, ";"); diff --git a/src/refactor/forloop/ForLoopToFunctionalTest.rsc b/src/refactor/forloop/ForLoopToFunctionalTest.rsc index 9886e3d..ab0183a 100644 --- a/src/refactor/forloop/ForLoopToFunctionalTest.rsc +++ b/src/refactor/forloop/ForLoopToFunctionalTest.rsc @@ -8,6 +8,8 @@ import refactor::forloop::ForLoopToFunctional; import MethodVar; import LocalVariablesFinder; import LocalVariablesFinderTestResources; +import refactor::forloop::ProspectiveOperationTestResources; +import ParseTreeVisualization; public test bool ex1() { fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T1.java|; @@ -42,22 +44,6 @@ public test bool reduceAsNotTheLastOperationShouldNotBeRefactored() { return false; } -// TODO nested loops needed to be changed in ProspectiveOperation -//public test bool nestedLoops() { -// fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/NestedLoops.java|; -// methodBody = parse(#MethodBody, readFile(fileLoc)); -// methodHeader = parse(#MethodHeader, "void testComplexBuilder()"); -// set[MethodVar] methodVars = findLocalVariables(methodHeader, methodBody); -// fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T2For.java|; -// EnhancedForStatement forStmt = parse(#EnhancedForStatement, "for (Integer red : colorElem) {\n for (Integer green : colorElem) {\n for (Integer blue : colorElem) {\n webSafeColorsBuilder.add((red \<\< 16) + (green \<\< 8) + blue);\n }\n }\n }"); -// VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "red"); -// Expression collectionId = parse(#Expression, "colorElem"); -// -// refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); -// -// return false; -//} - public test bool shouldRefactorReduceWithCompoundPlusAssignmentOperator() { fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T2.java|; methodBody = parse(#MethodBody, readFile(fileLoc)); @@ -136,21 +122,49 @@ public test bool shouldThrowExceptionWhenALoopWithOnlyOneReferenceToOutsideNonEf return false; } -public test bool shouldRefactorToReduceWithPostIncrement() { - throw "Not yet implemented"; - - methodHeader = parse(#MethodHeader, "\ ImmutableSortedMultiset\ copyOfSortedEntries(Comparator\ comparator, Collection\\> entries)"); - methodBodyLoc = |project://rascal-Java8/testes/localVariables/MethodBodyReduceWithPostIncrement|; +public test bool shouldWorkWithThrowStatementInsideAnIfThatIsNotTheLastStatement() { + tuple [set[MethodVar] vars, EnhancedForStatement loop] loopWithThrowStatement = loopWithThrowStatement(); + methodBodyLoc = |project://rascal-Java8//testes/localVariables/MethodBodyPostDecrementedVar|; methodBody = parse(#MethodBody, readFile(methodBodyLoc)); - methodVars = findLocalVariables(methodHeader, methodBody); - forStmt = parse(#EnhancedForStatement, "for (Entry\ entry : entries) {\n elementsBuilder.add(entry.getElement());\n // cumulativeCounts[i + 1] = cumulativeCounts[i] + entry.getCount();\n i++;\n }"); - VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "entry"); - Expression collectionId = parse(#Expression, "entries"); + VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "key"); + Expression collectionId = parse(#Expression, "keysToLoad"); - try { - refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); - } catch: - return true; - - return false; -} \ No newline at end of file + refactoredStatement = buildRefactoredEnhancedFor(loopWithThrowStatement.vars, loopWithThrowStatement.loop, methodBody, iteratedVarName, collectionId); + + return "" == "keysToLoad.forEach(key -\> {\nV value = newEntries.get(key);\nif (value == null) {\n throw new InvalidCacheLoadException(\"loadAll failed to return a value for \" + key);\n }\nresult.put(key, value);\n});"; +} + +//public test bool shouldRefactorToReduceWithPostIncrement() { +// throw "Not yet implemented"; +// +// methodHeader = parse(#MethodHeader, "\ ImmutableSortedMultiset\ copyOfSortedEntries(Comparator\ comparator, Collection\\> entries)"); +// methodBodyLoc = |project://rascal-Java8/testes/localVariables/MethodBodyReduceWithPostIncrement|; +// methodBody = parse(#MethodBody, readFile(methodBodyLoc)); +// methodVars = findLocalVariables(methodHeader, methodBody); +// forStmt = parse(#EnhancedForStatement, "for (Entry\ entry : entries) {\n elementsBuilder.add(entry.getElement());\n // cumulativeCounts[i + 1] = cumulativeCounts[i] + entry.getCount();\n i++;\n }"); +// VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "entry"); +// Expression collectionId = parse(#Expression, "entries"); +// +// try { +// refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); +// } catch: +// return true; +// +// return false; +//} + +// TODO nested loops needed to be changed in ProspectiveOperation +//public test bool nestedLoops() { +// fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/NestedLoops.java|; +// methodBody = parse(#MethodBody, readFile(fileLoc)); +// methodHeader = parse(#MethodHeader, "void testComplexBuilder()"); +// set[MethodVar] methodVars = findLocalVariables(methodHeader, methodBody); +// fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T2For.java|; +// EnhancedForStatement forStmt = parse(#EnhancedForStatement, "for (Integer red : colorElem) {\n for (Integer green : colorElem) {\n for (Integer blue : colorElem) {\n webSafeColorsBuilder.add((red \<\< 16) + (green \<\< 8) + blue);\n }\n }\n }"); +// VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "red"); +// Expression collectionId = parse(#Expression, "colorElem"); +// +// refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); +// +// return false; +//} \ No newline at end of file From 15cfb511ad57d7ffe6b408d5bb17d8919c58f48b Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 11 May 2017 20:57:33 -0300 Subject: [PATCH 124/154] Getting right another 2 examples that weren't working before! --- .../forloop/ForLoopToFunctionalTest.rsc | 28 +++++++++++++++++++ .../MethodBodyIfAsNotAFilter | 22 +++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 testes/ForLoopToFunctional/MethodBodyIfAsNotAFilter diff --git a/src/refactor/forloop/ForLoopToFunctionalTest.rsc b/src/refactor/forloop/ForLoopToFunctionalTest.rsc index ab0183a..5918200 100644 --- a/src/refactor/forloop/ForLoopToFunctionalTest.rsc +++ b/src/refactor/forloop/ForLoopToFunctionalTest.rsc @@ -134,6 +134,34 @@ public test bool shouldWorkWithThrowStatementInsideAnIfThatIsNotTheLastStatement return "" == "keysToLoad.forEach(key -\> {\nV value = newEntries.get(key);\nif (value == null) {\n throw new InvalidCacheLoadException(\"loadAll failed to return a value for \" + key);\n }\nresult.put(key, value);\n});"; } +public test bool loopWithIfWithTwoStatementsInsideBlockShouldRefactorInnerIfAsMap() { + tuple [set[MethodVar] vars, EnhancedForStatement loop] loop = loopWithIfWithTwoStatementsInsideBlock(); + methodBodyLoc = |project://rascal-Java8//testes/ForLoopToFunctional/MethodBodyIfWithTwoStmtsInsideAndStmtAfterBlock.java|; + methodBody = parse(#MethodBody, readFile(methodBodyLoc)); + VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "endpoint"); + Expression collectionId = parse(#Expression, "endpoints"); + + refactoredStatement = buildRefactoredEnhancedFor(loop.vars, loop.loop, methodBody, iteratedVarName, collectionId); + + return "" == "endpoints.stream().filter(endpoint -\> isIncluded(endpoint)).map(endpoint -\> endpointHandlerMapping.getPath(endpoint.getPath())).map(path -\> {\npaths.add(path);\nreturn path;\n}).map(path -\> {\nif (!path.equals(\"\")) {\r\n\t\t\t\t\t\tpaths.add(path + \"/**\");\r\n\t\t\t\t\t\t// Add Spring MVC-generated additional paths\r\n\t\t\t\t\t\tpaths.add(path + \".*\");\r\n\t\t\t\t\t}\nreturn path;\n}).forEach(path -\> {\npaths.add(path + \"/\");\n});"; +} + +public test bool anotherIfThatIsMap() { + methodHeader = parse(#MethodHeader, "void afterPropertiesSet() throws Exception"); + methodBodyLoc = |project://rascal-Java8/testes/ForLoopToFunctional/MethodBodyIfAsNotAFilter|; + methodBody = parse(#MethodBody, readFile(methodBodyLoc)); + methodVars = findLocalVariables(methodHeader, methodBody); + forStmt = parse(#EnhancedForStatement, "for (Endpoint\ endpoint : delegates) {if (isGenericEndpoint(endpoint.getClass()) && endpoint.isEnabled()) {EndpointMvcAdapter adapter = new EndpointMvcAdapter(endpoint);String path = determinePath(endpoint,this.applicationContext.getEnvironment());if (path != null) {adapter.setPath(path);}this.endpoints.add(adapter);}}"); + VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "endpoint"); + Expression collectionId = parse(#Expression, "delegates"); + + refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); + + println(refactoredStatement); + + return "" == "delegates.stream().filter(endpoint -\> isGenericEndpoint(endpoint.getClass()) && endpoint.isEnabled()).map(endpoint -\> {\nEndpointMvcAdapter adapter = new EndpointMvcAdapter(endpoint);\nString path = determinePath(endpoint,this.applicationContext.getEnvironment());\nif (path != null) {adapter.setPath(path);}\nreturn adapter;\n}).forEach(adapter -\> {\nthis.endpoints.add(adapter);\n});"; +} + //public test bool shouldRefactorToReduceWithPostIncrement() { // throw "Not yet implemented"; // diff --git a/testes/ForLoopToFunctional/MethodBodyIfAsNotAFilter b/testes/ForLoopToFunctional/MethodBodyIfAsNotAFilter new file mode 100644 index 0000000..d292517 --- /dev/null +++ b/testes/ForLoopToFunctional/MethodBodyIfAsNotAFilter @@ -0,0 +1,22 @@ +{ + Collection existing = BeanFactoryUtils + .beansOfTypeIncludingAncestors(this.applicationContext, MvcEndpoint.class) + .values(); + this.endpoints.addAll(existing); + this.customTypes = findEndpointClasses(existing); + @SuppressWarnings("rawtypes") + Collection delegates = BeanFactoryUtils + .beansOfTypeIncludingAncestors(this.applicationContext, Endpoint.class) + .values(); + for (Endpoint endpoint : delegates) { + if (isGenericEndpoint(endpoint.getClass()) && endpoint.isEnabled()) { + EndpointMvcAdapter adapter = new EndpointMvcAdapter(endpoint); + String path = determinePath(endpoint, + this.applicationContext.getEnvironment()); + if (path != null) { + adapter.setPath(path); + } + this.endpoints.add(adapter); + } + } + } \ No newline at end of file From 826c267aec11d091e7b1e59ea622b85ef686e6b2 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 11 May 2017 21:52:17 -0300 Subject: [PATCH 125/154] Changing variable's name that was forgotten. --- src/ForLoop.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ForLoop.rsc b/src/ForLoop.rsc index c4bfe3f..b8ad2fd 100644 --- a/src/ForLoop.rsc +++ b/src/ForLoop.rsc @@ -105,7 +105,7 @@ private bool isLoopRefactorable(set[MethodVar] methodLocalVariables, Expression // TODO extract module and test it private bool loopBodyPassConditions(Statement loopBody) { returnCount = 0; - visit(stmt) { + visit(loopBody) { case (ThrowStatement) `throw new ( );`: { if ("" in checkedExceptionClasses) return false; } From fc8379b90c2704bf6d05e5e02298df3d1f68e5b7 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sat, 13 May 2017 23:27:05 -0300 Subject: [PATCH 126/154] ForLoopToFunctional refactors loops iterating on 'this.field'. - We actually don't have complete functional tests. -- We don't exercise the entire refactor stack. --- No tests starting from ForLoop. --- No tests for the entire preconditions checks too. - An "overly strong precondition" is what prevents the refactor. -- We are ignoring loops iterating on 'this.field' --- It's actually considered a method call right now. --- .../forloop/ForLoopToFunctionalTest.rsc | 39 +- testes/classFields/ForIteratingOnThisField | 3 + testes/classFields/ForIteratingOnThisField2 | 3 + .../MethodBodyIteratingOnThisField | 17 + .../MethodBodyIteratingOnThisField2 | 6 + .../TomcatServletWebServerFactory.java | 872 ++++++++++++++++++ 6 files changed, 938 insertions(+), 2 deletions(-) create mode 100644 testes/classFields/ForIteratingOnThisField create mode 100644 testes/classFields/ForIteratingOnThisField2 create mode 100644 testes/classFields/MethodBodyIteratingOnThisField create mode 100644 testes/classFields/MethodBodyIteratingOnThisField2 create mode 100644 testes/classFields/TomcatServletWebServerFactory.java diff --git a/src/refactor/forloop/ForLoopToFunctionalTest.rsc b/src/refactor/forloop/ForLoopToFunctionalTest.rsc index 5918200..a941dd8 100644 --- a/src/refactor/forloop/ForLoopToFunctionalTest.rsc +++ b/src/refactor/forloop/ForLoopToFunctionalTest.rsc @@ -9,6 +9,7 @@ import MethodVar; import LocalVariablesFinder; import LocalVariablesFinderTestResources; import refactor::forloop::ProspectiveOperationTestResources; +import refactor::forloop::ClassFieldsFinder; import ParseTreeVisualization; public test bool ex1() { @@ -157,11 +158,45 @@ public test bool anotherIfThatIsMap() { refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); - println(refactoredStatement); - return "" == "delegates.stream().filter(endpoint -\> isGenericEndpoint(endpoint.getClass()) && endpoint.isEnabled()).map(endpoint -\> {\nEndpointMvcAdapter adapter = new EndpointMvcAdapter(endpoint);\nString path = determinePath(endpoint,this.applicationContext.getEnvironment());\nif (path != null) {adapter.setPath(path);}\nreturn adapter;\n}).forEach(adapter -\> {\nthis.endpoints.add(adapter);\n});"; } +public test bool shouldRefactorLoopIteratingOnThisField() { + methodHeader = parse(#MethodHeader, "WebServer getWebServer(ServletContextInitializer... initializers)"); + methodBodyLoc = |project://rascal-Java8/testes/classFields/MethodBodyIteratingOnThisField|; + methodBody = parse(#MethodBody, readFile(methodBodyLoc)); + methodVars = findLocalVariables(methodHeader, methodBody); + fileForLoc = |project://rascal-Java8/testes/classFields/ForIteratingOnThisField|; + EnhancedForStatement forStmt = parse(#EnhancedForStatement, readFile(fileForLoc)); + VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "additionalConnector"); + Expression collectionId = parse(#Expression, "this.additionalTomcatConnectors"); + + classFields = findClassFields(parse(#CompilationUnit, readFile(|project://rascal-Java8/testes/classFields/TomcatServletWebServerFactory.java|))); + vars = methodVars + classFields; + + refactoredStatement = buildRefactoredEnhancedFor(vars, forStmt, methodBody, iteratedVarName, collectionId); + + return "" == "this.additionalTomcatConnectors.forEach(additionalConnector -\> {\ntomcat.getService().addConnector(additionalConnector);\n});"; +} + +public test bool shouldRefactorLoopIteratingOnThisField2() { + methodHeader = parse(#MethodHeader, "void configureEngine(Engine engine)"); + methodBodyLoc = |project://rascal-Java8/testes/classFields/MethodBodyIteratingOnThisField2|; + methodBody = parse(#MethodBody, readFile(methodBodyLoc)); + methodVars = findLocalVariables(methodHeader, methodBody); + fileForLoc = |project://rascal-Java8/testes/classFields/ForIteratingOnThisField2|; + EnhancedForStatement forStmt = parse(#EnhancedForStatement, readFile(fileForLoc)); + VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "valve"); + Expression collectionId = parse(#Expression, "this.engineValves"); + + classFields = findClassFields(parse(#CompilationUnit, readFile(|project://rascal-Java8/testes/classFields/TomcatServletWebServerFactory.java|))); + vars = methodVars + classFields; + + refactoredStatement = buildRefactoredEnhancedFor(vars, forStmt, methodBody, iteratedVarName, collectionId); + + return "" == "this.engineValves.forEach(valve -\> {\nengine.getPipeline().addValve(valve);\n});"; +} + //public test bool shouldRefactorToReduceWithPostIncrement() { // throw "Not yet implemented"; // diff --git a/testes/classFields/ForIteratingOnThisField b/testes/classFields/ForIteratingOnThisField new file mode 100644 index 0000000..6fff176 --- /dev/null +++ b/testes/classFields/ForIteratingOnThisField @@ -0,0 +1,3 @@ +for (Connector additionalConnector : this.additionalTomcatConnectors) { + tomcat.getService().addConnector(additionalConnector); + } \ No newline at end of file diff --git a/testes/classFields/ForIteratingOnThisField2 b/testes/classFields/ForIteratingOnThisField2 new file mode 100644 index 0000000..fadf1e2 --- /dev/null +++ b/testes/classFields/ForIteratingOnThisField2 @@ -0,0 +1,3 @@ +for (Valve valve : this.engineValves) { + engine.getPipeline().addValve(valve); + } \ No newline at end of file diff --git a/testes/classFields/MethodBodyIteratingOnThisField b/testes/classFields/MethodBodyIteratingOnThisField new file mode 100644 index 0000000..a5848b6 --- /dev/null +++ b/testes/classFields/MethodBodyIteratingOnThisField @@ -0,0 +1,17 @@ +{ + Tomcat tomcat = new Tomcat(); + File baseDir = (this.baseDirectory != null ? this.baseDirectory + : createTempDir("tomcat")); + tomcat.setBaseDir(baseDir.getAbsolutePath()); + Connector connector = new Connector(this.protocol); + tomcat.getService().addConnector(connector); + customizeConnector(connector); + tomcat.setConnector(connector); + tomcat.getHost().setAutoDeploy(false); + configureEngine(tomcat.getEngine()); + for (Connector additionalConnector : this.additionalTomcatConnectors) { + tomcat.getService().addConnector(additionalConnector); + } + prepareContext(tomcat.getHost(), initializers); + return getTomcatWebServer(tomcat); + } \ No newline at end of file diff --git a/testes/classFields/MethodBodyIteratingOnThisField2 b/testes/classFields/MethodBodyIteratingOnThisField2 new file mode 100644 index 0000000..11d16c0 --- /dev/null +++ b/testes/classFields/MethodBodyIteratingOnThisField2 @@ -0,0 +1,6 @@ +{ + engine.setBackgroundProcessorDelay(this.backgroundProcessorDelay); + for (Valve valve : this.engineValves) { + engine.getPipeline().addValve(valve); + } + } \ No newline at end of file diff --git a/testes/classFields/TomcatServletWebServerFactory.java b/testes/classFields/TomcatServletWebServerFactory.java new file mode 100644 index 0000000..d57b959 --- /dev/null +++ b/testes/classFields/TomcatServletWebServerFactory.java @@ -0,0 +1,872 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.web.embedded.tomcat; + +import java.io.File; +import java.io.FileNotFoundException; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import javax.servlet.ServletContainerInitializer; + +import org.apache.catalina.Context; +import org.apache.catalina.Engine; +import org.apache.catalina.Host; +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleEvent; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.Manager; +import org.apache.catalina.Valve; +import org.apache.catalina.WebResourceRoot.ResourceSetType; +import org.apache.catalina.Wrapper; +import org.apache.catalina.connector.Connector; +import org.apache.catalina.loader.WebappLoader; +import org.apache.catalina.session.StandardManager; +import org.apache.catalina.startup.Tomcat; +import org.apache.catalina.startup.Tomcat.FixContextListener; +import org.apache.catalina.webresources.TomcatURLStreamHandlerFactory; +import org.apache.coyote.AbstractProtocol; +import org.apache.coyote.ProtocolHandler; +import org.apache.coyote.http11.AbstractHttp11JsseProtocol; +import org.apache.coyote.http11.AbstractHttp11Protocol; +import org.apache.coyote.http11.Http11NioProtocol; +import org.apache.tomcat.util.net.SSLHostConfig; + +import org.springframework.boot.web.server.Compression; +import org.springframework.boot.web.server.ErrorPage; +import org.springframework.boot.web.server.MimeMappings; +import org.springframework.boot.web.server.Ssl; +import org.springframework.boot.web.server.Ssl.ClientAuth; +import org.springframework.boot.web.server.SslStoreProvider; +import org.springframework.boot.web.server.WebServer; +import org.springframework.boot.web.server.WebServerException; +import org.springframework.boot.web.servlet.ServletContextInitializer; +import org.springframework.boot.web.servlet.server.AbstractServletWebServerFactory; +import org.springframework.context.ResourceLoaderAware; +import org.springframework.core.io.ResourceLoader; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; +import org.springframework.util.ResourceUtils; +import org.springframework.util.StringUtils; + +/** + * {@link AbstractServletWebServerFactory} that can be used to create + * {@link TomcatWebServer}s. Can be initialized using Spring's + * {@link ServletContextInitializer}s or Tomcat {@link LifecycleListener}s. + *

+ * Unless explicitly configured otherwise this factory will created containers that + * listens for HTTP requests on port 8080. + * + * @author Phillip Webb + * @author Dave Syer + * @author Brock Mills + * @author Stephane Nicoll + * @author Andy Wilkinson + * @author Eddú Meléndez + * @author Christoffer Sawicki + * @since 2.0.0 + * @see #setPort(int) + * @see #setContextLifecycleListeners(Collection) + * @see TomcatWebServer + */ +public class TomcatServletWebServerFactory extends AbstractServletWebServerFactory + implements ResourceLoaderAware { + + private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); + + private static final Set> NO_CLASSES = Collections.emptySet(); + + /** + * The class name of default protocol used. + */ + public static final String DEFAULT_PROTOCOL = "org.apache.coyote.http11.Http11NioProtocol"; + + private File baseDirectory; + + private List engineValves = new ArrayList<>(); + + private List contextValves = new ArrayList<>(); + + private List contextLifecycleListeners = new ArrayList<>(); + + private List tomcatContextCustomizers = new ArrayList<>(); + + private List tomcatConnectorCustomizers = new ArrayList<>(); + + private List additionalTomcatConnectors = new ArrayList<>(); + + private ResourceLoader resourceLoader; + + private String protocol = DEFAULT_PROTOCOL; + + private Set tldSkipPatterns = new LinkedHashSet<>(TldSkipPatterns.DEFAULT); + + private Charset uriEncoding = DEFAULT_CHARSET; + + private int backgroundProcessorDelay; + + /** + * Create a new {@link TomcatServletWebServerFactory} instance. + */ + public TomcatServletWebServerFactory() { + super(); + } + + /** + * Create a new {@link TomcatServletWebServerFactory} that listens for requests using + * the specified port. + * @param port the port to listen on + */ + public TomcatServletWebServerFactory(int port) { + super(port); + } + + /** + * Create a new {@link TomcatServletWebServerFactory} with the specified context path + * and port. + * @param contextPath the root context path + * @param port the port to listen on + */ + public TomcatServletWebServerFactory(String contextPath, int port) { + super(contextPath, port); + } + + @Override + public WebServer getWebServer(ServletContextInitializer... initializers) { + Tomcat tomcat = new Tomcat(); + File baseDir = (this.baseDirectory != null ? this.baseDirectory + : createTempDir("tomcat")); + tomcat.setBaseDir(baseDir.getAbsolutePath()); + Connector connector = new Connector(this.protocol); + tomcat.getService().addConnector(connector); + customizeConnector(connector); + tomcat.setConnector(connector); + tomcat.getHost().setAutoDeploy(false); + configureEngine(tomcat.getEngine()); + for (Connector additionalConnector : this.additionalTomcatConnectors) { + tomcat.getService().addConnector(additionalConnector); + } + prepareContext(tomcat.getHost(), initializers); + return getTomcatWebServer(tomcat); + } + + private void configureEngine(Engine engine) { + engine.setBackgroundProcessorDelay(this.backgroundProcessorDelay); + for (Valve valve : this.engineValves) { + engine.getPipeline().addValve(valve); + } + } + + protected void prepareContext(Host host, ServletContextInitializer[] initializers) { + File docBase = getValidDocumentRoot(); + docBase = (docBase != null ? docBase : createTempDir("tomcat-docbase")); + final TomcatEmbeddedContext context = new TomcatEmbeddedContext(); + context.setName(getContextPath()); + context.setDisplayName(getDisplayName()); + context.setPath(getContextPath()); + context.setDocBase(docBase.getAbsolutePath()); + context.addLifecycleListener(new FixContextListener()); + context.setParentClassLoader( + this.resourceLoader != null ? this.resourceLoader.getClassLoader() + : ClassUtils.getDefaultClassLoader()); + resetDefaultLocaleMapping(context); + addLocaleMappings(context); + try { + context.setUseRelativeRedirects(false); + } + catch (NoSuchMethodError ex) { + // Tomcat is < 8.0.30. Continue + } + SkipPatternJarScanner.apply(context, this.tldSkipPatterns); + WebappLoader loader = new WebappLoader(context.getParentClassLoader()); + loader.setLoaderClass(TomcatEmbeddedWebappClassLoader.class.getName()); + loader.setDelegate(true); + context.setLoader(loader); + if (isRegisterDefaultServlet()) { + addDefaultServlet(context); + } + if (shouldRegisterJspServlet()) { + addJspServlet(context); + addJasperInitializer(context); + } + context.addLifecycleListener(new StaticResourceConfigurer(context)); + ServletContextInitializer[] initializersToUse = mergeInitializers(initializers); + configureContext(context, initializersToUse); + host.addChild(context); + postProcessContext(context); + } + + /** + * Override Tomcat's default locale mappings to align with other servers. See + * {@code org.apache.catalina.util.CharsetMapperDefault.properties}. + * @param context the context to reset + */ + private void resetDefaultLocaleMapping(TomcatEmbeddedContext context) { + context.addLocaleEncodingMappingParameter(Locale.ENGLISH.toString(), + DEFAULT_CHARSET.displayName()); + context.addLocaleEncodingMappingParameter(Locale.FRENCH.toString(), + DEFAULT_CHARSET.displayName()); + } + + private void addLocaleMappings(TomcatEmbeddedContext context) { + for (Map.Entry entry : getLocaleCharsetMappings().entrySet()) { + Locale locale = entry.getKey(); + Charset charset = entry.getValue(); + context.addLocaleEncodingMappingParameter(locale.toString(), + charset.toString()); + } + } + + private void addDefaultServlet(Context context) { + Wrapper defaultServlet = context.createWrapper(); + defaultServlet.setName("default"); + defaultServlet.setServletClass("org.apache.catalina.servlets.DefaultServlet"); + defaultServlet.addInitParameter("debug", "0"); + defaultServlet.addInitParameter("listings", "false"); + defaultServlet.setLoadOnStartup(1); + // Otherwise the default location of a Spring DispatcherServlet cannot be set + defaultServlet.setOverridable(true); + context.addChild(defaultServlet); + addServletMapping(context, "/", "default"); + } + + private void addJspServlet(Context context) { + Wrapper jspServlet = context.createWrapper(); + jspServlet.setName("jsp"); + jspServlet.setServletClass(getJsp().getClassName()); + jspServlet.addInitParameter("fork", "false"); + for (Entry initParameter : getJsp().getInitParameters() + .entrySet()) { + jspServlet.addInitParameter(initParameter.getKey(), initParameter.getValue()); + } + jspServlet.setLoadOnStartup(3); + context.addChild(jspServlet); + addServletMapping(context, "*.jsp", "jsp"); + addServletMapping(context, "*.jspx", "jsp"); + } + + @SuppressWarnings("deprecation") + private void addServletMapping(Context context, String pattern, String name) { + context.addServletMapping(pattern, name); + } + + private void addJasperInitializer(TomcatEmbeddedContext context) { + try { + ServletContainerInitializer initializer = (ServletContainerInitializer) ClassUtils + .forName("org.apache.jasper.servlet.JasperInitializer", null) + .newInstance(); + context.addServletContainerInitializer(initializer, null); + } + catch (Exception ex) { + // Probably not Tomcat 8 + } + } + + // Needs to be protected so it can be used by subclasses + protected void customizeConnector(Connector connector) { + int port = (getPort() >= 0 ? getPort() : 0); + connector.setPort(port); + if (StringUtils.hasText(this.getServerHeader())) { + connector.setAttribute("server", this.getServerHeader()); + } + if (connector.getProtocolHandler() instanceof AbstractProtocol) { + customizeProtocol((AbstractProtocol) connector.getProtocolHandler()); + } + if (getUriEncoding() != null) { + connector.setURIEncoding(getUriEncoding().name()); + } + + // If ApplicationContext is slow to start we want Tomcat not to bind to the socket + // prematurely... + connector.setProperty("bindOnInit", "false"); + + if (getSsl() != null && getSsl().isEnabled()) { + customizeSsl(connector); + } + if (getCompression() != null && getCompression().getEnabled()) { + customizeCompression(connector); + } + for (TomcatConnectorCustomizer customizer : this.tomcatConnectorCustomizers) { + customizer.customize(connector); + } + } + + private void customizeProtocol(AbstractProtocol protocol) { + if (getAddress() != null) { + protocol.setAddress(getAddress()); + } + } + + private void customizeSsl(Connector connector) { + ProtocolHandler handler = connector.getProtocolHandler(); + Assert.state(handler instanceof AbstractHttp11JsseProtocol, + "To use SSL, the connector's protocol handler must be an " + + "AbstractHttp11JsseProtocol subclass"); + configureSsl((AbstractHttp11JsseProtocol) handler, getSsl()); + connector.setScheme("https"); + connector.setSecure(true); + } + + private void customizeCompression(Connector connector) { + ProtocolHandler handler = connector.getProtocolHandler(); + if (handler instanceof AbstractHttp11Protocol) { + AbstractHttp11Protocol protocol = (AbstractHttp11Protocol) handler; + Compression compression = getCompression(); + protocol.setCompression("on"); + protocol.setCompressionMinSize(compression.getMinResponseSize()); + protocol.setCompressibleMimeType( + StringUtils.arrayToCommaDelimitedString(compression.getMimeTypes())); + if (getCompression().getExcludedUserAgents() != null) { + protocol.setNoCompressionUserAgents( + StringUtils.arrayToCommaDelimitedString( + getCompression().getExcludedUserAgents())); + } + } + } + + /** + * Configure Tomcat's {@link AbstractHttp11JsseProtocol} for SSL. + * @param protocol the protocol + * @param ssl the ssl details + */ + protected void configureSsl(AbstractHttp11JsseProtocol protocol, Ssl ssl) { + protocol.setSSLEnabled(true); + protocol.setSslProtocol(ssl.getProtocol()); + configureSslClientAuth(protocol, ssl); + protocol.setKeystorePass(ssl.getKeyStorePassword()); + protocol.setKeyPass(ssl.getKeyPassword()); + protocol.setKeyAlias(ssl.getKeyAlias()); + String ciphers = StringUtils.arrayToCommaDelimitedString(ssl.getCiphers()); + protocol.setCiphers(StringUtils.hasText(ciphers) ? ciphers : null); + if (ssl.getEnabledProtocols() != null) { + try { + for (SSLHostConfig sslHostConfig : protocol.findSslHostConfigs()) { + sslHostConfig.setProtocols(StringUtils + .arrayToCommaDelimitedString(ssl.getEnabledProtocols())); + } + } + catch (NoSuchMethodError ex) { + // Tomcat 8.0.x or earlier + Assert.isTrue( + protocol.setProperty("sslEnabledProtocols", + StringUtils.arrayToCommaDelimitedString( + ssl.getEnabledProtocols())), + "Failed to set sslEnabledProtocols"); + } + } + if (getSslStoreProvider() != null) { + TomcatURLStreamHandlerFactory instance = TomcatURLStreamHandlerFactory + .getInstance(); + instance.addUserFactory( + new SslStoreProviderUrlStreamHandlerFactory(getSslStoreProvider())); + protocol.setKeystoreFile( + SslStoreProviderUrlStreamHandlerFactory.KEY_STORE_URL); + protocol.setTruststoreFile( + SslStoreProviderUrlStreamHandlerFactory.TRUST_STORE_URL); + } + else { + configureSslKeyStore(protocol, ssl); + configureSslTrustStore(protocol, ssl); + } + } + + private void configureSslClientAuth(AbstractHttp11JsseProtocol protocol, Ssl ssl) { + if (ssl.getClientAuth() == ClientAuth.NEED) { + protocol.setClientAuth(Boolean.TRUE.toString()); + } + else if (ssl.getClientAuth() == ClientAuth.WANT) { + protocol.setClientAuth("want"); + } + } + + protected void configureSslStoreProvider(AbstractHttp11JsseProtocol protocol, + SslStoreProvider sslStoreProvider) { + Assert.isInstanceOf(Http11NioProtocol.class, protocol, + "SslStoreProvider can only be used with Http11NioProtocol"); + } + + private void configureSslKeyStore(AbstractHttp11JsseProtocol protocol, Ssl ssl) { + try { + protocol.setKeystoreFile(ResourceUtils.getURL(ssl.getKeyStore()).toString()); + } + catch (FileNotFoundException ex) { + throw new WebServerException("Could not load key store: " + ex.getMessage(), + ex); + } + if (ssl.getKeyStoreType() != null) { + protocol.setKeystoreType(ssl.getKeyStoreType()); + } + if (ssl.getKeyStoreProvider() != null) { + protocol.setKeystoreProvider(ssl.getKeyStoreProvider()); + } + } + + private void configureSslTrustStore(AbstractHttp11JsseProtocol protocol, Ssl ssl) { + + if (ssl.getTrustStore() != null) { + try { + protocol.setTruststoreFile( + ResourceUtils.getURL(ssl.getTrustStore()).toString()); + } + catch (FileNotFoundException ex) { + throw new WebServerException( + "Could not load trust store: " + ex.getMessage(), ex); + } + } + protocol.setTruststorePass(ssl.getTrustStorePassword()); + if (ssl.getTrustStoreType() != null) { + protocol.setTruststoreType(ssl.getTrustStoreType()); + } + if (ssl.getTrustStoreProvider() != null) { + protocol.setTruststoreProvider(ssl.getTrustStoreProvider()); + } + } + + /** + * Configure the Tomcat {@link Context}. + * @param context the Tomcat context + * @param initializers initializers to apply + */ + protected void configureContext(Context context, + ServletContextInitializer[] initializers) { + TomcatStarter starter = new TomcatStarter(initializers); + if (context instanceof TomcatEmbeddedContext) { + // Should be true + ((TomcatEmbeddedContext) context).setStarter(starter); + } + context.addServletContainerInitializer(starter, NO_CLASSES); + for (LifecycleListener lifecycleListener : this.contextLifecycleListeners) { + context.addLifecycleListener(lifecycleListener); + } + for (Valve valve : this.contextValves) { + context.getPipeline().addValve(valve); + } + for (ErrorPage errorPage : getErrorPages()) { + new TomcatErrorPage(errorPage).addToContext(context); + } + for (MimeMappings.Mapping mapping : getMimeMappings()) { + context.addMimeMapping(mapping.getExtension(), mapping.getMimeType()); + } + configureSession(context); + for (TomcatContextCustomizer customizer : this.tomcatContextCustomizers) { + customizer.customize(context); + } + } + + private void configureSession(Context context) { + long sessionTimeout = getSessionTimeoutInMinutes(); + context.setSessionTimeout((int) sessionTimeout); + if (isPersistSession()) { + Manager manager = context.getManager(); + if (manager == null) { + manager = new StandardManager(); + context.setManager(manager); + } + configurePersistSession(manager); + } + else { + context.addLifecycleListener(new DisablePersistSessionListener()); + } + } + + private void configurePersistSession(Manager manager) { + Assert.state(manager instanceof StandardManager, + "Unable to persist HTTP session state using manager type " + + manager.getClass().getName()); + File dir = getValidSessionStoreDir(); + File file = new File(dir, "SESSIONS.ser"); + ((StandardManager) manager).setPathname(file.getAbsolutePath()); + } + + private long getSessionTimeoutInMinutes() { + long sessionTimeout = getSessionTimeout(); + if (sessionTimeout > 0) { + sessionTimeout = Math.max(TimeUnit.SECONDS.toMinutes(sessionTimeout), 1L); + } + return sessionTimeout; + } + + /** + * Post process the Tomcat {@link Context} before it used with the Tomcat Server. + * Subclasses can override this method to apply additional processing to the + * {@link Context}. + * @param context the Tomcat {@link Context} + */ + protected void postProcessContext(Context context) { + } + + /** + * Factory method called to create the {@link TomcatWebServer}. Subclasses can + * override this method to return a different {@link TomcatWebServer} or apply + * additional processing to the Tomcat server. + * @param tomcat the Tomcat server. + * @return a new {@link TomcatWebServer} instance + */ + protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) { + return new TomcatWebServer(tomcat, getPort() >= 0); + } + + @Override + public void setResourceLoader(ResourceLoader resourceLoader) { + this.resourceLoader = resourceLoader; + } + + /** + * Set the Tomcat base directory. If not specified a temporary directory will be used. + * @param baseDirectory the tomcat base directory + */ + public void setBaseDirectory(File baseDirectory) { + this.baseDirectory = baseDirectory; + } + + /** + * A comma-separated list of jars to ignore for TLD scanning. See Tomcat's + * catalina.properties for typical values. Defaults to a list drawn from that source. + * @param tldSkip the jars to skip when scanning for TLDs etc + * @deprecated as of 1.5 in favor of {@link #setTldSkipPatterns(Collection)} + */ + @Deprecated + public void setTldSkip(String tldSkip) { + Assert.notNull(tldSkip, "TldSkip must not be null"); + setTldSkipPatterns(StringUtils.commaDelimitedListToSet(tldSkip)); + } + + /** + * Returns a mutable set of the patterns that match jars to ignore for TLD scanning. + * @return the list of jars to ignore for TLD scanning + */ + public Set getTldSkipPatterns() { + return this.tldSkipPatterns; + } + + /** + * Set the patterns that match jars to ignore for TLD scanning. See Tomcat's + * catalina.properties for typical values. Defaults to a list drawn from that source. + * @param patterns the jar patterns to skip when scanning for TLDs etc + */ + public void setTldSkipPatterns(Collection patterns) { + Assert.notNull(patterns, "Patterns must not be null"); + this.tldSkipPatterns = new LinkedHashSet<>(patterns); + } + + /** + * Add patterns that match jars to ignore for TLD scanning. See Tomcat's + * catalina.properties for typical values. + * @param patterns the additional jar patterns to skip when scanning for TLDs etc + */ + public void addTldSkipPatterns(String... patterns) { + Assert.notNull(patterns, "Patterns must not be null"); + this.tldSkipPatterns.addAll(Arrays.asList(patterns)); + } + + /** + * The Tomcat protocol to use when create the {@link Connector}. + * @param protocol the protocol + * @see Connector#Connector(String) + */ + public void setProtocol(String protocol) { + Assert.hasLength(protocol, "Protocol must not be empty"); + this.protocol = protocol; + } + + /** + * Set {@link Valve}s that should be applied to the Tomcat {@link Engine}. Calling + * this method will replace any existing valves. + * @param engineValves the valves to set + */ + public void setEngineValves(Collection engineValves) { + Assert.notNull(engineValves, "Valves must not be null"); + this.engineValves = new ArrayList<>(engineValves); + } + + /** + * Returns a mutable collection of the {@link Valve}s that will be applied to the + * Tomcat {@link Engine}. + * @return the engineValves the valves that will be applied + */ + public Collection getEngineValves() { + return this.engineValves; + } + + /** + * Add {@link Valve}s that should be applied to the Tomcat {@link Engine}. + * @param engineValves the valves to add + */ + public void addEngineValves(Valve... engineValves) { + Assert.notNull(engineValves, "Valves must not be null"); + this.engineValves.addAll(Arrays.asList(engineValves)); + } + + /** + * Set {@link Valve}s that should be applied to the Tomcat {@link Context}. Calling + * this method will replace any existing valves. + * @param contextValves the valves to set + */ + public void setContextValves(Collection contextValves) { + Assert.notNull(contextValves, "Valves must not be null"); + this.contextValves = new ArrayList<>(contextValves); + } + + /** + * Returns a mutable collection of the {@link Valve}s that will be applied to the + * Tomcat {@link Context}. + * @return the contextValves the valves that will be applied + * @see #getEngineValves() + */ + public Collection getContextValves() { + return this.contextValves; + } + + /** + * Add {@link Valve}s that should be applied to the Tomcat {@link Context}. + * @param contextValves the valves to add + */ + public void addContextValves(Valve... contextValves) { + Assert.notNull(contextValves, "Valves must not be null"); + this.contextValves.addAll(Arrays.asList(contextValves)); + } + + /** + * Set {@link LifecycleListener}s that should be applied to the Tomcat {@link Context} + * . Calling this method will replace any existing listeners. + * @param contextLifecycleListeners the listeners to set + */ + public void setContextLifecycleListeners( + Collection contextLifecycleListeners) { + Assert.notNull(contextLifecycleListeners, + "ContextLifecycleListeners must not be null"); + this.contextLifecycleListeners = new ArrayList<>(contextLifecycleListeners); + } + + /** + * Returns a mutable collection of the {@link LifecycleListener}s that will be applied + * to the Tomcat {@link Context} . + * @return the contextLifecycleListeners the listeners that will be applied + */ + public Collection getContextLifecycleListeners() { + return this.contextLifecycleListeners; + } + + /** + * Add {@link LifecycleListener}s that should be added to the Tomcat {@link Context}. + * @param contextLifecycleListeners the listeners to add + */ + public void addContextLifecycleListeners( + LifecycleListener... contextLifecycleListeners) { + Assert.notNull(contextLifecycleListeners, + "ContextLifecycleListeners must not be null"); + this.contextLifecycleListeners.addAll(Arrays.asList(contextLifecycleListeners)); + } + + /** + * Set {@link TomcatContextCustomizer}s that should be applied to the Tomcat + * {@link Context} . Calling this method will replace any existing customizers. + * @param tomcatContextCustomizers the customizers to set + */ + public void setTomcatContextCustomizers( + Collection tomcatContextCustomizers) { + Assert.notNull(tomcatContextCustomizers, + "TomcatContextCustomizers must not be null"); + this.tomcatContextCustomizers = new ArrayList<>(tomcatContextCustomizers); + } + + /** + * Returns a mutable collection of the {@link TomcatContextCustomizer}s that will be + * applied to the Tomcat {@link Context} . + * @return the listeners that will be applied + */ + public Collection getTomcatContextCustomizers() { + return this.tomcatContextCustomizers; + } + + /** + * Add {@link TomcatContextCustomizer}s that should be added to the Tomcat + * {@link Context}. + * @param tomcatContextCustomizers the customizers to add + */ + public void addContextCustomizers( + TomcatContextCustomizer... tomcatContextCustomizers) { + Assert.notNull(tomcatContextCustomizers, + "TomcatContextCustomizers must not be null"); + this.tomcatContextCustomizers.addAll(Arrays.asList(tomcatContextCustomizers)); + } + + /** + * Set {@link TomcatConnectorCustomizer}s that should be applied to the Tomcat + * {@link Connector} . Calling this method will replace any existing customizers. + * @param tomcatConnectorCustomizers the customizers to set + */ + public void setTomcatConnectorCustomizers( + Collection tomcatConnectorCustomizers) { + Assert.notNull(tomcatConnectorCustomizers, + "TomcatConnectorCustomizers must not be null"); + this.tomcatConnectorCustomizers = new ArrayList<>(tomcatConnectorCustomizers); + } + + /** + * Add {@link TomcatContextCustomizer}s that should be added to the Tomcat + * {@link Connector}. + * @param tomcatConnectorCustomizers the customizers to add + */ + public void addConnectorCustomizers( + TomcatConnectorCustomizer... tomcatConnectorCustomizers) { + Assert.notNull(tomcatConnectorCustomizers, + "TomcatConnectorCustomizers must not be null"); + this.tomcatConnectorCustomizers.addAll(Arrays.asList(tomcatConnectorCustomizers)); + } + + /** + * Returns a mutable collection of the {@link TomcatConnectorCustomizer}s that will be + * applied to the Tomcat {@link Context} . + * @return the listeners that will be applied + */ + public Collection getTomcatConnectorCustomizers() { + return this.tomcatConnectorCustomizers; + } + + /** + * Add {@link Connector}s in addition to the default connector, e.g. for SSL or AJP + * @param connectors the connectors to add + */ + public void addAdditionalTomcatConnectors(Connector... connectors) { + Assert.notNull(connectors, "Connectors must not be null"); + this.additionalTomcatConnectors.addAll(Arrays.asList(connectors)); + } + + /** + * Returns a mutable collection of the {@link Connector}s that will be added to the + * Tomcat. + * @return the additionalTomcatConnectors + */ + public List getAdditionalTomcatConnectors() { + return this.additionalTomcatConnectors; + } + + /** + * Set the character encoding to use for URL decoding. If not specified 'UTF-8' will + * be used. + * @param uriEncoding the uri encoding to set + */ + public void setUriEncoding(Charset uriEncoding) { + this.uriEncoding = uriEncoding; + } + + /** + * Returns the character encoding to use for URL decoding. + * @return the URI encoding + */ + public Charset getUriEncoding() { + return this.uriEncoding; + } + + /** + * Sets the background processor delay in seconds. + * @param delay the delay in seconds + * @since 1.4.1 + */ + public void setBackgroundProcessorDelay(int delay) { + this.backgroundProcessorDelay = delay; + } + + /** + * {@link LifecycleListener} to disable persistence in the {@link StandardManager}. A + * {@link LifecycleListener} is used so not to interfere with Tomcat's default manager + * creation logic. + */ + private static class DisablePersistSessionListener implements LifecycleListener { + + @Override + public void lifecycleEvent(LifecycleEvent event) { + if (event.getType().equals(Lifecycle.START_EVENT)) { + Context context = (Context) event.getLifecycle(); + Manager manager = context.getManager(); + if (manager != null && manager instanceof StandardManager) { + ((StandardManager) manager).setPathname(null); + } + } + } + + } + + private final class StaticResourceConfigurer implements LifecycleListener { + + private final Context context; + + private StaticResourceConfigurer(Context context) { + this.context = context; + } + + @Override + public void lifecycleEvent(LifecycleEvent event) { + if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) { + addResourceJars(getUrlsOfJarsWithMetaInfResources()); + } + } + + private void addResourceJars(List resourceJarUrls) { + for (URL url : resourceJarUrls) { + String file = url.getFile(); + if (file.endsWith(".jar") || file.endsWith(".jar!/")) { + String jar = url.toString(); + if (!jar.startsWith("jar:")) { + // A jar file in the file system. Convert to Jar URL. + jar = "jar:" + jar + "!/"; + } + addResourceSet(jar); + } + else { + addResourceSet(url.toString()); + } + } + } + + private void addResourceSet(String resource) { + try { + if (isInsideNestedJar(resource)) { + // It's a nested jar but we now don't want the suffix because Tomcat + // is going to try and locate it as a root URL (not the resource + // inside it) + resource = resource.substring(0, resource.length() - 2); + } + URL url = new URL(resource); + String path = "/META-INF/resources"; + this.context.getResources().createWebResourceSet( + ResourceSetType.RESOURCE_JAR, "/", url, path); + } + catch (Exception ex) { + // Ignore (probably not a directory) + } + } + + private boolean isInsideNestedJar(String dir) { + return dir.indexOf("!/") < dir.lastIndexOf("!/"); + } + + } + +} From dbf00668b91e0f39239396d135468831930e3b85 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 14 May 2017 00:29:10 -0300 Subject: [PATCH 127/154] Successfully checking if a field called by 'this.fieldName' is a Collection. - As long as the field is not inherited. --- src/ForLoop.rsc | 7 +++-- src/MethodVar.rsc | 2 ++ .../forloop/EnhancedLoopExpression.rsc | 30 ++++++++++++++----- .../forloop/EnhancedLoopExpressionTest.rsc | 13 ++++++++ 4 files changed, 41 insertions(+), 11 deletions(-) diff --git a/src/ForLoop.rsc b/src/ForLoop.rsc index b8ad2fd..e733a5b 100644 --- a/src/ForLoop.rsc +++ b/src/ForLoop.rsc @@ -48,6 +48,7 @@ private void lookForEnhancedForStatementsInMethod(CompilationUnit unit, MethodDe } } +// TODO What happens when two for statements are refactored inside the same method? private void lookForEnhancedForStatementsInMethodBody(CompilationUnit unit, MethodHeader methodHeader, MethodBody methodBody) { set[MethodVar] availableVars = {}; alreadyComputedCurrentMethodAvailableVars = false; @@ -97,9 +98,9 @@ private void lookForEnhancedForStatementsInMethodBody(CompilationUnit unit, Meth } } -private bool isLoopRefactorable(set[MethodVar] methodLocalVariables, Expression collectionId, Statement loopBody) { - return loopBodyPassConditions(loopBody) && isIteratingOnCollection(collectionId, methodLocalVariables) && - atMostOneReferenceToNonEffectiveFinalVar(methodLocalVariables, loopBody); +private bool isLoopRefactorable(set[MethodVar] availableVariables, Expression collectionId, Statement loopBody) { + return loopBodyPassConditions(loopBody) && isIteratingOnCollection(collectionId, availableVariables) && + atMostOneReferenceToNonEffectiveFinalVar(availableVariables, loopBody); } // TODO extract module and test it diff --git a/src/MethodVar.rsc b/src/MethodVar.rsc index 484760b..a1dd490 100644 --- a/src/MethodVar.rsc +++ b/src/MethodVar.rsc @@ -90,6 +90,8 @@ public bool isEffectiveFinal(MethodVar methodVar) { // FIXME This will break if 'this.varName' is referenced, as we are removing the class field // Would need to treat 'this.*' and change how we find vars by name +// One idea is to keep both localVariables AND classFields as separate lists. +// if both exists, a reference to a field can only be made by 'this.field' public set[MethodVar] retainLocalVariablesIfDuplicates(set[MethodVar] classFields, set[MethodVar] localVars) { duplicatedNames = retrieveAllNames(classFields) & retrieveAllNames(localVars); duplicatedClassFields = { field | MethodVar field <- classFields, field.name in duplicatedNames }; diff --git a/src/refactor/forloop/EnhancedLoopExpression.rsc b/src/refactor/forloop/EnhancedLoopExpression.rsc index 6f2cbbd..41234b2 100644 --- a/src/refactor/forloop/EnhancedLoopExpression.rsc +++ b/src/refactor/forloop/EnhancedLoopExpression.rsc @@ -14,21 +14,35 @@ import IO; // Relying on compiler to help finding if it's an array or not // Compiler gives error if expression is not Array/Collection // Therefore we only check if the expression is an Array -public bool isIteratingOnCollection(Expression exp, set[MethodVar] localVariables) { - if (isExpAnIdentifier(exp)) - return isIdentifierACollection(exp, localVariables); +public bool isIteratingOnCollection(Expression exp, set[MethodVar] availableVariables) { + if (!isMethodInvocation(exp)) + return isIdentifierACollection(exp, availableVariables); else return false; } -private bool isExpAnIdentifier(Expression exp) { - expStr = unparse(exp); - return !contains(expStr, ".") && !contains(expStr, "("); +// XXX Ignoring Casts too. +// Redundant for now, because any method invocation will contain '(' +// But not everything that have '(' will be a method invocation. (Casts for instance) +private bool isMethodInvocation(Expression exp) { + expStr = ""; + return contains(expStr, "(") && parsesAsMethodInvocation(exp); } -private bool isIdentifierACollection(Expression exp, set[MethodVar] localVariables) { +private bool parsesAsMethodInvocation(str expStr) { + try { + parse(#MethodInvocation, expStr); + return true; + } catch: + return false; +} + +private bool isIdentifierACollection(Expression exp, set[MethodVar] availableVariables) { varName = trim(unparse(exp)); - var = findByName(localVariables, varName); + // TODO eventually change/remove when dealing correctly with fields + local variables + varName = replaceFirst(varName, "this.", ""); + + var = findByName(availableVariables, varName); return !isTypePlainArray(var) && !isIterable(var); } diff --git a/src/refactor/forloop/EnhancedLoopExpressionTest.rsc b/src/refactor/forloop/EnhancedLoopExpressionTest.rsc index 1dea380..91d4c9c 100644 --- a/src/refactor/forloop/EnhancedLoopExpressionTest.rsc +++ b/src/refactor/forloop/EnhancedLoopExpressionTest.rsc @@ -6,6 +6,7 @@ import ParseTree; import MethodVar; import LocalVariablesFinder; import LocalVariablesFinderTestResources; +import refactor::forloop::ClassFieldsFinder; import refactor::forloop::EnhancedLoopExpression; public test bool iterableShouldReturnFalse() { @@ -39,4 +40,16 @@ public test bool iterableParamShouldReturnFalse() { localVariables = findLocalVariables(methodHeader, methodBody); return isIteratingOnCollection(exp, localVariables) == false; +} + +public test bool thisFieldListShouldReturnTrue() { + exp = parse(#Expression, "this.engineValves"); + methodHeader = parse(#MethodHeader, "void configureEngine(Engine engine)"); + methodBodyLoc = |project://rascal-Java8/testes/classFields/MethodBodyIteratingOnThisField2|; + methodBody = parse(#MethodBody, readFile(methodBodyLoc)); + localVariables = findLocalVariables(methodHeader, methodBody); + classFields = findClassFields(parse(#CompilationUnit, readFile(|project://rascal-Java8/testes/classFields/TomcatServletWebServerFactory.java|))); + vars = localVariables + classFields; + + return isIteratingOnCollection(exp, vars) == true; } \ No newline at end of file From 623543aefaff635766d04e006cf7eae44c5e8f47 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 14 May 2017 00:29:46 -0300 Subject: [PATCH 128/154] Removing a forgotten debug println() in a test. --- src/refactor/forloop/test/BreakIntoStatementsTest.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/refactor/forloop/test/BreakIntoStatementsTest.rsc b/src/refactor/forloop/test/BreakIntoStatementsTest.rsc index 8cb746c..1308691 100644 --- a/src/refactor/forloop/test/BreakIntoStatementsTest.rsc +++ b/src/refactor/forloop/test/BreakIntoStatementsTest.rsc @@ -114,7 +114,7 @@ public test bool shouldIncludeLocalVariableDeclarationInsideBlock() { block = "{\nupdated.put(snapshot.getFolder(), snapshot);\nChangedFiles changedFiles = previous.getChangedFiles(snapshot,\r\n this.triggerFilter);\n}"; stmts = breakIntoStatements(block); - printStmtsBrokenInto(stmts); + return size(stmts) == 2 && "" == "updated.put(snapshot.getFolder(), snapshot);" && stmts[0].stmtType == "ExpressionStatement" && From 1f4978cbfa436e84af59e174014a15bb146dae6d Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 14 May 2017 00:34:16 -0300 Subject: [PATCH 129/154] Fixing some old tests. --- src/refactor/forloop/AvailableVariablesTest.rsc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/refactor/forloop/AvailableVariablesTest.rsc b/src/refactor/forloop/AvailableVariablesTest.rsc index 1b87fba..34141fb 100644 --- a/src/refactor/forloop/AvailableVariablesTest.rsc +++ b/src/refactor/forloop/AvailableVariablesTest.rsc @@ -9,8 +9,8 @@ import IO; public test bool methodParamShouldBeAvailableVar() { prOp = prospectiveOperation("writer.write(thing);", FOR_EACH); - methodVars = {methodVar(false, "thing", "String", false, true), - methodVar(false, "writer", "PrintWriter", true, false)}; + methodVars = {methodVar(false, "thing", "String", false, true, false), + methodVar(false, "writer", "PrintWriter", true, false, false)}; availableVars = retrieveAvailableVariables(prOp, methodVars); @@ -20,8 +20,8 @@ public test bool methodParamShouldBeAvailableVar() { public test bool varWithinLoopShouldNotBeAvailable() { prOp = prospectiveOperation("rule.hasErrors()", FILTER); - methodVars = {methodVar(false, "count", "int", false, false), - methodVar(false, "rule", "ElementRule", false, true)}; + methodVars = {methodVar(false, "count", "int", false, false, false), + methodVar(false, "rule", "ElementRule", false, true, false)}; availableVars = retrieveAvailableVariables(prOp, methodVars); @@ -30,8 +30,8 @@ public test bool varWithinLoopShouldNotBeAvailable() { public test bool varNotWithinLoopShouldBeAvailable() { prOp = prospectiveOperation("rule.hasErrors()", FILTER); - methodVars = {methodVar(false, "count", "int", false, false), - methodVar(false, "rule", "ElementRule", false, true)}; + methodVars = {methodVar(false, "count", "int", false, false, false), + methodVar(false, "rule", "ElementRule", false, true, false)}; availableVars = retrieveAvailableVariables(prOp, methodVars); @@ -48,9 +48,9 @@ public test bool localVariableDeclarationShouldBeAvailableVar() { "cl" in availableVars; } -public test bool LocalVariableDeclAlongWithVarNotWithinLoopShouldBeAvailableVars() { +public test bool localVariableDeclAlongWithVarNotWithinLoopShouldBeAvailableVars() { prOp = prospectiveOperation("ClassLoader cl = entry.getKey();", MAP); - methodVars = {methodVar(false, "result", "List\", false, false)}; + methodVars = {methodVar(false, "result", "List\", false, false, false)}; availableVars = retrieveAvailableVariables(prOp, methodVars); From d9d009e8e906b2e16d1795453098ce63a0f8c05a Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 14 May 2017 00:49:21 -0300 Subject: [PATCH 130/154] Fixing wrong old parameter in method call. --- src/refactor/forloop/EnhancedLoopExpression.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/refactor/forloop/EnhancedLoopExpression.rsc b/src/refactor/forloop/EnhancedLoopExpression.rsc index 41234b2..eb9a32c 100644 --- a/src/refactor/forloop/EnhancedLoopExpression.rsc +++ b/src/refactor/forloop/EnhancedLoopExpression.rsc @@ -26,7 +26,7 @@ public bool isIteratingOnCollection(Expression exp, set[MethodVar] availableVari // But not everything that have '(' will be a method invocation. (Casts for instance) private bool isMethodInvocation(Expression exp) { expStr = ""; - return contains(expStr, "(") && parsesAsMethodInvocation(exp); + return contains(expStr, "(") && parsesAsMethodInvocation(expStr); } private bool parsesAsMethodInvocation(str expStr) { From b0d01f946147b4e7fdf962a3243ecb4eb56f27c7 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 14 May 2017 02:05:18 -0300 Subject: [PATCH 131/154] Ignoring loops that contains any type of continue statement. - Lambdaficator refactors some, we are not doing this right now. --- src/ForLoop.rsc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ForLoop.rsc b/src/ForLoop.rsc index e733a5b..50176c4 100644 --- a/src/ForLoop.rsc +++ b/src/ForLoop.rsc @@ -120,7 +120,10 @@ private bool loopBodyPassConditions(Statement loopBody) { returnCount += 1; } - + + // TODO remove in case we refactor loops with if with continue + case ContinueStatement continueStmt: return false; + // labeled continue. case (ContinueStatement) `continue ;`: return false; } From e97c5b535a89e5bab7b5c94b6f6f7426426a4c2b Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Tue, 16 May 2017 18:14:16 -0300 Subject: [PATCH 132/154] Changing everything ForLoopToFunctional modules' folders. --- .../java/analysis}/ExceptionFinder.rsc | 0 .../analysis/test}/ExceptionFinderTest.rsc | 0 .../forloop/AvailableVariables.rsc | 6 +- .../forloop/BreakIntoStatements.rsc | 2 +- .../forloop/ClassFieldsFinder.rsc | 4 +- .../forloop/EnhancedLoopExpression.rsc | 4 +- .../java/refactoring/forloop}/ForLoop.rsc | 0 .../forloop/ForLoopBodyReferences.rsc | 4 +- .../forloop/ForLoopToFunctional.rsc | 16 ++--- .../forloop}/LocalVariablesFinder.rsc | 4 +- .../java/refactoring/forloop}/MethodVar.rsc | 2 +- .../refactoring}/forloop/OperationType.rsc | 2 +- .../forloop/ProspectiveOperation.rsc | 8 +-- .../refactoring}/forloop/UsedVariables.rsc | 6 +- .../forloop/test}/AvailableVariablesTest.rsc | 10 ++-- .../forloop/test/BreakIntoStatementsTest.rsc | 18 +++--- .../forloop/test}/ClassFieldsFinderTest.rsc | 8 +-- .../test}/EnhancedLoopExpressionTest.rsc | 18 +++--- .../test/ForLoopBodyReferencesTest.rsc | 16 ++--- .../forloop/test}/ForLoopToFunctionalTest.rsc | 60 ++++++++++--------- .../test}/LocalVariablesFinderTest.rsc | 8 +-- .../test}/ProspectiveOperationTest.rsc | 10 ++-- .../forloop/test}/UsedVariablesTest.rsc | 10 ++-- .../LocalVariablesFinderTestResources.rsc | 30 +++++----- .../ProspectiveOperationTestResources.rsc | 38 ++++++------ .../EnhancedForOnIterable.java | 0 ...IfWithTwoStmtsInsideAndStmtAfterBlock.java | 0 .../ForWith3StatementsMapBody.java | 0 .../ForWithMultiStatementMap.java | 0 .../ForLoopToFunctional/InnerLoop1.java | 0 .../ForLoopToFunctional/InnerLoop2.java | 0 .../LoopWithInnerWhile.java | 0 .../MethodBodyIfAsNotAFilter | 0 ...IfWithTwoStmtsInsideAndStmtAfterBlock.java | 0 .../MethodBodyInnerLoop1.java | 0 .../MethodBodyInnerLoop2.java | 0 .../MethodBodyLoopWithInnerWhile.java | 0 .../MethodBodyWIth3StatementsMapBody.java | 0 .../MethodBodyWithMultiStatementMap.java | 0 .../ForLoopToFunctional/NestedLoops.java | 0 .../ForLoopToFunctional/SimpleForEach.java | 0 .../{ => forloop}/ForLoopToFunctional/T1.java | 0 .../{ => forloop}/ForLoopToFunctional/T2.java | 0 .../ForLoopToFunctional/T2For.java | 0 .../ForLoopToFunctional/T2For2.java | 0 .../ContinueAndReturnEnhancedLoop | 0 .../FilterAndMergedForEach | 0 .../FilterMapReduceEnhancedLoop | 0 .../SimpleShortEnhancedLoop | 0 .../classFields/ForIteratingOnThisField | 0 .../classFields/ForIteratingOnThisField2 | 0 .../MethodBodyIteratingOnThisField | 0 .../MethodBodyIteratingOnThisField2 | 0 .../TomcatServletWebServerFactory.java | 0 .../localVariables/ClassWithFields.java | 0 .../EnhancedForLoopFinalVarDecl | 0 .../EnhancedForLoopVarsWithinLoop | 0 .../EnhancedForLoopWithException | 0 .../IterableParameterMethodBody | 0 .../MethodBodyAssignmentInsideLoop | 0 .../MethodBodyPostDecrementedVar | 0 .../MethodBodyPostIncrementedVar | 0 .../MethodBodyPostIncrementedVar2 | 0 .../MethodBodyPostIncrementedVar3 | 0 .../MethodBodyReduceWithPostIncrement | 0 .../MethodBodyWithAnonnymousInnerClass | 0 ...WithTwoReferencesToOutsideNonEffectiveVars | 0 .../MultiplePlainArrayDeclarations | 0 .../NonEffectiveFinalUsedInEnhancedFor | 0 69 files changed, 143 insertions(+), 141 deletions(-) rename src/{ => lang/java/analysis}/ExceptionFinder.rsc (100%) rename src/{ => lang/java/analysis/test}/ExceptionFinderTest.rsc (100%) rename src/{refactor => lang/java/refactoring}/forloop/AvailableVariables.rsc (87%) rename src/{refactor => lang/java/refactoring}/forloop/BreakIntoStatements.rsc (96%) rename src/{refactor => lang/java/refactoring}/forloop/ClassFieldsFinder.rsc (93%) rename src/{refactor => lang/java/refactoring}/forloop/EnhancedLoopExpression.rsc (93%) rename src/{ => lang/java/refactoring/forloop}/ForLoop.rsc (100%) rename src/{refactor => lang/java/refactoring}/forloop/ForLoopBodyReferences.rsc (93%) rename src/{refactor => lang/java/refactoring}/forloop/ForLoopToFunctional.rsc (96%) rename src/{ => lang/java/refactoring/forloop}/LocalVariablesFinder.rsc (98%) rename src/{ => lang/java/refactoring/forloop}/MethodVar.rsc (98%) rename src/{refactor => lang/java/refactoring}/forloop/OperationType.rsc (77%) rename src/{refactor => lang/java/refactoring}/forloop/ProspectiveOperation.rsc (97%) rename src/{refactor => lang/java/refactoring}/forloop/UsedVariables.rsc (94%) rename src/{refactor/forloop => lang/java/refactoring/forloop/test}/AvailableVariablesTest.rsc (87%) rename src/{refactor => lang/java/refactoring}/forloop/test/BreakIntoStatementsTest.rsc (86%) rename src/{refactor/forloop => lang/java/refactoring/forloop/test}/ClassFieldsFinderTest.rsc (71%) rename src/{refactor/forloop => lang/java/refactoring/forloop/test}/EnhancedLoopExpressionTest.rsc (70%) rename src/{refactor => lang/java/refactoring}/forloop/test/ForLoopBodyReferencesTest.rsc (78%) rename src/{refactor/forloop => lang/java/refactoring/forloop/test}/ForLoopToFunctionalTest.rsc (83%) rename src/{ => lang/java/refactoring/forloop/test}/LocalVariablesFinderTest.rsc (96%) rename src/{refactor/forloop => lang/java/refactoring/forloop/test}/ProspectiveOperationTest.rsc (95%) rename src/{refactor/forloop => lang/java/refactoring/forloop/test}/UsedVariablesTest.rsc (87%) rename src/{ => lang/java/refactoring/forloop/test/resources}/LocalVariablesFinderTestResources.rsc (79%) rename src/{refactor/forloop => lang/java/refactoring/forloop/test/resources}/ProspectiveOperationTestResources.rsc (77%) rename testes/{ => forloop}/ForLoopToFunctional/EnhancedForOnIterable.java (100%) rename testes/{ => forloop}/ForLoopToFunctional/ForIfWithTwoStmtsInsideAndStmtAfterBlock.java (100%) rename testes/{ => forloop}/ForLoopToFunctional/ForWith3StatementsMapBody.java (100%) rename testes/{ => forloop}/ForLoopToFunctional/ForWithMultiStatementMap.java (100%) rename testes/{ => forloop}/ForLoopToFunctional/InnerLoop1.java (100%) rename testes/{ => forloop}/ForLoopToFunctional/InnerLoop2.java (100%) rename testes/{ => forloop}/ForLoopToFunctional/LoopWithInnerWhile.java (100%) rename testes/{ => forloop}/ForLoopToFunctional/MethodBodyIfAsNotAFilter (100%) rename testes/{ => forloop}/ForLoopToFunctional/MethodBodyIfWithTwoStmtsInsideAndStmtAfterBlock.java (100%) rename testes/{ => forloop}/ForLoopToFunctional/MethodBodyInnerLoop1.java (100%) rename testes/{ => forloop}/ForLoopToFunctional/MethodBodyInnerLoop2.java (100%) rename testes/{ => forloop}/ForLoopToFunctional/MethodBodyLoopWithInnerWhile.java (100%) rename testes/{ => forloop}/ForLoopToFunctional/MethodBodyWIth3StatementsMapBody.java (100%) rename testes/{ => forloop}/ForLoopToFunctional/MethodBodyWithMultiStatementMap.java (100%) rename testes/{ => forloop}/ForLoopToFunctional/NestedLoops.java (100%) rename testes/{ => forloop}/ForLoopToFunctional/SimpleForEach.java (100%) rename testes/{ => forloop}/ForLoopToFunctional/T1.java (100%) rename testes/{ => forloop}/ForLoopToFunctional/T2.java (100%) rename testes/{ => forloop}/ForLoopToFunctional/T2For.java (100%) rename testes/{ => forloop}/ForLoopToFunctional/T2For2.java (100%) rename testes/{ => forloop}/ProspectiveOperation/ContinueAndReturnEnhancedLoop (100%) rename testes/{ => forloop}/ProspectiveOperation/FilterAndMergedForEach (100%) rename testes/{ => forloop}/ProspectiveOperation/FilterMapReduceEnhancedLoop (100%) rename testes/{ => forloop}/ProspectiveOperation/SimpleShortEnhancedLoop (100%) rename testes/{ => forloop}/classFields/ForIteratingOnThisField (100%) rename testes/{ => forloop}/classFields/ForIteratingOnThisField2 (100%) rename testes/{ => forloop}/classFields/MethodBodyIteratingOnThisField (100%) rename testes/{ => forloop}/classFields/MethodBodyIteratingOnThisField2 (100%) rename testes/{ => forloop}/classFields/TomcatServletWebServerFactory.java (100%) rename testes/{ => forloop}/localVariables/ClassWithFields.java (100%) rename testes/{ => forloop}/localVariables/EnhancedForLoopFinalVarDecl (100%) rename testes/{ => forloop}/localVariables/EnhancedForLoopVarsWithinLoop (100%) rename testes/{ => forloop}/localVariables/EnhancedForLoopWithException (100%) rename testes/{ => forloop}/localVariables/IterableParameterMethodBody (100%) rename testes/{ => forloop}/localVariables/MethodBodyAssignmentInsideLoop (100%) rename testes/{ => forloop}/localVariables/MethodBodyPostDecrementedVar (100%) rename testes/{ => forloop}/localVariables/MethodBodyPostIncrementedVar (100%) rename testes/{ => forloop}/localVariables/MethodBodyPostIncrementedVar2 (100%) rename testes/{ => forloop}/localVariables/MethodBodyPostIncrementedVar3 (100%) rename testes/{ => forloop}/localVariables/MethodBodyReduceWithPostIncrement (100%) rename testes/{ => forloop}/localVariables/MethodBodyWithAnonnymousInnerClass (100%) rename testes/{ => forloop}/localVariables/MethodBodyWithTwoReferencesToOutsideNonEffectiveVars (100%) rename testes/{ => forloop}/localVariables/MultiplePlainArrayDeclarations (100%) rename testes/{ => forloop}/localVariables/NonEffectiveFinalUsedInEnhancedFor (100%) diff --git a/src/ExceptionFinder.rsc b/src/lang/java/analysis/ExceptionFinder.rsc similarity index 100% rename from src/ExceptionFinder.rsc rename to src/lang/java/analysis/ExceptionFinder.rsc diff --git a/src/ExceptionFinderTest.rsc b/src/lang/java/analysis/test/ExceptionFinderTest.rsc similarity index 100% rename from src/ExceptionFinderTest.rsc rename to src/lang/java/analysis/test/ExceptionFinderTest.rsc diff --git a/src/refactor/forloop/AvailableVariables.rsc b/src/lang/java/refactoring/forloop/AvailableVariables.rsc similarity index 87% rename from src/refactor/forloop/AvailableVariables.rsc rename to src/lang/java/refactoring/forloop/AvailableVariables.rsc index 6004786..857adcc 100644 --- a/src/refactor/forloop/AvailableVariables.rsc +++ b/src/lang/java/refactoring/forloop/AvailableVariables.rsc @@ -1,10 +1,10 @@ -module refactor::forloop::AvailableVariables +module lang::java::refactoring::forloop::AvailableVariables import Set; import lang::java::\syntax::Java18; import ParseTree; -import MethodVar; -import refactor::forloop::ProspectiveOperation; +import lang::java::refactoring::forloop::MethodVar; +import lang::java::refactoring::forloop::ProspectiveOperation; // XXX assess the necessity to verify these others conditions: // fields declared in class, inherited and visible from imported classes ?? diff --git a/src/refactor/forloop/BreakIntoStatements.rsc b/src/lang/java/refactoring/forloop/BreakIntoStatements.rsc similarity index 96% rename from src/refactor/forloop/BreakIntoStatements.rsc rename to src/lang/java/refactoring/forloop/BreakIntoStatements.rsc index 61a6c12..710b805 100644 --- a/src/refactor/forloop/BreakIntoStatements.rsc +++ b/src/lang/java/refactoring/forloop/BreakIntoStatements.rsc @@ -1,4 +1,4 @@ -module refactor::forloop::BreakIntoStatements +module lang::java::refactoring::forloop::BreakIntoStatements import IO; import List; diff --git a/src/refactor/forloop/ClassFieldsFinder.rsc b/src/lang/java/refactoring/forloop/ClassFieldsFinder.rsc similarity index 93% rename from src/refactor/forloop/ClassFieldsFinder.rsc rename to src/lang/java/refactoring/forloop/ClassFieldsFinder.rsc index 18956c9..d991895 100644 --- a/src/refactor/forloop/ClassFieldsFinder.rsc +++ b/src/lang/java/refactoring/forloop/ClassFieldsFinder.rsc @@ -1,11 +1,11 @@ -module refactor::forloop::ClassFieldsFinder +module lang::java::refactoring::forloop::ClassFieldsFinder import IO; import lang::java::\syntax::Java18; import ParseTree; import String; import Set; -import MethodVar; +import lang::java::refactoring::forloop::MethodVar; // M3 isn't very helpful here. // We can't really get type + var name diff --git a/src/refactor/forloop/EnhancedLoopExpression.rsc b/src/lang/java/refactoring/forloop/EnhancedLoopExpression.rsc similarity index 93% rename from src/refactor/forloop/EnhancedLoopExpression.rsc rename to src/lang/java/refactoring/forloop/EnhancedLoopExpression.rsc index eb9a32c..b7ceb8c 100644 --- a/src/refactor/forloop/EnhancedLoopExpression.rsc +++ b/src/lang/java/refactoring/forloop/EnhancedLoopExpression.rsc @@ -1,10 +1,10 @@ -module refactor::forloop::EnhancedLoopExpression +module lang::java::refactoring::forloop::EnhancedLoopExpression import lang::java::\syntax::Java18; import ParseTree; -import MethodVar; import String; import IO; +import lang::java::refactoring::forloop::MethodVar; // XXX Only checking iterable variables defined in method (local and parameter) // Need to verify class and instance variables too! diff --git a/src/ForLoop.rsc b/src/lang/java/refactoring/forloop/ForLoop.rsc similarity index 100% rename from src/ForLoop.rsc rename to src/lang/java/refactoring/forloop/ForLoop.rsc diff --git a/src/refactor/forloop/ForLoopBodyReferences.rsc b/src/lang/java/refactoring/forloop/ForLoopBodyReferences.rsc similarity index 93% rename from src/refactor/forloop/ForLoopBodyReferences.rsc rename to src/lang/java/refactoring/forloop/ForLoopBodyReferences.rsc index e16cb40..f932f2f 100644 --- a/src/refactor/forloop/ForLoopBodyReferences.rsc +++ b/src/lang/java/refactoring/forloop/ForLoopBodyReferences.rsc @@ -1,11 +1,11 @@ -module refactor::forloop::ForLoopBodyReferences +module lang::java::refactoring::forloop::ForLoopBodyReferences import lang::java::\syntax::Java18; import String; import ParseTree; import IO; import Set; -import MethodVar; +import lang::java::refactoring::forloop::MethodVar; public bool atMostOneReferenceToNonEffectiveFinalVar(set[MethodVar] localVariables, Statement loopBody) { return getTotalOfNonEffectiveFinalVarsReferenced(localVariables, loopBody) <= 1; diff --git a/src/refactor/forloop/ForLoopToFunctional.rsc b/src/lang/java/refactoring/forloop/ForLoopToFunctional.rsc similarity index 96% rename from src/refactor/forloop/ForLoopToFunctional.rsc rename to src/lang/java/refactoring/forloop/ForLoopToFunctional.rsc index 4c93d68..d5613db 100644 --- a/src/refactor/forloop/ForLoopToFunctional.rsc +++ b/src/lang/java/refactoring/forloop/ForLoopToFunctional.rsc @@ -1,4 +1,4 @@ -module refactor::forloop::ForLoopToFunctional +module lang::java::refactoring::forloop::ForLoopToFunctional import IO; import List; @@ -6,13 +6,13 @@ import Set; import String; import lang::java::\syntax::Java18; import ParseTree; -import MethodVar; -import refactor::forloop::ProspectiveOperation; -import refactor::forloop::UsedVariables; -import refactor::forloop::AvailableVariables; -import refactor::forloop::OperationType; -import refactor::forloop::ForLoopBodyReferences; -import refactor::forloop::BreakIntoStatements; +import lang::java::refactoring::forloop::MethodVar; +import lang::java::refactoring::forloop::ProspectiveOperation; +import lang::java::refactoring::forloop::UsedVariables; +import lang::java::refactoring::forloop::AvailableVariables; +import lang::java::refactoring::forloop::OperationType; +import lang::java::refactoring::forloop::ForLoopBodyReferences; +import lang::java::refactoring::forloop::BreakIntoStatements; public data ComposableProspectiveOperation = composableProspectiveOperation(ProspectiveOperation prOp, set[str] neededVars, set[str] availableVars); diff --git a/src/LocalVariablesFinder.rsc b/src/lang/java/refactoring/forloop/LocalVariablesFinder.rsc similarity index 98% rename from src/LocalVariablesFinder.rsc rename to src/lang/java/refactoring/forloop/LocalVariablesFinder.rsc index e92efd2..0670417 100644 --- a/src/LocalVariablesFinder.rsc +++ b/src/lang/java/refactoring/forloop/LocalVariablesFinder.rsc @@ -1,11 +1,11 @@ -module LocalVariablesFinder +module lang::java::refactoring::forloop::LocalVariablesFinder import IO; import lang::java::\syntax::Java18; import ParseTree; import Set; import String; -import MethodVar; +import lang::java::refactoring::forloop::MethodVar; public set[MethodVar] findLocalVariables(MethodHeader methodHeader, MethodBody methodBody) { return findVariablesAsParameters(methodHeader) + findVariablesInsideBody(methodBody); diff --git a/src/MethodVar.rsc b/src/lang/java/refactoring/forloop/MethodVar.rsc similarity index 98% rename from src/MethodVar.rsc rename to src/lang/java/refactoring/forloop/MethodVar.rsc index a1dd490..ee36a71 100644 --- a/src/MethodVar.rsc +++ b/src/lang/java/refactoring/forloop/MethodVar.rsc @@ -1,4 +1,4 @@ -module MethodVar +module lang::java::refactoring::forloop::MethodVar import Set; import String; diff --git a/src/refactor/forloop/OperationType.rsc b/src/lang/java/refactoring/forloop/OperationType.rsc similarity index 77% rename from src/refactor/forloop/OperationType.rsc rename to src/lang/java/refactoring/forloop/OperationType.rsc index a65568a..9dda9ff 100644 --- a/src/refactor/forloop/OperationType.rsc +++ b/src/lang/java/refactoring/forloop/OperationType.rsc @@ -1,4 +1,4 @@ -module refactor::forloop::OperationType +module lang::java::refactoring::forloop::OperationType public str FILTER = "filter"; public str MAP = "map"; diff --git a/src/refactor/forloop/ProspectiveOperation.rsc b/src/lang/java/refactoring/forloop/ProspectiveOperation.rsc similarity index 97% rename from src/refactor/forloop/ProspectiveOperation.rsc rename to src/lang/java/refactoring/forloop/ProspectiveOperation.rsc index 6b77f38..9bdf04c 100644 --- a/src/refactor/forloop/ProspectiveOperation.rsc +++ b/src/lang/java/refactoring/forloop/ProspectiveOperation.rsc @@ -1,14 +1,14 @@ -module refactor::forloop::ProspectiveOperation +module lang::java::refactoring::forloop::ProspectiveOperation import IO; import List; import String; import lang::java::\syntax::Java18; import ParseTree; -import MethodVar; -import refactor::forloop::OperationType; import ParseTreeVisualization; -import refactor::forloop::BreakIntoStatements; +import lang::java::refactoring::forloop::MethodVar; +import lang::java::refactoring::forloop::OperationType; +import lang::java::refactoring::forloop::BreakIntoStatements; public data ProspectiveOperation = prospectiveOperation(str stmt, str operation); diff --git a/src/refactor/forloop/UsedVariables.rsc b/src/lang/java/refactoring/forloop/UsedVariables.rsc similarity index 94% rename from src/refactor/forloop/UsedVariables.rsc rename to src/lang/java/refactoring/forloop/UsedVariables.rsc index 5ab7656..e8f2a83 100644 --- a/src/refactor/forloop/UsedVariables.rsc +++ b/src/lang/java/refactoring/forloop/UsedVariables.rsc @@ -1,12 +1,12 @@ -module refactor::forloop::UsedVariables +module lang::java::refactoring::forloop::UsedVariables import IO; import String; import Set; import lang::java::\syntax::Java18; import ParseTree; -import MethodVar; -import refactor::forloop::ProspectiveOperation; +import lang::java::refactoring::forloop::MethodVar; +import lang::java::refactoring::forloop::ProspectiveOperation; public set[str] retrieveUsedVariables(ProspectiveOperation prOp) { set[str] usedVariables = {}; diff --git a/src/refactor/forloop/AvailableVariablesTest.rsc b/src/lang/java/refactoring/forloop/test/AvailableVariablesTest.rsc similarity index 87% rename from src/refactor/forloop/AvailableVariablesTest.rsc rename to src/lang/java/refactoring/forloop/test/AvailableVariablesTest.rsc index 34141fb..aae5dc8 100644 --- a/src/refactor/forloop/AvailableVariablesTest.rsc +++ b/src/lang/java/refactoring/forloop/test/AvailableVariablesTest.rsc @@ -1,11 +1,11 @@ -module refactor::forloop::AvailableVariablesTest +module lang::java::refactoring::forloop::\test::AvailableVariablesTest -import refactor::forloop::AvailableVariables; -import refactor::forloop::ProspectiveOperation; -import refactor::forloop::OperationType; -import MethodVar; import Set; import IO; +import lang::java::refactoring::forloop::AvailableVariables; +import lang::java::refactoring::forloop::ProspectiveOperation; +import lang::java::refactoring::forloop::OperationType; +import lang::java::refactoring::forloop::MethodVar; public test bool methodParamShouldBeAvailableVar() { prOp = prospectiveOperation("writer.write(thing);", FOR_EACH); diff --git a/src/refactor/forloop/test/BreakIntoStatementsTest.rsc b/src/lang/java/refactoring/forloop/test/BreakIntoStatementsTest.rsc similarity index 86% rename from src/refactor/forloop/test/BreakIntoStatementsTest.rsc rename to src/lang/java/refactoring/forloop/test/BreakIntoStatementsTest.rsc index 1308691..5c61546 100644 --- a/src/refactor/forloop/test/BreakIntoStatementsTest.rsc +++ b/src/lang/java/refactoring/forloop/test/BreakIntoStatementsTest.rsc @@ -1,15 +1,15 @@ -module refactor::forloop::\test::BreakIntoStatementsTest +module lang::java::refactoring::forloop::\test::BreakIntoStatementsTest import IO; -import refactor::forloop::BreakIntoStatements; +import lang::java::refactoring::forloop::BreakIntoStatements; import lang::java::\syntax::Java18; -import refactor::forloop::ProspectiveOperationTestResources; -import refactor::forloop::ForLoopBodyReferences; +import lang::java::refactoring::forloop::ProspectiveOperationTestResources; +import lang::java::refactoring::forloop::ForLoopBodyReferences; import ParseTree; import ParseTreeVisualization; public test bool ex1() { - fileLoc = |project://rascal-Java8//testes/ProspectiveOperation/SimpleShortEnhancedLoop|; + fileLoc = |project://rascal-Java8//testes/forloop/ProspectiveOperation/SimpleShortEnhancedLoop|; enhancedForLoop = parse(#EnhancedForStatement, readFile(fileLoc)); loopBody = retrieveLoopBodyFromEnhancedFor(enhancedForLoop); @@ -22,7 +22,7 @@ public test bool ex1() { } public test bool ex2() { - fileLoc = |project://rascal-Java8//testes/ProspectiveOperation/ContinueAndReturnEnhancedLoop|; + fileLoc = |project://rascal-Java8//testes/forloop/ProspectiveOperation/ContinueAndReturnEnhancedLoop|; enhancedForLoop = parse(#EnhancedForStatement, readFile(fileLoc)); loopBody = retrieveLoopBodyFromEnhancedFor(enhancedForLoop); @@ -36,7 +36,7 @@ public test bool ex2() { } public test bool ex3() { - fileLoc = |project://rascal-Java8//testes/ProspectiveOperation/FilterMapReduceEnhancedLoop|; + fileLoc = |project://rascal-Java8//testes/forloop/ProspectiveOperation/FilterMapReduceEnhancedLoop|; enhancedForLoop = parse(#EnhancedForStatement, readFile(fileLoc)); loopBody = retrieveLoopBodyFromEnhancedFor(enhancedForLoop); @@ -77,7 +77,7 @@ public test bool ex5() { } public test bool ex6() { - fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/ForIfWithTwoStmtsInsideAndStmtAfterBlock.java|; + fileForLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/ForIfWithTwoStmtsInsideAndStmtAfterBlock.java|; enhancedForLoop = parse(#EnhancedForStatement, readFile(fileForLoc)); loopBody = retrieveLoopBodyFromEnhancedFor(enhancedForLoop); @@ -90,7 +90,7 @@ public test bool ex6() { // inside the if after the loop from previous example public test bool ex7() { - fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/ForIfWithTwoStmtsInsideAndStmtAfterBlock.java|; + fileForLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/ForIfWithTwoStmtsInsideAndStmtAfterBlock.java|; enhancedForLoop = parse(#EnhancedForStatement, readFile(fileForLoc)); loopBody = retrieveLoopBodyFromEnhancedFor(enhancedForLoop); list[Stmt] stmts = []; diff --git a/src/refactor/forloop/ClassFieldsFinderTest.rsc b/src/lang/java/refactoring/forloop/test/ClassFieldsFinderTest.rsc similarity index 71% rename from src/refactor/forloop/ClassFieldsFinderTest.rsc rename to src/lang/java/refactoring/forloop/test/ClassFieldsFinderTest.rsc index 8afffd0..40a65a4 100644 --- a/src/refactor/forloop/ClassFieldsFinderTest.rsc +++ b/src/lang/java/refactoring/forloop/test/ClassFieldsFinderTest.rsc @@ -1,13 +1,13 @@ -module refactor::forloop::ClassFieldsFinderTest +module lang::java::refactoring::forloop::\test::ClassFieldsFinderTest import lang::java::\syntax::Java18; import ParseTree; -import refactor::forloop::ClassFieldsFinder; -import MethodVar; +import lang::java::refactoring::forloop::ClassFieldsFinder; +import lang::java::refactoring::forloop::MethodVar; import Set; public test bool shouldReturnAllClassFields() { - fileLoc = |project://rascal-Java8//testes/localVariables/ClassWithFields.java|; + fileLoc = |project://rascal-Java8//testes/forloop/localVariables/ClassWithFields.java|; unit = parse(#CompilationUnit, fileLoc); classFields = findClassFields(unit); diff --git a/src/refactor/forloop/EnhancedLoopExpressionTest.rsc b/src/lang/java/refactoring/forloop/test/EnhancedLoopExpressionTest.rsc similarity index 70% rename from src/refactor/forloop/EnhancedLoopExpressionTest.rsc rename to src/lang/java/refactoring/forloop/test/EnhancedLoopExpressionTest.rsc index 91d4c9c..98404e1 100644 --- a/src/refactor/forloop/EnhancedLoopExpressionTest.rsc +++ b/src/lang/java/refactoring/forloop/test/EnhancedLoopExpressionTest.rsc @@ -1,13 +1,13 @@ -module refactor::forloop::EnhancedLoopExpressionTest +module lang::java::refactoring::forloop::\test::EnhancedLoopExpressionTest import IO; import lang::java::\syntax::Java18; import ParseTree; -import MethodVar; -import LocalVariablesFinder; -import LocalVariablesFinderTestResources; -import refactor::forloop::ClassFieldsFinder; -import refactor::forloop::EnhancedLoopExpression; +import lang::java::refactoring::forloop::MethodVar; +import lang::java::refactoring::forloop::LocalVariablesFinder; +import lang::java::refactoring::forloop::\test::resources::LocalVariablesFinderTestResources; +import lang::java::refactoring::forloop::ClassFieldsFinder; +import lang::java::refactoring::forloop::EnhancedLoopExpression; public test bool iterableShouldReturnFalse() { params = paramsEnhancedForOnIterable(); @@ -24,7 +24,7 @@ private tuple[Expression exp, set[MethodVar] localVariables] paramsEnhancedForOn } private tuple[MethodHeader methodHeader, MethodBody methodBody] getEnhancedForOnIterable() { - fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/EnhancedForOnIterable.java|; + fileLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/EnhancedForOnIterable.java|; methodDeclaration = parse(#MethodDeclaration, readFile(fileLoc)); visit(methodDeclaration) { case (MethodDeclaration) ` `: { @@ -45,10 +45,10 @@ public test bool iterableParamShouldReturnFalse() { public test bool thisFieldListShouldReturnTrue() { exp = parse(#Expression, "this.engineValves"); methodHeader = parse(#MethodHeader, "void configureEngine(Engine engine)"); - methodBodyLoc = |project://rascal-Java8/testes/classFields/MethodBodyIteratingOnThisField2|; + methodBodyLoc = |project://rascal-Java8/testes/forloop/classFields/MethodBodyIteratingOnThisField2|; methodBody = parse(#MethodBody, readFile(methodBodyLoc)); localVariables = findLocalVariables(methodHeader, methodBody); - classFields = findClassFields(parse(#CompilationUnit, readFile(|project://rascal-Java8/testes/classFields/TomcatServletWebServerFactory.java|))); + classFields = findClassFields(parse(#CompilationUnit, readFile(|project://rascal-Java8/testes/forloop/classFields/TomcatServletWebServerFactory.java|))); vars = localVariables + classFields; return isIteratingOnCollection(exp, vars) == true; diff --git a/src/refactor/forloop/test/ForLoopBodyReferencesTest.rsc b/src/lang/java/refactoring/forloop/test/ForLoopBodyReferencesTest.rsc similarity index 78% rename from src/refactor/forloop/test/ForLoopBodyReferencesTest.rsc rename to src/lang/java/refactoring/forloop/test/ForLoopBodyReferencesTest.rsc index cd68379..9c96254 100644 --- a/src/refactor/forloop/test/ForLoopBodyReferencesTest.rsc +++ b/src/lang/java/refactoring/forloop/test/ForLoopBodyReferencesTest.rsc @@ -1,15 +1,15 @@ -module refactor::forloop::\test::ForLoopBodyReferencesTest +module lang::java::refactoring::forloop::\test::ForLoopBodyReferencesTest import IO; import lang::java::\syntax::Java18; import ParseTree; import Set; -import refactor::forloop::ForLoopBodyReferences; -import MethodVar; -import LocalVariablesFinder; +import lang::java::refactoring::forloop::ForLoopBodyReferences; +import lang::java::refactoring::forloop::MethodVar; +import lang::java::refactoring::forloop::LocalVariablesFinder; public test bool variablesReferenced1() { - fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/ForWith3StatementsMapBody.java|; + fileForLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/ForWith3StatementsMapBody.java|; forStmt = parse(#EnhancedForStatement, readFile(fileForLoc)); loopBody = retrieveLoopBodyFromEnhancedFor(forStmt); @@ -24,7 +24,7 @@ public test bool variablesReferenced1() { } public test bool variablesReferenced2() { - fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/ForWithMultiStatementMap.java|; + fileForLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/ForWithMultiStatementMap.java|; EnhancedForStatement forStmt = parse(#EnhancedForStatement, readFile(fileForLoc)); loopBody = retrieveLoopBodyFromEnhancedFor(forStmt); @@ -39,7 +39,7 @@ public test bool variablesReferenced2() { } public test bool variablesReferenced3() { - fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T2For2.java|; + fileForLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/T2For2.java|; EnhancedForStatement forStmt = parse(#EnhancedForStatement, readFile(fileForLoc)); loopBody = retrieveLoopBodyFromEnhancedFor(forStmt); @@ -68,7 +68,7 @@ public test bool variablesReferenced4() { public test bool shouldBeRefactorableWhenOneReferenceFound() { methodHeader = parse(#MethodHeader, "\ ImmutableSortedMultiset\ copyOfSortedEntries(Comparator\ comparator, Collection\\> entries)"); - methodBodyLoc = |project://rascal-Java8/testes/localVariables/MethodBodyWithTwoReferencesToOutsideNonEffectiveVars|; + methodBodyLoc = |project://rascal-Java8/testes/forloop/localVariables/MethodBodyWithTwoReferencesToOutsideNonEffectiveVars|; methodBody = parse(#MethodBody, readFile(methodBodyLoc)); localVariables = findLocalVariables(methodHeader, methodBody); forStmt = parse(#EnhancedForStatement, "for (Entry\ entry : entries) {\n elementsBuilder.add(entry.getElement());\n cumulativeCounts[i + 1] = cumulativeCounts[i] + entry.getCount();\n i++;\n }"); diff --git a/src/refactor/forloop/ForLoopToFunctionalTest.rsc b/src/lang/java/refactoring/forloop/test/ForLoopToFunctionalTest.rsc similarity index 83% rename from src/refactor/forloop/ForLoopToFunctionalTest.rsc rename to src/lang/java/refactoring/forloop/test/ForLoopToFunctionalTest.rsc index a941dd8..5125742 100644 --- a/src/refactor/forloop/ForLoopToFunctionalTest.rsc +++ b/src/lang/java/refactoring/forloop/test/ForLoopToFunctionalTest.rsc @@ -1,19 +1,21 @@ -module refactor::forloop::ForLoopToFunctionalTest +module lang::java::refactoring::forloop::\test::ForLoopToFunctionalTest import IO; import String; import lang::java::\syntax::Java18; import ParseTree; -import refactor::forloop::ForLoopToFunctional; -import MethodVar; -import LocalVariablesFinder; -import LocalVariablesFinderTestResources; -import refactor::forloop::ProspectiveOperationTestResources; -import refactor::forloop::ClassFieldsFinder; import ParseTreeVisualization; +import lang::java::refactoring::forloop::ForLoopToFunctional; +import lang::java::refactoring::forloop::MethodVar; +import lang::java::refactoring::forloop::LocalVariablesFinder; +import lang::java::refactoring::forloop::ClassFieldsFinder; +import lang::java::refactoring::forloop::\test::resources::LocalVariablesFinderTestResources; +import lang::java::refactoring::forloop::\test::resources::ProspectiveOperationTestResources; + + public test bool ex1() { - fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T1.java|; + fileLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/T1.java|; methodBody = parse(#MethodBody, readFile(fileLoc)); methodHeader = parse(#MethodHeader, "TestSuite createTestSuite()"); set[MethodVar] methodVars = findLocalVariables(methodHeader, methodBody); @@ -27,11 +29,11 @@ public test bool ex1() { } public test bool reduceAsNotTheLastOperationShouldNotBeRefactored() { - fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T2.java|; + fileLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/T2.java|; methodBody = parse(#MethodBody, readFile(fileLoc)); methodHeader = parse(#MethodHeader, "void assertInvariants(Map\ map)"); set[MethodVar] methodVars = findLocalVariables(methodHeader, methodBody); - fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T2For.java|; + fileForLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/T2For.java|; EnhancedForStatement forStmt = parse(#EnhancedForStatement, readFile(fileForLoc)); VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "key"); Expression collectionId = parse(#Expression, "keySet"); @@ -46,11 +48,11 @@ public test bool reduceAsNotTheLastOperationShouldNotBeRefactored() { } public test bool shouldRefactorReduceWithCompoundPlusAssignmentOperator() { - fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T2.java|; + fileLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/T2.java|; methodBody = parse(#MethodBody, readFile(fileLoc)); methodHeader = parse(#MethodHeader, "void assertInvariants(Map\ map)"); set[MethodVar] methodVars = findLocalVariables(methodHeader, methodBody); - fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T2For2.java|; + fileForLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/T2For2.java|; EnhancedForStatement forStmt = parse(#EnhancedForStatement, readFile(fileForLoc)); VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "entry"); Expression collectionId = parse(#Expression, "entrySet"); @@ -61,11 +63,11 @@ public test bool shouldRefactorReduceWithCompoundPlusAssignmentOperator() { } public test bool shouldAddReturnToMapWithMoreThanOneStatement() { - methodBodyLoc = |project://rascal-Java8//testes/ForLoopToFunctional/MethodBodyWithMultiStatementMap.java|; + methodBodyLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/MethodBodyWithMultiStatementMap.java|; methodBody = parse(#MethodBody, readFile(methodBodyLoc)); methodHeader = parse(#MethodHeader, "Iterable\\> findAll()"); set[MethodVar] methodVars = findLocalVariables(methodHeader, methodBody); - fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/ForWithMultiStatementMap.java|; + fileForLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/ForWithMultiStatementMap.java|; EnhancedForStatement forStmt = parse(#EnhancedForStatement, readFile(fileForLoc)); VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "v"); Expression collectionId = parse(#Expression, "values"); @@ -76,11 +78,11 @@ public test bool shouldAddReturnToMapWithMoreThanOneStatement() { } public test bool shouldAddCorrectReturnTo3StmtsMapBody() { - methodBodyLoc = |project://rascal-Java8//testes/ForLoopToFunctional/MethodBodyWIth3StatementsMapBody.java|; + methodBodyLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/MethodBodyWIth3StatementsMapBody.java|; methodBody = parse(#MethodBody, readFile(methodBodyLoc)); methodHeader = parse(#MethodHeader, "void updateSnapshots(Collection\ snapshots)"); set[MethodVar] methodVars = findLocalVariables(methodHeader, methodBody); - fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/ForWith3StatementsMapBody.java|; + fileForLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/ForWith3StatementsMapBody.java|; EnhancedForStatement forStmt = parse(#EnhancedForStatement, readFile(fileForLoc)); VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "snapshot"); Expression collectionId = parse(#Expression, "snapshots"); @@ -108,7 +110,7 @@ public test bool shouldThrowExceptionWhenALoopWithOnlyOneReferenceToOutsideNonEf public test bool shouldThrowExceptionWhenALoopWithOnlyOneReferenceToOutsideNonEffectiveFinalVarIsNotAReducer2() { methodHeader = parse(#MethodHeader, "\ ImmutableSortedMultiset\ copyOfSortedEntries(Comparator\ comparator, Collection\\> entries)"); - methodBodyLoc = |project://rascal-Java8/testes/localVariables/MethodBodyWithTwoReferencesToOutsideNonEffectiveVars|; + methodBodyLoc = |project://rascal-Java8/testes/forloop/localVariables/MethodBodyWithTwoReferencesToOutsideNonEffectiveVars|; methodBody = parse(#MethodBody, readFile(methodBodyLoc)); methodVars = findLocalVariables(methodHeader, methodBody); forStmt = parse(#EnhancedForStatement, "for (Entry\ entry : entries) {\n elementsBuilder.add(entry.getElement());\n cumulativeCounts[i + 1] = cumulativeCounts[i] + entry.getCount();\n i++;\n }"); @@ -125,7 +127,7 @@ public test bool shouldThrowExceptionWhenALoopWithOnlyOneReferenceToOutsideNonEf public test bool shouldWorkWithThrowStatementInsideAnIfThatIsNotTheLastStatement() { tuple [set[MethodVar] vars, EnhancedForStatement loop] loopWithThrowStatement = loopWithThrowStatement(); - methodBodyLoc = |project://rascal-Java8//testes/localVariables/MethodBodyPostDecrementedVar|; + methodBodyLoc = |project://rascal-Java8//testes/forloop/localVariables/MethodBodyPostDecrementedVar|; methodBody = parse(#MethodBody, readFile(methodBodyLoc)); VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "key"); Expression collectionId = parse(#Expression, "keysToLoad"); @@ -137,7 +139,7 @@ public test bool shouldWorkWithThrowStatementInsideAnIfThatIsNotTheLastStatement public test bool loopWithIfWithTwoStatementsInsideBlockShouldRefactorInnerIfAsMap() { tuple [set[MethodVar] vars, EnhancedForStatement loop] loop = loopWithIfWithTwoStatementsInsideBlock(); - methodBodyLoc = |project://rascal-Java8//testes/ForLoopToFunctional/MethodBodyIfWithTwoStmtsInsideAndStmtAfterBlock.java|; + methodBodyLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/MethodBodyIfWithTwoStmtsInsideAndStmtAfterBlock.java|; methodBody = parse(#MethodBody, readFile(methodBodyLoc)); VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "endpoint"); Expression collectionId = parse(#Expression, "endpoints"); @@ -149,7 +151,7 @@ public test bool loopWithIfWithTwoStatementsInsideBlockShouldRefactorInnerIfAsMa public test bool anotherIfThatIsMap() { methodHeader = parse(#MethodHeader, "void afterPropertiesSet() throws Exception"); - methodBodyLoc = |project://rascal-Java8/testes/ForLoopToFunctional/MethodBodyIfAsNotAFilter|; + methodBodyLoc = |project://rascal-Java8/testes/forloop/ForLoopToFunctional/MethodBodyIfAsNotAFilter|; methodBody = parse(#MethodBody, readFile(methodBodyLoc)); methodVars = findLocalVariables(methodHeader, methodBody); forStmt = parse(#EnhancedForStatement, "for (Endpoint\ endpoint : delegates) {if (isGenericEndpoint(endpoint.getClass()) && endpoint.isEnabled()) {EndpointMvcAdapter adapter = new EndpointMvcAdapter(endpoint);String path = determinePath(endpoint,this.applicationContext.getEnvironment());if (path != null) {adapter.setPath(path);}this.endpoints.add(adapter);}}"); @@ -163,15 +165,15 @@ public test bool anotherIfThatIsMap() { public test bool shouldRefactorLoopIteratingOnThisField() { methodHeader = parse(#MethodHeader, "WebServer getWebServer(ServletContextInitializer... initializers)"); - methodBodyLoc = |project://rascal-Java8/testes/classFields/MethodBodyIteratingOnThisField|; + methodBodyLoc = |project://rascal-Java8/testes/forloop/classFields/MethodBodyIteratingOnThisField|; methodBody = parse(#MethodBody, readFile(methodBodyLoc)); methodVars = findLocalVariables(methodHeader, methodBody); - fileForLoc = |project://rascal-Java8/testes/classFields/ForIteratingOnThisField|; + fileForLoc = |project://rascal-Java8/testes/forloop/classFields/ForIteratingOnThisField|; EnhancedForStatement forStmt = parse(#EnhancedForStatement, readFile(fileForLoc)); VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "additionalConnector"); Expression collectionId = parse(#Expression, "this.additionalTomcatConnectors"); - classFields = findClassFields(parse(#CompilationUnit, readFile(|project://rascal-Java8/testes/classFields/TomcatServletWebServerFactory.java|))); + classFields = findClassFields(parse(#CompilationUnit, readFile(|project://rascal-Java8/testes/forloop/classFields/TomcatServletWebServerFactory.java|))); vars = methodVars + classFields; refactoredStatement = buildRefactoredEnhancedFor(vars, forStmt, methodBody, iteratedVarName, collectionId); @@ -181,15 +183,15 @@ public test bool shouldRefactorLoopIteratingOnThisField() { public test bool shouldRefactorLoopIteratingOnThisField2() { methodHeader = parse(#MethodHeader, "void configureEngine(Engine engine)"); - methodBodyLoc = |project://rascal-Java8/testes/classFields/MethodBodyIteratingOnThisField2|; + methodBodyLoc = |project://rascal-Java8/testes/forloop/classFields/MethodBodyIteratingOnThisField2|; methodBody = parse(#MethodBody, readFile(methodBodyLoc)); methodVars = findLocalVariables(methodHeader, methodBody); - fileForLoc = |project://rascal-Java8/testes/classFields/ForIteratingOnThisField2|; + fileForLoc = |project://rascal-Java8/testes/forloop/classFields/ForIteratingOnThisField2|; EnhancedForStatement forStmt = parse(#EnhancedForStatement, readFile(fileForLoc)); VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "valve"); Expression collectionId = parse(#Expression, "this.engineValves"); - classFields = findClassFields(parse(#CompilationUnit, readFile(|project://rascal-Java8/testes/classFields/TomcatServletWebServerFactory.java|))); + classFields = findClassFields(parse(#CompilationUnit, readFile(|project://rascal-Java8/testes/forloop/classFields/TomcatServletWebServerFactory.java|))); vars = methodVars + classFields; refactoredStatement = buildRefactoredEnhancedFor(vars, forStmt, methodBody, iteratedVarName, collectionId); @@ -201,7 +203,7 @@ public test bool shouldRefactorLoopIteratingOnThisField2() { // throw "Not yet implemented"; // // methodHeader = parse(#MethodHeader, "\ ImmutableSortedMultiset\ copyOfSortedEntries(Comparator\ comparator, Collection\\> entries)"); -// methodBodyLoc = |project://rascal-Java8/testes/localVariables/MethodBodyReduceWithPostIncrement|; +// methodBodyLoc = |project://rascal-Java8/testes/forloop/localVariables/MethodBodyReduceWithPostIncrement|; // methodBody = parse(#MethodBody, readFile(methodBodyLoc)); // methodVars = findLocalVariables(methodHeader, methodBody); // forStmt = parse(#EnhancedForStatement, "for (Entry\ entry : entries) {\n elementsBuilder.add(entry.getElement());\n // cumulativeCounts[i + 1] = cumulativeCounts[i] + entry.getCount();\n i++;\n }"); @@ -218,11 +220,11 @@ public test bool shouldRefactorLoopIteratingOnThisField2() { // TODO nested loops needed to be changed in ProspectiveOperation //public test bool nestedLoops() { -// fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/NestedLoops.java|; +// fileLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/NestedLoops.java|; // methodBody = parse(#MethodBody, readFile(fileLoc)); // methodHeader = parse(#MethodHeader, "void testComplexBuilder()"); // set[MethodVar] methodVars = findLocalVariables(methodHeader, methodBody); -// fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T2For.java|; +// fileForLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/T2For.java|; // EnhancedForStatement forStmt = parse(#EnhancedForStatement, "for (Integer red : colorElem) {\n for (Integer green : colorElem) {\n for (Integer blue : colorElem) {\n webSafeColorsBuilder.add((red \<\< 16) + (green \<\< 8) + blue);\n }\n }\n }"); // VariableDeclaratorId iteratedVarName = parse(#VariableDeclaratorId, "red"); // Expression collectionId = parse(#Expression, "colorElem"); diff --git a/src/LocalVariablesFinderTest.rsc b/src/lang/java/refactoring/forloop/test/LocalVariablesFinderTest.rsc similarity index 96% rename from src/LocalVariablesFinderTest.rsc rename to src/lang/java/refactoring/forloop/test/LocalVariablesFinderTest.rsc index 7074abc..a9b8fe5 100644 --- a/src/LocalVariablesFinderTest.rsc +++ b/src/lang/java/refactoring/forloop/test/LocalVariablesFinderTest.rsc @@ -1,10 +1,10 @@ -module LocalVariablesFinderTest +module lang::java::refactoring::forloop::\test::LocalVariablesFinderTest import IO; -import LocalVariablesFinderTestResources; -import LocalVariablesFinder; import Set; -import MethodVar; +import lang::java::refactoring::forloop::\test::resources::LocalVariablesFinderTestResources; +import lang::java::refactoring::forloop::LocalVariablesFinder; +import lang::java::refactoring::forloop::MethodVar; public test bool shouldHaveTheEnhancedDeclaredVarAsFinal() { methodBody = enhancedForLoopFinalVarDecl(); diff --git a/src/refactor/forloop/ProspectiveOperationTest.rsc b/src/lang/java/refactoring/forloop/test/ProspectiveOperationTest.rsc similarity index 95% rename from src/refactor/forloop/ProspectiveOperationTest.rsc rename to src/lang/java/refactoring/forloop/test/ProspectiveOperationTest.rsc index 8b25973..6c4177b 100644 --- a/src/refactor/forloop/ProspectiveOperationTest.rsc +++ b/src/lang/java/refactoring/forloop/test/ProspectiveOperationTest.rsc @@ -1,12 +1,12 @@ -module refactor::forloop::ProspectiveOperationTest +module lang::java::refactoring::forloop::\test::ProspectiveOperationTest -import refactor::forloop::ProspectiveOperation; -import refactor::forloop::ProspectiveOperationTestResources; -import refactor::forloop::OperationType; -import MethodVar; import lang::java::\syntax::Java18; import IO; import List; +import lang::java::refactoring::forloop::ProspectiveOperation; +import lang::java::refactoring::forloop::\test::resources::ProspectiveOperationTestResources; +import lang::java::refactoring::forloop::OperationType; +import lang::java::refactoring::forloop::MethodVar; public test bool shouldReturnAForEachOnSimpleShortExample() { tuple [set[MethodVar] vars, EnhancedForStatement loop] simpleShort = simpleShort(); diff --git a/src/refactor/forloop/UsedVariablesTest.rsc b/src/lang/java/refactoring/forloop/test/UsedVariablesTest.rsc similarity index 87% rename from src/refactor/forloop/UsedVariablesTest.rsc rename to src/lang/java/refactoring/forloop/test/UsedVariablesTest.rsc index 37a9162..0574dc7 100644 --- a/src/refactor/forloop/UsedVariablesTest.rsc +++ b/src/lang/java/refactoring/forloop/test/UsedVariablesTest.rsc @@ -1,11 +1,11 @@ -module refactor::forloop::UsedVariablesTest +module lang::java::refactoring::forloop::\test::UsedVariablesTest -import refactor::forloop::UsedVariables; -import refactor::forloop::ProspectiveOperation; -import refactor::forloop::OperationType; -import MethodVar; import Set; import IO; +import lang::java::refactoring::forloop::UsedVariables; +import lang::java::refactoring::forloop::ProspectiveOperation; +import lang::java::refactoring::forloop::OperationType; +import lang::java::refactoring::forloop::MethodVar; public test bool methodInvocationWithArg() { prOp = prospectiveOperation("writer.write(thing);", FOR_EACH); diff --git a/src/LocalVariablesFinderTestResources.rsc b/src/lang/java/refactoring/forloop/test/resources/LocalVariablesFinderTestResources.rsc similarity index 79% rename from src/LocalVariablesFinderTestResources.rsc rename to src/lang/java/refactoring/forloop/test/resources/LocalVariablesFinderTestResources.rsc index 10e3506..78c73ad 100644 --- a/src/LocalVariablesFinderTestResources.rsc +++ b/src/lang/java/refactoring/forloop/test/resources/LocalVariablesFinderTestResources.rsc @@ -1,9 +1,9 @@ -module LocalVariablesFinderTestResources +module lang::java::refactoring::forloop::\test::resources::LocalVariablesFinderTestResources import IO; import lang::java::\syntax::Java18; import ParseTree; -import MethodVar; +import lang::java::refactoring::forloop::MethodVar; public MethodHeader emptyMethodHeader() { header = "void method()"; @@ -36,17 +36,17 @@ public MethodBody emptyMethodBody() { } public MethodBody enhancedForLoopFinalVarDecl() { - fileLoc = |project://rascal-Java8//testes/localVariables/EnhancedForLoopFinalVarDecl|; + fileLoc = |project://rascal-Java8//testes/forloop/localVariables/EnhancedForLoopFinalVarDecl|; return parse(#MethodBody, readFile(fileLoc)); } public MethodBody enhancedForLoopWithException() { - fileLoc = |project://rascal-Java8//testes/localVariables/EnhancedForLoopWithException|; + fileLoc = |project://rascal-Java8//testes/forloop/localVariables/EnhancedForLoopWithException|; return parse(#MethodBody, readFile(fileLoc)); } public MethodBody arrayVariables() { - fileLoc = |project://rascal-Java8//testes/localVariables/MultiplePlainArrayDeclarations|; + fileLoc = |project://rascal-Java8//testes/forloop/localVariables/MultiplePlainArrayDeclarations|; return parse(#MethodBody, readFile(fileLoc)); } @@ -97,7 +97,7 @@ public MethodHeader varsWithinTheLoopMethodHeader() { } public MethodBody varsWithinTheLoopMethodBody() { - fileLoc = |project://rascal-Java8//testes/localVariables/EnhancedForLoopVarsWithinLoop|; + fileLoc = |project://rascal-Java8//testes/forloop/localVariables/EnhancedForLoopVarsWithinLoop|; return parse(#MethodBody, readFile(fileLoc)); } @@ -107,7 +107,7 @@ public MethodHeader nonEffectiveFinalUsedInEnhancedForMethodHeader() { } public MethodBody nonEffectiveFinalUsedInEnhancedForMethodBody() { - fileLoc = |project://rascal-Java8//testes/localVariables/NonEffectiveFinalUsedInEnhancedFor|; + fileLoc = |project://rascal-Java8//testes/forloop/localVariables/NonEffectiveFinalUsedInEnhancedFor|; return parse(#MethodBody, readFile(fileLoc)); } @@ -117,7 +117,7 @@ public MethodHeader iterableParameterMethodHeader() { } public MethodBody iterableParameterMethodBody() { - fileLoc = |project://rascal-Java8//testes/localVariables/IterableParameterMethodBody|; + fileLoc = |project://rascal-Java8//testes/forloop/localVariables/IterableParameterMethodBody|; return parse(#MethodBody, readFile(fileLoc)); } @@ -127,7 +127,7 @@ public MethodHeader methodWithAnonnymousInnerClassMethodHeader() { } public MethodBody methodWithAnonnymousInnerClassMethodBody() { - fileLoc = |project://rascal-Java8//testes/localVariables/MethodBodyWithAnonnymousInnerClass|; + fileLoc = |project://rascal-Java8//testes/forloop/localVariables/MethodBodyWithAnonnymousInnerClass|; return parse(#MethodBody, readFile(fileLoc)); } @@ -137,7 +137,7 @@ public MethodHeader postIncrementedVarMethodHeader() { } public MethodBody postIncrementedVarMethodBody() { - fileLoc = |project://rascal-Java8//testes/localVariables/MethodBodyPostIncrementedVar|; + fileLoc = |project://rascal-Java8//testes/forloop/localVariables/MethodBodyPostIncrementedVar|; return parse(#MethodBody, readFile(fileLoc)); } @@ -147,7 +147,7 @@ public MethodHeader postIncrementedVar2MethodHeader() { } public MethodBody postIncrementedVar2MethodBody() { - fileLoc = |project://rascal-Java8//testes/localVariables/MethodBodyPostIncrementedVar2|; + fileLoc = |project://rascal-Java8//testes/forloop/localVariables/MethodBodyPostIncrementedVar2|; return parse(#MethodBody, readFile(fileLoc)); } @@ -157,7 +157,7 @@ public MethodHeader postIncrementedVar3MethodHeader() { } public MethodBody postIncrementedVar3MethodBody() { - fileLoc = |project://rascal-Java8//testes/localVariables/MethodBodyPostIncrementedVar3|; + fileLoc = |project://rascal-Java8//testes/forloop/localVariables/MethodBodyPostIncrementedVar3|; return parse(#MethodBody, readFile(fileLoc)); } @@ -168,7 +168,7 @@ public MethodHeader postDecrementedVarMethodHeader() { } public MethodBody postDecrementedVarMethodBody() { - fileLoc = |project://rascal-Java8//testes/localVariables/MethodBodyPostDecrementedVar|; + fileLoc = |project://rascal-Java8//testes/forloop/localVariables/MethodBodyPostDecrementedVar|; return parse(#MethodBody, readFile(fileLoc)); } @@ -178,7 +178,7 @@ public MethodHeader assignmentInsideForMethodHeader() { } public MethodBody assignmentInsideForMethodBody() { - fileLoc = |project://rascal-Java8//testes/localVariables/MethodBodyAssignmentInsideLoop|; + fileLoc = |project://rascal-Java8//testes/forloop/localVariables/MethodBodyAssignmentInsideLoop|; return parse(#MethodBody, readFile(fileLoc)); } @@ -188,6 +188,6 @@ public MethodHeader twoNonEffectiveFinalVarsInsideLoopMethodHeader() { } public MethodBody twoNonEffectiveFinalVarsInsideLoopMethodBody() { - methodBodyLoc = |project://rascal-Java8/testes/localVariables/MethodBodyWithTwoReferencesToOutsideNonEffectiveVars|; + methodBodyLoc = |project://rascal-Java8/testes/forloop/localVariables/MethodBodyWithTwoReferencesToOutsideNonEffectiveVars|; return parse(#MethodBody, readFile(methodBodyLoc)); } \ No newline at end of file diff --git a/src/refactor/forloop/ProspectiveOperationTestResources.rsc b/src/lang/java/refactoring/forloop/test/resources/ProspectiveOperationTestResources.rsc similarity index 77% rename from src/refactor/forloop/ProspectiveOperationTestResources.rsc rename to src/lang/java/refactoring/forloop/test/resources/ProspectiveOperationTestResources.rsc index e4f50f0..d6cd615 100644 --- a/src/refactor/forloop/ProspectiveOperationTestResources.rsc +++ b/src/lang/java/refactoring/forloop/test/resources/ProspectiveOperationTestResources.rsc @@ -1,19 +1,19 @@ -module refactor::forloop::ProspectiveOperationTestResources +module lang::java::refactoring::forloop::\test::resources::ProspectiveOperationTestResources import IO; import lang::java::\syntax::Java18; import ParseTree; -import MethodVar; -import LocalVariablesFinder; +import lang::java::refactoring::forloop::MethodVar; +import lang::java::refactoring::forloop::LocalVariablesFinder; public tuple [set[MethodVar] vars, EnhancedForStatement loop] simpleShort() { - fileLoc = |project://rascal-Java8//testes/ProspectiveOperation/SimpleShortEnhancedLoop|; + fileLoc = |project://rascal-Java8//testes/forloop/ProspectiveOperation/SimpleShortEnhancedLoop|; enhancedForLoop = parse(#EnhancedForStatement, readFile(fileLoc)); return <{}, enhancedForLoop>; } public tuple [set[MethodVar] vars, EnhancedForStatement loop] continueAndReturn() { - fileLoc = |project://rascal-Java8//testes/ProspectiveOperation/ContinueAndReturnEnhancedLoop|; + fileLoc = |project://rascal-Java8//testes/forloop/ProspectiveOperation/ContinueAndReturnEnhancedLoop|; enhancedForLoop = parse(#EnhancedForStatement, readFile(fileLoc)); return ; } @@ -25,7 +25,7 @@ private set[MethodVar] continueAndReturnVars() { } public tuple [set[MethodVar] vars, EnhancedForStatement loop] filterMapReduce() { - fileLoc = |project://rascal-Java8//testes/ProspectiveOperation/FilterMapReduceEnhancedLoop|; + fileLoc = |project://rascal-Java8//testes/forloop/ProspectiveOperation/FilterMapReduceEnhancedLoop|; enhancedForLoop = parse(#EnhancedForStatement, readFile(fileLoc)); return ; } @@ -37,7 +37,7 @@ private set[MethodVar] filterMapReduceVars() { } public tuple [set[MethodVar] vars, EnhancedForStatement loop] filterAndMergedForEach() { - fileLoc = |project://rascal-Java8//testes/ProspectiveOperation/FilterAndMergedForEach|; + fileLoc = |project://rascal-Java8//testes/forloop/ProspectiveOperation/FilterAndMergedForEach|; enhancedForLoop = parse(#EnhancedForStatement, readFile(fileLoc)); return ; } @@ -49,52 +49,52 @@ private set[MethodVar] filterAndMergedForEachVars() { } public tuple [set[MethodVar] vars, EnhancedForStatement loop] multipleMapsAndEndingReducer() { - fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T2For2.java|; + fileForLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/T2For2.java|; EnhancedForStatement forStmt = parse(#EnhancedForStatement, readFile(fileForLoc)); return ; } private set[MethodVar] multipleMapsAndEndingReducerVars() { - fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/T2.java|; + fileLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/T2.java|; methodBody = parse(#MethodBody, readFile(fileLoc)); methodHeader = parse(#MethodHeader, "void assertInvariants(Map\ map)"); return findLocalVariables(methodHeader, methodBody); } public tuple [set[MethodVar] vars, EnhancedForStatement loop] innerLoop1() { - fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/InnerLoop1.java|; + fileForLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/InnerLoop1.java|; EnhancedForStatement forStmt = parse(#EnhancedForStatement, readFile(fileForLoc)); return ; } private set[MethodVar] innerLoop1Vars() { - fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/MethodBodyInnerLoop1.java|; + fileLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/MethodBodyInnerLoop1.java|; methodBody = parse(#MethodBody, readFile(fileLoc)); methodHeader = parse(#MethodHeader, "\ Graph\ transitiveClosure(Graph\ graph)"); return findLocalVariables(methodHeader, methodBody); } public tuple [set[MethodVar] vars, EnhancedForStatement loop] innerLoop2() { - fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/InnerLoop2.java|; + fileForLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/InnerLoop2.java|; EnhancedForStatement forStmt = parse(#EnhancedForStatement, readFile(fileForLoc)); return ; } private set[MethodVar] innerLoop2Vars() { - fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/MethodBodyInnerLoop2.java|; + fileLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/MethodBodyInnerLoop2.java|; methodBody = parse(#MethodBody, readFile(fileLoc)); methodHeader = parse(#MethodHeader, "ImmutableList\ getAnnotatedMethodsNotCached(Class\ clazz)"); return findLocalVariables(methodHeader, methodBody); } public tuple [set[MethodVar] vars, EnhancedForStatement loop] loopWithInnerWhile() { - fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/LoopWithInnerWhile.java|; + fileForLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/LoopWithInnerWhile.java|; EnhancedForStatement forStmt = parse(#EnhancedForStatement, readFile(fileForLoc)); return ; } private set[MethodVar] loopWithInnerWhileVars() { - fileLoc = |project://rascal-Java8//testes/ForLoopToFunctional/MethodBodyLoopWithInnerWhile.java|; + fileLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/MethodBodyLoopWithInnerWhile.java|; methodBody = parse(#MethodBody, readFile(fileLoc)); methodHeader = parse(#MethodHeader, "ImmutableList\ getAnnotatedMethodsNotCached(Class\ clazz)"); return findLocalVariables(methodHeader, methodBody); @@ -107,7 +107,7 @@ public tuple [set[MethodVar] vars, EnhancedForStatement loop] loopReduceWithPost private set[MethodVar] loopReduceWithPostIncrementVars() { methodHeader = parse(#MethodHeader, "\ ImmutableSortedMultiset\ copyOfSortedEntries(Comparator\ comparator, Collection\\> entries)"); - methodBodyLoc = |project://rascal-Java8/testes/localVariables/MethodBodyReduceWithPostIncrement|; + methodBodyLoc = |project://rascal-Java8/testes/forloop/localVariables/MethodBodyReduceWithPostIncrement|; methodBody = parse(#MethodBody, readFile(methodBodyLoc)); return findLocalVariables(methodHeader, methodBody); } @@ -119,20 +119,20 @@ public tuple [set[MethodVar] vars, EnhancedForStatement loop] loopWithThrowState private set[MethodVar] loopWithThrowStatementVars() { methodHeader = parse(#MethodHeader, "ImmutableMap\ getAll(Iterable\ keys) throws ExecutionException"); - methodBodyLoc = |project://rascal-Java8//testes/localVariables/MethodBodyPostDecrementedVar|; + methodBodyLoc = |project://rascal-Java8//testes/forloop/localVariables/MethodBodyPostDecrementedVar|; methodBody = parse(#MethodBody, readFile(methodBodyLoc)); return findLocalVariables(methodHeader, methodBody); } public tuple [set[MethodVar] vars, EnhancedForStatement loop] loopWithIfWithTwoStatementsInsideBlock() { - fileForLoc = |project://rascal-Java8//testes/ForLoopToFunctional/ForIfWithTwoStmtsInsideAndStmtAfterBlock.java|; + fileForLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/ForIfWithTwoStmtsInsideAndStmtAfterBlock.java|; EnhancedForStatement forStmt = parse(#EnhancedForStatement, readFile(fileForLoc)); return ; } private set[MethodVar] loopWithIfWithTwoStatementsInsideBlockVars() { methodHeader = parse(#MethodHeader, "String[] getPaths(EndpointHandlerMapping endpointHandlerMapping)"); - methodBodyLoc = |project://rascal-Java8//testes/ForLoopToFunctional/MethodBodyIfWithTwoStmtsInsideAndStmtAfterBlock.java|; + methodBodyLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/MethodBodyIfWithTwoStmtsInsideAndStmtAfterBlock.java|; methodBody = parse(#MethodBody, readFile(methodBodyLoc)); return findLocalVariables(methodHeader, methodBody); } \ No newline at end of file diff --git a/testes/ForLoopToFunctional/EnhancedForOnIterable.java b/testes/forloop/ForLoopToFunctional/EnhancedForOnIterable.java similarity index 100% rename from testes/ForLoopToFunctional/EnhancedForOnIterable.java rename to testes/forloop/ForLoopToFunctional/EnhancedForOnIterable.java diff --git a/testes/ForLoopToFunctional/ForIfWithTwoStmtsInsideAndStmtAfterBlock.java b/testes/forloop/ForLoopToFunctional/ForIfWithTwoStmtsInsideAndStmtAfterBlock.java similarity index 100% rename from testes/ForLoopToFunctional/ForIfWithTwoStmtsInsideAndStmtAfterBlock.java rename to testes/forloop/ForLoopToFunctional/ForIfWithTwoStmtsInsideAndStmtAfterBlock.java diff --git a/testes/ForLoopToFunctional/ForWith3StatementsMapBody.java b/testes/forloop/ForLoopToFunctional/ForWith3StatementsMapBody.java similarity index 100% rename from testes/ForLoopToFunctional/ForWith3StatementsMapBody.java rename to testes/forloop/ForLoopToFunctional/ForWith3StatementsMapBody.java diff --git a/testes/ForLoopToFunctional/ForWithMultiStatementMap.java b/testes/forloop/ForLoopToFunctional/ForWithMultiStatementMap.java similarity index 100% rename from testes/ForLoopToFunctional/ForWithMultiStatementMap.java rename to testes/forloop/ForLoopToFunctional/ForWithMultiStatementMap.java diff --git a/testes/ForLoopToFunctional/InnerLoop1.java b/testes/forloop/ForLoopToFunctional/InnerLoop1.java similarity index 100% rename from testes/ForLoopToFunctional/InnerLoop1.java rename to testes/forloop/ForLoopToFunctional/InnerLoop1.java diff --git a/testes/ForLoopToFunctional/InnerLoop2.java b/testes/forloop/ForLoopToFunctional/InnerLoop2.java similarity index 100% rename from testes/ForLoopToFunctional/InnerLoop2.java rename to testes/forloop/ForLoopToFunctional/InnerLoop2.java diff --git a/testes/ForLoopToFunctional/LoopWithInnerWhile.java b/testes/forloop/ForLoopToFunctional/LoopWithInnerWhile.java similarity index 100% rename from testes/ForLoopToFunctional/LoopWithInnerWhile.java rename to testes/forloop/ForLoopToFunctional/LoopWithInnerWhile.java diff --git a/testes/ForLoopToFunctional/MethodBodyIfAsNotAFilter b/testes/forloop/ForLoopToFunctional/MethodBodyIfAsNotAFilter similarity index 100% rename from testes/ForLoopToFunctional/MethodBodyIfAsNotAFilter rename to testes/forloop/ForLoopToFunctional/MethodBodyIfAsNotAFilter diff --git a/testes/ForLoopToFunctional/MethodBodyIfWithTwoStmtsInsideAndStmtAfterBlock.java b/testes/forloop/ForLoopToFunctional/MethodBodyIfWithTwoStmtsInsideAndStmtAfterBlock.java similarity index 100% rename from testes/ForLoopToFunctional/MethodBodyIfWithTwoStmtsInsideAndStmtAfterBlock.java rename to testes/forloop/ForLoopToFunctional/MethodBodyIfWithTwoStmtsInsideAndStmtAfterBlock.java diff --git a/testes/ForLoopToFunctional/MethodBodyInnerLoop1.java b/testes/forloop/ForLoopToFunctional/MethodBodyInnerLoop1.java similarity index 100% rename from testes/ForLoopToFunctional/MethodBodyInnerLoop1.java rename to testes/forloop/ForLoopToFunctional/MethodBodyInnerLoop1.java diff --git a/testes/ForLoopToFunctional/MethodBodyInnerLoop2.java b/testes/forloop/ForLoopToFunctional/MethodBodyInnerLoop2.java similarity index 100% rename from testes/ForLoopToFunctional/MethodBodyInnerLoop2.java rename to testes/forloop/ForLoopToFunctional/MethodBodyInnerLoop2.java diff --git a/testes/ForLoopToFunctional/MethodBodyLoopWithInnerWhile.java b/testes/forloop/ForLoopToFunctional/MethodBodyLoopWithInnerWhile.java similarity index 100% rename from testes/ForLoopToFunctional/MethodBodyLoopWithInnerWhile.java rename to testes/forloop/ForLoopToFunctional/MethodBodyLoopWithInnerWhile.java diff --git a/testes/ForLoopToFunctional/MethodBodyWIth3StatementsMapBody.java b/testes/forloop/ForLoopToFunctional/MethodBodyWIth3StatementsMapBody.java similarity index 100% rename from testes/ForLoopToFunctional/MethodBodyWIth3StatementsMapBody.java rename to testes/forloop/ForLoopToFunctional/MethodBodyWIth3StatementsMapBody.java diff --git a/testes/ForLoopToFunctional/MethodBodyWithMultiStatementMap.java b/testes/forloop/ForLoopToFunctional/MethodBodyWithMultiStatementMap.java similarity index 100% rename from testes/ForLoopToFunctional/MethodBodyWithMultiStatementMap.java rename to testes/forloop/ForLoopToFunctional/MethodBodyWithMultiStatementMap.java diff --git a/testes/ForLoopToFunctional/NestedLoops.java b/testes/forloop/ForLoopToFunctional/NestedLoops.java similarity index 100% rename from testes/ForLoopToFunctional/NestedLoops.java rename to testes/forloop/ForLoopToFunctional/NestedLoops.java diff --git a/testes/ForLoopToFunctional/SimpleForEach.java b/testes/forloop/ForLoopToFunctional/SimpleForEach.java similarity index 100% rename from testes/ForLoopToFunctional/SimpleForEach.java rename to testes/forloop/ForLoopToFunctional/SimpleForEach.java diff --git a/testes/ForLoopToFunctional/T1.java b/testes/forloop/ForLoopToFunctional/T1.java similarity index 100% rename from testes/ForLoopToFunctional/T1.java rename to testes/forloop/ForLoopToFunctional/T1.java diff --git a/testes/ForLoopToFunctional/T2.java b/testes/forloop/ForLoopToFunctional/T2.java similarity index 100% rename from testes/ForLoopToFunctional/T2.java rename to testes/forloop/ForLoopToFunctional/T2.java diff --git a/testes/ForLoopToFunctional/T2For.java b/testes/forloop/ForLoopToFunctional/T2For.java similarity index 100% rename from testes/ForLoopToFunctional/T2For.java rename to testes/forloop/ForLoopToFunctional/T2For.java diff --git a/testes/ForLoopToFunctional/T2For2.java b/testes/forloop/ForLoopToFunctional/T2For2.java similarity index 100% rename from testes/ForLoopToFunctional/T2For2.java rename to testes/forloop/ForLoopToFunctional/T2For2.java diff --git a/testes/ProspectiveOperation/ContinueAndReturnEnhancedLoop b/testes/forloop/ProspectiveOperation/ContinueAndReturnEnhancedLoop similarity index 100% rename from testes/ProspectiveOperation/ContinueAndReturnEnhancedLoop rename to testes/forloop/ProspectiveOperation/ContinueAndReturnEnhancedLoop diff --git a/testes/ProspectiveOperation/FilterAndMergedForEach b/testes/forloop/ProspectiveOperation/FilterAndMergedForEach similarity index 100% rename from testes/ProspectiveOperation/FilterAndMergedForEach rename to testes/forloop/ProspectiveOperation/FilterAndMergedForEach diff --git a/testes/ProspectiveOperation/FilterMapReduceEnhancedLoop b/testes/forloop/ProspectiveOperation/FilterMapReduceEnhancedLoop similarity index 100% rename from testes/ProspectiveOperation/FilterMapReduceEnhancedLoop rename to testes/forloop/ProspectiveOperation/FilterMapReduceEnhancedLoop diff --git a/testes/ProspectiveOperation/SimpleShortEnhancedLoop b/testes/forloop/ProspectiveOperation/SimpleShortEnhancedLoop similarity index 100% rename from testes/ProspectiveOperation/SimpleShortEnhancedLoop rename to testes/forloop/ProspectiveOperation/SimpleShortEnhancedLoop diff --git a/testes/classFields/ForIteratingOnThisField b/testes/forloop/classFields/ForIteratingOnThisField similarity index 100% rename from testes/classFields/ForIteratingOnThisField rename to testes/forloop/classFields/ForIteratingOnThisField diff --git a/testes/classFields/ForIteratingOnThisField2 b/testes/forloop/classFields/ForIteratingOnThisField2 similarity index 100% rename from testes/classFields/ForIteratingOnThisField2 rename to testes/forloop/classFields/ForIteratingOnThisField2 diff --git a/testes/classFields/MethodBodyIteratingOnThisField b/testes/forloop/classFields/MethodBodyIteratingOnThisField similarity index 100% rename from testes/classFields/MethodBodyIteratingOnThisField rename to testes/forloop/classFields/MethodBodyIteratingOnThisField diff --git a/testes/classFields/MethodBodyIteratingOnThisField2 b/testes/forloop/classFields/MethodBodyIteratingOnThisField2 similarity index 100% rename from testes/classFields/MethodBodyIteratingOnThisField2 rename to testes/forloop/classFields/MethodBodyIteratingOnThisField2 diff --git a/testes/classFields/TomcatServletWebServerFactory.java b/testes/forloop/classFields/TomcatServletWebServerFactory.java similarity index 100% rename from testes/classFields/TomcatServletWebServerFactory.java rename to testes/forloop/classFields/TomcatServletWebServerFactory.java diff --git a/testes/localVariables/ClassWithFields.java b/testes/forloop/localVariables/ClassWithFields.java similarity index 100% rename from testes/localVariables/ClassWithFields.java rename to testes/forloop/localVariables/ClassWithFields.java diff --git a/testes/localVariables/EnhancedForLoopFinalVarDecl b/testes/forloop/localVariables/EnhancedForLoopFinalVarDecl similarity index 100% rename from testes/localVariables/EnhancedForLoopFinalVarDecl rename to testes/forloop/localVariables/EnhancedForLoopFinalVarDecl diff --git a/testes/localVariables/EnhancedForLoopVarsWithinLoop b/testes/forloop/localVariables/EnhancedForLoopVarsWithinLoop similarity index 100% rename from testes/localVariables/EnhancedForLoopVarsWithinLoop rename to testes/forloop/localVariables/EnhancedForLoopVarsWithinLoop diff --git a/testes/localVariables/EnhancedForLoopWithException b/testes/forloop/localVariables/EnhancedForLoopWithException similarity index 100% rename from testes/localVariables/EnhancedForLoopWithException rename to testes/forloop/localVariables/EnhancedForLoopWithException diff --git a/testes/localVariables/IterableParameterMethodBody b/testes/forloop/localVariables/IterableParameterMethodBody similarity index 100% rename from testes/localVariables/IterableParameterMethodBody rename to testes/forloop/localVariables/IterableParameterMethodBody diff --git a/testes/localVariables/MethodBodyAssignmentInsideLoop b/testes/forloop/localVariables/MethodBodyAssignmentInsideLoop similarity index 100% rename from testes/localVariables/MethodBodyAssignmentInsideLoop rename to testes/forloop/localVariables/MethodBodyAssignmentInsideLoop diff --git a/testes/localVariables/MethodBodyPostDecrementedVar b/testes/forloop/localVariables/MethodBodyPostDecrementedVar similarity index 100% rename from testes/localVariables/MethodBodyPostDecrementedVar rename to testes/forloop/localVariables/MethodBodyPostDecrementedVar diff --git a/testes/localVariables/MethodBodyPostIncrementedVar b/testes/forloop/localVariables/MethodBodyPostIncrementedVar similarity index 100% rename from testes/localVariables/MethodBodyPostIncrementedVar rename to testes/forloop/localVariables/MethodBodyPostIncrementedVar diff --git a/testes/localVariables/MethodBodyPostIncrementedVar2 b/testes/forloop/localVariables/MethodBodyPostIncrementedVar2 similarity index 100% rename from testes/localVariables/MethodBodyPostIncrementedVar2 rename to testes/forloop/localVariables/MethodBodyPostIncrementedVar2 diff --git a/testes/localVariables/MethodBodyPostIncrementedVar3 b/testes/forloop/localVariables/MethodBodyPostIncrementedVar3 similarity index 100% rename from testes/localVariables/MethodBodyPostIncrementedVar3 rename to testes/forloop/localVariables/MethodBodyPostIncrementedVar3 diff --git a/testes/localVariables/MethodBodyReduceWithPostIncrement b/testes/forloop/localVariables/MethodBodyReduceWithPostIncrement similarity index 100% rename from testes/localVariables/MethodBodyReduceWithPostIncrement rename to testes/forloop/localVariables/MethodBodyReduceWithPostIncrement diff --git a/testes/localVariables/MethodBodyWithAnonnymousInnerClass b/testes/forloop/localVariables/MethodBodyWithAnonnymousInnerClass similarity index 100% rename from testes/localVariables/MethodBodyWithAnonnymousInnerClass rename to testes/forloop/localVariables/MethodBodyWithAnonnymousInnerClass diff --git a/testes/localVariables/MethodBodyWithTwoReferencesToOutsideNonEffectiveVars b/testes/forloop/localVariables/MethodBodyWithTwoReferencesToOutsideNonEffectiveVars similarity index 100% rename from testes/localVariables/MethodBodyWithTwoReferencesToOutsideNonEffectiveVars rename to testes/forloop/localVariables/MethodBodyWithTwoReferencesToOutsideNonEffectiveVars diff --git a/testes/localVariables/MultiplePlainArrayDeclarations b/testes/forloop/localVariables/MultiplePlainArrayDeclarations similarity index 100% rename from testes/localVariables/MultiplePlainArrayDeclarations rename to testes/forloop/localVariables/MultiplePlainArrayDeclarations diff --git a/testes/localVariables/NonEffectiveFinalUsedInEnhancedFor b/testes/forloop/localVariables/NonEffectiveFinalUsedInEnhancedFor similarity index 100% rename from testes/localVariables/NonEffectiveFinalUsedInEnhancedFor rename to testes/forloop/localVariables/NonEffectiveFinalUsedInEnhancedFor From 961f194f2915814b2ea0e6b44665601106c14467 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Tue, 16 May 2017 18:16:48 -0300 Subject: [PATCH 133/154] Redoing merge in M3Util --- src/lang/java/m3/M3Util.rsc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lang/java/m3/M3Util.rsc b/src/lang/java/m3/M3Util.rsc index 097e63c..08628bb 100644 --- a/src/lang/java/m3/M3Util.rsc +++ b/src/lang/java/m3/M3Util.rsc @@ -18,6 +18,10 @@ list[loc] listAllClassFiles(loc location) { return findAllFiles(location, "class"); } +list[loc] listAllJavaFiles(loc location) { + return findAllFiles(location, "java"); +} + /* * computes a list of class names from a classpath, * that is, a list of Jar files. From e0716d8e87d418f5bb7786eb1e4c9b9017457417 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Tue, 16 May 2017 18:37:28 -0300 Subject: [PATCH 134/154] Fixing wrong import --- .../java/refactoring/forloop/test/BreakIntoStatementsTest.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lang/java/refactoring/forloop/test/BreakIntoStatementsTest.rsc b/src/lang/java/refactoring/forloop/test/BreakIntoStatementsTest.rsc index 5c61546..e8a5b7e 100644 --- a/src/lang/java/refactoring/forloop/test/BreakIntoStatementsTest.rsc +++ b/src/lang/java/refactoring/forloop/test/BreakIntoStatementsTest.rsc @@ -3,7 +3,7 @@ module lang::java::refactoring::forloop::\test::BreakIntoStatementsTest import IO; import lang::java::refactoring::forloop::BreakIntoStatements; import lang::java::\syntax::Java18; -import lang::java::refactoring::forloop::ProspectiveOperationTestResources; +import lang::java::refactoring::forloop::\test::resources::ProspectiveOperationTestResources; import lang::java::refactoring::forloop::ForLoopBodyReferences; import ParseTree; import ParseTreeVisualization; From 2df4e55abc4a8e894597c35b4b07d041533ce495 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Tue, 16 May 2017 18:57:23 -0300 Subject: [PATCH 135/154] ForLoop renamed to EnhancedForLoopRefactorer --- ...ForLoop.rsc => EnhancedForLoopRefactorer.rsc} | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) rename src/lang/java/refactoring/forloop/{ForLoop.rsc => EnhancedForLoopRefactorer.rsc} (88%) diff --git a/src/lang/java/refactoring/forloop/ForLoop.rsc b/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc similarity index 88% rename from src/lang/java/refactoring/forloop/ForLoop.rsc rename to src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc index 50176c4..7b93b69 100644 --- a/src/lang/java/refactoring/forloop/ForLoop.rsc +++ b/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc @@ -1,15 +1,15 @@ -module ForLoop +module lang::java::refactoring::forloop::EnhancedForLoopRefactorer import IO; import lang::java::\syntax::Java18; import ParseTree; -import LocalVariablesFinder; -import refactor::forloop::EnhancedLoopExpression; -import refactor::forloop::ForLoopBodyReferences; -import refactor::forloop::ForLoopToFunctional; -import refactor::forloop::ClassFieldsFinder; -import MethodVar; import util::Math; +import lang::java::refactoring::forloop::LocalVariablesFinder; +import lang::java::refactoring::forloop::EnhancedLoopExpression; +import lang::java::refactoring::forloop::ForLoopBodyReferences; +import lang::java::refactoring::forloop::ForLoopToFunctional; +import lang::java::refactoring::forloop::ClassFieldsFinder; +import lang::java::refactoring::forloop::MethodVar; private set[str] checkedExceptionClasses; @@ -19,7 +19,7 @@ private bool alreadyComputedClassFields; private int refactoredCount = 0; -public void findForLoops(list[loc] locs, set[str] checkedExceptions) { +public void forLoopToFunctional(list[loc] locs, set[str] checkedExceptions) { refactoredCount = 0; checkedExceptionClasses = checkedExceptions; for(fileLoc <- locs) { From 45f7dada89f119bd915013aa92df5d41303fdfda Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Mon, 29 May 2017 15:39:13 -0300 Subject: [PATCH 136/154] Starting to write a test for the entire refactor --- .../forloop/EnhancedForLoopRefactorer.rsc | 4 +++- .../test/EnhancedForLoopRefactorerTest.rsc | 10 +++++++++ .../forloop/test/ProspectiveOperationTest.rsc | 11 ++++++++++ .../ProspectiveOperationTestResources.rsc | 22 +++++++++++++++++++ 4 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 src/lang/java/refactoring/forloop/test/EnhancedForLoopRefactorerTest.rsc diff --git a/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc b/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc index 7b93b69..a182643 100644 --- a/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc +++ b/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc @@ -55,7 +55,9 @@ private void lookForEnhancedForStatementsInMethodBody(CompilationUnit unit, Meth top-down visit(methodBody) { case EnhancedForStatement forStmt: { - + println("for"); + println(forStmt); + println(); if(!alreadyComputedClassFields) { currentClassFields = findClassFields(unit); alreadyComputedClassFields = true; diff --git a/src/lang/java/refactoring/forloop/test/EnhancedForLoopRefactorerTest.rsc b/src/lang/java/refactoring/forloop/test/EnhancedForLoopRefactorerTest.rsc new file mode 100644 index 0000000..4e714a4 --- /dev/null +++ b/src/lang/java/refactoring/forloop/test/EnhancedForLoopRefactorerTest.rsc @@ -0,0 +1,10 @@ +module lang::java::refactoring::forloop::\test::EnhancedForLoopRefactorerTest + +import IO; +import lang::java::refactoring::forloop::EnhancedForLoopRefactorer; + +public test bool refactorableInnerLoopButNotOuterLoop() { + classLoc = |project://rascal-Java8//testes/forloop/Refactorer/ClassRefactorableInnerLoopButNotOuter|; + forLoopToFunctional([classLoc], {}); + return false; +} \ No newline at end of file diff --git a/src/lang/java/refactoring/forloop/test/ProspectiveOperationTest.rsc b/src/lang/java/refactoring/forloop/test/ProspectiveOperationTest.rsc index 6c4177b..2331587 100644 --- a/src/lang/java/refactoring/forloop/test/ProspectiveOperationTest.rsc +++ b/src/lang/java/refactoring/forloop/test/ProspectiveOperationTest.rsc @@ -141,6 +141,17 @@ public test bool innerIfAsNotTheLastStatementShouldBeAMap() { prospectiveOperations[4].operation == FOR_EACH; } +public void shouldThrowExceptionOnLoopWithInnerLoop() { + tuple [set[MethodVar] vars, EnhancedForStatement loop] loop = outerLoopWithInnerLoop(); + + try { + prospectiveOperations = retrieveProspectiveOperations(loop.vars, loop.loop); + return false; + } catch: + return true; + +} + //public test bool shouldIdentifyPostIncrementAsReduce() { // throw "Not yet implemented"; // diff --git a/src/lang/java/refactoring/forloop/test/resources/ProspectiveOperationTestResources.rsc b/src/lang/java/refactoring/forloop/test/resources/ProspectiveOperationTestResources.rsc index d6cd615..56fd7c3 100644 --- a/src/lang/java/refactoring/forloop/test/resources/ProspectiveOperationTestResources.rsc +++ b/src/lang/java/refactoring/forloop/test/resources/ProspectiveOperationTestResources.rsc @@ -5,6 +5,7 @@ import lang::java::\syntax::Java18; import ParseTree; import lang::java::refactoring::forloop::MethodVar; import lang::java::refactoring::forloop::LocalVariablesFinder; +import lang::java::refactoring::forloop::ClassFieldsFinder; public tuple [set[MethodVar] vars, EnhancedForStatement loop] simpleShort() { fileLoc = |project://rascal-Java8//testes/forloop/ProspectiveOperation/SimpleShortEnhancedLoop|; @@ -135,4 +136,25 @@ private set[MethodVar] loopWithIfWithTwoStatementsInsideBlockVars() { methodBodyLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/MethodBodyIfWithTwoStmtsInsideAndStmtAfterBlock.java|; methodBody = parse(#MethodBody, readFile(methodBodyLoc)); return findLocalVariables(methodHeader, methodBody); +} + +public tuple [set[MethodVar] vars, EnhancedForStatement loop] outerLoopWithInnerLoop() { + methodHeader = parse(#MethodHeader, "void scanPackage(ClassPathScanningCandidateComponentProvider componentProvider, String packageToScan)"); + loopLoc = |project://rascal-Java8//testes/forloop/Refactorer/LoopRefactorableInnerLoopButNotOuter|; + loopStr = readFile(loopLoc); + forStmt = parse(#EnhancedForStatement, loopStr); + methodBody = parse(#MethodBody, "{" + loopStr + "}"); + + localVars = findLocalVariables(methodHeader, methodBody); + classLoc = |project://rascal-Java8//testes/forloop/Refactorer/ClassRefactorableInnerLoopButNotOuter|; + classFields = findClassFields(parse(#CompilationUnit, classLoc)); + availableVars = localVars + classFields; + + return ; +} + +public tuple [set[MethodVar] vars, EnhancedForStatement loop] innerLoopInsideOuter() { + tuple [set[MethodVar] vars, EnhancedForStatement loop] loop = outerLoopWithInnerLoop(); + loop.loop = "for (ServletComponentHandler handler : HANDLERS) {\n handler.handle(((ScannedGenericBeanDefinition) candidate),\n (BeanDefinitionRegistry) this.applicationContext);\n }"; + return loop; } \ No newline at end of file From e841847c23397b089ce25b7889e05817e7cbc00d Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sat, 10 Jun 2017 22:48:33 -0300 Subject: [PATCH 137/154] Finally transforming a compilation unit with the refactors. --- .../forloop/EnhancedForLoopRefactorer.rsc | 67 +++++++++++-------- .../test/EnhancedForLoopRefactorerTest.rsc | 9 ++- 2 files changed, 47 insertions(+), 29 deletions(-) diff --git a/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc b/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc index a182643..75a2a5b 100644 --- a/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc +++ b/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc @@ -11,7 +11,9 @@ import lang::java::refactoring::forloop::ForLoopToFunctional; import lang::java::refactoring::forloop::ClassFieldsFinder; import lang::java::refactoring::forloop::MethodVar; -private set[str] checkedExceptionClasses; +private bool PRINT_DEBUG = false; + +private set[str] checkedExceptionClasses = {}; private set[MethodVar] currentClassFields = {}; @@ -26,38 +28,43 @@ public void forLoopToFunctional(list[loc] locs, set[str] checkedExceptions) { javaFileContent = readFile(fileLoc); try { unit = parse(#CompilationUnit, javaFileContent); - alreadyComputedClassFields = false; - lookForForStatements(unit); + refactorEnhancedForStatements(unit); } catch: continue; } println("refactoredCount: " + toString(refactoredCount)); } -private void lookForForStatements(CompilationUnit unit) { - visit(unit) { - case MethodDeclaration methodDeclaration: - lookForEnhancedForStatementsInMethod(unit, methodDeclaration); - } -} - -private void lookForEnhancedForStatementsInMethod(CompilationUnit unit, MethodDeclaration methodDeclaration) { - visit(methodDeclaration) { - case (MethodDeclaration) ` `: - lookForEnhancedForStatementsInMethodBody(unit, methodHeader, methodBody); - } +// Losing format after a method is refactored. +public CompilationUnit refactorEnhancedForStatements(CompilationUnit unit) { + alreadyComputedClassFields = false; + CompilationUnit refactoredUnit = visit(unit) { + case (MethodDeclaration) ` `: { + MethodBody refactoredMethoBody = visit(mBody) { + case MethodBody methodBody: insert refactorEnhancedForStatementsInMethodBody(unit, methodHeader, methodBody); + }; + + insert((MethodDeclaration) ` `); + } + }; + + return refactoredUnit; } // TODO What happens when two for statements are refactored inside the same method? -private void lookForEnhancedForStatementsInMethodBody(CompilationUnit unit, MethodHeader methodHeader, MethodBody methodBody) { +private MethodBody refactorEnhancedForStatementsInMethodBody(CompilationUnit unit, MethodHeader methodHeader, MethodBody methodBody) { set[MethodVar] availableVars = {}; alreadyComputedCurrentMethodAvailableVars = false; + MethodBody refactoredMethodBody = methodBody; top-down visit(methodBody) { case EnhancedForStatement forStmt: { - println("for"); - println(forStmt); - println(); + if(PRINT_DEBUG) { + println("for"); + println(forStmt); + println(); + } + if(!alreadyComputedClassFields) { currentClassFields = findClassFields(unit); alreadyComputedClassFields = true; @@ -77,27 +84,31 @@ private void lookForEnhancedForStatementsInMethodBody(CompilationUnit unit, Meth if(isLoopRefactorable(availableVars, collectionId, loopBody)) { try { - refactored = refactorEnhancedToFunctional(availableVars, enhancedForStmt, methodBody, iteratedVarName, collectionId); + refactoredMethodBody = refactorEnhancedToFunctional(availableVars, enhancedForStmt, methodBody, iteratedVarName, collectionId); refactoredCount += 1; - println("refactored: " + toString(refactoredCount)); - println(enhancedForStmt); - println("---"); - println(refactored); - println(); - } catch: { + + if(PRINT_DEBUG) { + println("refactored: " + toString(refactoredCount)); + println(enhancedForStmt); + println("---"); + println(refactoredMethodBody); + println(); + } + } catch: continue; - } } } } } - } + } } case (EnhancedForStatementNoShortIf) `for ( : ) `: println("TODO"); } + + return refactoredMethodBody; } private bool isLoopRefactorable(set[MethodVar] availableVariables, Expression collectionId, Statement loopBody) { diff --git a/src/lang/java/refactoring/forloop/test/EnhancedForLoopRefactorerTest.rsc b/src/lang/java/refactoring/forloop/test/EnhancedForLoopRefactorerTest.rsc index 4e714a4..e34255e 100644 --- a/src/lang/java/refactoring/forloop/test/EnhancedForLoopRefactorerTest.rsc +++ b/src/lang/java/refactoring/forloop/test/EnhancedForLoopRefactorerTest.rsc @@ -1,10 +1,17 @@ module lang::java::refactoring::forloop::\test::EnhancedForLoopRefactorerTest import IO; +import ParseTree; +import lang::java::\syntax::Java18; import lang::java::refactoring::forloop::EnhancedForLoopRefactorer; public test bool refactorableInnerLoopButNotOuterLoop() { classLoc = |project://rascal-Java8//testes/forloop/Refactorer/ClassRefactorableInnerLoopButNotOuter|; - forLoopToFunctional([classLoc], {}); + unit = parse(#CompilationUnit, classLoc); + refactored = refactorEnhancedForStatements(unit); + + println("\n\n printando teste \n\n"); + println(refactored); + return false; } \ No newline at end of file From 0d209ad7a9415984d1bff8a41723e9c7a14eaf2a Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sat, 10 Jun 2017 23:39:45 -0300 Subject: [PATCH 138/154] Fixing typos --- .../java/refactoring/forloop/EnhancedForLoopRefactorer.rsc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc b/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc index 75a2a5b..69a950e 100644 --- a/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc +++ b/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc @@ -35,16 +35,16 @@ public void forLoopToFunctional(list[loc] locs, set[str] checkedExceptions) { println("refactoredCount: " + toString(refactoredCount)); } -// Losing format after a method is refactored. +// Losing formatting after a method is refactored. public CompilationUnit refactorEnhancedForStatements(CompilationUnit unit) { alreadyComputedClassFields = false; CompilationUnit refactoredUnit = visit(unit) { case (MethodDeclaration) ` `: { - MethodBody refactoredMethoBody = visit(mBody) { + MethodBody refactoredMethodBody = visit(mBody) { case MethodBody methodBody: insert refactorEnhancedForStatementsInMethodBody(unit, methodHeader, methodBody); }; - insert((MethodDeclaration) ` `); + insert((MethodDeclaration) ` `); } }; From de0588c05d29e26ad6455c249687c497be21848d Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 11 Jun 2017 11:25:21 -0300 Subject: [PATCH 139/154] Test case for refactoring an inner loop, but not an outer loop. --- .../forloop/EnhancedForLoopRefactorer.rsc | 4 ++-- .../test/EnhancedForLoopRefactorerTest.rsc | 18 ++++++++---------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc b/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc index 69a950e..515ce43 100644 --- a/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc +++ b/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc @@ -17,7 +17,7 @@ private set[str] checkedExceptionClasses = {}; private set[MethodVar] currentClassFields = {}; -private bool alreadyComputedClassFields; +private bool alreadyComputedClassFields = false; private int refactoredCount = 0; @@ -52,7 +52,7 @@ public CompilationUnit refactorEnhancedForStatements(CompilationUnit unit) { } // TODO What happens when two for statements are refactored inside the same method? -private MethodBody refactorEnhancedForStatementsInMethodBody(CompilationUnit unit, MethodHeader methodHeader, MethodBody methodBody) { +public MethodBody refactorEnhancedForStatementsInMethodBody(CompilationUnit unit, MethodHeader methodHeader, MethodBody methodBody) { set[MethodVar] availableVars = {}; alreadyComputedCurrentMethodAvailableVars = false; MethodBody refactoredMethodBody = methodBody; diff --git a/src/lang/java/refactoring/forloop/test/EnhancedForLoopRefactorerTest.rsc b/src/lang/java/refactoring/forloop/test/EnhancedForLoopRefactorerTest.rsc index e34255e..1bd896a 100644 --- a/src/lang/java/refactoring/forloop/test/EnhancedForLoopRefactorerTest.rsc +++ b/src/lang/java/refactoring/forloop/test/EnhancedForLoopRefactorerTest.rsc @@ -1,17 +1,15 @@ module lang::java::refactoring::forloop::\test::EnhancedForLoopRefactorerTest -import IO; -import ParseTree; -import lang::java::\syntax::Java18; import lang::java::refactoring::forloop::EnhancedForLoopRefactorer; +import lang::java::refactoring::forloop::\test::resources::RefactorerTestResources; -public test bool refactorableInnerLoopButNotOuterLoop() { - classLoc = |project://rascal-Java8//testes/forloop/Refactorer/ClassRefactorableInnerLoopButNotOuter|; - unit = parse(#CompilationUnit, classLoc); - refactored = refactorEnhancedForStatements(unit); +// comparing an entire file is not that practical +// comparing methods then +// but definitely should automate test for entire compilation unit +public test bool shouldRefactorInnerLoopButNoutOuterLoop() { + refactorable = innerLoopButNotOuterLoop(); - println("\n\n printando teste \n\n"); - println(refactored); + refactored = refactorEnhancedForStatementsInMethodBody(refactorable.unit, refactorable.header, refactorable.body); - return false; + return refactored == refactorable.refactored; } \ No newline at end of file From 46044ba1fcb3f5b6aa7a14799c5c984d0d5a6257 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 11 Jun 2017 13:37:00 -0300 Subject: [PATCH 140/154] Counting occurrences and test case for inner loop. --- .../forloop/EnhancedForLoopRefactorer.rsc | 85 +++++++++---------- .../test/EnhancedForLoopRefactorerTest.rsc | 6 +- .../resources/RefactorerTestResources.rsc | 18 ++++ 3 files changed, 63 insertions(+), 46 deletions(-) create mode 100644 src/lang/java/refactoring/forloop/test/resources/RefactorerTestResources.rsc diff --git a/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc b/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc index 515ce43..154420d 100644 --- a/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc +++ b/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc @@ -36,79 +36,76 @@ public void forLoopToFunctional(list[loc] locs, set[str] checkedExceptions) { } // Losing formatting after a method is refactored. -public CompilationUnit refactorEnhancedForStatements(CompilationUnit unit) { +public tuple[CompilationUnit unit, int occurrences] refactorEnhancedForStatements(CompilationUnit unit) { + int occurrences = 0; alreadyComputedClassFields = false; CompilationUnit refactoredUnit = visit(unit) { case (MethodDeclaration) ` `: { MethodBody refactoredMethodBody = visit(mBody) { - case MethodBody methodBody: insert refactorEnhancedForStatementsInMethodBody(unit, methodHeader, methodBody); + case MethodBody methodBody: { + refactored = refactorEnhancedForStatementsInMethodBody(unit, methodHeader, methodBody); + occurrences += refactored.occurrences; + insert refactored.body; + } }; insert((MethodDeclaration) ` `); } }; - return refactoredUnit; + return ; } // TODO What happens when two for statements are refactored inside the same method? -public MethodBody refactorEnhancedForStatementsInMethodBody(CompilationUnit unit, MethodHeader methodHeader, MethodBody methodBody) { +public tuple[MethodBody body, int occurrences] refactorEnhancedForStatementsInMethodBody(CompilationUnit unit, MethodHeader methodHeader, MethodBody methodBody) { set[MethodVar] availableVars = {}; alreadyComputedCurrentMethodAvailableVars = false; + occurrences = 0; + MethodBody refactoredMethodBody = methodBody; top-down visit(methodBody) { - case EnhancedForStatement forStmt: { - if(PRINT_DEBUG) { - println("for"); - println(forStmt); - println(); - } - - if(!alreadyComputedClassFields) { - currentClassFields = findClassFields(unit); - alreadyComputedClassFields = true; - } - - if(!alreadyComputedCurrentMethodAvailableVars) { - methodVars = findLocalVariables(methodHeader, methodBody); - availableVars = retainLocalVariablesIfDuplicates(currentClassFields, methodVars); - alreadyComputedAvailableVars = true; - } + case EnhancedForStatement enhancedForStmt: + visit(enhancedForStmt) { - top-down visit(forStmt) { - case EnhancedForStatement enhancedForStmt: { - visit(enhancedForStmt) { - case (EnhancedForStatement) `for ( : ) `: { - - if(isLoopRefactorable(availableVars, collectionId, loopBody)) { - - try { - refactoredMethodBody = refactorEnhancedToFunctional(availableVars, enhancedForStmt, methodBody, iteratedVarName, collectionId); - refactoredCount += 1; + case (EnhancedForStatement) `for ( : ) `: { + + if(!alreadyComputedClassFields) { + currentClassFields = findClassFields(unit); + alreadyComputedClassFields = true; + } + + if(!alreadyComputedCurrentMethodAvailableVars) { + methodVars = findLocalVariables(methodHeader, methodBody); + availableVars = retainLocalVariablesIfDuplicates(currentClassFields, methodVars); + alreadyComputedAvailableVars = true; + } - if(PRINT_DEBUG) { - println("refactored: " + toString(refactoredCount)); - println(enhancedForStmt); - println("---"); - println(refactoredMethodBody); - println(); - } - } catch: - continue; - + if(isLoopRefactorable(availableVars, collectionId, loopBody)) { + + try { + refactoredMethodBody = refactorEnhancedToFunctional(availableVars, enhancedForStmt, methodBody, iteratedVarName, collectionId); + occurrences += 1; + + if(PRINT_DEBUG) { + println("refactored: " + toString(occurrences)); + println(enhancedForStmt); + println("---"); + println(refactoredMethodBody); + println(); } - } + } catch: + continue; } } + } - } case (EnhancedForStatementNoShortIf) `for ( : ) `: println("TODO"); } - return refactoredMethodBody; + return ; } private bool isLoopRefactorable(set[MethodVar] availableVariables, Expression collectionId, Statement loopBody) { diff --git a/src/lang/java/refactoring/forloop/test/EnhancedForLoopRefactorerTest.rsc b/src/lang/java/refactoring/forloop/test/EnhancedForLoopRefactorerTest.rsc index 1bd896a..e8907f7 100644 --- a/src/lang/java/refactoring/forloop/test/EnhancedForLoopRefactorerTest.rsc +++ b/src/lang/java/refactoring/forloop/test/EnhancedForLoopRefactorerTest.rsc @@ -1,9 +1,10 @@ module lang::java::refactoring::forloop::\test::EnhancedForLoopRefactorerTest +import IO; import lang::java::refactoring::forloop::EnhancedForLoopRefactorer; import lang::java::refactoring::forloop::\test::resources::RefactorerTestResources; -// comparing an entire file is not that practical +// comparing an entire file is not that practical // comparing methods then // but definitely should automate test for entire compilation unit public test bool shouldRefactorInnerLoopButNoutOuterLoop() { @@ -11,5 +12,6 @@ public test bool shouldRefactorInnerLoopButNoutOuterLoop() { refactored = refactorEnhancedForStatementsInMethodBody(refactorable.unit, refactorable.header, refactorable.body); - return refactored == refactorable.refactored; + return refactored.body == refactorable.refactored && + refactored.occurrences == 1; } \ No newline at end of file diff --git a/src/lang/java/refactoring/forloop/test/resources/RefactorerTestResources.rsc b/src/lang/java/refactoring/forloop/test/resources/RefactorerTestResources.rsc new file mode 100644 index 0000000..eb288d8 --- /dev/null +++ b/src/lang/java/refactoring/forloop/test/resources/RefactorerTestResources.rsc @@ -0,0 +1,18 @@ +module lang::java::refactoring::forloop::\test::resources::RefactorerTestResources + +import IO; +import ParseTree; +import lang::java::\syntax::Java18; + +public data RefactorableFor = refactorableFor(CompilationUnit unit, MethodHeader header, MethodBody body, MethodBody refactored); + +public RefactorableFor innerLoopButNotOuterLoop() { + classLoc = |project://rascal-Java8//testes/forloop/Refactorer/ServletComponentRegisteringPostProcessor.java|; + unit = parse(#CompilationUnit, readFile(classLoc)); + header = parse(#MethodHeader, "void scanPackage(\r\n\t\t\tClassPathScanningCandidateComponentProvider componentProvider,\r\n\t\t\tString packageToScan)"); + body = parse(#MethodBody, "{\r\n\t\tfor (BeanDefinition candidate : componentProvider\r\n\t\t\t\t.findCandidateComponents(packageToScan)) {\r\n\t\t\tif (candidate instanceof ScannedGenericBeanDefinition) {\r\n\t\t\t\tfor (ServletComponentHandler handler : HANDLERS) {\r\n\t\t\t\t\thandler.handle(((ScannedGenericBeanDefinition) candidate),\r\n\t\t\t\t\t\t\t(BeanDefinitionRegistry) this.applicationContext);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}"); + + refactored = parse(#MethodBody, "{\r\n\t\tfor (BeanDefinition candidate : componentProvider\r\n\t\t\t\t.findCandidateComponents(packageToScan)) {\r\n\t\t\tif (candidate instanceof ScannedGenericBeanDefinition) {\r\n\t\t\t\tHANDLERS.forEach(handler -\> {\nhandler.handle(((ScannedGenericBeanDefinition) candidate),\r\n\t\t\t\t\t\t\t(BeanDefinitionRegistry) this.applicationContext);\n});\r\n\t\t\t}\r\n\t\t}\r\n\t}"); + + return refactorableFor(unit, header, body, refactored); +} \ No newline at end of file From 99dfb952c6a32c9a12af0046658e8ff92352fff6 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 11 Jun 2017 14:28:44 -0300 Subject: [PATCH 141/154] Removing folder 'testes' from .gitignore --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index b3dafd1..c5e82d7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ -bin -testes \ No newline at end of file +bin \ No newline at end of file From b8288a3afba55a3a145d8b44eed3c1059fffb1fc Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 11 Jun 2017 14:54:02 -0300 Subject: [PATCH 142/154] Fixing the declaration of a test case. Of course it was a failing test. --- .../forloop/test/ProspectiveOperationTest.rsc | 2 +- .../ProspectiveOperationTestResources.rsc | 2 +- .../LoopRefactorableInnerLoopButNotOuter | 9 ++ ...vletComponentRegisteringPostProcessor.java | 116 ++++++++++++++++++ 4 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 testes/forloop/Refactorer/LoopRefactorableInnerLoopButNotOuter create mode 100644 testes/forloop/Refactorer/ServletComponentRegisteringPostProcessor.java diff --git a/src/lang/java/refactoring/forloop/test/ProspectiveOperationTest.rsc b/src/lang/java/refactoring/forloop/test/ProspectiveOperationTest.rsc index 2331587..347a02b 100644 --- a/src/lang/java/refactoring/forloop/test/ProspectiveOperationTest.rsc +++ b/src/lang/java/refactoring/forloop/test/ProspectiveOperationTest.rsc @@ -141,7 +141,7 @@ public test bool innerIfAsNotTheLastStatementShouldBeAMap() { prospectiveOperations[4].operation == FOR_EACH; } -public void shouldThrowExceptionOnLoopWithInnerLoop() { +public test bool shouldThrowExceptionOnLoopWithInnerLoop() { tuple [set[MethodVar] vars, EnhancedForStatement loop] loop = outerLoopWithInnerLoop(); try { diff --git a/src/lang/java/refactoring/forloop/test/resources/ProspectiveOperationTestResources.rsc b/src/lang/java/refactoring/forloop/test/resources/ProspectiveOperationTestResources.rsc index 56fd7c3..cdb224b 100644 --- a/src/lang/java/refactoring/forloop/test/resources/ProspectiveOperationTestResources.rsc +++ b/src/lang/java/refactoring/forloop/test/resources/ProspectiveOperationTestResources.rsc @@ -146,7 +146,7 @@ public tuple [set[MethodVar] vars, EnhancedForStatement loop] outerLoopWithInner methodBody = parse(#MethodBody, "{" + loopStr + "}"); localVars = findLocalVariables(methodHeader, methodBody); - classLoc = |project://rascal-Java8//testes/forloop/Refactorer/ClassRefactorableInnerLoopButNotOuter|; + classLoc = |project://rascal-Java8//testes/forloop/Refactorer/ServletComponentRegisteringPostProcessor.java|; classFields = findClassFields(parse(#CompilationUnit, classLoc)); availableVars = localVars + classFields; diff --git a/testes/forloop/Refactorer/LoopRefactorableInnerLoopButNotOuter b/testes/forloop/Refactorer/LoopRefactorableInnerLoopButNotOuter new file mode 100644 index 0000000..ab71835 --- /dev/null +++ b/testes/forloop/Refactorer/LoopRefactorableInnerLoopButNotOuter @@ -0,0 +1,9 @@ +for (BeanDefinition candidate : componentProvider + .findCandidateComponents(packageToScan)) { + if (candidate instanceof ScannedGenericBeanDefinition) { + for (ServletComponentHandler handler : HANDLERS) { + handler.handle(((ScannedGenericBeanDefinition) candidate), + (BeanDefinitionRegistry) this.applicationContext); + } + } + } \ No newline at end of file diff --git a/testes/forloop/Refactorer/ServletComponentRegisteringPostProcessor.java b/testes/forloop/Refactorer/ServletComponentRegisteringPostProcessor.java new file mode 100644 index 0000000..4d9b41f --- /dev/null +++ b/testes/forloop/Refactorer/ServletComponentRegisteringPostProcessor.java @@ -0,0 +1,116 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.web.servlet; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; +import org.springframework.context.annotation.ScannedGenericBeanDefinition; +import org.springframework.web.context.WebApplicationContext; + +/** + * {@link BeanFactoryPostProcessor} that registers beans for Servlet components found via + * package scanning. + * + * @author Andy Wilkinson + * @see ServletComponentScan + * @see ServletComponentScanRegistrar + */ +class ServletComponentRegisteringPostProcessor + implements BeanFactoryPostProcessor, ApplicationContextAware { + + private static final List HANDLERS; + + static { + List handlers = new ArrayList<>(); + handlers.add(new WebServletHandler()); + handlers.add(new WebFilterHandler()); + handlers.add(new WebListenerHandler()); + HANDLERS = Collections.unmodifiableList(handlers); + } + + private final Set packagesToScan; + + private ApplicationContext applicationContext; + + ServletComponentRegisteringPostProcessor(Set packagesToScan) { + this.packagesToScan = packagesToScan; + } + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) + throws BeansException { + if (isRunningInEmbeddedWebServer()) { + ClassPathScanningCandidateComponentProvider componentProvider = createComponentProvider(); + for (String packageToScan : this.packagesToScan) { + scanPackage(componentProvider, packageToScan); + } + } + } + + private void scanPackage( + ClassPathScanningCandidateComponentProvider componentProvider, + String packageToScan) { + for (BeanDefinition candidate : componentProvider + .findCandidateComponents(packageToScan)) { + if (candidate instanceof ScannedGenericBeanDefinition) { + for (ServletComponentHandler handler : HANDLERS) { + handler.handle(((ScannedGenericBeanDefinition) candidate), + (BeanDefinitionRegistry) this.applicationContext); + } + } + } + } + + private boolean isRunningInEmbeddedWebServer() { + return this.applicationContext instanceof WebApplicationContext + && ((WebApplicationContext) this.applicationContext) + .getServletContext() == null; + } + + private ClassPathScanningCandidateComponentProvider createComponentProvider() { + ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider( + false); + componentProvider.setEnvironment(this.applicationContext.getEnvironment()); + componentProvider.setResourceLoader(this.applicationContext); + for (ServletComponentHandler handler : HANDLERS) { + componentProvider.addIncludeFilter(handler.getTypeFilter()); + } + return componentProvider; + } + + Set getPackagesToScan() { + return Collections.unmodifiableSet(this.packagesToScan); + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) + throws BeansException { + this.applicationContext = applicationContext; + } + +} From bee31a006b68c2cd267dc7a797100e97b131c2bf Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 11 Jun 2017 17:51:45 -0300 Subject: [PATCH 143/154] Not breaking into prospective operation an inner loop inside an if --- .../java/refactoring/forloop/ProspectiveOperation.rsc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/lang/java/refactoring/forloop/ProspectiveOperation.rsc b/src/lang/java/refactoring/forloop/ProspectiveOperation.rsc index 9bdf04c..5c6cdc4 100644 --- a/src/lang/java/refactoring/forloop/ProspectiveOperation.rsc +++ b/src/lang/java/refactoring/forloop/ProspectiveOperation.rsc @@ -5,7 +5,7 @@ import List; import String; import lang::java::\syntax::Java18; import ParseTree; -import ParseTreeVisualization; +import java::lang::analysis::ParseTreeVisualization; import lang::java::refactoring::forloop::MethodVar; import lang::java::refactoring::forloop::OperationType; import lang::java::refactoring::forloop::BreakIntoStatements; @@ -17,6 +17,7 @@ private list[MethodVar] methodLocalVars; public list[ProspectiveOperation] retrieveProspectiveOperations(set[MethodVar] localVars, EnhancedForStatement forStmt) { methodLocalVars = localVars; list[ProspectiveOperation] prospectiveOperations = []; + // TODO can receive as parameter only the loopBody from Refactorer. saving a visit. top-down visit(forStmt) { case (EnhancedForStatement) `for ( : ) `: { prospectiveOperations = retrieveProspectiveOperationsFromStatement(stmt); @@ -91,6 +92,10 @@ private list[ProspectiveOperation] retrieveProspectiveOperationsFromIfThenStatem foundReturn = true; prOps += createAnyMatchOrNoneMatchPrOp("", ""); } + + case IfThenElseStatement ifElseStmt: throw "Not Refactoring If/Else for now"; + case ForStatement _: throw "Not Refactoring Inner Loops for now"; + case WhileStatement _: throw "Not Refactoring While Loops inside ForStatement for now"; } if (!foundReturn) { @@ -102,6 +107,7 @@ private list[ProspectiveOperation] retrieveProspectiveOperationsFromIfThenStatem } } } + } } } From a6bcbb90dec4c42f1a31d101f0573cd46a45f1fe Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 11 Jun 2017 17:51:45 -0300 Subject: [PATCH 144/154] Fixing helper test method to reflect how 'production' code is working --- src/lang/java/refactoring/forloop/ForLoopBodyReferences.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lang/java/refactoring/forloop/ForLoopBodyReferences.rsc b/src/lang/java/refactoring/forloop/ForLoopBodyReferences.rsc index f932f2f..c322377 100644 --- a/src/lang/java/refactoring/forloop/ForLoopBodyReferences.rsc +++ b/src/lang/java/refactoring/forloop/ForLoopBodyReferences.rsc @@ -16,7 +16,7 @@ public int getTotalOfNonEffectiveFinalVarsReferenced(set[MethodVar] localVariabl } public Statement retrieveLoopBodyFromEnhancedFor(EnhancedForStatement forStmt) { - visit (forStmt) { + top-down-break visit (forStmt) { case (EnhancedForStatement) `for ( : ) `: return loopBody; } From 85ef54793ac0d6741e1807ce95b49c91d5d88a99 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 11 Jun 2017 17:51:45 -0300 Subject: [PATCH 145/154] Fixing import of ParseTreeVisualization (changed folder) --- .../java/refactoring/forloop/test/BreakIntoStatementsTest.rsc | 2 +- .../java/refactoring/forloop/test/ForLoopToFunctionalTest.rsc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lang/java/refactoring/forloop/test/BreakIntoStatementsTest.rsc b/src/lang/java/refactoring/forloop/test/BreakIntoStatementsTest.rsc index e8a5b7e..0a2230a 100644 --- a/src/lang/java/refactoring/forloop/test/BreakIntoStatementsTest.rsc +++ b/src/lang/java/refactoring/forloop/test/BreakIntoStatementsTest.rsc @@ -6,7 +6,7 @@ import lang::java::\syntax::Java18; import lang::java::refactoring::forloop::\test::resources::ProspectiveOperationTestResources; import lang::java::refactoring::forloop::ForLoopBodyReferences; import ParseTree; -import ParseTreeVisualization; +import java::lang::analysis::ParseTreeVisualization; public test bool ex1() { fileLoc = |project://rascal-Java8//testes/forloop/ProspectiveOperation/SimpleShortEnhancedLoop|; diff --git a/src/lang/java/refactoring/forloop/test/ForLoopToFunctionalTest.rsc b/src/lang/java/refactoring/forloop/test/ForLoopToFunctionalTest.rsc index 5125742..e35dfcb 100644 --- a/src/lang/java/refactoring/forloop/test/ForLoopToFunctionalTest.rsc +++ b/src/lang/java/refactoring/forloop/test/ForLoopToFunctionalTest.rsc @@ -4,7 +4,7 @@ import IO; import String; import lang::java::\syntax::Java18; import ParseTree; -import ParseTreeVisualization; +import java::lang::analysis::ParseTreeVisualization; import lang::java::refactoring::forloop::ForLoopToFunctional; import lang::java::refactoring::forloop::MethodVar; From 935aedddbc1dd221cba6d61fadd3f9d907c78143 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 11 Jun 2017 17:51:45 -0300 Subject: [PATCH 146/154] Refactoring correctly the inner loop but not the outsider. --- .../java/refactoring/forloop/EnhancedForLoopRefactorer.rsc | 7 +++++-- .../forloop/test/EnhancedForLoopRefactorerTest.rsc | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc b/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc index 154420d..e8af419 100644 --- a/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc +++ b/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc @@ -94,8 +94,11 @@ public tuple[MethodBody body, int occurrences] refactorEnhancedForStatementsInMe println(refactoredMethodBody); println(); } - } catch: - continue; + } catch: { + // ignore. continuing + // 'continue' do not works as expected in 'visit' statements + ; + } } } diff --git a/src/lang/java/refactoring/forloop/test/EnhancedForLoopRefactorerTest.rsc b/src/lang/java/refactoring/forloop/test/EnhancedForLoopRefactorerTest.rsc index e8907f7..1babb40 100644 --- a/src/lang/java/refactoring/forloop/test/EnhancedForLoopRefactorerTest.rsc +++ b/src/lang/java/refactoring/forloop/test/EnhancedForLoopRefactorerTest.rsc @@ -8,7 +8,7 @@ import lang::java::refactoring::forloop::\test::resources::RefactorerTestResourc // comparing methods then // but definitely should automate test for entire compilation unit public test bool shouldRefactorInnerLoopButNoutOuterLoop() { - refactorable = innerLoopButNotOuterLoop(); + RefactorableFor refactorable = innerLoopButNotOuterLoop(); refactored = refactorEnhancedForStatementsInMethodBody(refactorable.unit, refactorable.header, refactorable.body); From 11b688caf816aceb21a23c40192da61aa9f80087 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Sun, 11 Jun 2017 17:51:45 -0300 Subject: [PATCH 147/154] Small improvements on comments and stuff --- .../java/refactoring/forloop/EnhancedForLoopRefactorer.rsc | 6 ++++-- src/lang/java/refactoring/forloop/ForLoopToFunctional.rsc | 7 +------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc b/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc index e8af419..16f0a92 100644 --- a/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc +++ b/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc @@ -11,7 +11,7 @@ import lang::java::refactoring::forloop::ForLoopToFunctional; import lang::java::refactoring::forloop::ClassFieldsFinder; import lang::java::refactoring::forloop::MethodVar; -private bool PRINT_DEBUG = false; +private bool PRINT_DEBUG = true; private set[str] checkedExceptionClasses = {}; @@ -87,8 +87,10 @@ public tuple[MethodBody body, int occurrences] refactorEnhancedForStatementsInMe refactoredMethodBody = refactorEnhancedToFunctional(availableVars, enhancedForStmt, methodBody, iteratedVarName, collectionId); occurrences += 1; + refactoredCount += 1; + if(PRINT_DEBUG) { - println("refactored: " + toString(occurrences)); + println("refactored: " + toString(refactoredCount)); println(enhancedForStmt); println("---"); println(refactoredMethodBody); diff --git a/src/lang/java/refactoring/forloop/ForLoopToFunctional.rsc b/src/lang/java/refactoring/forloop/ForLoopToFunctional.rsc index d5613db..01b7463 100644 --- a/src/lang/java/refactoring/forloop/ForLoopToFunctional.rsc +++ b/src/lang/java/refactoring/forloop/ForLoopToFunctional.rsc @@ -17,10 +17,6 @@ import lang::java::refactoring::forloop::BreakIntoStatements; public data ComposableProspectiveOperation = composableProspectiveOperation(ProspectiveOperation prOp, set[str] neededVars, set[str] availableVars); public MethodBody refactorEnhancedToFunctional(set[MethodVar] methodVars, EnhancedForStatement forStmt, MethodBody methodBody, VariableDeclaratorId iteratedVarName, Expression collectionId) { - return buildRefactoredMethodBody(methodVars, forStmt, methodBody, iteratedVarName, collectionId); -} - -private MethodBody buildRefactoredMethodBody(set[MethodVar] methodVars, EnhancedForStatement forStmt, MethodBody methodBody, VariableDeclaratorId iteratedVarName, Expression collectionId) { refactored = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); forStatement = parse(#Statement, unparse(forStmt)); refactoredMethodBody = refactorToFunctional(methodBody, forStatement, refactored); @@ -86,7 +82,6 @@ private list[ComposableProspectiveOperation] mergeIntoComposableOperations(list[ ComposableProspectiveOperation beforeLast = composablePrOps[opsSize - 2]; merged = mergeComposablePrOps(beforeLast, last); - // XXX analyze if this "merging" is correct. probably not composablePrOps = slice(composablePrOps, 0, opsSize - 2) + merged; opsSize = size(composablePrOps); @@ -321,7 +316,7 @@ private str getLambdaBodyForMapWhenLocalVariableDeclaration(str stmt) { throw "No variable initializer in MAP"; } -// TODO check for prefix and postfix increment/decrement after ProspectiveOperation is working +// TODO check if prefix and postfix increment/decrement after ProspectiveOperation is working private str buildMapReduceOperation(set[MethodVar] methodVars, ComposableProspectiveOperation cPrOp) { mapOperation = ""; reduceOperation = ""; From c90adade4b9673a8fad1c91d052c5746038235e7 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 22 Jun 2017 21:31:33 -0300 Subject: [PATCH 148/154] Preparing to name lambda arg with the same name as LocalVariableDeclaration - This is actually a little different implementation from LAMBDAFICATOR --- src/lang/java/refactoring/forloop/ForLoopToFunctional.rsc | 8 ++++++-- .../refactoring/forloop/test/ForLoopToFunctionalTest.rsc | 6 +++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/lang/java/refactoring/forloop/ForLoopToFunctional.rsc b/src/lang/java/refactoring/forloop/ForLoopToFunctional.rsc index 01b7463..690b04a 100644 --- a/src/lang/java/refactoring/forloop/ForLoopToFunctional.rsc +++ b/src/lang/java/refactoring/forloop/ForLoopToFunctional.rsc @@ -217,7 +217,7 @@ private ComposableProspectiveOperation addReturnToMapBody(ComposableProspectiveO else stmts += stmt; - varName = isEmpty(nextNeededVars) ? "_item" : getOneFrom(nextNeededVars); + varName = retrieveLambdaParameterNameWhenNotSingleStmtVarDecl(nextNeededVars); stmts += "return ;"; block = transformStatementsInBlock(stmts); @@ -268,7 +268,11 @@ private str buildChainableOperation(set[MethodVar] methodVars, ComposableProspec } private str retrieveLambdaParameterName(ComposableProspectiveOperation cPrOp) { - return isEmpty(cPrOp.neededVars) ? "_item" : getOneFrom(cPrOp.neededVars); + return retrieveLambdaParameterNameWhenNotSingleStmtVarDecl(cPrOp.neededVars); +} + +private str retrieveLambdaParameterNameWhenNotSingleStmtVarDecl(set[str] neededVars) { + return isEmpty(neededVars) ? "_item" : getOneFrom(neededVars); } private str retrieveLambdaBody(ProspectiveOperation prOp) { diff --git a/src/lang/java/refactoring/forloop/test/ForLoopToFunctionalTest.rsc b/src/lang/java/refactoring/forloop/test/ForLoopToFunctionalTest.rsc index e35dfcb..0ae6fe9 100644 --- a/src/lang/java/refactoring/forloop/test/ForLoopToFunctionalTest.rsc +++ b/src/lang/java/refactoring/forloop/test/ForLoopToFunctionalTest.rsc @@ -14,7 +14,7 @@ import lang::java::refactoring::forloop::\test::resources::LocalVariablesFinderT import lang::java::refactoring::forloop::\test::resources::ProspectiveOperationTestResources; -public test bool ex1() { +public test bool shouldNameLambdaArgWithTheSameNameWhenMapIsASingleStmtVarDeclaration() { fileLoc = |project://rascal-Java8//testes/forloop/ForLoopToFunctional/T1.java|; methodBody = parse(#MethodBody, readFile(fileLoc)); methodHeader = parse(#MethodHeader, "TestSuite createTestSuite()"); @@ -25,7 +25,7 @@ public test bool ex1() { refactoredStatement = buildRefactoredEnhancedFor(methodVars, forStmt, methodBody, iteratedVarName, collectionId); - return "" == "testers.stream().map(testerClass -\> makeSuiteForTesterClass((Class\\>) testerClass)).filter(testerSuite -\> testerSuite.countTestCases() \> 0).forEach(testerSuite -\> {\n suite.addTest(testerSuite);\n });"; + return "" == "testers.stream().map(testerSuite -\> makeSuiteForTesterClass((Class\\>) testerClass)).filter(testerSuite -\> testerSuite.countTestCases() \> 0).forEach(testerSuite -\> {\n suite.addTest(testerSuite);\n });"; } public test bool reduceAsNotTheLastOperationShouldNotBeRefactored() { @@ -146,7 +146,7 @@ public test bool loopWithIfWithTwoStatementsInsideBlockShouldRefactorInnerIfAsMa refactoredStatement = buildRefactoredEnhancedFor(loop.vars, loop.loop, methodBody, iteratedVarName, collectionId); - return "" == "endpoints.stream().filter(endpoint -\> isIncluded(endpoint)).map(endpoint -\> endpointHandlerMapping.getPath(endpoint.getPath())).map(path -\> {\npaths.add(path);\nreturn path;\n}).map(path -\> {\nif (!path.equals(\"\")) {\r\n\t\t\t\t\t\tpaths.add(path + \"/**\");\r\n\t\t\t\t\t\t// Add Spring MVC-generated additional paths\r\n\t\t\t\t\t\tpaths.add(path + \".*\");\r\n\t\t\t\t\t}\nreturn path;\n}).forEach(path -\> {\npaths.add(path + \"/\");\n});"; + return "" == "endpoints.stream().filter(endpoint -\> isIncluded(endpoint)).map(path -\> endpointHandlerMapping.getPath(endpoint.getPath())).map(path -\> {\npaths.add(path);\nreturn path;\n}).map(path -\> {\nif (!path.equals(\"\")) {\r\n\t\t\t\t\t\tpaths.add(path + \"/**\");\r\n\t\t\t\t\t\t// Add Spring MVC-generated additional paths\r\n\t\t\t\t\t\tpaths.add(path + \".*\");\r\n\t\t\t\t\t}\nreturn path;\n}).forEach(path -\> {\npaths.add(path + \"/\");\n});"; } public test bool anotherIfThatIsMap() { From dc4c2dcc8d2786d666d128182d6653130569c609 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Thu, 22 Jun 2017 21:31:33 -0300 Subject: [PATCH 149/154] Lambda arg with the same name as/when single local variable declaration stmt --- .../forloop/ForLoopToFunctional.rsc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/lang/java/refactoring/forloop/ForLoopToFunctional.rsc b/src/lang/java/refactoring/forloop/ForLoopToFunctional.rsc index 690b04a..6789198 100644 --- a/src/lang/java/refactoring/forloop/ForLoopToFunctional.rsc +++ b/src/lang/java/refactoring/forloop/ForLoopToFunctional.rsc @@ -268,9 +268,28 @@ private str buildChainableOperation(set[MethodVar] methodVars, ComposableProspec } private str retrieveLambdaParameterName(ComposableProspectiveOperation cPrOp) { + singleStmtVarDecl = checkIfSingleStmtVarDecl(cPrOp.prOp.stmt); + if (singleStmtVarDecl.condition) + return singleStmtVarDecl.name; return retrieveLambdaParameterNameWhenNotSingleStmtVarDecl(cPrOp.neededVars); } +private tuple[bool condition, str name] checkIfSingleStmtVarDecl(str stmt) { + semiCollonOccurrences = findAll("", ";"); + isSingleStmt = size(semiCollonOccurrences) == 1; + if(isSingleStmt) { + try { + lvdl = parse(#LocalVariableDeclarationStatement, stmt); + visit (lvdl) { + case (VariableDeclaratorId) ``: + return ">; + } + } catch: + return ; + } + return ; +} + private str retrieveLambdaParameterNameWhenNotSingleStmtVarDecl(set[str] neededVars) { return isEmpty(neededVars) ? "_item" : getOneFrom(neededVars); } From acbc1a001ce39db1207b3d2ef09c01d66db26689 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Fri, 23 Jun 2017 11:53:58 -0300 Subject: [PATCH 150/154] Fixing ExceptionFinder module declaration --- src/lang/java/analysis/ExceptionFinder.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lang/java/analysis/ExceptionFinder.rsc b/src/lang/java/analysis/ExceptionFinder.rsc index 63a6bbd..9ceefa3 100644 --- a/src/lang/java/analysis/ExceptionFinder.rsc +++ b/src/lang/java/analysis/ExceptionFinder.rsc @@ -1,4 +1,4 @@ -module ExceptionFinder +module lang::java::analysis::ExceptionFinder import IO; import lang::java::m3::M3Util; @@ -16,7 +16,7 @@ private data ClassAndSuperClass = classAndSuperClass(str className, str superCla private bool printAllFileNamesThatCouldNotBeParsed = false; -set[str] findCheckedExceptions(list[loc] javaFilesLocations) { +public set[str] findCheckedExceptions(list[loc] javaFilesLocations) { initializeClassesFound(); for(javaFileLocation <- javaFilesLocations) tryToVisitFileLookingForClassesWithSubClasses(javaFileLocation); From 16f90fa4dcd4cbf03f5a9a0d41b5857a99703da5 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Fri, 23 Jun 2017 11:54:23 -0300 Subject: [PATCH 151/154] Integrating ForLoopToFunctional into Driver --- src/Driver.rsc | 9 ++++++++- .../refactoring/forloop/EnhancedForLoopRefactorer.rsc | 11 ++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/Driver.rsc b/src/Driver.rsc index 17315ee..941d50e 100644 --- a/src/Driver.rsc +++ b/src/Driver.rsc @@ -19,6 +19,9 @@ import lang::java::refactoring::AnonymousToLambda; import lang::java::refactoring::ExistPatternToLambda; import lang::java::refactoring::FilterPattern; +import lang::java::refactoring::forloop::EnhancedForLoopRefactorer; +import lang::java::analysis::ExceptionFinder; + import lang::java::util::ManageCompilationUnit; import lang::java::m3::M3Util; import lang::java::\syntax::Java18; @@ -55,7 +58,11 @@ public void refactorProjects(loc input, bool verbose = true) { case /DI/: executeTransformations(projectFiles, toInt(projectDescriptor[3]), verbose, refactorDiamond, "diamond"); case /AC/: executeTransformations(projectFiles, toInt(projectDescriptor[3]), verbose, refactorAnonymousInnerClass, "aic"); case /EP/: executeTransformations(projectFiles, toInt(projectDescriptor[3]), verbose, refactorExistPattern, "exist pattern"); - case /FP/: executeTransformations(projectFiles, toInt(projectDescriptor[3]), verbose, refactorFilterPattern, "filter pattern"); + case /FP/: executeTransformations(projectFiles, toInt(projectDescriptor[3]), verbose, refactorFilterPattern, "filter pattern"); + case /FUNC/: { + checkedExceptionClasses = findCheckedExceptions(projectFiles); + executeTransformations(projectFiles, toInt(projectDescriptor[3]), verbose, refactorForLoopToFunctional, "ForLoopToFunctional"); + } default: logMessage(" ... nothing to be done"); } } diff --git a/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc b/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc index 16f0a92..3758cfc 100644 --- a/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc +++ b/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc @@ -11,9 +11,9 @@ import lang::java::refactoring::forloop::ForLoopToFunctional; import lang::java::refactoring::forloop::ClassFieldsFinder; import lang::java::refactoring::forloop::MethodVar; -private bool PRINT_DEBUG = true; +private bool PRINT_DEBUG = false; -private set[str] checkedExceptionClasses = {}; +public set[str] checkedExceptionClasses = {}; private set[MethodVar] currentClassFields = {}; @@ -21,6 +21,7 @@ private bool alreadyComputedClassFields = false; private int refactoredCount = 0; +// Method for debugging. Not used by driver public void forLoopToFunctional(list[loc] locs, set[str] checkedExceptions) { refactoredCount = 0; checkedExceptionClasses = checkedExceptions; @@ -28,7 +29,7 @@ public void forLoopToFunctional(list[loc] locs, set[str] checkedExceptions) { javaFileContent = readFile(fileLoc); try { unit = parse(#CompilationUnit, javaFileContent); - refactorEnhancedForStatements(unit); + refactorForLoopToFunctional(unit); } catch: continue; } @@ -36,7 +37,7 @@ public void forLoopToFunctional(list[loc] locs, set[str] checkedExceptions) { } // Losing formatting after a method is refactored. -public tuple[CompilationUnit unit, int occurrences] refactorEnhancedForStatements(CompilationUnit unit) { +public tuple[int occurrences, CompilationUnit unit] refactorForLoopToFunctional(CompilationUnit unit) { int occurrences = 0; alreadyComputedClassFields = false; CompilationUnit refactoredUnit = visit(unit) { @@ -53,7 +54,7 @@ public tuple[CompilationUnit unit, int occurrences] refactorEnhancedForStatemen } }; - return ; + return ; } // TODO What happens when two for statements are refactored inside the same method? From 6c52f69c345fe96258bd78b6abc5a2e1ade5fef8 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Fri, 23 Jun 2017 14:41:50 -0300 Subject: [PATCH 152/154] Avoiding, the max we can, to not modify other methods. - The transformations are mostly having identation problems. --- .../refactoring/forloop/EnhancedForLoopRefactorer.rsc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc b/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc index 3758cfc..03d2d1d 100644 --- a/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc +++ b/src/lang/java/refactoring/forloop/EnhancedForLoopRefactorer.rsc @@ -42,6 +42,8 @@ public tuple[int occurrences, CompilationUnit unit] refactorForLoopToFunctional( alreadyComputedClassFields = false; CompilationUnit refactoredUnit = visit(unit) { case (MethodDeclaration) ` `: { + refactoredCountBeforeCurrentMethod = refactoredCount; + MethodBody refactoredMethodBody = visit(mBody) { case MethodBody methodBody: { refactored = refactorEnhancedForStatementsInMethodBody(unit, methodHeader, methodBody); @@ -50,7 +52,11 @@ public tuple[int occurrences, CompilationUnit unit] refactorForLoopToFunctional( } }; - insert((MethodDeclaration) ` `); + // Avoiding adding extra blank spaces when method is not refactored. + // Not sure why, also not a big deal, but is annoying + methodWasRefactored = refactoredCountBeforeCurrentMethod != refactoredCount; + if (methodWasRefactored) + insert((MethodDeclaration) ` `); } }; From 16361f9958c461bc77274aa2327f05fc88bde296 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Fri, 23 Jun 2017 14:42:05 -0300 Subject: [PATCH 153/154] Fixing a typo in Driver's logs. --- src/Driver.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Driver.rsc b/src/Driver.rsc index 941d50e..a2a7c13 100644 --- a/src/Driver.rsc +++ b/src/Driver.rsc @@ -100,7 +100,7 @@ public void executeTransformations(list[loc] files, int percent, bool verbose, t int totalOfChangedFiles = exportResults(toApply, processedFiles, verbose, name); t1 = now(); logMessage("- Number of files: " + toString(size(files))); - logMessage("- Processed Filies: " + toString(size(processedFiles))); + logMessage("- Processed Files: " + toString(size(processedFiles))); logMessage("- Exported Files: " + toString(size(toApply))); logMessage("- Total of files changed: " + toString(totalOfChangedFiles)); logMessage("- Total of transformations: " + toString(totalOfTransformations)); From 0fbc73f997402c4ff314b708ef31db2d55810907 Mon Sep 17 00:00:00 2001 From: Diego Marcilio Date: Fri, 23 Jun 2017 14:51:17 -0300 Subject: [PATCH 154/154] Fixing ExceptionFinderTest --- src/lang/java/analysis/test/ExceptionFinderTest.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lang/java/analysis/test/ExceptionFinderTest.rsc b/src/lang/java/analysis/test/ExceptionFinderTest.rsc index bd07cc2..422db10 100644 --- a/src/lang/java/analysis/test/ExceptionFinderTest.rsc +++ b/src/lang/java/analysis/test/ExceptionFinderTest.rsc @@ -1,8 +1,8 @@ -module ExceptionFinderTest +module lang::java::analysis::\test::ExceptionFinderTest import lang::java::m3::M3Util; import IO; -import ExceptionFinder; +import lang::java::analysis::ExceptionFinder; private loc zipFile = |jar:///D:/exception-hierarchy.zip!|; private list[loc] javaClassesLocations = listAllJavaFiles(zipFile);