diff --git a/monticore-grammar/src/main/java/de/monticore/types/check/ISynthesizeComponent.java b/monticore-grammar/src/main/java/de/monticore/types/check/ISynthesizeComponent.java index 3bfd7cdfae..c871e5fdb3 100644 --- a/monticore-grammar/src/main/java/de/monticore/types/check/ISynthesizeComponent.java +++ b/monticore-grammar/src/main/java/de/monticore/types/check/ISynthesizeComponent.java @@ -3,6 +3,7 @@ import de.monticore.types.mcbasictypes._ast.ASTMCType; import de.monticore.types.mcbasictypes._visitor.MCBasicTypesTraverser; +import de.se_rwth.commons.logging.Log; import org.checkerframework.checker.nullness.qual.NonNull; import java.util.Optional; @@ -30,6 +31,12 @@ public interface ISynthesizeComponent { default Optional synthesize(@NonNull ASTMCType mcType) { this.init(); mcType.accept(this.getTraverser()); - return this.getResult(); + Optional res = this.getResult(); + if (res.isEmpty()) { + Log.error(String.format("0xD0104 Cannot resolve component '%s'", mcType.toString()), + mcType.get_SourcePositionStart(), mcType.get_SourcePositionEnd() + ); + } + return res; } } diff --git a/monticore-grammar/src/main/java/de/monticore/types/check/SynthesizeCompKindFromMCBasicTypes.java b/monticore-grammar/src/main/java/de/monticore/types/check/SynthesizeCompKindFromMCBasicTypes.java index f6764719d9..a304dc16f2 100644 --- a/monticore-grammar/src/main/java/de/monticore/types/check/SynthesizeCompKindFromMCBasicTypes.java +++ b/monticore-grammar/src/main/java/de/monticore/types/check/SynthesizeCompKindFromMCBasicTypes.java @@ -50,9 +50,6 @@ public void handle(@NonNull ASTMCQualifiedType node) { List comp = enclScope.resolveComponentTypeMany(node.getMCQualifiedName().getQName()); if (comp.isEmpty()) { - Log.error(String.format("0xD0104 Cannot resolve component '%s'", node.getMCQualifiedName().getQName()), - node.get_SourcePositionStart(), node.get_SourcePositionEnd() - ); this.resultWrapper.setResultAbsent(); } else { CompKindExpression result = new CompKindOfComponentType(comp.get(0)); diff --git a/monticore-grammar/src/main/java/de/monticore/types/check/SynthesizeCompKindFromMCSimpleGenericTypes.java b/monticore-grammar/src/main/java/de/monticore/types/check/SynthesizeCompKindFromMCSimpleGenericTypes.java index f00e3a05db..ecbf75a2ad 100644 --- a/monticore-grammar/src/main/java/de/monticore/types/check/SynthesizeCompKindFromMCSimpleGenericTypes.java +++ b/monticore-grammar/src/main/java/de/monticore/types/check/SynthesizeCompKindFromMCSimpleGenericTypes.java @@ -57,9 +57,6 @@ public void handle(@NonNull ASTMCBasicGenericType mcType) { List compSym = enclScope.resolveComponentTypeMany(compName); if (compSym.isEmpty()) { - Log.error(String.format("0xD0104 Cannot resolve component '%s'", mcType.getNameList().stream().reduce("", String::concat)), - mcType.get_SourcePositionStart(), mcType.get_SourcePositionEnd() - ); this.resultWrapper.setResultAbsent(); } else { if (compSym.size() > 1) { diff --git a/monticore-grammar/src/test/grammars/de/monticore/types/ComponentSymbolsWithMCBasicTypesTest.mc4 b/monticore-grammar/src/test/grammars/de/monticore/types/ComponentSymbolsWithMCBasicTypesTest.mc4 new file mode 100644 index 0000000000..0fcc3b9ec2 --- /dev/null +++ b/monticore-grammar/src/test/grammars/de/monticore/types/ComponentSymbolsWithMCBasicTypesTest.mc4 @@ -0,0 +1,10 @@ +/* (c) https://github.com/MontiCore/monticore */ + +package de.monticore.types; + +component grammar ComponentSymbolsWithMCBasicTypesTest extends + de.monticore.symbols.CompSymbols, + de.monticore.symbols.OOSymbols, + de.monticore.types.MCBasicTypes, + de.monticore.types.MCSimpleGenericTypes { +} \ No newline at end of file diff --git a/monticore-grammar/src/test/java/de/monticore/types/check/FullSynthesizeCompKindFromMCBasicTypesTest.java b/monticore-grammar/src/test/java/de/monticore/types/check/FullSynthesizeCompKindFromMCBasicTypesTest.java new file mode 100644 index 0000000000..4a38b76014 --- /dev/null +++ b/monticore-grammar/src/test/java/de/monticore/types/check/FullSynthesizeCompKindFromMCBasicTypesTest.java @@ -0,0 +1,67 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.types.check; + +import de.monticore.runtime.junit.AbstractMCTest; +import de.monticore.runtime.junit.MCAssertions; +import de.monticore.symbols.compsymbols._symboltable.ComponentTypeSymbol; +import de.monticore.types.MCTypeFacade; +import de.monticore.types.componentsymbolswithmcbasictypestest.ComponentSymbolsWithMCBasicTypesTestMill; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Optional; + +public class FullSynthesizeCompKindFromMCBasicTypesTest extends AbstractMCTest { + + @BeforeEach + public void setup() { + LogStub.init(); + Log.enableFailQuick(false); + Log.clearFindings(); + + ComponentSymbolsWithMCBasicTypesTestMill.reset(); + ComponentSymbolsWithMCBasicTypesTestMill.init(); + } + + @Test + public void synthesizesCompKind_forResolvableComponentTypeSymbol() { + // Given + ComponentTypeSymbol typeA = ComponentSymbolsWithMCBasicTypesTestMill.componentTypeSymbolBuilder() + .setName("A") + .setSpannedScope(ComponentSymbolsWithMCBasicTypesTestMill.scope()) + .build(); + ComponentSymbolsWithMCBasicTypesTestMill.globalScope().add(typeA); + typeA.setEnclosingScope(ComponentSymbolsWithMCBasicTypesTestMill.globalScope()); + + ASTMCType ast = MCTypeFacade.getInstance().createQualifiedType("A"); + ast.setEnclosingScope(ComponentSymbolsWithMCBasicTypesTestMill.globalScope()); + + FullSynthesizeCompKindFromMCBasicTypes synth = new FullSynthesizeCompKindFromMCBasicTypes(); + + // When + Optional res = synth.synthesize(ast); + + // Then + Assertions.assertTrue(res.isPresent()); + Assertions.assertTrue(res.get().isComponentType()); + Assertions.assertEquals(typeA, res.get().getTypeInfo()); + } + + @Test + public void shouldLogErrorOnPrimitive() { + // Given + ASTMCType ast = MCTypeFacade.getInstance().createIntType(); + FullSynthesizeCompKindFromMCBasicTypes synth = new FullSynthesizeCompKindFromMCBasicTypes(); + + // When + Optional result = synth.synthesize(ast); + + // Then + Assertions.assertTrue(result.isEmpty(), "Expected no CompKindExpression for primitive 'int'"); + MCAssertions.assertHasFindingStartingWith("0xD0104"); + } +} diff --git a/monticore-grammar/src/test/java/de/monticore/types/check/SynthesizeComponentFromMCBasicTypesTest.java b/monticore-grammar/src/test/java/de/monticore/types/check/SynthesizeComponentFromMCBasicTypesTest.java new file mode 100644 index 0000000000..c3a57cdfa6 --- /dev/null +++ b/monticore-grammar/src/test/java/de/monticore/types/check/SynthesizeComponentFromMCBasicTypesTest.java @@ -0,0 +1,139 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.types.check; + +import de.monticore.runtime.junit.AbstractMCTest; +import de.monticore.runtime.junit.MCAssertions; +import de.monticore.symbols.compsymbols._symboltable.ComponentTypeSymbol; +import de.monticore.types.MCTypeFacade; +import de.monticore.types.componentsymbolswithmcbasictypestest.ComponentSymbolsWithMCBasicTypesTestMill; +import de.monticore.types.componentsymbolswithmcbasictypestest._visitor.ComponentSymbolsWithMCBasicTypesTestTraverser; +import de.monticore.types.mcbasictypes._ast.ASTMCQualifiedType; +import de.monticore.types.mcbasictypes._ast.ASTMCVoidType; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +public class SynthesizeComponentFromMCBasicTypesTest extends AbstractMCTest { + + @BeforeEach + public void setup() { + LogStub.init(); + Log.enableFailQuick(false); + Log.clearFindings(); + + ComponentSymbolsWithMCBasicTypesTestMill.reset(); + ComponentSymbolsWithMCBasicTypesTestMill.init(); + } + + @ParameterizedTest + @ValueSource(strings = {"Foo", "qual.Foo"}) + public void shouldHandleMCQualifiedType(String qualifiedCompName) { + var globalScope = ComponentSymbolsWithMCBasicTypesTestMill.globalScope(); + + ASTMCQualifiedType ast = MCTypeFacade.getInstance().createQualifiedType(qualifiedCompName); + ast.setEnclosingScope(globalScope); + + ComponentTypeSymbol symbol = ComponentSymbolsWithMCBasicTypesTestMill.componentTypeSymbolBuilder() + .setName(ast.getMCQualifiedName().getBaseName()) + .setSpannedScope(ComponentSymbolsWithMCBasicTypesTestMill.scope()) + .build(); + + if (qualifiedCompName.equals("qual.Foo")) { + var qualScope = ComponentSymbolsWithMCBasicTypesTestMill.scope(); + qualScope.setName("qual"); + qualScope.add(symbol); + qualScope.addSubScope(symbol.getSpannedScope()); + globalScope.addSubScope(qualScope); + } else { + globalScope.add(symbol); + globalScope.addSubScope(symbol.getSpannedScope()); + } + + CompKindCheckResult result = new CompKindCheckResult(); + SynthesizeCompKindFromMCBasicTypes synth = + new SynthesizeCompKindFromMCBasicTypes(result); + + // When + synth.handle(ast); + + // Then + Assertions.assertTrue(result.getResult().isPresent()); + Assertions.assertTrue(result.getResult().get().isComponentType()); + Assertions.assertEquals(symbol, result.getResult().get().getTypeInfo()); + } + + @Test + public void shouldLogErrorForDuplicateSymbols() { + // Given + ASTMCQualifiedType ast = MCTypeFacade.getInstance().createQualifiedType("Foo"); + ast.setEnclosingScope(ComponentSymbolsWithMCBasicTypesTestMill.globalScope()); + + + ComponentTypeSymbol compSymbol1 = ComponentSymbolsWithMCBasicTypesTestMill.componentTypeSymbolBuilder() + .setName(ast.getMCQualifiedName().getBaseName()) + .setSpannedScope(ComponentSymbolsWithMCBasicTypesTestMill.scope()) + .build(); + ComponentSymbolsWithMCBasicTypesTestMill.globalScope().add(compSymbol1); + ComponentSymbolsWithMCBasicTypesTestMill.globalScope().addSubScope(compSymbol1.getSpannedScope()); + + ComponentTypeSymbol compSymbol2 = ComponentSymbolsWithMCBasicTypesTestMill.componentTypeSymbolBuilder() + .setName(ast.getMCQualifiedName().getBaseName()) + .setSpannedScope(ComponentSymbolsWithMCBasicTypesTestMill.scope()) + .build(); + ComponentSymbolsWithMCBasicTypesTestMill.globalScope().add(compSymbol2); + ComponentSymbolsWithMCBasicTypesTestMill.globalScope().addSubScope(compSymbol2.getSpannedScope()); + + CompKindCheckResult result = new CompKindCheckResult(); + SynthesizeCompKindFromMCBasicTypes synth = new SynthesizeCompKindFromMCBasicTypes(result); + + // When + synth.handle(ast); + + // Then + Assertions.assertTrue(result.getResult().isPresent()); + Assertions.assertTrue(result.getResult().get().isComponentType()); + Assertions.assertEquals(compSymbol1, result.getResult().get().getTypeInfo()); + MCAssertions.assertHasFindingStartingWith("0xD0105"); + } + + @ParameterizedTest + @ValueSource(strings = {"Foo", "qual.Foo"}) + public void shouldNotLogErrorForMissingSymbol(String qualifiedName) { + // Given + ASTMCQualifiedType astNormalComp = MCTypeFacade.getInstance().createQualifiedType(qualifiedName); + astNormalComp.setEnclosingScope(ComponentSymbolsWithMCBasicTypesTestMill.globalScope()); + + CompKindCheckResult result = new CompKindCheckResult(); + SynthesizeCompKindFromMCBasicTypes synth4normal = new SynthesizeCompKindFromMCBasicTypes(result); + + // When + synth4normal.handle(astNormalComp); + + // Then + Assertions.assertFalse(result.getResult().isPresent()); + } + + @Test + public void shouldNotHandleVoidType() { + // Given + ASTMCVoidType voidType = ComponentSymbolsWithMCBasicTypesTestMill.mCVoidTypeBuilder().build(); + CompKindCheckResult resultWrapper = new CompKindCheckResult(); + SynthesizeCompKindFromMCBasicTypes synth = new SynthesizeCompKindFromMCBasicTypes(resultWrapper); + + // Attach a traverser to the synth, as we do not override the handle method and thus the synth tries to traverse the + // AST. In the end this should result in an empty synth result, however, if we do not attach a traverser, this will + // Result in an error instead. + ComponentSymbolsWithMCBasicTypesTestTraverser traverser = ComponentSymbolsWithMCBasicTypesTestMill.traverser(); + traverser.setMCBasicTypesHandler(synth); + + // When + synth.handle(voidType); + + // Then + Assertions.assertFalse(resultWrapper.getResult().isPresent()); + } +} diff --git a/monticore-grammar/src/test/java/de/monticore/types/check/SynthesizeComponentFromMCSimpleGenericTypesTest.java b/monticore-grammar/src/test/java/de/monticore/types/check/SynthesizeComponentFromMCSimpleGenericTypesTest.java new file mode 100644 index 0000000000..7c5e00d8cd --- /dev/null +++ b/monticore-grammar/src/test/java/de/monticore/types/check/SynthesizeComponentFromMCSimpleGenericTypesTest.java @@ -0,0 +1,286 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.types.check; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import de.monticore.runtime.junit.AbstractMCTest; +import de.monticore.runtime.junit.MCAssertions; +import de.monticore.symbols.basicsymbols.BasicSymbolsMill; +import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol; +import de.monticore.symbols.compsymbols._symboltable.ComponentTypeSymbol; +import de.monticore.symbols.oosymbols._symboltable.OOTypeSymbol; +import de.monticore.types.MCTypeFacade; +import de.monticore.types.componentsymbolswithmcbasictypestest.ComponentSymbolsWithMCBasicTypesTestMill; +import de.monticore.types.componentsymbolswithmcbasictypestest._symboltable.IComponentSymbolsWithMCBasicTypesTestScope; +import de.monticore.types.mcbasictypes._ast.ASTMCPrimitiveType; +import de.monticore.types.mcbasictypes._ast.ASTMCQualifiedType; +import de.monticore.types.mcbasictypes._ast.ASTMCType; +import de.monticore.types.mcbasictypes.types3.MCBasicTypesTypeVisitor; +import de.monticore.types.mccollectiontypes._ast.ASTMCBasicTypeArgument; +import de.monticore.types.mccollectiontypes._ast.ASTMCPrimitiveTypeArgument; +import de.monticore.types.mccollectiontypes.types3.MCCollectionTypesTypeVisitor; +import de.monticore.types.mcsimplegenerictypes._ast.ASTMCBasicGenericType; +import de.monticore.types.mcsimplegenerictypes._ast.ASTMCBasicGenericTypeBuilder; +import de.monticore.types.mcsimplegenerictypes._ast.ASTMCCustomTypeArgument; +import de.monticore.types.mcsimplegenerictypes.types3.MCSimpleGenericTypesTypeVisitor; +import de.monticore.types3.Type4Ast; +import de.monticore.types3.generics.context.InferenceContext4Ast; +import de.monticore.types3.util.MapBasedTypeCheck3; +import de.se_rwth.commons.logging.Log; +import de.se_rwth.commons.logging.LogStub; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.provider.ValueSource; + +import javax.annotation.Nonnull; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +public class SynthesizeComponentFromMCSimpleGenericTypesTest extends AbstractMCTest { + + @BeforeEach + public void setup() { + Log.clearFindings(); + LogStub.init(); + Log.enableFailQuick(false); + Log.clearFindings(); + + ComponentSymbolsWithMCBasicTypesTestMill.reset(); + ComponentSymbolsWithMCBasicTypesTestMill.init(); + BasicSymbolsMill.initializePrimitives(); + BasicSymbolsMill.initializeString(); + + Type4Ast type4Ast = new Type4Ast(); + InferenceContext4Ast ctx4Ast = new InferenceContext4Ast(); + + var traverser = ComponentSymbolsWithMCBasicTypesTestMill.traverser(); + + MCBasicTypesTypeVisitor basicTypesVisitor = new MCBasicTypesTypeVisitor(); + basicTypesVisitor.setType4Ast(type4Ast); + traverser.add4MCBasicTypes(basicTypesVisitor); + + MCCollectionTypesTypeVisitor collVisitor = new MCCollectionTypesTypeVisitor(); + collVisitor.setType4Ast(type4Ast); + traverser.add4MCCollectionTypes(collVisitor); + + MCSimpleGenericTypesTypeVisitor simpleGenVisitor = new MCSimpleGenericTypesTypeVisitor(); + simpleGenVisitor.setType4Ast(type4Ast); + traverser.add4MCSimpleGenericTypes(simpleGenVisitor); + + new MapBasedTypeCheck3(traverser, type4Ast, ctx4Ast).setThisAsDelegate(); + } + + @ParameterizedTest + @ValueSource(strings = {"Comp", "scoop.Comp"}) + public void shouldHandleMCBasicGenericType(String qualifiedCompName) { + // Given + var globalScope = ComponentSymbolsWithMCBasicTypesTestMill.globalScope(); + + IComponentSymbolsWithMCBasicTypesTestScope localScope = ComponentSymbolsWithMCBasicTypesTestMill.scope(); + localScope.setName("scoop"); + globalScope.addSubScope(localScope); + + ComponentTypeSymbol compSym = createComponentType("Comp", "K", "V"); + addWithSpannedScope(localScope, compSym); + + TypeSymbol stringSym = BasicSymbolsMill.globalScope() + .resolveType(BasicSymbolsMill.STRING) + .orElseThrow(); + + OOTypeSymbol listSym = ComponentSymbolsWithMCBasicTypesTestMill.oOTypeSymbolBuilder() + .setName("List") + .setSpannedScope(ComponentSymbolsWithMCBasicTypesTestMill.scope()) + .build(); + listSym.addTypeVarSymbol(ComponentSymbolsWithMCBasicTypesTestMill.typeVarSymbolBuilder().setName("T").build()); + addWithSpannedScope(localScope, listSym); + + ASTMCQualifiedType astStringLocal = createQualifiedType( + ImmutableList.of("String"), + localScope, + localScope + ); + + ASTMCType astListOfStringLocal = createGenericType( + ImmutableList.of("List"), + localScope, + astStringLocal + ); + + ASTMCQualifiedType compNameAst = MCTypeFacade.getInstance().createQualifiedType(qualifiedCompName); + List compNameParts = compNameAst.getMCQualifiedName().getPartsList(); + boolean qualified = compNameParts.size() > 1; + + IComponentSymbolsWithMCBasicTypesTestScope enclScope = qualified ? globalScope : localScope; + + ASTMCBasicGenericType astComp = createGenericType( + compNameParts, + enclScope, + astStringLocal, + astListOfStringLocal + ); + + // When + CompKindCheckResult wrapper = new CompKindCheckResult(); + new SynthesizeCompKindFromMCSimpleGenericTypes(wrapper).handle(astComp); + + // Then + Assertions.assertTrue(wrapper.getResult().isPresent(), "Expected synthesis result to be present"); + Assertions.assertInstanceOf(CompKindOfGenericComponentType.class, wrapper.getResult().get()); + CompKindOfGenericComponentType result = (CompKindOfGenericComponentType) wrapper.getResult().get(); + + Assertions.assertEquals(compSym, result.getTypeInfo()); + Assertions.assertEquals(astComp, result.getSourceNode().orElseThrow()); + + Assertions.assertEquals(stringSym, result.getTypeBindingFor("K").orElseThrow().getTypeInfo()); + + SymTypeExpression v = result.getTypeBindingFor("V").orElseThrow(); + Assertions.assertInstanceOf(SymTypeOfGenerics.class, v); + SymTypeOfGenerics vGen = (SymTypeOfGenerics) v; + Assertions.assertEquals(listSym, vGen.getTypeInfo()); + Assertions.assertEquals(stringSym, vGen.getArgument(0).getTypeInfo()); + + MCAssertions.assertNoFindings(); + } + + @Test + public void shouldNotHandleMCBasicGenericTypeBecauseCompTypeUnresolvable() { + // Given + ASTMCQualifiedType astString = createQualifiedType( + ImmutableList.of("String"), + ComponentSymbolsWithMCBasicTypesTestMill.globalScope(), + ComponentSymbolsWithMCBasicTypesTestMill.globalScope() + ); + + ASTMCBasicGenericType astComp = createGenericType( + ImmutableList.of("Unresolvable"), + ComponentSymbolsWithMCBasicTypesTestMill.globalScope(), + astString + ); + + // When + CompKindCheckResult wrapper = new CompKindCheckResult(); + new SynthesizeCompKindFromMCSimpleGenericTypes(wrapper).handle(astComp); + + // Then + Assertions.assertTrue(wrapper.getResult().isEmpty()); + } + + @Test + public void shouldLogErrorForDuplicateSymbols() { + // Given + IComponentSymbolsWithMCBasicTypesTestScope localScope = ComponentSymbolsWithMCBasicTypesTestMill.scope(); + localScope.setName("scoop"); + ComponentSymbolsWithMCBasicTypesTestMill.globalScope().addSubScope(localScope); + + ComponentTypeSymbol comp1 = createComponentType("Comp", "T"); + ComponentTypeSymbol comp2 = createComponentType("Comp", "T"); + addWithSpannedScope(localScope, comp1); + addWithSpannedScope(localScope, comp2); + + ASTMCQualifiedType astString = createQualifiedType( + ImmutableList.of("String"), + localScope, + localScope + ); + + ASTMCBasicGenericType astComp = createGenericType( + ImmutableList.of("Comp"), + localScope, + astString + ); + + // When + CompKindCheckResult wrapper = new CompKindCheckResult(); + new SynthesizeCompKindFromMCSimpleGenericTypes(wrapper).handle(astComp); + + // Then + MCAssertions.assertHasFindingStartingWith("0xD0105"); + Assertions.assertTrue(wrapper.getResult().isPresent()); + Assertions.assertInstanceOf(CompKindOfGenericComponentType.class, wrapper.getResult().get()); + Assertions.assertEquals(astComp, wrapper.getResult().get().getSourceNode().orElseThrow()); + } + + private static void addWithSpannedScope(IComponentSymbolsWithMCBasicTypesTestScope scope, ComponentTypeSymbol sym) { + scope.add(sym); + scope.addSubScope(sym.getSpannedScope()); + } + + private static void addWithSpannedScope(IComponentSymbolsWithMCBasicTypesTestScope scope, OOTypeSymbol sym) { + scope.add(sym); + scope.addSubScope(sym.getSpannedScope()); + } + + private static ComponentTypeSymbol createComponentType(String name, String... typeParams) { + var builder = ComponentSymbolsWithMCBasicTypesTestMill.componentTypeSymbolBuilder() + .setName(name) + .setSpannedScope(ComponentSymbolsWithMCBasicTypesTestMill.scope()); + + builder.setTypeParameters( + Arrays.stream(typeParams) + .map(tp -> ComponentSymbolsWithMCBasicTypesTestMill.typeVarSymbolBuilder().setName(tp).build()) + .collect(ImmutableList.toImmutableList()) + ); + + return builder.build(); + } + + private static ASTMCQualifiedType createQualifiedType( + List nameParts, + IComponentSymbolsWithMCBasicTypesTestScope typeEnclosingScope, + IComponentSymbolsWithMCBasicTypesTestScope nameEnclosingScope + ) { + ASTMCQualifiedType type = ComponentSymbolsWithMCBasicTypesTestMill.mCQualifiedTypeBuilder() + .setMCQualifiedName(ComponentSymbolsWithMCBasicTypesTestMill.mCQualifiedNameBuilder() + .addAllParts(nameParts) + .build()) + .build(); + + type.setEnclosingScope(typeEnclosingScope); + type.getMCQualifiedName().setEnclosingScope(nameEnclosingScope); + return type; + } + + /** + * Returns a {@link ASTMCBasicGenericType} whose format is {@code name.parts}. + * All newly created AST objects are enclosed by {@code enclScope}. + */ + protected static ASTMCBasicGenericType createGenericType(@Nonnull List nameParts, + @Nonnull IComponentSymbolsWithMCBasicTypesTestScope enclScope, + @Nonnull ASTMCType... typeArgs) { + Preconditions.checkNotNull(nameParts); + Preconditions.checkNotNull(enclScope); + Preconditions.checkNotNull(typeArgs); + Preconditions.checkArgument(Arrays.stream(typeArgs).allMatch(Objects::nonNull)); + + ASTMCBasicGenericTypeBuilder builder = ComponentSymbolsWithMCBasicTypesTestMill.mCBasicGenericTypeBuilder() + .setNamesList(nameParts); + + for (ASTMCType typeArg : typeArgs) { + if (typeArg instanceof ASTMCPrimitiveType) { + ASTMCPrimitiveType asPrimitiveType = (ASTMCPrimitiveType) typeArg; + ASTMCPrimitiveTypeArgument asArg = ComponentSymbolsWithMCBasicTypesTestMill.mCPrimitiveTypeArgumentBuilder() + .setMCPrimitiveType(asPrimitiveType).build(); + asArg.setEnclosingScope(enclScope); + builder.addMCTypeArgument(asArg); + + } else if (typeArg instanceof ASTMCQualifiedType) { + ASTMCQualifiedType asQualType = (ASTMCQualifiedType) typeArg; + ASTMCBasicTypeArgument asArg = ComponentSymbolsWithMCBasicTypesTestMill.mCBasicTypeArgumentBuilder().setMCQualifiedType(asQualType).build(); + asArg.setEnclosingScope(enclScope); + builder.addMCTypeArgument(asArg); + + } else { + ASTMCCustomTypeArgument asArg = ComponentSymbolsWithMCBasicTypesTestMill.mCCustomTypeArgumentBuilder().setMCType(typeArg).build(); + asArg.setEnclosingScope(enclScope); + builder.addMCTypeArgument(asArg); + } + } + + ASTMCBasicGenericType type = builder.build(); + type.setEnclosingScope(enclScope); + return type; + } +}