Skip to content

Commit 8aa80a3

Browse files
committed
#243: Only disable warnings when it is a map with a String key type and support nested references
1 parent 03403db commit 8aa80a3

5 files changed

Lines changed: 86 additions & 24 deletions

File tree

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ public final PsiElement resolve() {
6969
}
7070

7171
if ( previous != null ) {
72-
PsiType psiType = canDescendIntoType( previous.resolvedType() ) ? previous.resolvedType() : null;
72+
PsiType previousResolvedType = previous.resolvedType();
73+
PsiType psiType = supportsNestedReferenceForType( previousResolvedType ) ? previousResolvedType : null;
7374
return psiType == null ? null : resolveInternal( value, psiType );
7475
}
7576

@@ -78,6 +79,10 @@ public final PsiElement resolve() {
7879
return mappingMethod == null ? null : resolveInternal( value, mappingMethod );
7980
}
8081

82+
protected boolean supportsNestedReferenceForType(@Nullable PsiType psiType) {
83+
return canDescendIntoType( psiType );
84+
}
85+
8186
/**
8287
* Resolved the reference from the {@code value} for the reference {@code psiClass}
8388
*

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ PsiElement resolveInternal(@NotNull String value, @NotNull PsiType psiType) {
5757
return null;
5858
}
5959

60+
if ( MapstructUtil.isMapWithStringKeyType( psiType ) ) {
61+
return psiClass;
62+
}
63+
6064
PsiRecordComponent recordComponent = findRecordComponent( value, psiClass );
6165
if ( recordComponent != null ) {
6266
return recordComponent;
@@ -78,6 +82,11 @@ PsiElement resolveInternal(@NotNull String value, @NotNull PsiType psiType) {
7882
return null;
7983
}
8084

85+
@Override
86+
protected boolean supportsNestedReferenceForType(@Nullable PsiType psiType) {
87+
return super.supportsNestedReferenceForType( psiType ) || MapstructUtil.isMapWithStringKeyType( psiType );
88+
}
89+
8190
@Override
8291
PsiElement resolveInternal(@NotNull String value, @NotNull PsiMethod mappingMethod) {
8392
PsiParameter[] sourceParameters = MapstructUtil.getSourceParameters( mappingMethod );

src/main/java/org/mapstruct/intellij/inspection/MapstructReferenceInspection.java

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import com.intellij.codeInspection.ProblemHighlightType;
99
import com.intellij.codeInspection.ProblemsHolder;
1010
import com.intellij.openapi.util.TextRange;
11-
import com.intellij.psi.CommonClassNames;
1211
import com.intellij.psi.ContributedReferenceHost;
1312
import com.intellij.psi.PsiClass;
1413
import com.intellij.psi.PsiElement;
@@ -19,11 +18,11 @@
1918
import com.intellij.psi.PsiReference;
2019
import com.intellij.psi.PsiType;
2120
import com.intellij.psi.util.PsiTreeUtil;
22-
import com.intellij.psi.util.PsiUtil;
2321
import org.jetbrains.annotations.NotNull;
2422
import org.jetbrains.annotations.Nullable;
2523
import org.mapstruct.intellij.codeinsight.references.BaseReference;
2624
import org.mapstruct.intellij.codeinsight.references.BaseValueMappingReference;
25+
import org.mapstruct.intellij.util.MapstructUtil;
2726

2827
/**
2928
* Inspection that checks if mapstruct references can be resolved.
@@ -76,34 +75,28 @@ private boolean shouldRegisterProblem(BaseReference reference) {
7675
return valueMappingReference.getEnumClass() != null;
7776
}
7877

79-
if ( singleSourceParameterIsOfTypeMap( reference.getMappingMethod() ) ) {
78+
if ( hasSingleStringKeyMapSourceParameter( reference.getMappingMethod() ) ) {
79+
// MapStruct allows source values as map keys, even if they are not resolvable as Java properties.
80+
// Therefore, we don't report an unresolved reference problem here.
8081
return false;
8182
}
8283

8384
return !containingClassIsAnnotationType( reference.getElement() );
8485
}
8586

86-
private boolean singleSourceParameterIsOfTypeMap(@Nullable PsiMethod mappingMethod) {
87+
private boolean hasSingleStringKeyMapSourceParameter(@Nullable PsiMethod mappingMethod) {
8788

8889
if ( mappingMethod != null ) {
89-
PsiParameter[] parameters = mappingMethod.getParameterList().getParameters();
90-
if ( parameters.length > 0 ) {
90+
PsiParameter[] parameters = MapstructUtil.getSourceParameters( mappingMethod );
91+
if ( parameters.length == 1 ) {
9192
PsiType parameterType = parameters[0].getType();
92-
return isMapType( parameterType );
93+
return MapstructUtil.isMapWithStringKeyType( parameterType );
9394
}
9495
}
9596

9697
return false;
9798
}
9899

99-
private boolean isMapType(PsiType type) {
100-
PsiClass psiClass = PsiUtil.resolveClassInType( type );
101-
if ( psiClass == null ) {
102-
return false;
103-
}
104-
return CommonClassNames.JAVA_UTIL_MAP.equals( psiClass.getQualifiedName() );
105-
}
106-
107100
private boolean containingClassIsAnnotationType(PsiElement element) {
108101

109102
PsiClass containingClass = PsiTreeUtil.getParentOfType( element, PsiClass.class );

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

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import java.util.Map;
1313
import java.util.function.Function;
1414
import java.util.stream.Stream;
15-
import javax.swing.Icon;
15+
import javax.swing.*;
1616

1717
import com.intellij.codeInsight.AnnotationUtil;
1818
import com.intellij.codeInsight.lookup.LookupElement;
@@ -659,4 +659,33 @@ public static boolean isInheritInverseConfiguration(PsiMethod method) {
659659
return isAnnotated( method, INHERIT_INVERSE_CONFIGURATION_FQN, AnnotationUtil.CHECK_TYPE );
660660
}
661661

662+
/**
663+
* Checks if the given type is a {@link java.util.Map} with a {@link String} key type.
664+
*
665+
* @param type to be checked
666+
* @return {@code true} if the {@code type} is a {@link java.util.Map} with a {@link String} key type,
667+
* {@code false} otherwise
668+
*/
669+
public static boolean isMapWithStringKeyType(@Nullable PsiType type) {
670+
if ( type == null ) {
671+
return false;
672+
}
673+
674+
PsiClass psiClass = PsiUtil.resolveClassInType( type );
675+
if ( psiClass == null ||
676+
!CommonClassNames.JAVA_UTIL_MAP.equals( psiClass.getQualifiedName() ) ) {
677+
return false;
678+
}
679+
680+
if ( !( type instanceof PsiClassType ct ) ) {
681+
return false;
682+
}
683+
684+
PsiType[] parameters = ct.getParameters();
685+
if ( parameters.length == 0 ) {
686+
return false;
687+
}
688+
689+
return parameters[0].equalsToText( CommonClassNames.JAVA_LANG_STRING );
690+
}
662691
}

