Skip to content

Commit 9188a98

Browse files
committed
Refactor CodeAdapter.java
1 parent 61c0d25 commit 9188a98

9 files changed

Lines changed: 624 additions & 535 deletions

File tree

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
package de.monticore.codeAdaption;
2+
3+
import de.monticore.cdbasis._ast.ASTCDCompilationUnit;
4+
import de.monticore.cdbasis._ast.ASTCDType;
5+
import de.monticore.codeAdaption.handler.multiIncarnation.IncarnationContext;
6+
import de.monticore.codeAdaption.utils.AdapterUtils;
7+
import de.monticore.codeAdaption.utils.CDModelIndex;
8+
import de.monticore.codeAdaption.utils.JavaSourceNames;
9+
import de.monticore.codeAdaption.utils.visitors.JavaAstElemCollector;
10+
import de.monticore.codeAdaption.validator.CodeValidator;
11+
import de.monticore.java.javadsl.JavaDSLMill;
12+
import de.monticore.java.javadsl._ast.ASTOrdinaryCompilationUnit;
13+
import de.monticore.java.javadsl._ast.ASTTypeDeclaration;
14+
import de.monticore.java.javadsl._visitor.JavaDSLTraverser;
15+
import de.monticore.symboltable.ISymbol;
16+
import de.se_rwth.commons.logging.Log;
17+
import java.util.ArrayList;
18+
import java.util.LinkedHashMap;
19+
import java.util.LinkedHashSet;
20+
import java.util.List;
21+
import java.util.Map;
22+
import java.util.Optional;
23+
import java.util.Set;
24+
25+
/** Merges, filters, splits, and deduplicates Java AST units produced by mapping runs. */
26+
final class AdaptedCodeMerger {
27+
28+
Set<ASTOrdinaryCompilationUnit> mergeAdaptedCode(
29+
Set<ASTOrdinaryCompilationUnit> actualCode,
30+
Set<ASTOrdinaryCompilationUnit> newAdaptedCode) {
31+
if (actualCode.isEmpty()) {
32+
return deduplicateBySimpleName(newAdaptedCode);
33+
}
34+
35+
Set<ASTOrdinaryCompilationUnit> deduplicatedNew = deduplicateBySimpleName(newAdaptedCode);
36+
37+
for (ASTOrdinaryCompilationUnit newAdapted : deduplicatedNew) {
38+
String newSimpleName = AdapterUtils.getSimpleFileName(newAdapted);
39+
40+
Optional<ASTOrdinaryCompilationUnit> actual =
41+
actualCode.stream()
42+
.filter(file -> AdapterUtils.getSimpleFileName(file).equals(newSimpleName))
43+
.findAny();
44+
45+
if (actual.isEmpty()) {
46+
actualCode.add(newAdapted);
47+
} else {
48+
actualCode.remove(actual.get());
49+
actualCode.add(AdapterUtils.mergeAsts(actual.get(), newAdapted));
50+
}
51+
}
52+
return actualCode;
53+
}
54+
55+
Set<ASTOrdinaryCompilationUnit> filterCodeForMapping(
56+
Set<ASTOrdinaryCompilationUnit> javaFiles,
57+
CodeValidator validator,
58+
IncarnationContext context) {
59+
validator.initializeTypeMatcher(javaFiles);
60+
Set<ASTOrdinaryCompilationUnit> result = new LinkedHashSet<>();
61+
for (ASTOrdinaryCompilationUnit unit : javaFiles) {
62+
JavaAstElemCollector collector = collect(unit);
63+
64+
boolean mappedTopLevel =
65+
collector.getAllTypeDeclarations().stream()
66+
.map(validator::getMatchedType)
67+
.filter(Optional::isPresent)
68+
.map(Optional::get)
69+
.flatMap(matching -> matching.getReferences().stream())
70+
.anyMatch(
71+
reference -> {
72+
List<ISymbol> incarnations = context.getIncarnations(reference);
73+
return incarnations != null && !incarnations.isEmpty();
74+
});
75+
boolean ignoredTopLevel =
76+
collector.getAllTypeDeclarations().stream()
77+
.map(validator::getMatchedType)
78+
.filter(Optional::isPresent)
79+
.map(Optional::get)
80+
.anyMatch(matching -> !matching.mustBePerform());
81+
if (mappedTopLevel || ignoredTopLevel) {
82+
result.add(unit);
83+
}
84+
}
85+
return result;
86+
}
87+
88+
/**
89+
* Builds the final generated code on top of concrete handwritten classes. Adapted pattern types
90+
* with the same simple file name are merged into the concrete class, while reference-only
91+
* template artifacts such are filtered out.
92+
*/
93+
Set<ASTOrdinaryCompilationUnit> mergeAdaptedCodeIntoConcreteBase(
94+
Set<ASTOrdinaryCompilationUnit> concreteCode,
95+
Set<ASTOrdinaryCompilationUnit> adaptedCode,
96+
ASTCDCompilationUnit conCD) {
97+
98+
Set<String> concreteTypeNames =
99+
CDModelIndex.of(conCD).types().stream()
100+
.map(ASTCDType::getName)
101+
.collect(java.util.stream.Collectors.toCollection(LinkedHashSet::new));
102+
103+
Set<ASTOrdinaryCompilationUnit> result =
104+
new LinkedHashSet<>(deduplicateBySimpleName(concreteCode));
105+
106+
for (ASTOrdinaryCompilationUnit adaptedUnit : deduplicateBySimpleName(adaptedCode)) {
107+
String adaptedTypeName = getPrimaryTypeName(adaptedUnit).orElse("");
108+
if (!shouldKeepAdaptedUnit(adaptedTypeName, concreteTypeNames)) {
109+
continue;
110+
}
111+
112+
String adaptedFileName = AdapterUtils.getSimpleFileName(adaptedUnit);
113+
Optional<ASTOrdinaryCompilationUnit> concreteMatch =
114+
result.stream()
115+
.filter(unit -> AdapterUtils.getSimpleFileName(unit).equals(adaptedFileName))
116+
.findFirst();
117+
118+
if (concreteMatch.isPresent()) {
119+
result.remove(concreteMatch.get());
120+
result.add(AdapterUtils.mergeAsts(concreteMatch.get(), adaptedUnit));
121+
} else {
122+
result.add(adaptedUnit);
123+
}
124+
}
125+
126+
return deduplicateBySimpleName(result);
127+
}
128+
129+
Set<ASTOrdinaryCompilationUnit> splitCompilationUnitsByType(
130+
Set<ASTOrdinaryCompilationUnit> units) {
131+
Set<ASTOrdinaryCompilationUnit> result = new LinkedHashSet<>();
132+
for (ASTOrdinaryCompilationUnit unit : units) {
133+
JavaAstElemCollector collector = collect(unit);
134+
List<ASTTypeDeclaration> types = new ArrayList<>(collector.getAllTypeDeclarations());
135+
if (types.size() <= 1) {
136+
result.add(unit);
137+
continue;
138+
}
139+
140+
for (ASTTypeDeclaration type : types) {
141+
ASTOrdinaryCompilationUnit copy = unit.deepClone();
142+
JavaAstElemCollector copyCollector = collect(copy);
143+
for (ASTTypeDeclaration copiedType : copyCollector.getAllTypeDeclarations()) {
144+
if (!copiedType.getName().equals(type.getName())) {
145+
copy.removeTypeDeclaration(copiedType);
146+
}
147+
}
148+
149+
String fileName = type.getName() + ".java";
150+
copy.get_SourcePositionStart().setFileName(fileName);
151+
Log.info("splitCompilationUnitsByType -> created unit: " + fileName, "CodeAdapter");
152+
result.add(copy);
153+
}
154+
}
155+
return result;
156+
}
157+
158+
private boolean shouldKeepAdaptedUnit(String typeName, Set<String> concreteTypeNames) {
159+
if (typeName == null || typeName.isEmpty()) {
160+
return false;
161+
}
162+
if (concreteTypeNames.contains(typeName)) {
163+
return true;
164+
}
165+
return concreteTypeNames.stream()
166+
.anyMatch(
167+
concreteName -> typeName.startsWith(concreteName) || typeName.endsWith(concreteName));
168+
}
169+
170+
private Optional<String> getPrimaryTypeName(ASTOrdinaryCompilationUnit unit) {
171+
return collect(unit).getAllTypeDeclarations().stream()
172+
.map(ASTTypeDeclaration::getName)
173+
.findFirst();
174+
}
175+
176+
private Set<ASTOrdinaryCompilationUnit> deduplicateBySimpleName(
177+
Set<ASTOrdinaryCompilationUnit> files) {
178+
Map<String, ASTOrdinaryCompilationUnit> bySimpleName = new LinkedHashMap<>();
179+
180+
for (ASTOrdinaryCompilationUnit file : files) {
181+
String simpleName = AdapterUtils.getSimpleFileName(file);
182+
String fullPath = AdapterUtils.getFileName(file);
183+
184+
ASTOrdinaryCompilationUnit existing = bySimpleName.get(simpleName);
185+
if (existing == null) {
186+
bySimpleName.put(simpleName, file);
187+
} else {
188+
String existingPath = AdapterUtils.getFileName(existing);
189+
if (JavaSourceNames.pathDepth(fullPath) > JavaSourceNames.pathDepth(existingPath)) {
190+
bySimpleName.put(simpleName, file);
191+
}
192+
}
193+
}
194+
195+
return new LinkedHashSet<>(bySimpleName.values());
196+
}
197+
198+
private JavaAstElemCollector collect(ASTOrdinaryCompilationUnit unit) {
199+
JavaAstElemCollector collector = new JavaAstElemCollector();
200+
JavaDSLTraverser traverser = JavaDSLMill.traverser();
201+
traverser.add4JavaDSL(collector);
202+
unit.accept(traverser);
203+
return collector;
204+
}
205+
}

0 commit comments

Comments
 (0)