Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ licenseFormat.dependsOn licenseFormatForKotlin
licenseTest.dependsOn licenseTestData

checkstyle {
toolVersion = '8.36.1'
toolVersion = '10.12.0'

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checkstyle 8.36.1 cannot parse Java pattern-matching switch expressions (used in resolvedType()), e.g.:

Output before up version

MapstructSourceReference.java:138:17: unexpected token: psiType

config = resources.text.fromUri("https://raw.githubusercontent.com/mapstruct/mapstruct/master/build-config/src/main/resources/build-config/checkstyle.xml")
configProperties = [
'checkstyle.cache.file': layout.buildDirectory.get().asFile.toPath( ).resolve( 'checkstyle-cachefile').toString(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ public String getValue() {
return super.getValue();
}

@Nullable
public MapstructBaseReference getPrevious() {
return this.previous;
}

@Nullable
@Override
public final PsiElement resolve() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package org.mapstruct.intellij.codeinsight.references;

import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;

import com.intellij.codeInsight.lookup.LookupElement;
Expand All @@ -23,6 +24,7 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.mapstruct.intellij.util.MapstructUtil;
import org.mapstruct.intellij.util.SourceUtils;

import static org.mapstruct.intellij.util.MapstructUtil.asLookup;
import static org.mapstruct.intellij.util.MapstructUtil.findRecordComponent;
Expand Down Expand Up @@ -133,21 +135,31 @@ Object[] getVariantsInternal(@NotNull PsiMethod mappingMethod) {
@Override
PsiType resolvedType() {
PsiElement element = resolve();

if ( element instanceof PsiMethod psiMethod ) {
return psiMethod.getReturnType();
}
else if ( element instanceof PsiParameter psiParameter ) {
return psiParameter.getType();
}
else if ( element instanceof PsiRecordComponent psiRecordComponent ) {
return psiRecordComponent.getType();
}
else if ( element instanceof PsiField psiField ) {
return psiField.getType();
PsiType elementType = switch ( element ) {
case PsiMethod psiMethod -> psiMethod.getReturnType();
case PsiParameter psiParameter -> psiParameter.getType();
case PsiRecordComponent psiRecordComponent -> psiRecordComponent.getType();
case PsiField psiField -> psiField.getType();
case null, default -> null;
};

if ( elementType == null ) {
return null;
}

return null;
PsiType contextType = Optional.ofNullable( getPrevious() )
.map( MapstructBaseReference::resolvedType )
.or( () -> Optional.ofNullable( this.getMappingMethod() )
.map( MapstructUtil::getSourceParameters )
.filter( params -> params.length == 1 )
.map( psiParameters -> psiParameters[0] )
.map( SourceUtils::getParameterType )
)
.orElse( null );

return PsiUtil.resolveGenericsClassInType( contextType )
.getSubstitutor()
.substitute( elementType );
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;

import com.intellij.codeInsight.AnnotationUtil;
Expand All @@ -27,7 +28,6 @@
import com.intellij.psi.util.PsiUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.mapstruct.Mapping;
import org.mapstruct.intellij.util.MapStructVersion;
import org.mapstruct.intellij.util.MapstructUtil;
import org.mapstruct.intellij.util.TargetType;
Expand Down Expand Up @@ -203,21 +203,28 @@ Object[] getVariantsInternal(@NotNull PsiMethod mappingMethod) {
@Override
PsiType resolvedType() {
PsiElement element = resolve();

if ( element instanceof PsiMethod psiMethod ) {
return firstParameterPsiType( psiMethod );
}
else if ( element instanceof PsiParameter psiParameter ) {
return psiParameter.getType();
}
else if ( element instanceof PsiRecordComponent psiRecordComponent ) {
return psiRecordComponent.getType();
}
else if ( element instanceof PsiField psiField ) {
return psiField.getType();
PsiType elementType = switch ( element ) {
case PsiMethod psiMethod -> firstParameterPsiType( psiMethod );
case PsiParameter psiParameter -> psiParameter.getType();
case PsiRecordComponent psiRecordComponent -> psiRecordComponent.getType();
case PsiField psiField -> psiField.getType();
case null, default -> null;
};

if ( elementType == null ) {
return null;
}

return null;
PsiType contextType = Optional.ofNullable( getPrevious() )
.map( MapstructBaseReference::resolvedType )
.or( () -> Optional.ofNullable( getMappingMethod() )
.map( TargetUtils::getRelevantType )
)
.orElse( null );

return PsiUtil.resolveGenericsClassInType( contextType )
.getSubstitutor()
.substitute( elementType );
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

import com.intellij.codeInsight.completion.LightFixtureCompletionTestCase;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess;
import com.intellij.testFramework.LightProjectDescriptor;
import com.intellij.testFramework.PsiTestUtil;
import com.intellij.util.PathUtil;
Expand All @@ -29,7 +28,13 @@ protected void setUp() throws Exception {
super.setUp();
final String mapstructLibPath = PathUtil.toSystemIndependentName( new File( BUILD_LIBS_DIRECTORY )
.getAbsolutePath() );
VfsRootAccess.allowRootAccess( getTestRootDisposable(), mapstructLibPath );

allowAccessToDirsIfExists(
BUILD_LIBS_DIRECTORY,
"testData",
"build/test-libs"
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you changes this code? I think this could break building on other OS (Windows)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this specifically to ensure the tests run correctly on Windows. Without these configurations, the testing framework is unable to access packages

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example, before fix

14:52:40,037 FINE   .intellij.openapi.command.impl - finishCommand: name = Renaming method setTestName(String) of class org.mapstruct.intellij.test.examples.SimpleMapper.Target to setNewName, groupId = null 
14:52:40,039 SEVERE                 #TestFramework - Test failed 
com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess$VfsRootAccessNotAllowedError: File accessed outside allowed roots: file://D:/projects/github/mapstruct-idea/testData/usages/RenameTargetReferenceAfter.java;

PsiTestUtil.addLibrary(
myFixture.getProjectDisposable(),
myFixture.getModule(),
Expand Down
109 changes: 109 additions & 0 deletions src/test/java/org/mapstruct/intellij/MapstructCompletionTestCase.java
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,115 @@ public void testFluentGenericTargetMapper() {
);
}

public void testGenericCarWrapperSourceAutoCompleteAfterCar() {
configureByTestName();

assertThat( myItems )
.extracting( LookupElement::getLookupString )
.containsExactlyInAnyOrder(
"winCode"
);

assertThat( myItems )
.extracting( LookupElementPresentation::renderElement )
.usingRecursiveFieldByFieldElementComparator()
.containsExactlyInAnyOrder(
createVariable( "winCode", "String" )
);
}

public void testGenericCarWrapperTargetAutoCompleteAfterCar() {
configureByTestName();

assertThat( myItems )
.extracting( LookupElement::getLookupString )
.containsExactlyInAnyOrder( "winCode" );

assertThat( myItems )
.extracting( LookupElementPresentation::renderElement )
.usingRecursiveFieldByFieldElementComparator()
.containsExactlyInAnyOrder( createVariable( "winCode", "String" ) );
}

public void testGenericCarWrapperSourceAutoCompleteAfterCarWithoutParameterPrefix() {
configureByTestName();

assertThat( myItems )
.extracting( LookupElement::getLookupString )
.containsExactlyInAnyOrder( "winCode" );

assertThat( myItems )
.extracting( LookupElementPresentation::renderElement )
.usingRecursiveFieldByFieldElementComparator()
.containsExactlyInAnyOrder( createVariable( "winCode", "String" ) );
}

public void testGenericConstructorCarMapper() {
configureByTestName();

assertThat( myItems )
.extracting( LookupElement::getLookupString )
.containsExactlyInAnyOrder( "winCode" );

assertThat( myItems )
.extracting( LookupElementPresentation::renderElement )
.usingRecursiveFieldByFieldElementComparator()
.containsExactlyInAnyOrder( createVariable( "winCode", "String" ) );
}

public void testGenericRecordConstructorTargetMapper() {
configureByTestName();

assertThat( myItems )
.extracting( LookupElement::getLookupString )
.containsExactlyInAnyOrder( "winCode" );

assertThat( myItems )
.extracting( LookupElementPresentation::renderElement )
.usingRecursiveFieldByFieldElementComparator()
.usingElementComparatorIgnoringFields( "myIcon", "myTail" )
.containsExactlyInAnyOrder( createParameter( "winCode", "String" ) );
}

public void testGenericConstructorMappingTargetUpdateMapper() {
configureByTestName();

assertThat( myItems )
.extracting( LookupElement::getLookupString )
.containsExactlyInAnyOrder( "winCode" );

assertThat( myItems )
.extracting( LookupElementPresentation::renderElement )
.usingRecursiveFieldByFieldElementComparator()
.containsExactlyInAnyOrder( createVariable( "winCode", "String" ) );
}

public void testGenericTwoTypeParamsConstructorTargetMapper() {
configureByTestName();

assertThat( myItems )
.extracting( LookupElement::getLookupString )
.containsExactlyInAnyOrder( "serial" );

assertThat( myItems )
.extracting( LookupElementPresentation::renderElement )
.usingRecursiveFieldByFieldElementComparator()
.containsExactlyInAnyOrder( createVariable( "serial", "String" ) );
}

public void testGenericNestedGenericTargetMapper() {
configureByTestName();

assertThat( myItems )
.extracting( LookupElement::getLookupString )
.containsExactlyInAnyOrder( "winCode" );

assertThat( myItems )
.extracting( LookupElementPresentation::renderElement )
.usingRecursiveFieldByFieldElementComparator()
.containsExactlyInAnyOrder( createVariable( "winCode", "String" ) );
}

public void testVariantsCarMapperNoSourceClass() {
myFixture.configureByFile( "CarMapperNoSourceClass.java" );
complete();
Expand Down
56 changes: 56 additions & 0 deletions testData/mapping/GenericCarWrapperSourceAutoCompleteAfterCar.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at https://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.ap.test.complex;

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;

@Mapper
public interface GenericCarWrapperMapper {

@Mapping(target = "id", source = "wrapper.car.<caret>winCode")
CarEntity toCarDto(CarWrapper<Car> wrapper);
}

class CarEntity {

private String id;

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

}

class Car {

private String winCode;

public String getWinCode() {
return winCode;
}

public void setWinCode(String winCode) {
this.winCode = winCode;
}
}

class CarWrapper<T> {

private T car;

public T getCar() {
return car;
}

public void setCar(T car) {
this.car = car;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at https://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.ap.test.complex;

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;

@Mapper
public interface GenericCarWrapperSourceAutoCompleteAfterCarWithoutParameterPrefix {
@Mapping(target = "id", source = "car.<caret>winCode")
CarEntity toCarDto(CarWrapper<Car> wrapper);
}

class CarEntity {
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}

class Car {
private String winCode;
public String getWinCode() {
return winCode;
}
public void setWinCode(String winCode) {
this.winCode = winCode;
}
}

class CarWrapper<T> {
private T car;
public T getCar() {
return car;
}
public void setCar(T car) {
this.car = car;
}
}
Loading