Skip to content

Commit 4eb96e8

Browse files
committed
#226: Reference only accessible qualified methods
1 parent f178b56 commit 4eb96e8

File tree

5 files changed

+191
-2
lines changed

5 files changed

+191
-2
lines changed

src/main/java/org/mapstruct/intellij/codeinsight/references/MapstructMappingQualifiedByNameReference.java

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import com.intellij.psi.PsiClass;
1919
import com.intellij.psi.PsiElement;
2020
import com.intellij.psi.PsiMethod;
21+
import com.intellij.psi.PsiModifier;
2122
import com.intellij.psi.PsiParameter;
2223
import com.intellij.psi.PsiReference;
2324
import com.intellij.psi.PsiType;
@@ -113,12 +114,41 @@ private Stream<PsiMethod> findAllNamedMethodsFromThisAndReferencedMappers(@NotNu
113114
Stream<PsiMethod> internalMethods = Stream.of( containingClass.getMethods() )
114115
.filter( MapstructUtil::isNamedMethod );
115116

116-
Stream<PsiMethod> externalMethods = findNamedMethodsInUsedMappers( containingClass );
117+
Stream<PsiMethod> externalMethods = findNamedMethodsInUsedMappers( containingClass )
118+
.filter( method -> methodIsAccessibleFrom( method, containingClass ) );
117119

118120
return Stream.concat( internalMethods, externalMethods )
119121
.filter( this::methodHasReturnType );
120122
}
121123

