Skip to content

Commit 7138c2d

Browse files
committed
#16 Move logic for finding public fields into MapStructUtil and make sure unmapped target / source properties inspection checks public fields
1 parent 6660811 commit 7138c2d

5 files changed

Lines changed: 156 additions & 68 deletions

File tree

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

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
package org.mapstruct.intellij.codeinsight.references;
77

88
import java.util.Objects;
9-
import java.util.Set;
10-
import java.util.stream.Collectors;
119
import java.util.stream.Stream;
1210

1311
import com.intellij.codeInsight.lookup.LookupElement;
@@ -16,19 +14,20 @@
1614
import com.intellij.psi.PsiElement;
1715
import com.intellij.psi.PsiField;
1816
import com.intellij.psi.PsiLiteral;
17+
import com.intellij.psi.PsiMember;
1918
import com.intellij.psi.PsiMethod;
2019
import com.intellij.psi.PsiParameter;
2120
import com.intellij.psi.PsiReference;
2221
import com.intellij.psi.PsiType;
22+
import com.intellij.psi.PsiVariable;
2323
import com.intellij.psi.util.PsiUtil;
2424
import org.jetbrains.annotations.NotNull;
2525
import org.jetbrains.annotations.Nullable;
2626
import org.mapstruct.intellij.util.MapstructUtil;
2727

28-
import static org.mapstruct.intellij.util.MapstructUtil.asLookup;
2928
import static org.mapstruct.intellij.util.MapstructUtil.isPublic;
3029
import static org.mapstruct.intellij.util.SourceUtils.getParameterType;
31-
import static org.mapstruct.intellij.util.SourceUtils.publicGetters;
30+
import static org.mapstruct.intellij.util.SourceUtils.publicReadAccessors;
3231