testData/bugs/_243/DisableSourcePropertyInspectionOnMapTest.java

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,46 @@
99

1010
import org.mapstruct.Mapper;
1111
import org.mapstruct.Mapping;
12+
import org.mapstruct.MappingTarget;
1213

1314
@Mapper
1415
abstract class Issue243Mapper {
1516

16-
@Mapping(source = "exDate", target = "exDate", dateFormat = "yyyy-MM-dd")
17-
@Mapping(source = "payDate", target = "payDate", dateFormat = "yyyy-MM-dd")
18-
@Mapping(source = "recordDate", target = "recordDate", dateFormat = "yyyy-MM-dd")
19-
@Mapping(source = "annDate", target = "annDate", dateFormat = "yyyy-MM-dd")
20-
public abstract CorporateAction toCorporateAction(Map<String, String> rowValues);
17+
@Mapping(source = "exDate", target = "exDate")
18+
@Mapping(source = "payDate", target = "payDate")
19+
public abstract CorporateAction mapWithStringKeyMap(Map<String, String> rowValues);
20+
21+
@Mapping(source = "exDate", target = "exDate")
22+
public abstract void updateWithStringKeyMap(Map<String, String> rowValues, @MappingTarget CorporateAction target);
23+
24+
@Mapping(source = "exDate", target = "exDate")
25+
public abstract CorporateAction mapWithObjectValueMap(Map<String, Object> rowValues);
26+
27+
@Mapping(source = "<error descr="Unknown property 'exDate'">exDate</error>", target = "exDate")
28+
public abstract CorporateAction mapWithIntegerKeyMap(Map<Integer, String> rowValues);
29+
30+
@Mapping(source = "<error descr="Unknown property 'exDate'">exDate</error>", target = "exDate")
31+
public abstract void updateWithIntegerKeyMap(
32+
Map<Integer, String> rowValues,
33+
@MappingTarget CorporateAction target
34+
);
35+
36+
@Mapping(source = "<error descr="Unknown property 'exDate'">exDate</error>", target = "exDate")
37+
@Mapping(source = "payDate", target = "payDate")
38+
public abstract CorporateAction mapWithMultipleSources(
39+
Map<String, String> rowValues,
40+
LocalDate payDate
41+
);
42+
43+
@Mapping(source = "rowValues.exDate", target = "exDate")
44+
@Mapping(source = "payDate", target = "payDate")
45+
public abstract CorporateAction mapWithMultipleSourcesAndMapName(
46+
Map<String, String> rowValues,
47+
LocalDate payDate
48+
);
2149
}
2250

2351
class CorporateAction {
2452
public LocalDate exDate;
2553
public LocalDate payDate;
26-
public LocalDate recordDate;
27-
public LocalDate annDate;
2854
}

0 commit comments

Comments
 (0)