124+
private boolean methodIsAccessibleFrom(PsiMethod method, PsiClass containingClass) {
125+
PsiClass methodClass = method.getContainingClass();
126+
if ( methodClass == null ) {
127+
return false;
128+
}
129+
130+
if ( method.hasModifierProperty( PsiModifier.PRIVATE ) ) {
131+
return false;
132+
}
133+
134+
if ( method.hasModifierProperty( PsiModifier.PUBLIC ) ) {
135+
return true;
136+
}
137+
138+
if ( method.hasModifierProperty( PsiModifier.PROTECTED ) ) {
139+
return methodClass.equals( containingClass );
140+
}
141+
142+
return haveSamePackage( containingClass, methodClass );
143+
}
144+
145+
private boolean haveSamePackage(PsiClass firstClass, PsiClass secondClass) {
146+
return Objects.equals(
147+
StringUtil.getPackageName( Objects.requireNonNull( firstClass.getQualifiedName() ) ),
148+
StringUtil.getPackageName( Objects.requireNonNull( secondClass.getQualifiedName() ) )
149+
);
150+
}
151+
122152
@NotNull
123153
private Stream<PsiMethod> findNamedMethodsInUsedMappers(@Nullable PsiClass containingClass) {
124154

src/test/java/org/mapstruct/intellij/completion/MappingQualifiedByNameCompletionTestCase.java

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,59 @@ private void assertQualifiedByNameInsideMapperConfigAutoComplete() {
8383
assertThat( myItems )
8484
.extracting( LookupElementPresentation::renderElement )
8585
.usingRecursiveFieldByFieldElementComparator()
86+
.describedAs( "methods of mappers from @MapperConfig(uses = ...)" )
8687
.containsOnly(
87-
// methods of mappers from @MapperConfig(uses = ...)
8888
createMethod( "unwrapOptional", "T", " OptionalMapper#unwrapOptional(Optional<T>)" )
8989
);
9090
}
9191

92+
public void testMappingQualifiedByNameWithAllPossibleVisibilities() {
93+
configureByTestName();
94+
assertAutoCompleteOfValidVisibilities();
95+
}
96+
97+
private void assertAutoCompleteOfValidVisibilities() {
98+
99+
assertThat( myItems )
100+
.extracting( LookupElement::getLookupString )
101+
.containsExactlyInAnyOrder(
102+
"internalModifierPackagePrivate",
103+
"internalModifierPrivate",
104+
"internalModifierProtected",
105+
"internalModifierPublic",
106+
"samePackageModifierPackagePrivate",
107+
"samePackageModifierPublic",
108+
"externalPackageModifierPublic"
109+
);
110+
111+
assertThat( myItems )
112+
.extracting( LookupElementPresentation::renderElement )
113+
.usingRecursiveFieldByFieldElementComparator()
114+
.containsExactlyInAnyOrder(
115+
createMethod(
116+
"internalModifierPackagePrivate",
117+
"String",
118+
" CarMapper#internalModifierPackagePrivate(String)"
119+
),
120+
createMethod( "internalModifierPrivate", "String", " CarMapper#internalModifierPrivate(String)" ),
121+
createMethod( "internalModifierProtected", "String", " CarMapper#internalModifierProtected(String)" ),
122+
createMethod( "internalModifierPublic", "String", " CarMapper#internalModifierPublic(String)" ),
123+
createMethod(
124+
"samePackageModifierPackagePrivate",
125+
"String",
126+
" SamePackageMapper#samePackageModifierPackagePrivate(String)"
127+
),
128+
createMethod(
129+
"samePackageModifierPublic",
130+
"String",
131+
" SamePackageMapper#samePackageModifierPublic(String)"
132+
),
133+
createMethod(
134+
"externalPackageModifierPublic",
135+
"String",
136+
" ExternalMapper#externalPackageModifierPublic(String)"
137+
)
138+
);
139+
}
140+
92141
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright MapStruct Authors.
3+
*
4+
* Licensed under the Apache License version 2.0, available at https://www.apache.org/licenses/LICENSE-2.0
5+
*/
6+
package org.mapstruct.ap.test.complex;
7+
8+
import org.example.dto.Car;
9+
import org.example.dto.CarDto;
10+
import org.mapstruct.Mapper;
11+
import org.mapstruct.Mapping;
12+
import org.mapstruct.Named;
13+
import org.mapstruct.ap.test.complex.SamePackageMapper;
14+
import org.mapstruct.helper.qualifiedbyname.external.ExternalMapper;
15+
16+
@Mapper(uses = { ExternalMapper.class, SamePackageMapper.class })
17+
public interface CarMapper {
18+
19+
@Mapping(target = "make", qualifiedByName = "<caret>")
20+
CarDto carToCarDto(Car car);
21+
22+
@Named("internalModifierPackagePrivate")
23+
String internalModifierPackagePrivate(String value) {
24+
return "";
25+
}
26+
27+
@Named("internalModifierPrivate")
28+
private String internalModifierPrivate(String value) {
29+
return "";
30+
}
31+
32+
@Named("internalModifierProtected")
33+
protected String internalModifierProtected(String value) {
34+
return "";
35+
}
36+
37+
@Named("internalModifierPublic")
38+
public String internalModifierPublic(String value) {
39+
return "";
40+
}
41+
42+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright MapStruct Authors.
3+
*
4+
* Licensed under the Apache License version 2.0, available at https://www.apache.org/licenses/LICENSE-2.0
5+
*/
6+
package org.mapstruct.helper.qualifiedbyname.external;
7+
8+
import org.mapstruct.Mapper;
9+
import org.mapstruct.Named;
10+
11+
@Mapper
12+
public abstract class ExternalMapper {
13+
14+
@Named("externalPackageModifierPackagePrivate")
15+
String externalPackageModifierPackagePrivate(String value) {
16+
return "";
17+
}
18+
19+
@Named("externalPackageModifierPrivate")
20+
private String externalPackageModifierPrivate(String value) {
21+
return "";
22+
}
23+
24+
@Named("externalPackageModifierProtected")
25+
protected String externalPackageModifierProtected(String value) {
26+
return "";
27+
}
28+
29+
@Named("externalPackageModifierPublic")
30+
public String externalPackageModifierPublic(String value) {
31+
return "";
32+
}
33+
34+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright MapStruct Authors.
3+
*
4+
* Licensed under the Apache License version 2.0, available at https://www.apache.org/licenses/LICENSE-2.0
5+
*/
6+
package org.mapstruct.ap.test.complex;
7+
8+
import org.mapstruct.Mapper;
9+
import org.mapstruct.Named;
10+
11+
@Mapper
12+
public abstract class SamePackageMapper {
13+
14+
@Named("samePackageModifierPackagePrivate")
15+
String samePackageModifierPackagePrivate(String value) {
16+
return "";
17+
}
18+
19+
@Named("samePackageModifierPrivate")
20+
private String samePackageModifierPrivate(String value) {
21+
return "";
22+
}
23+
24+
@Named("samePackageModifierProtected")
25+
protected String samePackageModifierProtected(String value) {
26+
return "";
27+
}
28+
29+
@Named("samePackageModifierPublic")
30+
public String samePackageModifierPublic(String value) {
31+
return "";
32+
}
33+
34+
}

0 commit comments

Comments
 (0)