3332
/**
3433
* Reference for {@link org.mapstruct.Mapping#source()}.
@@ -96,20 +95,9 @@ PsiElement resolveInternal(@NotNull String value, @NotNull PsiMethod mappingMeth
9695
@NotNull
9796
@Override
9897
Object[] getVariantsInternal(@NotNull PsiType psiType) {
99-
Set<LookupElement> elements = publicGetters( psiType )
100-
.map( pair -> MapstructUtil.asLookup( pair, PsiMethod::getReturnType ) )
101-
.collect( Collectors.toSet() );
102-
103-
PsiClass psiClass = PsiUtil.resolveClassInType( psiType );
104-
if ( psiClass != null ) {
105-
for ( PsiField field : psiClass.getAllFields() ) {
106-
if ( isPublic( field ) ) {
107-
elements.add( asLookup( field ) );
108-
}
109-
}
110-
}
111-
112-
return elements.toArray();
98+
return publicReadAccessors( psiType )
99+
.map( pair -> MapstructUtil.asLookup( pair, MapstructSourceReference::memberPsiType ) )
100+
.toArray();
113101
}
114102

115103
@NotNull
@@ -146,4 +134,17 @@ else if ( element instanceof PsiParameter ) {
146134
static PsiReference[] create(PsiLiteral psiLiteral) {
147135
return MapstructBaseReference.create( psiLiteral, MapstructSourceReference::new );
148136
}
137+
138+
private static PsiType memberPsiType(PsiMember psiMember) {
139+
if ( psiMember instanceof PsiMethod ) {
140+
return ( (PsiMethod) psiMember ).getReturnType();
141+
}
142+
else if ( psiMember instanceof PsiVariable ) {
143+
return ( (PsiVariable) psiMember ).getType();
144+
}
145+
else {
146+
return null;
147+
}
148+
149+
}
149150
}

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

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
package org.mapstruct.intellij.codeinsight.references;
77

88
import java.util.Objects;
9-
import java.util.Set;
10-
import java.util.stream.Collectors;
119
import java.util.stream.Stream;
1210

1311
import com.intellij.codeInsight.lookup.LookupElement;
@@ -17,19 +15,20 @@
1715
import com.intellij.psi.PsiElement;
1816
import com.intellij.psi.PsiField;
1917
import com.intellij.psi.PsiLiteral;
18+
import com.intellij.psi.PsiMember;
2019
import com.intellij.psi.PsiMethod;
2120
import com.intellij.psi.PsiParameter;
2221
import com.intellij.psi.PsiReference;
2322
import com.intellij.psi.PsiType;
23+
import com.intellij.psi.PsiVariable;
2424
import com.intellij.psi.util.PsiUtil;
2525
import org.jetbrains.annotations.NotNull;
2626
import org.jetbrains.annotations.Nullable;
2727
import org.mapstruct.intellij.util.MapstructUtil;
2828

29-
import static org.mapstruct.intellij.util.MapstructUtil.asLookup;
3029
import static org.mapstruct.intellij.util.MapstructUtil.isPublicModifiable;
3130
import static org.mapstruct.intellij.util.TargetUtils.getRelevantType;
32-
import static org.mapstruct.intellij.util.TargetUtils.publicSetters;
31+
import static org.mapstruct.intellij.util.TargetUtils.publicWriteAccessors;
3332
import static org.mapstruct.intellij.util.TargetUtils.resolveBuilderOrSelfClass;
3433

3534
/**
@@ -112,23 +111,9 @@ PsiElement resolveInternal(@NotNull String value, @NotNull PsiMethod mappingMeth
112111
@NotNull
113112
@Override
114113
Object[] getVariantsInternal(@NotNull PsiType psiType) {
115-
116-
Set<LookupElement> elements = publicSetters( psiType, builderSupportPresent )
117-
.map( pair -> asLookup(
118-
pair,
119-
MapstructTargetReference::firstParameterPsiType
120-
) ).collect( Collectors.toSet() );
121-
122-
PsiClass psiClass = PsiUtil.resolveClassInType( psiType );
123-
if ( psiClass != null ) {
124-
for ( PsiField field : psiClass.getAllFields() ) {
125-
if ( isPublicModifiable( field ) ) {
126-
elements.add( asLookup( field ) );
127-
}
128-
}
129-
}
130-
131-
return elements.toArray();
114+
return publicWriteAccessors( psiType, builderSupportPresent )
115+
.map( pair -> MapstructUtil.asLookup( pair, MapstructTargetReference::memberPsiType ) )
116+
.toArray();
132117
}
133118

134119
@NotNull
@@ -161,6 +146,19 @@ static PsiReference[] create(PsiLiteral psiLiteral) {
161146
return MapstructBaseReference.create( psiLiteral, MapstructTargetReference::new );
162147
}
163148

149+
private static PsiType memberPsiType(PsiMember psiMember) {
150+
if ( psiMember instanceof PsiMethod ) {
151+
return firstParameterPsiType( (PsiMethod) psiMember );
152+
}
153+
else if ( psiMember instanceof PsiVariable ) {
154+
return ( (PsiVariable) psiMember ).getType();
155+
}
156+
else {
157+
return null;
158+
}
159+
160+
}
161+
164162
/**
165163
* Util function for extracting the type of the first parameter of a method.
166164
*

src/main/java/org/mapstruct/intellij/util/MapstructUtil.java

Lines changed: 61 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
package org.mapstruct.intellij.util;
77

88
import java.beans.Introspector;
9+
import java.util.ArrayList;
10+
import java.util.Collections;
11+
import java.util.List;
912
import java.util.function.Function;
1013
import java.util.stream.Stream;
1114

@@ -22,12 +25,15 @@
2225
import com.intellij.psi.PsiClassType;
2326
import com.intellij.psi.PsiField;
2427
import com.intellij.psi.PsiFile;
28+
import com.intellij.psi.PsiMember;
2529
import com.intellij.psi.PsiMethod;
2630
import com.intellij.psi.PsiModifier;
2731
import com.intellij.psi.PsiModifierList;
2832
import com.intellij.psi.PsiParameter;
2933
import com.intellij.psi.PsiSubstitutor;
3034
import com.intellij.psi.PsiType;
35+
import com.intellij.psi.PsiVariable;
36+
import com.intellij.psi.impl.PsiClassImplUtil;
3137
import com.intellij.psi.search.GlobalSearchScope;
3238
import com.intellij.psi.util.CachedValueProvider;
3339
import com.intellij.psi.util.CachedValuesManager;
@@ -85,32 +91,39 @@ public final class MapstructUtil {
8591
private MapstructUtil() {
8692
}
8793

88-
public static LookupElement asLookup(@NotNull Pair<PsiMethod, PsiSubstitutor> pair,
89-
Function<PsiMethod, PsiType> typeMapper) {
90-
PsiMethod method = pair.getFirst();
94+
public static <T extends PsiMember> LookupElement asLookup(@NotNull Pair<T, PsiSubstitutor> pair,
95+
Function<T, PsiType> typeMapper) {
96+
T member = pair.getFirst();
9197
PsiSubstitutor substitutor = pair.getSecond();
9298

93-
String propertyName = getPropertyName( method );
94-
LookupElementBuilder builder = LookupElementBuilder.create( method, propertyName )
99+
String propertyName = getPropertyName( member );
100+
LookupElementBuilder builder = LookupElementBuilder.create( member, propertyName )
95101
.withIcon( PlatformIcons.VARIABLE_ICON )
96102
.withPresentableText( propertyName )
97-
.withTailText( PsiFormatUtil.formatMethod( method, substitutor,
98-
0,
99-
PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_TYPE
100-
) );
101-
final PsiType type = typeMapper.apply( method );
103+
.withTailText( formatTailText( member, substitutor ) );
104+
final PsiType type = typeMapper.apply( member );
102105
if ( type != null ) {
103106
builder = builder.withTypeText( substitutor.substitute( type ).getPresentableText() );
104107
}
105108

106109
return builder;
107110
}
108111

109-
public static LookupElement asLookup(@NotNull PsiField field) {
110-
return LookupElementBuilder.create( field )
111-
.withIcon( PlatformIcons.FIELD_ICON )
112-
.withPresentableText( field.getNameIdentifier().getText() )
113-
.withTypeText( field.getType().getPresentableText() );
112+
private static String formatTailText(PsiMember member, PsiSubstitutor substitutor) {
113+
if ( member instanceof PsiMethod ) {
114+
return PsiFormatUtil.formatMethod(
115+
(PsiMethod) member,
116+
substitutor,
117+
0,
118+
PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_TYPE
119+
);
120+
}
121+
else if ( member instanceof PsiVariable ) {
122+
return PsiFormatUtil.formatVariable( (PsiVariable) member, 0, substitutor );
123+
}
124+
else {
125+
return "";
126+
}
114127
}
115128

116129
public static boolean isPublic(@NotNull PsiMethod method) {
@@ -218,6 +231,17 @@ public static boolean isBuildMethod(@NotNull PsiMethod buildMethod, @NotNull Psi
218231
TypeConversionUtil.isAssignable( typeToBuild, buildMethod.getReturnType() );
219232
}
220233

234+
@NotNull
235+
@NonNls
236+
public static String getPropertyName(@NotNull PsiMember psiMember) {
237+
if ( psiMember instanceof PsiMethod ) {
238+
return getPropertyName( (PsiMethod) psiMember );
239+
}
240+
else {
241+
return psiMember.getName() == null ? "" : psiMember.getName();
242+
}
243+
}
244+
221245
@NotNull
222246
@NonNls
223247
public static String getPropertyName(@NotNull PsiMethod method) {
@@ -349,6 +373,28 @@ public static PsiParameter[] getSourceParameters(@NotNull PsiMethod mappingMetho
349373
.toArray( PsiParameter[]::new );
350374
}
351375

376+
public static List<Pair<PsiField, PsiSubstitutor>> publicFields(PsiClass psiClass) {
377+
List<Pair<PsiField, PsiSubstitutor>> fieldPairs = PsiClassImplUtil.getAllWithSubstitutorsByMap(
378+
psiClass,
379+
PsiClassImplUtil.MemberType.FIELD
380+
);
381+
382+
if ( fieldPairs.isEmpty() ) {
383+
return Collections.emptyList();
384+
}
385+
386+
List<Pair<PsiField, PsiSubstitutor>> publicFields = new ArrayList<>( fieldPairs.size() );
387+
388+
for ( Pair<PsiField, PsiSubstitutor> fieldPair : fieldPairs ) {
389+
PsiField field = fieldPair.getFirst();
390+
if ( MapstructUtil.isPublic( field ) ) {
391+
publicFields.add( fieldPair );
392+
}
393+
}
394+
395+
return publicFields;
396+
}
397+
352398
/**
353399
* Checks if MapStruct can descend into a type. MapStruct, cannot descend into following types:
354400
* <ul>

src/main/java/org/mapstruct/intellij/util/SourceUtils.java

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
import com.intellij.openapi.util.Pair;
1717
import com.intellij.psi.PsiClass;
18+
import com.intellij.psi.PsiMember;
1819
import com.intellij.psi.PsiMethod;
1920
import com.intellij.psi.PsiParameter;
2021
import com.intellij.psi.PsiSubstitutor;
@@ -25,6 +26,7 @@
2526

2627
import static org.mapstruct.intellij.util.MapstructUtil.canDescendIntoType;
2728
import static org.mapstruct.intellij.util.MapstructUtil.getSourceParameters;
29+
import static org.mapstruct.intellij.util.MapstructUtil.publicFields;
2830

2931
/**
3032
* Utils for working with source properties (extracting sources for MapStruct).
@@ -50,7 +52,7 @@ public static Stream<String> findAllSourceProperties(@NotNull PsiMethod method)
5052
return Stream.of( sourceParameters[0] )
5153
.map( SourceUtils::getParameterType )
5254
.filter( Objects::nonNull )
53-
.flatMap( SourceUtils::publicGetters )
55+
.flatMap( SourceUtils::publicReadAccessors )
5456
.map( pair -> pair.getFirst() )
5557
.map( MapstructUtil::getPropertyName );
5658
}
@@ -85,17 +87,35 @@ public static PsiType getParameterType(@NotNull PsiParameter parameter) {
8587
}
8688

8789
/**
88-
* Extract all public getters with their psi substitutors from the given {@code psiType}
90+
* Extract all public read accessors (public getters and fields)
91+
* with their psi substitutors from the given {@code psiType}
8992
*
90-
* @param psiType to use to extract the getters
93+
* @param psiType to use to extract the accessors
9194
*
92-
* @return a stream that holds all public getters for the given {@code psiType}
95+
* @return a stream that holds all public read accessors for the given {@code psiType}
9396
*/
94-
public static Stream<Pair<PsiMethod, PsiSubstitutor>> publicGetters(@NotNull PsiType psiType) {
97+
public static Stream<Pair<? extends PsiMember, PsiSubstitutor>> publicReadAccessors(@NotNull PsiType psiType) {
9598
PsiClass psiClass = PsiUtil.resolveClassInType( psiType );
9699
if ( psiClass == null ) {
97100
return Stream.empty();
98101
}
102+
103+
List<Pair<? extends PsiMember, PsiSubstitutor>> publicReadAccessors = new ArrayList<>();
104+
105+
publicReadAccessors.addAll( publicGetters( psiClass ) );
106+
publicReadAccessors.addAll( publicFields( psiClass ) );
107+
108+
return publicReadAccessors.stream();
109+
}
110+
111+
/**
112+
* Extract all public getters with their psi substitutors from the given {@code psiClass}
113+
*
114+
* @param psiClass to use to extract the getters
115+
*
116+
* @return a list that holds all public getters for the given {@code psiClass}
117+
*/
118+
private static List<Pair<PsiMethod, PsiSubstitutor>> publicGetters(@NotNull PsiClass psiClass) {
99119
Set<PsiMethod> overriddenMethods = new HashSet<>();
100120
List<Pair<PsiMethod, PsiSubstitutor>> publicGetters = new ArrayList<>();
101121
for ( Pair<PsiMethod, PsiSubstitutor> pair : psiClass.getAllMethodsAndTheirSubstitutors() ) {
@@ -108,6 +128,6 @@ public static Stream<Pair<PsiMethod, PsiSubstitutor>> publicGetters(@NotNull Psi
108128
}
109129
}
110130

111-
return publicGetters.stream();
131+
return publicGetters;
112132
}
113133
}

0 commit comments

Comments
 (0)