Skip to content

Commit

Permalink
Added support for @Tolerate for @getter and @Setter
Browse files Browse the repository at this point in the history
Issue # 175
  • Loading branch information
Michail Plushnikov committed Jan 23, 2016
1 parent 8ca809b commit ef5fbc0
Show file tree
Hide file tree
Showing 12 changed files with 169 additions and 53 deletions.
Expand Up @@ -85,6 +85,7 @@ protected Collection<PsiField> filterGetterFields(@NotNull PsiClass psiClass) {
final Collection<PsiField> getterFields = new ArrayList<PsiField>();

final Collection<PsiMethod> classMethods = PsiClassUtil.collectClassMethodsIntern(psiClass);
filterToleratedElements(classMethods);

for (PsiField psiField : psiClass.getFields()) {
boolean createGetter = true;
Expand Down
Expand Up @@ -85,6 +85,7 @@ public Collection<PsiMethod> createFieldSetters(@NotNull PsiClass psiClass, @Not
@NotNull
protected Collection<PsiField> filterSetterFields(@NotNull PsiClass psiClass) {
final Collection<PsiMethod> classMethods = PsiClassUtil.collectClassMethodsIntern(psiClass);
filterToleratedElements(classMethods);

final Collection<PsiField> setterFields = new ArrayList<PsiField>();
for (PsiField psiField : psiClass.getFields()) {
Expand Down
Expand Up @@ -97,6 +97,7 @@ protected boolean validateExistingMethods(@NotNull PsiField psiField, @NotNull P
final AccessorsInfo accessorsInfo = AccessorsInfo.build(psiField);
final Collection<String> methodNames = LombokUtils.toAllGetterNames(accessorsInfo, psiField.getName(), isBoolean);
final Collection<PsiMethod> classMethods = PsiClassUtil.collectClassMethodsIntern(psiClass);
filterToleratedElements(classMethods);

for (String methodName : methodNames) {
if (PsiMethodUtil.hasSimilarMethod(classMethods, methodName, 0)) {
Expand Down
Expand Up @@ -87,6 +87,7 @@ protected boolean validateExistingMethods(@NotNull PsiField psiField, @NotNull P
final PsiClass psiClass = psiField.getContainingClass();
if (null != psiClass) {
final Collection<PsiMethod> classMethods = PsiClassUtil.collectClassMethodsIntern(psiClass);
filterToleratedElements(classMethods);

final boolean isBoolean = PsiType.BOOLEAN.equals(psiField.getType());
final Collection<String> methodNames = getAllSetterNames(psiField, isBoolean);
Expand Down
Expand Up @@ -36,7 +36,7 @@ public class PsiClassUtil {
@NotNull
public static Collection<PsiMethod> collectClassMethodsIntern(@NotNull PsiClass psiClass) {
if (psiClass instanceof PsiExtensibleClass) {
return ((PsiExtensibleClass) psiClass).getOwnMethods();
return new ArrayList<PsiMethod>(((PsiExtensibleClass) psiClass).getOwnMethods());
} else {
return filterPsiElements(psiClass, PsiMethod.class);
}
Expand Down
1 change: 1 addition & 0 deletions lombok-plugin/src/main/resources/META-INF/plugin.xml
Expand Up @@ -212,6 +212,7 @@
<li>Fixed #156: Exception in @Singular handling</li>
<li>Fixed #165: Can't correctly resolve multiple @Builder methods in same class having partial implementations</li>
<li>Fixed #172: "Lombok needs a default constructor in the base class" error in enum</li>
<li>Fixed #175: Added support for @Tolerate for @Getter and @Setter</li>
</ol>
</li>
<li>0.9.7
Expand Down
Expand Up @@ -5,6 +5,7 @@ daemon.donate.content=\
- Fixed (<a href="https://github.com/mplushnikov/lombok-intellij-plugin/issues/156">#156</a>): Exception in @Singular handling<br/>\
- Fixed (<a href="https://github.com/mplushnikov/lombok-intellij-plugin/issues/165">#165</a>): Can't correctly resolve multiple @Builder methods in same class having partial implementations<br/>\
- Fixed (<a href="https://github.com/mplushnikov/lombok-intellij-plugin/issues/172">#172</a>): "Lombok needs a default constructor in the base class" error in enum<br/>\
- Fixed (<a href="https://github.com/mplushnikov/lombok-intellij-plugin/issues/175">#175</a>): Added support for @Tolerate for @Getter and @Setter<br/>\
<br/>\
If you find my plugin helpful, donate me using <b>\
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick\\&hosted_button_id=3F9HXD7A2SMCN">PayPal</a></b>
32 changes: 32 additions & 0 deletions lombok-plugin/src/test/data/after/TolerateTest.java
@@ -0,0 +1,32 @@
import java.util.regex.Pattern;
class Tolerate {
private Pattern pattern;
public @lombok.experimental.Tolerate void setPattern(String pattern) {
setPattern(Pattern.compile(pattern));
}
public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") void setPattern(final Pattern pattern) {
this.pattern = pattern;
}
public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") Pattern getPattern() {
return this.pattern;
}
}
class Tolerate2 {
private final Pattern pattern;
public Tolerate2 withPattern(String pattern) {
return withPattern(Pattern.compile(pattern));
}
public Tolerate2 withPattern(String nameGlob, String extensionGlob) {
return withPattern(nameGlob.replace("*", ".*") + "\\." + extensionGlob.replace("*", ".*"));
}

public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") Pattern getPattern() {
return this.pattern;
}
public @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") Tolerate2 withPattern(final Pattern pattern) {
return this.pattern == pattern ? this : new Tolerate2(pattern);
}
public @java.beans.ConstructorProperties({"pattern"}) @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") Tolerate2(final Pattern pattern) {
this.pattern = pattern;
}
}
26 changes: 26 additions & 0 deletions lombok-plugin/src/test/data/before/TolerateTest.java
@@ -0,0 +1,26 @@
import java.util.regex.Pattern;

@lombok.Setter
@lombok.Getter
class Tolerate {
private Pattern pattern;

@lombok.experimental.Tolerate public void setPattern(String pattern) {
setPattern(Pattern.compile(pattern));
}
}

@lombok.Getter
@lombok.experimental.Wither
@lombok.AllArgsConstructor
class Tolerate2 {
private final Pattern pattern;

@lombok.experimental.Tolerate public Tolerate2 withPattern(String pattern) {
return withPattern(Pattern.compile(pattern));
}

public Tolerate2 withPattern(String nameGlob, String extensionGlob) {
return withPattern(nameGlob.replace("*", ".*") + "\\." + extensionGlob.replace("*", ".*"));
}
}
Expand Up @@ -21,9 +21,12 @@
import com.intellij.psi.PsiParameterList;
import com.intellij.psi.PsiReferenceList;
import com.intellij.psi.PsiType;
import com.intellij.util.containers.SortedList;
import org.apache.log4j.Logger;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;

Expand Down Expand Up @@ -173,54 +176,89 @@ private void compareModifiers(PsiModifierList beforeModifierList, PsiModifierLis
}
}


private void compareMethods(PsiClass beforeClass, PsiClass afterClass) {
PsiMethod[] beforeMethods = beforeClass.getMethods();
PsiMethod[] afterMethods = afterClass.getMethods();

LOG.info("Before methods for class " + beforeClass.getName() + ": " + Arrays.toString(beforeMethods));
LOG.info("After methods for class " + afterClass.getName() + ": " + Arrays.toString(afterMethods));

assertEquals("Method counts are different for Class: " + beforeClass.getName(), afterMethods.length, beforeMethods.length);
assertEquals("Methods are different for Class: " + beforeClass.getName(),
Arrays.toString(toList(afterMethods)), Arrays.toString(toList(beforeMethods)));

for (PsiMethod afterMethod : afterMethods) {
boolean compared = false;
final PsiModifierList afterModifierList = afterMethod.getModifierList();
for (PsiMethod beforeMethod : beforeMethods) {
if (afterMethod.getName().equals(beforeMethod.getName()) &&
afterMethod.getParameterList().getParametersCount() == beforeMethod.getParameterList().getParametersCount()) {
PsiModifierList beforeModifierList = beforeMethod.getModifierList();

compareModifiers(beforeModifierList, afterModifierList);
compareType(beforeMethod.getReturnType(), afterMethod.getReturnType(), afterMethod);
compareParams(beforeMethod.getParameterList(), afterMethod.getParameterList());
compareThrows(beforeMethod.getThrowsList(), afterMethod.getThrowsList(), afterMethod);

if (shouldCompareCodeBlocks()) {
final PsiCodeBlock beforeMethodBody = beforeMethod.getBody();
final PsiCodeBlock afterMethodBody = afterMethod.getBody();
if (null != beforeMethodBody && null != afterMethodBody) {

boolean codeBlocksAreEqual = beforeMethodBody.textMatches(afterMethodBody);
if (!codeBlocksAreEqual) {
String text1 = beforeMethodBody.getText().replaceAll("\\s+", "");
String text2 = afterMethodBody.getText().replaceAll("\\s+", "");
assertEquals("Methods not equal, Method: (" + afterMethod.getName() + ") Class:" + afterClass.getName(), text2, text1);
}
} else {
if (null != afterMethodBody) {
fail("MethodCodeBlocks is null: Method: (" + beforeMethod.getName() + ") Class:" + beforeClass.getName());
}
}
}

compared = true;
final Collection<PsiMethod> matchedMethods = filterMethods(beforeMethods, afterMethod);
if (matchedMethods.isEmpty()) {
fail("Method names are not equal, Method: (" + afterMethod.getName() + ") not found in class : " + beforeClass.getName());
}

for (PsiMethod beforeMethod : matchedMethods) {
compareMethod(beforeClass, afterClass, afterMethod, beforeMethod);
}
}
}

private void compareMethod(PsiClass beforeClass, PsiClass afterClass, PsiMethod afterMethod, PsiMethod beforeMethod) {
final PsiModifierList afterModifierList = afterMethod.getModifierList();
PsiModifierList beforeModifierList = beforeMethod.getModifierList();

compareModifiers(beforeModifierList, afterModifierList);
compareType(beforeMethod.getReturnType(), afterMethod.getReturnType(), afterMethod);
compareParams(beforeMethod.getParameterList(), afterMethod.getParameterList());
compareThrows(beforeMethod.getThrowsList(), afterMethod.getThrowsList(), afterMethod);

if (shouldCompareCodeBlocks()) {
final PsiCodeBlock beforeMethodBody = beforeMethod.getBody();
final PsiCodeBlock afterMethodBody = afterMethod.getBody();
if (null != beforeMethodBody && null != afterMethodBody) {

boolean codeBlocksAreEqual = beforeMethodBody.textMatches(afterMethodBody);
if (!codeBlocksAreEqual) {
String text1 = beforeMethodBody.getText().replaceAll("\\s+", "");
String text2 = afterMethodBody.getText().replaceAll("\\s+", "");
assertEquals("Methods not equal, Method: (" + afterMethod.getName() + ") Class:" + afterClass.getName(), text2, text1);
}
} else {
if (null != afterMethodBody) {
fail("MethodCodeBlocks is null: Method: (" + beforeMethod.getName() + ") Class:" + beforeClass.getName());
}
}
assertTrue("Method names are not equal, Method: (" + afterMethod.getName() + ") not found in class : " + beforeClass.getName(), compared);
}
}

private Collection<PsiMethod> filterMethods(PsiMethod[] beforeMethods, PsiMethod compareMethod) {
Collection<PsiMethod> result = new ArrayList<PsiMethod>();
for (PsiMethod psiMethod : beforeMethods) {
final PsiParameterList compareMethodParameterList = compareMethod.getParameterList();
final PsiParameterList psiMethodParameterList = psiMethod.getParameterList();
if (compareMethod.getName().equals(psiMethod.getName()) &&
compareMethodParameterList.getParametersCount() == psiMethodParameterList.getParametersCount()) {
final Collection<String> typesOfCompareMethod = mapToTypeString(compareMethodParameterList);
final Collection<String> typesOfPsiMethod = mapToTypeString(psiMethodParameterList);
if (typesOfCompareMethod.equals(typesOfPsiMethod)) {
result.add(psiMethod);
}
}
}
return result;
}

@NotNull
private Collection<String> mapToTypeString(PsiParameterList compareMethodParameterList) {
Collection<String> result = new ArrayList<String>();
final PsiParameter[] compareMethodParameterListParameters = compareMethodParameterList.getParameters();
for (PsiParameter compareMethodParameterListParameter : compareMethodParameterListParameters) {
result.add(stripJavaLang(compareMethodParameterListParameter.getType().getCanonicalText()));
}
return result;
}

private String[] toList(PsiMethod[] beforeMethods) {
SortedList<String> result = new SortedList<String>(String.CASE_INSENSITIVE_ORDER);
for (PsiMethod method : beforeMethods) {
result.add(method.getName());
}
return result.toArray(new String[result.size()]);
}

private void compareThrows(PsiReferenceList beforeThrows, PsiReferenceList afterThrows, PsiMethod psiMethod) {
PsiClassType[] beforeTypes = beforeThrows.getReferencedTypes();
PsiClassType[] afterTypes = afterThrows.getReferencedTypes();
Expand All @@ -238,33 +276,33 @@ private void compareThrows(PsiReferenceList beforeThrows, PsiReferenceList after
}
}

private void compareConstructors(PsiClass intellij, PsiClass theirs) {
PsiMethod[] intellijConstructors = intellij.getConstructors();
PsiMethod[] theirsConstructors = theirs.getConstructors();
private void compareConstructors(PsiClass beforeClass, PsiClass afterClass) {
PsiMethod[] beforeConstructors = beforeClass.getConstructors();
PsiMethod[] afterConstructors = afterClass.getConstructors();

LOG.debug("IntelliJ constructors for class " + intellij.getName() + ": " + Arrays.toString(intellijConstructors));
LOG.debug("Theirs constructors for class " + theirs.getName() + ": " + Arrays.toString(theirsConstructors));
LOG.debug("IntelliJ constructors for class " + beforeClass.getName() + ": " + Arrays.toString(beforeConstructors));
LOG.debug("Theirs constructors for class " + afterClass.getName() + ": " + Arrays.toString(afterConstructors));

assertEquals("Constructor counts are different for Class: " + intellij.getName(), theirsConstructors.length, intellijConstructors.length);
assertEquals("Constructor counts are different for Class: " + beforeClass.getName(), afterConstructors.length, beforeConstructors.length);

for (PsiMethod theirsConstructor : theirsConstructors) {
for (PsiMethod afterConstructor : afterConstructors) {
boolean compared = false;
final PsiModifierList theirsFieldModifierList = theirsConstructor.getModifierList();
for (PsiMethod intellijConstructor : intellijConstructors) {
if (theirsConstructor.getName().equals(intellijConstructor.getName()) &&
theirsConstructor.getParameterList().getParametersCount() == intellijConstructor.getParameterList().getParametersCount()) {
PsiModifierList intellijConstructorModifierList = intellijConstructor.getModifierList();
final PsiModifierList theirsFieldModifierList = afterConstructor.getModifierList();
for (PsiMethod beforeConstructor : beforeConstructors) {
if (afterConstructor.getName().equals(beforeConstructor.getName()) &&
afterConstructor.getParameterList().getParametersCount() == beforeConstructor.getParameterList().getParametersCount()) {
PsiModifierList intellijConstructorModifierList = beforeConstructor.getModifierList();

compareModifiers(intellijConstructorModifierList, theirsFieldModifierList);
compareType(intellijConstructor.getReturnType(), theirsConstructor.getReturnType(), theirsConstructor);
compareParams(intellijConstructor.getParameterList(), theirsConstructor.getParameterList());
compareType(beforeConstructor.getReturnType(), afterConstructor.getReturnType(), afterConstructor);
compareParams(beforeConstructor.getParameterList(), afterConstructor.getParameterList());

compared = true;
break;
}

}
assertTrue("Constructor names are not equal, Method: (" + theirsConstructor.getName() + ") not found in class : " + intellij.getName(), compared);
assertTrue("Constructor names are not equal, Method: (" + afterConstructor.getName() + ") not found in class : " + beforeClass.getName(), compared);
}
}

Expand Down
Expand Up @@ -52,7 +52,6 @@ public void testBuilderAndAllArgsConstructor() throws IOException {
doTest();
}

// TODO fixme
public void testBuilderMethodException() throws IOException {
doTest();
}
Expand Down
@@ -0,0 +1,15 @@
package de.plushnikov.lombok.tests;

import de.plushnikov.lombok.LombokParsingTestCase;

import java.io.IOException;

/**
* Unit tests for IntelliJPlugin for Lombok, based on lombok test classes
*/
public class TolerateTest extends LombokParsingTestCase {

public void testTolerateTest() throws IOException {
doTest();
}
}

0 comments on commit ef5fbc0

Please sign in to comment.